summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
Diffstat (limited to 'includes')
-rw-r--r--includes/AjaxDispatcher.php12
-rw-r--r--includes/AjaxResponse.php30
-rw-r--r--includes/AuthPlugin.php16
-rw-r--r--includes/Block.php158
-rw-r--r--includes/CategoryFinder.php4
-rw-r--r--includes/CategoryViewer.php2
-rw-r--r--includes/Collation.php8
-rw-r--r--includes/DefaultSettings.php563
-rw-r--r--includes/Defines.php7
-rw-r--r--includes/EditPage.php137
-rw-r--r--includes/Export.php4
-rw-r--r--includes/FileDeleteForm.php4
-rw-r--r--includes/GitInfo.php4
-rw-r--r--includes/GlobalFunctions.php265
-rw-r--r--includes/HistoryBlob.php8
-rw-r--r--includes/Hooks.php21
-rw-r--r--includes/Html.php111
-rw-r--r--includes/HttpFunctions.php6
-rw-r--r--includes/Import.php69
-rw-r--r--includes/Linker.php88
-rw-r--r--includes/MWNamespace.php12
-rw-r--r--includes/MWTimestamp.php42
-rw-r--r--includes/MagicWord.php13
-rw-r--r--includes/MediaWiki.php282
-rw-r--r--includes/Message.php81
-rw-r--r--includes/MimeMagic.php14
-rw-r--r--includes/MovePage.php67
-rw-r--r--includes/OutputPage.php525
-rw-r--r--includes/PHPVersionCheck.php146
-rw-r--r--includes/Preferences.php135
-rw-r--r--includes/PrefixSearch.php6
-rw-r--r--includes/ProtectionForm.php57
-rw-r--r--includes/Revision.php30
-rw-r--r--includes/RevisionList.php4
-rw-r--r--includes/Sanitizer.php111
-rw-r--r--includes/Setup.php74
-rw-r--r--includes/SiteStats.php4
-rw-r--r--includes/SquidPurgeClient.php24
-rw-r--r--includes/Status.php10
-rw-r--r--includes/StreamFile.php8
-rw-r--r--includes/StubObject.php2
-rw-r--r--includes/TemplateParser.php9
-rw-r--r--includes/Title.php270
-rw-r--r--includes/User.php528
-rw-r--r--includes/UserRightsProxy.php4
-rw-r--r--includes/WatchedItem.php79
-rw-r--r--includes/WebRequest.php113
-rw-r--r--includes/WebResponse.php19
-rw-r--r--includes/WebStart.php6
-rw-r--r--includes/WikiMap.php62
-rw-r--r--includes/Xml.php125
-rw-r--r--includes/XmlSelect.php132
-rw-r--r--includes/ZhConversion.php1949
-rw-r--r--includes/actions/Action.php10
-rw-r--r--includes/actions/DeleteAction.php2
-rw-r--r--includes/actions/EditAction.php2
-rw-r--r--includes/actions/HistoryAction.php33
-rw-r--r--includes/actions/InfoAction.php95
-rw-r--r--includes/actions/RawAction.php52
-rw-r--r--includes/actions/RevertAction.php2
-rw-r--r--includes/actions/RollbackAction.php3
-rw-r--r--includes/actions/UnprotectAction.php1
-rw-r--r--includes/actions/WatchAction.php2
-rw-r--r--includes/api/ApiBase.php169
-rw-r--r--includes/api/ApiBlock.php16
-rw-r--r--includes/api/ApiCreateAccount.php16
-rw-r--r--includes/api/ApiDelete.php4
-rw-r--r--includes/api/ApiEditPage.php86
-rw-r--r--includes/api/ApiEmailUser.php2
-rw-r--r--includes/api/ApiExpandTemplates.php32
-rw-r--r--includes/api/ApiFeedRecentChanges.php12
-rw-r--r--includes/api/ApiFeedWatchlist.php17
-rw-r--r--includes/api/ApiFileRevert.php2
-rw-r--r--includes/api/ApiFormatBase.php23
-rw-r--r--includes/api/ApiFormatFeedWrapper.php9
-rw-r--r--includes/api/ApiFormatJson.php16
-rw-r--r--includes/api/ApiFormatPhp.php3
-rw-r--r--includes/api/ApiFormatRaw.php28
-rw-r--r--includes/api/ApiFormatWddx.php162
-rw-r--r--includes/api/ApiFormatXml.php11
-rw-r--r--includes/api/ApiHelp.php188
-rw-r--r--includes/api/ApiImageRotate.php4
-rw-r--r--includes/api/ApiImport.php7
-rw-r--r--includes/api/ApiLogin.php19
-rw-r--r--includes/api/ApiMain.php209
-rw-r--r--includes/api/ApiMessage.php30
-rw-r--r--includes/api/ApiMove.php2
-rw-r--r--includes/api/ApiOptions.php14
-rw-r--r--includes/api/ApiPageSet.php69
-rw-r--r--includes/api/ApiParamInfo.php49
-rw-r--r--includes/api/ApiParse.php126
-rw-r--r--includes/api/ApiProtect.php9
-rw-r--r--includes/api/ApiQuery.php23
-rw-r--r--includes/api/ApiQueryAllCategories.php3
-rw-r--r--includes/api/ApiQueryAllDeletedRevisions.php45
-rw-r--r--includes/api/ApiQueryAllLinks.php1
-rw-r--r--includes/api/ApiQueryAllMessages.php8
-rw-r--r--includes/api/ApiQueryAllPages.php12
-rw-r--r--includes/api/ApiQueryAllUsers.php11
-rw-r--r--includes/api/ApiQueryBacklinksprop.php8
-rw-r--r--includes/api/ApiQueryBase.php21
-rw-r--r--includes/api/ApiQueryBlocks.php9
-rw-r--r--includes/api/ApiQueryCategories.php5
-rw-r--r--includes/api/ApiQueryCategoryInfo.php2
-rw-r--r--includes/api/ApiQueryCategoryMembers.php11
-rw-r--r--includes/api/ApiQueryContributors.php6
-rw-r--r--includes/api/ApiQueryDeletedRevisions.php8
-rw-r--r--includes/api/ApiQueryDeletedrevs.php2
-rw-r--r--includes/api/ApiQueryDuplicateFiles.php2
-rw-r--r--includes/api/ApiQueryExtLinksUsage.php3
-rw-r--r--includes/api/ApiQueryExternalLinks.php2
-rw-r--r--includes/api/ApiQueryFileRepoInfo.php24
-rw-r--r--includes/api/ApiQueryFilearchive.php5
-rw-r--r--includes/api/ApiQueryIWBacklinks.php1
-rw-r--r--includes/api/ApiQueryIWLinks.php3
-rw-r--r--includes/api/ApiQueryImageInfo.php6
-rw-r--r--includes/api/ApiQueryImages.php2
-rw-r--r--includes/api/ApiQueryInfo.php19
-rw-r--r--includes/api/ApiQueryLangBacklinks.php1
-rw-r--r--includes/api/ApiQueryLangLinks.php5
-rw-r--r--includes/api/ApiQueryLinks.php4
-rw-r--r--includes/api/ApiQueryLogEvents.php3
-rw-r--r--includes/api/ApiQueryPageProps.php4
-rw-r--r--includes/api/ApiQueryPagesWithProp.php3
-rw-r--r--includes/api/ApiQueryProtectedTitles.php5
-rw-r--r--includes/api/ApiQueryRandom.php181
-rw-r--r--includes/api/ApiQueryRecentChanges.php5
-rw-r--r--includes/api/ApiQueryRevisions.php101
-rw-r--r--includes/api/ApiQueryRevisionsBase.php38
-rw-r--r--includes/api/ApiQuerySearch.php32
-rw-r--r--includes/api/ApiQuerySiteinfo.php18
-rw-r--r--includes/api/ApiQueryStashImageInfo.php4
-rw-r--r--includes/api/ApiQueryTags.php3
-rw-r--r--includes/api/ApiQueryTokens.php4
-rw-r--r--includes/api/ApiQueryUserContributions.php5
-rw-r--r--includes/api/ApiQueryUserInfo.php52
-rw-r--r--includes/api/ApiQueryUsers.php7
-rw-r--r--includes/api/ApiQueryWatchlist.php5
-rw-r--r--includes/api/ApiQueryWatchlistRaw.php31
-rw-r--r--includes/api/ApiResult.php164
-rw-r--r--includes/api/ApiRevisionDelete.php4
-rw-r--r--includes/api/ApiRollback.php2
-rw-r--r--includes/api/ApiSetNotificationTimestamp.php4
-rw-r--r--includes/api/ApiStashEdit.php7
-rw-r--r--includes/api/ApiUnblock.php8
-rw-r--r--includes/api/ApiUndelete.php9
-rw-r--r--includes/api/ApiUpload.php24
-rw-r--r--includes/api/i18n/ar.json4
-rw-r--r--includes/api/i18n/ast.json10
-rw-r--r--includes/api/i18n/ba.json13
-rw-r--r--includes/api/i18n/bcl.json10
-rw-r--r--includes/api/i18n/be-tarask.json4
-rw-r--r--includes/api/i18n/br.json13
-rw-r--r--includes/api/i18n/bs.json5
-rw-r--r--includes/api/i18n/ca.json17
-rw-r--r--includes/api/i18n/ce.json3
-rw-r--r--includes/api/i18n/ckb.json8
-rw-r--r--includes/api/i18n/cs.json105
-rw-r--r--includes/api/i18n/de.json107
-rw-r--r--includes/api/i18n/el.json89
-rw-r--r--includes/api/i18n/en-gb.json2
-rw-r--r--includes/api/i18n/en.json457
-rw-r--r--includes/api/i18n/es.json564
-rw-r--r--includes/api/i18n/et.json42
-rw-r--r--includes/api/i18n/eu.json11
-rw-r--r--includes/api/i18n/fa.json7
-rw-r--r--includes/api/i18n/fi.json8
-rw-r--r--includes/api/i18n/fo.json39
-rw-r--r--includes/api/i18n/fr.json421
-rw-r--r--includes/api/i18n/gl.json414
-rw-r--r--includes/api/i18n/he.json1185
-rw-r--r--includes/api/i18n/ht.json8
-rw-r--r--includes/api/i18n/hu.json13
-rw-r--r--includes/api/i18n/ia.json3
-rw-r--r--includes/api/i18n/is.json10
-rw-r--r--includes/api/i18n/it.json90
-rw-r--r--includes/api/i18n/ja.json374
-rw-r--r--includes/api/i18n/ko.json78
-rw-r--r--includes/api/i18n/ksh.json669
-rw-r--r--includes/api/i18n/ku-latn.json23
-rw-r--r--includes/api/i18n/ky.json19
-rw-r--r--includes/api/i18n/lb.json65
-rw-r--r--includes/api/i18n/lv.json7
-rw-r--r--includes/api/i18n/mk.json241
-rw-r--r--includes/api/i18n/mr.json12
-rw-r--r--includes/api/i18n/nap.json12
-rw-r--r--includes/api/i18n/nb.json91
-rw-r--r--includes/api/i18n/ne.json13
-rw-r--r--includes/api/i18n/nl.json42
-rw-r--r--includes/api/i18n/oc.json73
-rw-r--r--includes/api/i18n/olo.json12
-rw-r--r--includes/api/i18n/or.json14
-rw-r--r--includes/api/i18n/pl.json256
-rw-r--r--includes/api/i18n/ps.json21
-rw-r--r--includes/api/i18n/pt-br.json276
-rw-r--r--includes/api/i18n/pt.json15
-rw-r--r--includes/api/i18n/qqq.json366
-rw-r--r--includes/api/i18n/ru.json197
-rw-r--r--includes/api/i18n/shn.json8
-rw-r--r--includes/api/i18n/si.json1
-rw-r--r--includes/api/i18n/sq.json12
-rw-r--r--includes/api/i18n/sv.json75
-rw-r--r--includes/api/i18n/ta.json13
-rw-r--r--includes/api/i18n/tr.json12
-rw-r--r--includes/api/i18n/uk.json1286
-rw-r--r--includes/api/i18n/vi.json75
-rw-r--r--includes/api/i18n/wuu.json8
-rw-r--r--includes/api/i18n/yi.json10
-rw-r--r--includes/api/i18n/zh-hans.json743
-rw-r--r--includes/api/i18n/zh-hant.json42
-rw-r--r--includes/cache/BacklinkCache.php6
-rw-r--r--includes/cache/CacheDependency.php8
-rw-r--r--includes/cache/FileCacheBase.php4
-rw-r--r--includes/cache/HTMLFileCache.php1
-rw-r--r--includes/cache/LCStoreStaticArray.php140
-rw-r--r--includes/cache/LinkBatch.php2
-rw-r--r--includes/cache/LinkCache.php87
-rw-r--r--includes/cache/LocalisationCache.php13
-rw-r--r--includes/cache/MessageBlobStore.php (renamed from includes/MessageBlobStore.php)45
-rw-r--r--includes/cache/MessageCache.php557
-rw-r--r--includes/cache/ResourceFileCache.php4
-rw-r--r--includes/cache/UserCache.php4
-rw-r--r--includes/changes/ChangesFeed.php4
-rw-r--r--includes/changes/ChangesList.php39
-rw-r--r--includes/changes/EnhancedChangesList.php262
-rw-r--r--includes/changes/RecentChange.php113
-rw-r--r--includes/changetags/ChangeTags.php (renamed from includes/ChangeTags.php)318
-rw-r--r--includes/changetags/ChangeTagsLogList.php3
-rw-r--r--includes/changetags/ChangeTagsRevisionList.php3
-rw-r--r--includes/clientpool/RedisConnectionPool.php108
-rw-r--r--includes/compat/CdbCompat.php (renamed from includes/CdbCompat.php)0
-rw-r--r--includes/compat/IPSetCompat.php28
-rw-r--r--includes/compat/normal/UtfNormal.php (renamed from includes/libs/normal/UtfNormal.php)0
-rw-r--r--includes/compat/normal/UtfNormalDefines.php (renamed from includes/libs/normal/UtfNormalDefines.php)0
-rw-r--r--includes/compat/normal/UtfNormalUtil.php (renamed from includes/libs/normal/UtfNormalUtil.php)1
-rw-r--r--includes/config/ConfigFactory.php3
-rw-r--r--includes/content/ContentHandler.php54
-rw-r--r--includes/content/CssContent.php44
-rw-r--r--includes/content/CssContentHandler.php19
-rw-r--r--includes/content/JavaScriptContent.php47
-rw-r--r--includes/content/JavaScriptContentHandler.php18
-rw-r--r--includes/content/TextContentHandler.php9
-rw-r--r--includes/content/WikitextContent.php4
-rw-r--r--includes/context/ContextSource.php1
-rw-r--r--includes/context/DerivativeContext.php7
-rw-r--r--includes/context/IContextSource.php3
-rw-r--r--includes/context/MutableContext.php82
-rw-r--r--includes/context/RequestContext.php20
-rw-r--r--includes/dao/DBAccessObjectUtils.php59
-rw-r--r--includes/db/DBConnRef.php524
-rw-r--r--includes/db/Database.php310
-rw-r--r--includes/db/DatabaseError.php19
-rw-r--r--includes/db/DatabaseMssql.php8
-rw-r--r--includes/db/DatabaseMysql.php40
-rw-r--r--includes/db/DatabaseMysqlBase.php82
-rw-r--r--includes/db/DatabaseMysqli.php43
-rw-r--r--includes/db/DatabaseOracle.php38
-rw-r--r--includes/db/DatabasePostgres.php25
-rw-r--r--includes/db/DatabaseSqlite.php49
-rw-r--r--includes/db/IDatabase.php1513
-rw-r--r--includes/db/LBFactory.php11
-rw-r--r--includes/db/LBFactoryMulti.php2
-rw-r--r--includes/db/LoadBalancer.php147
-rw-r--r--includes/db/LoadMonitor.php87
-rw-r--r--includes/db/LoadMonitorMySQL.php124
-rw-r--r--includes/debug/MWDebug.php6
-rw-r--r--includes/debug/logger/LegacyLogger.php101
-rw-r--r--includes/debug/logger/LegacySpi.php4
-rw-r--r--includes/debug/logger/LoggerFactory.php14
-rw-r--r--includes/debug/logger/MonologSpi.php35
-rw-r--r--includes/debug/logger/NullSpi.php8
-rw-r--r--includes/debug/logger/Spi.php8
-rw-r--r--includes/debug/logger/monolog/AvroFormatter.php139
-rw-r--r--includes/debug/logger/monolog/BufferHandler.php (renamed from includes/api/ApiFormatDump.php)55
-rw-r--r--includes/debug/logger/monolog/KafkaHandler.php224
-rw-r--r--includes/debug/logger/monolog/LegacyFormatter.php4
-rw-r--r--includes/debug/logger/monolog/LineFormatter.php177
-rw-r--r--includes/deferred/DeferredUpdates.php68
-rw-r--r--includes/deferred/HTMLCacheUpdate.php3
-rw-r--r--includes/deferred/LinksDeletionUpdate.php105
-rw-r--r--includes/deferred/LinksUpdate.php85
-rw-r--r--includes/deferred/SiteStatsUpdate.php14
-rw-r--r--includes/diff/DifferenceEngine.php27
-rw-r--r--includes/diff/TableDiffFormatter.php2
-rw-r--r--includes/diff/UnifiedDiffFormatter.php10
-rw-r--r--includes/exception/BadTitleError.php16
-rw-r--r--includes/exception/HttpError.php20
-rw-r--r--includes/exception/MWException.php8
-rw-r--r--includes/exception/MWExceptionHandler.php367
-rw-r--r--includes/filebackend/FSFile.php9
-rw-r--r--includes/filebackend/FileBackend.php15
-rw-r--r--includes/filebackend/FileBackendGroup.php2
-rw-r--r--includes/filebackend/FileBackendMultiWrite.php176
-rw-r--r--includes/filebackend/FileBackendStore.php80
-rw-r--r--includes/filebackend/FileOp.php4
-rw-r--r--includes/filebackend/MemoryFileBackend.php8
-rw-r--r--includes/filebackend/SwiftFileBackend.php151
-rw-r--r--includes/filebackend/TempFSFile.php15
-rw-r--r--includes/filebackend/lockmanager/DBLockManager.php2
-rw-r--r--includes/filebackend/lockmanager/FSLockManager.php4
-rw-r--r--includes/filebackend/lockmanager/LockManager.php1
-rw-r--r--includes/filerepo/FileBackendDBRepoWrapper.php356
-rw-r--r--includes/filerepo/FileRepo.php43
-rw-r--r--includes/filerepo/ForeignAPIRepo.php4
-rw-r--r--includes/filerepo/ForeignDBRepo.php32
-rw-r--r--includes/filerepo/ForeignDBViaLBRepo.php10
-rw-r--r--includes/filerepo/LocalRepo.php113
-rw-r--r--includes/filerepo/file/ArchivedFile.php4
-rw-r--r--includes/filerepo/file/File.php65
-rw-r--r--includes/filerepo/file/ForeignAPIFile.php19
-rw-r--r--includes/filerepo/file/LocalFile.php289
-rw-r--r--includes/gallery/PackedImageGallery.php4
-rw-r--r--includes/gallery/PackedOverlayImageGallery.php2
-rw-r--r--includes/gallery/TraditionalImageGallery.php4
-rw-r--r--includes/htmlform/HTMLAutoCompleteSelectField.php14
-rw-r--r--includes/htmlform/HTMLButtonField.php36
-rw-r--r--includes/htmlform/HTMLCheckField.php62
-rw-r--r--includes/htmlform/HTMLCheckMatrix.php42
-rw-r--r--includes/htmlform/HTMLForm.php185
-rw-r--r--includes/htmlform/HTMLFormField.php193
-rw-r--r--includes/htmlform/HTMLFormFieldWithButton.php73
-rw-r--r--includes/htmlform/HTMLInfoField.php10
-rw-r--r--includes/htmlform/HTMLMultiSelectField.php60
-rw-r--r--includes/htmlform/HTMLRadioField.php17
-rw-r--r--includes/htmlform/HTMLSelectAndOtherField.php5
-rw-r--r--includes/htmlform/HTMLSelectField.php22
-rw-r--r--includes/htmlform/HTMLSelectNamespace.php16
-rw-r--r--includes/htmlform/HTMLSelectNamespaceWithButton.php17
-rw-r--r--includes/htmlform/HTMLSelectOrOtherField.php4
-rw-r--r--includes/htmlform/HTMLSubmitField.php2
-rw-r--r--includes/htmlform/HTMLTextAreaField.php44
-rw-r--r--includes/htmlform/HTMLTextField.php61
-rw-r--r--includes/htmlform/HTMLTextFieldWithButton.php17
-rw-r--r--includes/htmlform/HTMLTitleTextField.php81
-rw-r--r--includes/htmlform/HTMLUserTextField.php47
-rw-r--r--includes/htmlform/OOUIHTMLForm.php221
-rw-r--r--includes/htmlform/VFormHTMLForm.php6
-rw-r--r--includes/installer/DatabaseInstaller.php4
-rw-r--r--includes/installer/DatabaseUpdater.php3
-rw-r--r--includes/installer/Installer.php51
-rw-r--r--includes/installer/LocalSettingsGenerator.php11
-rw-r--r--includes/installer/MssqlInstaller.php1
-rw-r--r--includes/installer/MssqlUpdater.php2
-rw-r--r--includes/installer/MysqlInstaller.php10
-rw-r--r--includes/installer/MysqlUpdater.php5
-rw-r--r--includes/installer/PostgresInstaller.php11
-rw-r--r--includes/installer/PostgresUpdater.php10
-rw-r--r--includes/installer/SqliteInstaller.php4
-rw-r--r--includes/installer/WebInstaller.php29
-rw-r--r--includes/installer/WebInstallerPage.php37
-rw-r--r--includes/installer/i18n/ar.json9
-rw-r--r--includes/installer/i18n/ast.json8
-rw-r--r--includes/installer/i18n/azb.json30
-rw-r--r--includes/installer/i18n/ba.json7
-rw-r--r--includes/installer/i18n/bcl.json1
-rw-r--r--includes/installer/i18n/be-tarask.json3
-rw-r--r--includes/installer/i18n/bg.json43
-rw-r--r--includes/installer/i18n/bn.json17
-rw-r--r--includes/installer/i18n/bs.json27
-rw-r--r--includes/installer/i18n/ca.json3
-rw-r--r--includes/installer/i18n/ce.json9
-rw-r--r--includes/installer/i18n/ckb.json1
-rw-r--r--includes/installer/i18n/cs.json3
-rw-r--r--includes/installer/i18n/cu.json4
-rw-r--r--includes/installer/i18n/da.json11
-rw-r--r--includes/installer/i18n/de-ch.json6
-rw-r--r--includes/installer/i18n/de.json2
-rw-r--r--includes/installer/i18n/el.json63
-rw-r--r--includes/installer/i18n/en-gb.json1
-rw-r--r--includes/installer/i18n/en.json2
-rw-r--r--includes/installer/i18n/eo.json10
-rw-r--r--includes/installer/i18n/es.json56
-rw-r--r--includes/installer/i18n/et.json7
-rw-r--r--includes/installer/i18n/eu.json4
-rw-r--r--includes/installer/i18n/fa.json19
-rw-r--r--includes/installer/i18n/fo.json15
-rw-r--r--includes/installer/i18n/fr.json3
-rw-r--r--includes/installer/i18n/fy.json1
-rw-r--r--includes/installer/i18n/gl.json7
-rw-r--r--includes/installer/i18n/he.json3
-rw-r--r--includes/installer/i18n/hi.json8
-rw-r--r--includes/installer/i18n/hu.json19
-rw-r--r--includes/installer/i18n/hy.json35
-rw-r--r--includes/installer/i18n/ia.json7
-rw-r--r--includes/installer/i18n/id.json1
-rw-r--r--includes/installer/i18n/it.json17
-rw-r--r--includes/installer/i18n/ja.json11
-rw-r--r--includes/installer/i18n/jut.json5
-rw-r--r--includes/installer/i18n/km.json3
-rw-r--r--includes/installer/i18n/kn.json4
-rw-r--r--includes/installer/i18n/ko.json76
-rw-r--r--includes/installer/i18n/ksh.json99
-rw-r--r--includes/installer/i18n/ku-latn.json48
-rw-r--r--includes/installer/i18n/lb.json3
-rw-r--r--includes/installer/i18n/lrc.json4
-rw-r--r--includes/installer/i18n/lv.json15
-rw-r--r--includes/installer/i18n/mai.json4
-rw-r--r--includes/installer/i18n/mg.json12
-rw-r--r--includes/installer/i18n/mk.json6
-rw-r--r--includes/installer/i18n/mr.json5
-rw-r--r--includes/installer/i18n/nan.json11
-rw-r--r--includes/installer/i18n/nap.json102
-rw-r--r--includes/installer/i18n/nb.json1
-rw-r--r--includes/installer/i18n/ne.json55
-rw-r--r--includes/installer/i18n/nl.json6
-rw-r--r--includes/installer/i18n/nn.json4
-rw-r--r--includes/installer/i18n/olo.json59
-rw-r--r--includes/installer/i18n/or.json17
-rw-r--r--includes/installer/i18n/pl.json19
-rw-r--r--includes/installer/i18n/pms.json4
-rw-r--r--includes/installer/i18n/ps.json22
-rw-r--r--includes/installer/i18n/pt-br.json19
-rw-r--r--includes/installer/i18n/pt.json6
-rw-r--r--includes/installer/i18n/qqq.json6
-rw-r--r--includes/installer/i18n/ro.json14
-rw-r--r--includes/installer/i18n/ru.json3
-rw-r--r--includes/installer/i18n/sah.json9
-rw-r--r--includes/installer/i18n/sco.json3
-rw-r--r--includes/installer/i18n/sd.json8
-rw-r--r--includes/installer/i18n/sk.json5
-rw-r--r--includes/installer/i18n/sq.json40
-rw-r--r--includes/installer/i18n/sr-ec.json5
-rw-r--r--includes/installer/i18n/su.json7
-rw-r--r--includes/installer/i18n/sv.json5
-rw-r--r--includes/installer/i18n/tokipona.json8
-rw-r--r--includes/installer/i18n/tr.json53
-rw-r--r--includes/installer/i18n/tt-cyrl.json7
-rw-r--r--includes/installer/i18n/udm.json12
-rw-r--r--includes/installer/i18n/uk.json13
-rw-r--r--includes/installer/i18n/vi.json5
-rw-r--r--includes/installer/i18n/wuu.json4
-rw-r--r--includes/installer/i18n/xmf.json33
-rw-r--r--includes/installer/i18n/yi.json15
-rw-r--r--includes/installer/i18n/zh-hans.json5
-rw-r--r--includes/installer/i18n/zh-hant.json12
-rw-r--r--includes/interwiki/Interwiki.php21
-rw-r--r--includes/jobqueue/Job.php46
-rw-r--r--includes/jobqueue/JobQueue.php81
-rw-r--r--includes/jobqueue/JobQueueDB.php98
-rw-r--r--includes/jobqueue/JobQueueFederated.php35
-rw-r--r--includes/jobqueue/JobQueueGroup.php143
-rw-r--r--includes/jobqueue/JobQueueRedis.php151
-rw-r--r--includes/jobqueue/JobRunner.php171
-rw-r--r--includes/jobqueue/JobSpecification.php71
-rw-r--r--includes/jobqueue/aggregator/JobQueueAggregator.php2
-rw-r--r--includes/jobqueue/aggregator/JobQueueAggregatorRedis.php8
-rw-r--r--includes/jobqueue/jobs/ActivityUpdateJob.php75
-rw-r--r--includes/jobqueue/jobs/AssembleUploadChunksJob.php2
-rw-r--r--includes/jobqueue/jobs/DoubleRedirectJob.php20
-rw-r--r--includes/jobqueue/jobs/DuplicateJob.php2
-rw-r--r--includes/jobqueue/jobs/EmaillingJob.php4
-rw-r--r--includes/jobqueue/jobs/EnotifNotifyJob.php2
-rw-r--r--includes/jobqueue/jobs/EnqueueJob.php21
-rw-r--r--includes/jobqueue/jobs/HTMLCacheUpdateJob.php2
-rw-r--r--includes/jobqueue/jobs/NullJob.php2
-rw-r--r--includes/jobqueue/jobs/PublishStashedFileJob.php2
-rw-r--r--includes/jobqueue/jobs/RecentChangesUpdateJob.php8
-rw-r--r--includes/jobqueue/jobs/RefreshLinksJob.php51
-rw-r--r--includes/jobqueue/jobs/ThumbnailRenderJob.php14
-rw-r--r--includes/jobqueue/jobs/UploadFromUrlJob.php6
-rw-r--r--includes/json/FormatJson.php2
-rw-r--r--includes/libs/BufferingStatsdDataFactory.php34
-rw-r--r--includes/libs/CSSMin.php73
-rw-r--r--includes/libs/HashRing.php4
-rw-r--r--includes/libs/HttpStatus.php28
-rw-r--r--includes/libs/IPSet.php276
-rw-r--r--includes/libs/JavaScriptMinifier.php8
-rw-r--r--includes/libs/MapCacheLRU.php7
-rw-r--r--includes/libs/MultiHttpClient.php55
-rw-r--r--includes/libs/ObjectFactory.php49
-rw-r--r--includes/libs/ProcessCacheLRU.php7
-rw-r--r--includes/libs/ReplacementArray.php9
-rw-r--r--includes/libs/RiffExtractor.php100
-rw-r--r--includes/libs/SamplingStatsdClient.php133
-rw-r--r--includes/libs/ScopedPHPTimeout.php84
-rw-r--r--includes/libs/XmlTypeCheck.php35
-rw-r--r--includes/libs/composer/ComposerLock.php3
-rw-r--r--includes/libs/eventrelayer/EventRelayer.php65
-rw-r--r--includes/libs/eventrelayer/EventRelayerMCRD.php66
-rw-r--r--includes/libs/objectcache/APCBagOStuff.php31
-rw-r--r--includes/libs/objectcache/BagOStuff.php201
-rw-r--r--includes/libs/objectcache/EmptyBagOStuff.php2
-rw-r--r--includes/libs/objectcache/HashBagOStuff.php14
-rw-r--r--includes/libs/objectcache/ReplicatedBagOStuff.php129
-rw-r--r--includes/libs/objectcache/WANObjectCache.php746
-rw-r--r--includes/libs/objectcache/WinCacheBagOStuff.php33
-rw-r--r--includes/libs/objectcache/XCacheBagOStuff.php23
-rw-r--r--includes/libs/virtualrest/ParsoidVirtualRESTService.php221
-rw-r--r--includes/libs/virtualrest/RestbaseVirtualRESTService.php242
-rw-r--r--includes/libs/virtualrest/SwiftVirtualRESTService.php6
-rw-r--r--includes/libs/virtualrest/VirtualRESTService.php15
-rw-r--r--includes/libs/virtualrest/VirtualRESTServiceClient.php12
-rw-r--r--includes/logging/ContentModelLogFormatter.php34
-rw-r--r--includes/logging/LogEntry.php34
-rw-r--r--includes/logging/LogEventsList.php8
-rw-r--r--includes/logging/LogFormatter.php10
-rw-r--r--includes/logging/LogPager.php5
-rw-r--r--includes/logging/PatrolLogFormatter.php6
-rw-r--r--includes/logging/ProtectLogFormatter.php70
-rw-r--r--includes/mail/EmailNotification.php61
-rw-r--r--includes/mail/UserMailer.php140
-rw-r--r--includes/media/Bitmap.php7
-rw-r--r--includes/media/BitmapMetadataHandler.php8
-rw-r--r--includes/media/DjVu.php96
-rw-r--r--includes/media/DjVuImage.php10
-rw-r--r--includes/media/Exif.php12
-rw-r--r--includes/media/ExifBitmap.php78
-rw-r--r--includes/media/FormatMetadata.php35
-rw-r--r--includes/media/GIF.php8
-rw-r--r--includes/media/GIFMetadataExtractor.php4
-rw-r--r--includes/media/IPTC.php4
-rw-r--r--includes/media/ImageHandler.php4
-rw-r--r--includes/media/Jpeg.php2
-rw-r--r--includes/media/JpegMetadataExtractor.php4
-rw-r--r--includes/media/MediaHandler.php4
-rw-r--r--includes/media/MediaTransformInvalidParametersException.php3
-rw-r--r--includes/media/PNG.php8
-rw-r--r--includes/media/PNGMetadataExtractor.php16
-rw-r--r--includes/media/SVG.php15
-rw-r--r--includes/media/SVGMetadataExtractor.php17
-rw-r--r--includes/media/TransformationalImageHandler.php2
-rw-r--r--includes/media/WebP.php306
-rw-r--r--includes/media/XCF.php6
-rw-r--r--includes/media/XMP.php245
-rw-r--r--includes/media/XMPInfo.php11
-rw-r--r--includes/media/XMPValidate.php60
-rw-r--r--includes/media/tinyrgb.iccbin0 -> 524 bytes
-rw-r--r--includes/mime.info2
-rw-r--r--includes/objectcache/MemcachedBagOStuff.php15
-rw-r--r--includes/objectcache/MemcachedClient.php15
-rw-r--r--includes/objectcache/MemcachedPeclBagOStuff.php22
-rw-r--r--includes/objectcache/MemcachedPhpBagOStuff.php14
-rw-r--r--includes/objectcache/MultiWriteBagOStuff.php88
-rw-r--r--includes/objectcache/ObjectCache.php189
-rw-r--r--includes/objectcache/ObjectCacheSessionHandler.php45
-rw-r--r--includes/objectcache/RedisBagOStuff.php130
-rw-r--r--includes/objectcache/SqlBagOStuff.php78
-rw-r--r--includes/page/Article.php129
-rw-r--r--includes/page/ImagePage.php35
-rw-r--r--includes/page/WikiPage.php417
-rw-r--r--includes/pager/ReverseChronologicalPager.php6
-rw-r--r--includes/pager/TablePager.php7
-rw-r--r--includes/parser/CacheTime.php2
-rw-r--r--includes/parser/CoreParserFunctions.php25
-rw-r--r--includes/parser/LinkHolderArray.php1
-rw-r--r--includes/parser/MWTidy.php323
-rw-r--r--includes/parser/Parser.php221
-rw-r--r--includes/parser/ParserCache.php51
-rw-r--r--includes/parser/ParserDiffTest.php21
-rw-r--r--includes/parser/ParserOptions.php99
-rw-r--r--includes/parser/ParserOutput.php37
-rw-r--r--includes/parser/Preprocessor_DOM.php26
-rw-r--r--includes/parser/Preprocessor_Hash.php24
-rw-r--r--includes/parser/StripState.php27
-rw-r--r--includes/password/EncryptedPassword.php2
-rw-r--r--includes/password/PasswordPolicyChecks.php115
-rw-r--r--includes/password/UserPasswordPolicy.php201
-rw-r--r--includes/poolcounter/PoolCounter.php9
-rw-r--r--includes/poolcounter/PoolCounterRedis.php7
-rw-r--r--includes/poolcounter/PoolWorkArticleView.php8
-rw-r--r--includes/profiler/ProfileSection.php5
-rw-r--r--includes/profiler/Profiler.php26
-rw-r--r--includes/profiler/ProfilerFunctions.php2
-rw-r--r--includes/profiler/ProfilerStub.php3
-rw-r--r--includes/profiler/ProfilerXhprof.php45
-rw-r--r--includes/profiler/SectionProfiler.php9
-rw-r--r--includes/profiler/TransactionProfiler.php56
-rw-r--r--includes/profiler/output/ProfilerOutputDump.php6
-rw-r--r--includes/profiler/output/ProfilerOutputStats.php6
-rw-r--r--includes/profiler/output/ProfilerOutputText.php2
-rw-r--r--includes/profiler/output/ProfilerOutputUdp.php2
-rw-r--r--includes/rcfeed/MachineReadableRCFeedFormatter.php4
-rw-r--r--includes/rcfeed/RCFeedFormatter.php3
-rw-r--r--includes/registration/CoreVersionChecker.php68
-rw-r--r--includes/registration/ExtensionProcessor.php27
-rw-r--r--includes/registration/ExtensionRegistry.php52
-rw-r--r--includes/registration/Processor.php20
-rw-r--r--includes/resourceloader/DerivativeResourceLoaderContext.php76
-rw-r--r--includes/resourceloader/ResourceLoader.php553
-rw-r--r--includes/resourceloader/ResourceLoaderContext.php33
-rw-r--r--includes/resourceloader/ResourceLoaderEditToolbarModule.php31
-rw-r--r--includes/resourceloader/ResourceLoaderFileModule.php122
-rw-r--r--includes/resourceloader/ResourceLoaderForeignApiModule.php33
-rw-r--r--includes/resourceloader/ResourceLoaderImage.php25
-rw-r--r--includes/resourceloader/ResourceLoaderImageModule.php193
-rw-r--r--includes/resourceloader/ResourceLoaderJqueryMsgModule.php66
-rw-r--r--includes/resourceloader/ResourceLoaderLanguageDataModule.php16
-rw-r--r--includes/resourceloader/ResourceLoaderLanguageNamesModule.php18
-rw-r--r--includes/resourceloader/ResourceLoaderModule.php479
-rw-r--r--includes/resourceloader/ResourceLoaderOOUIImageModule.php86
-rw-r--r--includes/resourceloader/ResourceLoaderRawFileModule.php52
-rw-r--r--includes/resourceloader/ResourceLoaderSiteModule.php9
-rw-r--r--includes/resourceloader/ResourceLoaderSkinModule.php13
-rw-r--r--includes/resourceloader/ResourceLoaderSpecialCharacterDataModule.php19
-rw-r--r--includes/resourceloader/ResourceLoaderStartUpModule.php191
-rw-r--r--includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php18
-rw-r--r--includes/resourceloader/ResourceLoaderUserDefaultsModule.php19
-rw-r--r--includes/resourceloader/ResourceLoaderUserOptionsModule.php21
-rw-r--r--includes/resourceloader/ResourceLoaderWikiModule.php198
-rw-r--r--includes/revisiondelete/RevDelItem.php2
-rw-r--r--includes/revisiondelete/RevDelList.php24
-rw-r--r--includes/revisiondelete/RevDelLogItem.php27
-rw-r--r--includes/revisiondelete/RevDelRevisionItem.php2
-rw-r--r--includes/revisiondelete/RevisionDeleter.php4
-rw-r--r--includes/search/SearchEngine.php4
-rw-r--r--includes/search/SearchHighlighter.php2
-rw-r--r--includes/search/SearchMySQL.php6
-rw-r--r--includes/search/SearchPostgres.php2
-rw-r--r--includes/search/SearchResultSet.php35
-rw-r--r--includes/search/SearchSqlite.php4
-rw-r--r--includes/site/CachingSiteStore.php6
-rw-r--r--includes/site/DBSiteStore.php6
-rw-r--r--includes/site/SiteExporter.php20
-rw-r--r--includes/site/SiteSQLStore.php2
-rw-r--r--includes/skins/MediaWikiI18N.php4
-rw-r--r--includes/skins/Skin.php48
-rw-r--r--includes/skins/SkinFallbackTemplate.php6
-rw-r--r--includes/skins/SkinTemplate.php23
-rw-r--r--includes/specialpage/ChangesListSpecialPage.php3
-rw-r--r--includes/specialpage/FormSpecialPage.php6
-rw-r--r--includes/specialpage/QueryPage.php49
-rw-r--r--includes/specialpage/RedirectSpecialPage.php33
-rw-r--r--includes/specialpage/SpecialPage.php27
-rw-r--r--includes/specialpage/SpecialPageFactory.php61
-rw-r--r--includes/specials/SpecialActiveusers.php29
-rw-r--r--includes/specials/SpecialAllMessages.php18
-rw-r--r--includes/specials/SpecialAllPages.php83
-rw-r--r--includes/specials/SpecialAncientpages.php6
-rw-r--r--includes/specials/SpecialBlock.php39
-rw-r--r--includes/specials/SpecialBlockList.php77
-rw-r--r--includes/specials/SpecialBrokenRedirects.php4
-rw-r--r--includes/specials/SpecialChangeContentModel.php223
-rw-r--r--includes/specials/SpecialChangeEmail.php13
-rw-r--r--includes/specials/SpecialChangePassword.php3
-rw-r--r--includes/specials/SpecialComparePages.php3
-rw-r--r--includes/specials/SpecialConfirmemail.php8
-rw-r--r--includes/specials/SpecialContributions.php8
-rw-r--r--includes/specials/SpecialDeletedContributions.php8
-rw-r--r--includes/specials/SpecialDiff.php8
-rw-r--r--includes/specials/SpecialDoubleRedirects.php5
-rw-r--r--includes/specials/SpecialEditTags.php20
-rw-r--r--includes/specials/SpecialEditWatchlist.php7
-rw-r--r--includes/specials/SpecialEmailuser.php7
-rw-r--r--includes/specials/SpecialExport.php207
-rw-r--r--includes/specials/SpecialFewestrevisions.php4
-rw-r--r--includes/specials/SpecialFileDuplicateSearch.php6
-rw-r--r--includes/specials/SpecialFilepath.php11
-rw-r--r--includes/specials/SpecialImport.php144
-rw-r--r--includes/specials/SpecialJavaScriptTest.php108
-rw-r--r--includes/specials/SpecialLinkSearch.php68
-rw-r--r--includes/specials/SpecialListDuplicatedFiles.php4
-rw-r--r--includes/specials/SpecialListfiles.php14
-rw-r--r--includes/specials/SpecialListredirects.php4
-rw-r--r--includes/specials/SpecialListusers.php16
-rw-r--r--includes/specials/SpecialLockdb.php4
-rw-r--r--includes/specials/SpecialMIMEsearch.php7
-rw-r--r--includes/specials/SpecialMediaStatistics.php12
-rw-r--r--includes/specials/SpecialMergeHistory.php2
-rw-r--r--includes/specials/SpecialMostcategories.php4
-rw-r--r--includes/specials/SpecialMostinterwikis.php4
-rw-r--r--includes/specials/SpecialMostlinked.php4
-rw-r--r--includes/specials/SpecialMostlinkedcategories.php2
-rw-r--r--includes/specials/SpecialMovepage.php338
-rw-r--r--includes/specials/SpecialMyLanguage.php26
-rw-r--r--includes/specials/SpecialMyRedirectPages.php55
-rw-r--r--includes/specials/SpecialNewpages.php4
-rw-r--r--includes/specials/SpecialPageLanguage.php7
-rw-r--r--includes/specials/SpecialPagesWithProp.php8
-rw-r--r--includes/specials/SpecialPasswordReset.php2
-rw-r--r--includes/specials/SpecialPermanentLink.php8
-rw-r--r--includes/specials/SpecialPreferences.php9
-rw-r--r--includes/specials/SpecialProtectedtitles.php12
-rw-r--r--includes/specials/SpecialRandomInCategory.php16
-rw-r--r--includes/specials/SpecialRandompage.php20
-rw-r--r--includes/specials/SpecialRecentchanges.php23
-rw-r--r--includes/specials/SpecialRecentchangeslinked.php1
-rw-r--r--includes/specials/SpecialResetTokens.php5
-rw-r--r--includes/specials/SpecialRevisiondelete.php36
-rw-r--r--includes/specials/SpecialRunJobs.php15
-rw-r--r--includes/specials/SpecialSearch.php152
-rw-r--r--includes/specials/SpecialShortpages.php2
-rw-r--r--includes/specials/SpecialSpecialpages.php27
-rw-r--r--includes/specials/SpecialStatistics.php43
-rw-r--r--includes/specials/SpecialTags.php97
-rw-r--r--includes/specials/SpecialUndelete.php15
-rw-r--r--includes/specials/SpecialUnlockdb.php4
-rw-r--r--includes/specials/SpecialUnusedcategories.php4
-rw-r--r--includes/specials/SpecialUnusedtemplates.php4
-rw-r--r--includes/specials/SpecialUnwatchedpages.php4
-rw-r--r--includes/specials/SpecialUpload.php14
-rw-r--r--includes/specials/SpecialUploadStash.php4
-rw-r--r--includes/specials/SpecialUserlogin.php115
-rw-r--r--includes/specials/SpecialUserrights.php8
-rw-r--r--includes/specials/SpecialVersion.php76
-rw-r--r--includes/specials/SpecialWantedfiles.php2
-rw-r--r--includes/specials/SpecialWantedtemplates.php5
-rw-r--r--includes/specials/SpecialWatchlist.php1
-rw-r--r--includes/specials/SpecialWhatlinkshere.php53
-rw-r--r--includes/templates/Usercreate.php8
-rw-r--r--includes/templates/Userlogin.php5
-rw-r--r--includes/tidy/Html5Depurate.php45
-rw-r--r--includes/tidy/RaggettBase.php47
-rw-r--r--includes/tidy/RaggettExternal.php73
-rw-r--r--includes/tidy/RaggettInternalHHVM.php29
-rw-r--r--includes/tidy/RaggettInternalPHP.php52
-rw-r--r--includes/tidy/RaggettWrapper.php89
-rw-r--r--includes/tidy/TidyDriverBase.php40
-rw-r--r--includes/tidy/tidy.conf (renamed from includes/tidy.conf)0
-rw-r--r--includes/title/MalformedTitleException.php54
-rw-r--r--includes/title/MediaWikiTitleCodec.php34
-rw-r--r--includes/title/TitleValue.php24
-rw-r--r--includes/upload/UploadBase.php93
-rw-r--r--includes/upload/UploadFromUrl.php4
-rw-r--r--includes/utils/AutoloadGenerator.php74
-rw-r--r--includes/utils/AvroValidator.php184
-rw-r--r--includes/utils/BatchRowIterator.php278
-rw-r--r--includes/utils/BatchRowUpdate.php133
-rw-r--r--includes/utils/BatchRowWriter.php71
-rw-r--r--includes/utils/IP.php6
-rw-r--r--includes/utils/MWCryptHKDF.php8
-rw-r--r--includes/utils/MWCryptRand.php8
-rw-r--r--includes/utils/RowUpdateGenerator.php39
-rw-r--r--includes/utils/UIDGenerator.php21
-rw-r--r--includes/utils/iterators/IteratorDecorator.php50
-rw-r--r--includes/utils/iterators/NotRecursiveIterator.php (renamed from includes/utils/MWFunction.php)29
-rw-r--r--includes/widget/AUTHORS.txt11
-rw-r--r--includes/widget/ComplexNamespaceInputWidget.php110
-rw-r--r--includes/widget/ComplexTitleInputWidget.php67
-rw-r--r--includes/widget/LICENSE.txt25
-rw-r--r--includes/widget/NamespaceInputWidget.php66
-rw-r--r--includes/widget/TitleInputWidget.php60
-rw-r--r--includes/widget/UserInputWidget.php29
732 files changed, 32314 insertions, 11064 deletions
diff --git a/includes/AjaxDispatcher.php b/includes/AjaxDispatcher.php
index b14114d7..96892d71 100644
--- a/includes/AjaxDispatcher.php
+++ b/includes/AjaxDispatcher.php
@@ -124,9 +124,9 @@ class AjaxDispatcher {
$result = call_user_func_array( $this->func_name, $this->args );
if ( $result === false || $result === null ) {
- wfDebug( __METHOD__ . ' ERROR while dispatching '
- . $this->func_name . "(" . var_export( $this->args, true ) . "): "
- . "no data returned\n" );
+ wfDebug( __METHOD__ . ' ERROR while dispatching ' .
+ $this->func_name . "(" . var_export( $this->args, true ) . "): " .
+ "no data returned\n" );
wfHttpError( 500, 'Internal Error',
"{$this->func_name} returned no data" );
@@ -141,9 +141,9 @@ class AjaxDispatcher {
wfDebug( __METHOD__ . ' dispatch complete for ' . $this->func_name . "\n" );
}
} catch ( Exception $e ) {
- wfDebug( __METHOD__ . ' ERROR while dispatching '
- . $this->func_name . "(" . var_export( $this->args, true ) . "): "
- . get_class( $e ) . ": " . $e->getMessage() . "\n" );
+ wfDebug( __METHOD__ . ' ERROR while dispatching ' .
+ $this->func_name . "(" . var_export( $this->args, true ) . "): " .
+ get_class( $e ) . ": " . $e->getMessage() . "\n" );
if ( !headers_sent() ) {
wfHttpError( 500, 'Internal Error',
diff --git a/includes/AjaxResponse.php b/includes/AjaxResponse.php
index 8e9f490f..6c2efc29 100644
--- a/includes/AjaxResponse.php
+++ b/includes/AjaxResponse.php
@@ -86,7 +86,7 @@ class AjaxResponse {
$this->mDisabled = false;
$this->mText = '';
- $this->mResponseCode = '200 OK';
+ $this->mResponseCode = 200;
$this->mLastModified = false;
$this->mContentType = 'application/x-wiki';
@@ -158,16 +158,20 @@ class AjaxResponse {
*/
function sendHeaders() {
if ( $this->mResponseCode ) {
- $n = preg_replace( '/^ *(\d+)/', '\1', $this->mResponseCode );
- header( "Status: " . $this->mResponseCode, true, (int)$n );
+ // For back-compat, it is supported that mResponseCode be a string like " 200 OK"
+ // (with leading space and the status message after). Cast response code to an integer
+ // to take advantage of PHP's conversion rules which will turn " 200 OK" into 200.
+ // http://php.net/string#language.types.string.conversion
+ $n = intval( trim( $this->mResponseCode ) );
+ HttpStatus::header( $n );
}
- header ( "Content-Type: " . $this->mContentType );
+ header( "Content-Type: " . $this->mContentType );
if ( $this->mLastModified ) {
- header ( "Last-Modified: " . $this->mLastModified );
+ header( "Last-Modified: " . $this->mLastModified );
} else {
- header ( "Last-Modified: " . gmdate( "D, d M Y H:i:s" ) . " GMT" );
+ header( "Last-Modified: " . gmdate( "D, d M Y H:i:s" ) . " GMT" );
}
if ( $this->mCacheDuration ) {
@@ -189,20 +193,20 @@ class AjaxResponse {
} else {
# Let the client do the caching. Cache is not purged.
- header ( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $this->mCacheDuration ) . " GMT" );
- header ( "Cache-Control: s-maxage={$this->mCacheDuration}," .
+ header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $this->mCacheDuration ) . " GMT" );
+ header( "Cache-Control: s-maxage={$this->mCacheDuration}," .
"public,max-age={$this->mCacheDuration}" );
}
} else {
# always expired, always modified
- header ( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" ); // Date in the past
- header ( "Cache-Control: no-cache, must-revalidate" ); // HTTP/1.1
- header ( "Pragma: no-cache" ); // HTTP/1.0
+ header( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" ); // Date in the past
+ header( "Cache-Control: no-cache, must-revalidate" ); // HTTP/1.1
+ header( "Pragma: no-cache" ); // HTTP/1.0
}
if ( $this->mVary ) {
- header ( "Vary: " . $this->mVary );
+ header( "Vary: " . $this->mVary );
}
}
@@ -246,7 +250,7 @@ class AjaxResponse {
$ismodsince >= $wgCacheEpoch
) {
ini_set( 'zlib.output_compression', 0 );
- $this->setResponseCode( "304 Not Modified" );
+ $this->setResponseCode( 304 );
$this->disable();
$this->mLastModified = $lastmod;
diff --git a/includes/AuthPlugin.php b/includes/AuthPlugin.php
index 45ad4d1b..badf47c3 100644
--- a/includes/AuthPlugin.php
+++ b/includes/AuthPlugin.php
@@ -120,6 +120,8 @@ class AuthPlugin {
* The User object is passed by reference so it can be modified; don't
* forget the & on your function declaration.
*
+ * @deprecated since 1.26, use the UserLoggedIn hook instead. And assigning
+ * a different User object to $user is no longer supported.
* @param User $user
* @return bool
*/
@@ -204,6 +206,7 @@ class AuthPlugin {
* Update user information in the external authentication database.
* Return true if successful.
*
+ * @deprecated since 1.26, use the UserSaveSettings hook instead.
* @param User $user
* @return bool
*/
@@ -215,6 +218,7 @@ class AuthPlugin {
* Update user groups in the external authentication database.
* Return true if successful.
*
+ * @deprecated since 1.26, use the UserGroupsChanged hook instead.
* @param User $user
* @param array $addgroups Groups to add.
* @param array $delgroups Groups to remove.
@@ -278,6 +282,8 @@ class AuthPlugin {
* The User object is passed by reference so it can be modified; don't
* forget the & on your function declaration.
*
+ * @deprecated since 1.26, use the UserLoggedIn hook instead. And assigning
+ * a different User object to $user is no longer supported.
* @param User $user
* @param bool $autocreate True if user is being autocreated on login
*/
@@ -326,11 +332,21 @@ class AuthPluginUser {
return -1;
}
+ /**
+ * Indicate whether the user is locked
+ * @deprecated since 1.26, use the UserIsLocked hook instead.
+ * @return bool
+ */
public function isLocked() {
# Override this!
return false;
}
+ /**
+ * Indicate whether the user is hidden
+ * @deprecated since 1.26, use the UserIsHidden hook instead.
+ * @return bool
+ */
public function isHidden() {
# Override this!
return false;
diff --git a/includes/Block.php b/includes/Block.php
index 873a26d8..c5a16fce 100644
--- a/includes/Block.php
+++ b/includes/Block.php
@@ -23,15 +23,16 @@ class Block {
/** @var string */
public $mReason;
- /** @var bool|string */
+ /** @var string */
public $mTimestamp;
- /** @var int */
+ /** @var bool */
public $mAuto;
- /** @var bool|string */
+ /** @var string */
public $mExpiry;
+ /** @var bool */
public $mHideName;
/** @var int */
@@ -65,10 +66,10 @@ class Block {
protected $blocker;
/** @var bool */
- protected $isHardblock = true;
+ protected $isHardblock;
/** @var bool */
- protected $isAutoblocking = true;
+ protected $isAutoblocking;
# TYPE constants
const TYPE_USER = 1;
@@ -78,59 +79,84 @@ class Block {
const TYPE_ID = 5;
/**
- * @todo FIXME: Don't know what the best format to have for this constructor
- * is, but fourteen optional parameters certainly isn't it.
- * @param string $address
- * @param int $user
- * @param int $by
- * @param string $reason
- * @param mixed $timestamp
- * @param int $auto
- * @param string $expiry
- * @param int $anonOnly
- * @param int $createAccount
- * @param int $enableAutoblock
- * @param int $hideName
- * @param int $blockEmail
- * @param int $allowUsertalk
- * @param string $byText
+ * Create a new block with specified parameters on a user, IP or IP range.
+ *
+ * @param array $options Parameters of the block:
+ * address string|User Target user name, User object, IP address or IP range
+ * user int Override target user ID (for foreign users)
+ * by int User ID of the blocker
+ * reason string Reason of the block
+ * timestamp string The time at which the block comes into effect
+ * auto bool Is this an automatic block?
+ * expiry string Timestamp of expiration of the block or 'infinity'
+ * anonOnly bool Only disallow anonymous actions
+ * createAccount bool Disallow creation of new accounts
+ * enableAutoblock bool Enable automatic blocking
+ * hideName bool Hide the target user name
+ * blockEmail bool Disallow sending emails
+ * allowUsertalk bool Allow the target to edit its own talk page
+ * byText string Username of the blocker (for foreign users)
+ *
+ * @since 1.26 accepts $options array instead of individual parameters; order
+ * of parameters above reflects the original order
*/
- function __construct( $address = '', $user = 0, $by = 0, $reason = '',
- $timestamp = 0, $auto = 0, $expiry = '', $anonOnly = 0, $createAccount = 0, $enableAutoblock = 0,
- $hideName = 0, $blockEmail = 0, $allowUsertalk = 0, $byText = ''
- ) {
- if ( $timestamp === 0 ) {
- $timestamp = wfTimestampNow();
- }
+ function __construct( $options = array() ) {
+ $defaults = array(
+ 'address' => '',
+ 'user' => null,
+ 'by' => null,
+ 'reason' => '',
+ 'timestamp' => '',
+ 'auto' => false,
+ 'expiry' => '',
+ 'anonOnly' => false,
+ 'createAccount' => false,
+ 'enableAutoblock' => false,
+ 'hideName' => false,
+ 'blockEmail' => false,
+ 'allowUsertalk' => false,
+ 'byText' => '',
+ );
- if ( count( func_get_args() ) > 0 ) {
- # Soon... :D
- # wfDeprecated( __METHOD__ . " with arguments" );
+ if ( func_num_args() > 1 || !is_array( $options ) ) {
+ $options = array_combine(
+ array_slice( array_keys( $defaults ), 0, func_num_args() ),
+ func_get_args()
+ );
+ wfDeprecated( __METHOD__ . ' with multiple arguments', '1.26' );
}
- $this->setTarget( $address );
- if ( $this->target instanceof User && $user ) {
- $this->forcedTargetID = $user; // needed for foreign users
- }
- if ( $by ) { // local user
- $this->setBlocker( User::newFromId( $by ) );
- } else { // foreign user
- $this->setBlocker( $byText );
+ $options += $defaults;
+
+ $this->setTarget( $options['address'] );
+
+ if ( $this->target instanceof User && $options['user'] ) {
+ # Needed for foreign users
+ $this->forcedTargetID = $options['user'];
}
- $this->mReason = $reason;
- $this->mTimestamp = wfTimestamp( TS_MW, $timestamp );
- $this->mAuto = $auto;
- $this->isHardblock( !$anonOnly );
- $this->prevents( 'createaccount', $createAccount );
- if ( $expiry == 'infinity' || $expiry == wfGetDB( DB_SLAVE )->getInfinity() ) {
- $this->mExpiry = 'infinity';
+
+ if ( $options['by'] ) {
+ # Local user
+ $this->setBlocker( User::newFromID( $options['by'] ) );
} else {
- $this->mExpiry = wfTimestamp( TS_MW, $expiry );
+ # Foreign user
+ $this->setBlocker( $options['byText'] );
}
- $this->isAutoblocking( $enableAutoblock );
- $this->mHideName = $hideName;
- $this->prevents( 'sendemail', $blockEmail );
- $this->prevents( 'editownusertalk', !$allowUsertalk );
+
+ $this->mReason = $options['reason'];
+ $this->mTimestamp = wfTimestamp( TS_MW, $options['timestamp'] );
+ $this->mExpiry = wfGetDB( DB_SLAVE )->decodeExpiry( $options['expiry'] );
+
+ # Boolean settings
+ $this->mAuto = (bool)$options['auto'];
+ $this->mHideName = (bool)$options['hideName'];
+ $this->isHardblock( !$options['anonOnly'] );
+ $this->isAutoblocking( (bool)$options['enableAutoblock'] );
+
+ # Prevention measures
+ $this->prevents( 'sendemail', (bool)$options['blockEmail'] );
+ $this->prevents( 'editownusertalk', !$options['allowUsertalk'] );
+ $this->prevents( 'createaccount', (bool)$options['createAccount'] );
$this->mFromMaster = false;
}
@@ -375,16 +401,11 @@ class Block {
$this->mTimestamp = wfTimestamp( TS_MW, $row->ipb_timestamp );
$this->mAuto = $row->ipb_auto;
$this->mHideName = $row->ipb_deleted;
- $this->mId = $row->ipb_id;
+ $this->mId = (int)$row->ipb_id;
$this->mParentBlockId = $row->ipb_parent_block_id;
// I wish I didn't have to do this
- $db = wfGetDB( DB_SLAVE );
- if ( $row->ipb_expiry == $db->getInfinity() ) {
- $this->mExpiry = 'infinity';
- } else {
- $this->mExpiry = wfTimestamp( TS_MW, $row->ipb_expiry );
- }
+ $this->mExpiry = wfGetDB( DB_SLAVE )->decodeExpiry( $row->ipb_expiry );
$this->isHardblock( !$row->ipb_anon_only );
$this->isAutoblocking( $row->ipb_enable_autoblock );
@@ -452,11 +473,15 @@ class Block {
$dbw->insert( 'ipblocks', $row, __METHOD__, array( 'IGNORE' ) );
$affected = $dbw->affectedRows();
+ $this->mId = $dbw->insertId();
# Don't collide with expired blocks.
- # Do this after trying to insert to avoid pointless gap locks.
+ # Do this after trying to insert to avoid locking.
if ( !$affected ) {
- $dbw->delete( 'ipblocks',
+ # T96428: The ipb_address index uses a prefix on a field, so
+ # use a standard SELECT + DELETE to avoid annoying gap locks.
+ $ids = $dbw->selectFieldValues( 'ipblocks',
+ 'ipb_id',
array(
'ipb_address' => $row['ipb_address'],
'ipb_user' => $row['ipb_user'],
@@ -464,13 +489,14 @@ class Block {
),
__METHOD__
);
-
- $dbw->insert( 'ipblocks', $row, __METHOD__, array( 'IGNORE' ) );
- $affected = $dbw->affectedRows();
+ if ( $ids ) {
+ $dbw->delete( 'ipblocks', array( 'ipb_id' => $ids ), __METHOD__ );
+ $dbw->insert( 'ipblocks', $row, __METHOD__, array( 'IGNORE' ) );
+ $affected = $dbw->affectedRows();
+ $this->mId = $dbw->insertId();
+ }
}
- $this->mId = $dbw->insertId();
-
if ( $affected ) {
$auto_ipd_ids = $this->doRetroactiveAutoblock();
return array( 'id' => $this->mId, 'autoIds' => $auto_ipd_ids );
@@ -1113,7 +1139,7 @@ class Block {
$blocks = array();
foreach ( $rows as $row ) {
$block = self::newFromRow( $row );
- if ( !$block->deleteIfExpired() ) {
+ if ( !$block->deleteIfExpired() ) {
$blocks[] = $block;
}
}
diff --git a/includes/CategoryFinder.php b/includes/CategoryFinder.php
index 33de7404..77c43bf0 100644
--- a/includes/CategoryFinder.php
+++ b/includes/CategoryFinder.php
@@ -27,7 +27,7 @@
* articles are in one or all of a given subset of categories.
*
* Example use :
- * <code>
+ * @code
* # Determines whether the article with the page_id 12345 is in both
* # "Category 1" and "Category 2" or their subcategories, respectively
*
@@ -39,7 +39,7 @@
* );
* $a = $cf->run();
* print implode( ',' , $a );
- * </code>
+ * @endcode
*
*/
class CategoryFinder {
diff --git a/includes/CategoryViewer.php b/includes/CategoryViewer.php
index 66079c01..e2c31a66 100644
--- a/includes/CategoryViewer.php
+++ b/includes/CategoryViewer.php
@@ -329,7 +329,7 @@ class CategoryViewer extends ContextSource {
'category' => array( 'LEFT JOIN', array(
'cat_title = page_title',
'page_namespace' => NS_CATEGORY
- ))
+ ) )
)
);
diff --git a/includes/Collation.php b/includes/Collation.php
index 481d8e70..c1f0b388 100644
--- a/includes/Collation.php
+++ b/includes/Collation.php
@@ -320,16 +320,16 @@ class IcuCollation extends Collation {
// intl extension produces non null-terminated
// strings. Appending '' fixes it so that it doesn't generate
// a warning on each access in debug php.
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$key = $this->mainCollator->getSortKey( $string ) . '';
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $key;
}
function getPrimarySortKey( $string ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$key = $this->primaryCollator->getSortKey( $string ) . '';
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $key;
}
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index c13aa5f4..268a8d19 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -75,7 +75,7 @@ $wgConfigRegistry = array(
* MediaWiki version number
* @since 1.2
*/
-$wgVersion = '1.25.3';
+$wgVersion = '1.26.0';
/**
* Name of the site. It must be changed in LocalSettings.php
@@ -83,6 +83,14 @@ $wgVersion = '1.25.3';
$wgSitename = 'MediaWiki';
/**
+ * When the wiki is running behind a proxy and this is set to true, assumes that the proxy exposes
+ * the wiki on the standard ports (443 for https and 80 for http).
+ * @var bool
+ * @since 1.26
+ */
+$wgAssumeProxiesUseDefaultProtocolPorts = true;
+
+/**
* URL of the server.
*
* @par Example:
@@ -203,7 +211,7 @@ $wgLoadScript = false;
/**
* The URL path of the skins directory.
- * Defaults to "{$wgScriptPath}/skins".
+ * Defaults to "{$wgResourceBasePath}/skins".
* @since 1.3
*/
$wgStylePath = false;
@@ -218,7 +226,7 @@ $wgLocalStylePath = false;
/**
* The URL path of the extensions directory.
- * Defaults to "{$wgScriptPath}/extensions".
+ * Defaults to "{$wgResourceBasePath}/extensions".
* @since 1.16
*/
$wgExtensionAssetsPath = false;
@@ -472,13 +480,13 @@ $wgImgAuthUrlPathMap = array();
*
* These settings describe a foreign MediaWiki installation. They are optional, and will be ignored
* for local repositories:
- * - descBaseUrl URL of image description pages, e.g. http://en.wikipedia.org/wiki/File:
+ * - descBaseUrl URL of image description pages, e.g. https://en.wikipedia.org/wiki/File:
* - scriptDirUrl URL of the MediaWiki installation, equivalent to $wgScriptPath, e.g.
- * http://en.wikipedia.org/w
+ * https://en.wikipedia.org/w
* - scriptExtension Script extension of the MediaWiki installation, equivalent to
* $wgScriptExtension, e.g. .php5 defaults to .php
*
- * - articleUrl Equivalent to $wgArticlePath, e.g. http://en.wikipedia.org/wiki/$1
+ * - articleUrl Equivalent to $wgArticlePath, e.g. https://en.wikipedia.org/wiki/$1
* - fetchDescription Fetch the text of the remote file description page. Equivalent to
* $wgFetchCommonsDescriptions.
* - abbrvThreshold File names over this size will use the short form of thumbnail names.
@@ -518,6 +526,16 @@ $wgForeignFileRepos = array();
$wgUseInstantCommons = false;
/**
+ * Array of foreign file repo names (set in $wgForeignFileRepos above) that
+ * are allowable upload targets. These wikis must have some method of
+ * authentication (i.e. CentralAuth), and be CORS-enabled for this wiki.
+ *
+ * Example:
+ * $wgForeignUploadTargets = array( 'shared' );
+ */
+$wgForeignUploadTargets = array();
+
+/**
* File backend structure configuration.
*
* This is an array of file backend configuration arrays.
@@ -717,7 +735,7 @@ $wgMinUploadChunkSize = 1024; # 1KB
*
* @par Example:
* @code
- * $wgUploadNavigationUrl = 'http://commons.wikimedia.org/wiki/Special:Upload';
+ * $wgUploadNavigationUrl = 'https://commons.wikimedia.org/wiki/Special:Upload';
* @endcode
*/
$wgUploadNavigationUrl = false;
@@ -777,7 +795,7 @@ $wgHashedSharedUploadDirectory = true;
*
* Please specify the namespace, as in the example below.
*/
-$wgRepositoryBaseUrl = "http://commons.wikimedia.org/wiki/File:";
+$wgRepositoryBaseUrl = "https://commons.wikimedia.org/wiki/File:";
/**
* This is the list of preferred extensions for uploading files. Uploading files
@@ -884,6 +902,7 @@ $wgMediaHandlers = array(
'image/png' => 'PNGHandler',
'image/gif' => 'GIFHandler',
'image/tiff' => 'TiffHandler',
+ 'image/webp' => 'WebPHandler',
'image/x-ms-bmp' => 'BmpHandler',
'image/x-bmp' => 'BmpHandler',
'image/x-xcf' => 'XCFHandler',
@@ -978,6 +997,14 @@ $wgJpegTran = '/usr/bin/jpegtran';
*/
$wgExiv2Command = '/usr/bin/exiv2';
+
+/**
+ * Path to exiftool binary. Used for lossless ICC profile swapping.
+ *
+ * @since 1.26
+ */
+$wgExiftool = '/usr/bin/exiftool';
+
/**
* Scalable Vector Graphics (SVG) may be uploaded as images.
* Since SVG support is not yet standard in browsers, it is
@@ -1012,7 +1039,7 @@ $wgSVGConverterPath = '';
/**
* Don't scale a SVG larger than this
*/
-$wgSVGMaxSize = 2048;
+$wgSVGMaxSize = 5120;
/**
* Don't read SVG metadata beyond this point.
@@ -1331,6 +1358,14 @@ $wgUploadThumbnailRenderHttpCustomHost = false;
$wgUploadThumbnailRenderHttpCustomDomain = false;
/**
+ * When this variable is true and JPGs use the sRGB ICC profile, swaps it for the more lightweight
+ * (and free) TinyRGB profile when generating thumbnails.
+ *
+ * @since 1.26
+ */
+$wgUseTinyRGBForJPGThumbnails = false;
+
+/**
* Default parameters for the "<gallery>" tag
*/
$wgGalleryOptions = array(
@@ -1580,7 +1615,8 @@ $wgEnotifRevealEditorAddress = false;
/**
* Send notification mails on minor edits to watchlist pages. This is enabled
- * by default. Does not affect user talk notifications.
+ * by default. User talk notifications are affected by this, $wgEnotifUserTalk, and
+ * the nominornewtalk user right.
*/
$wgEnotifMinorEdits = true;
@@ -1843,12 +1879,6 @@ $wgDBservers = false;
$wgLBFactoryConf = array( 'class' => 'LBFactorySimple' );
/**
- * How long to wait for a slave to catch up to the master
- * @deprecated since 1.24
- */
-$wgMasterWaitTimeout = 10;
-
-/**
* File to log database errors to
*/
$wgDBerrorLog = false;
@@ -1862,11 +1892,11 @@ $wgDBerrorLog = false;
*
* @par Examples:
* @code
- * $wgLocaltimezone = 'UTC';
- * $wgLocaltimezone = 'GMT';
- * $wgLocaltimezone = 'PST8PDT';
- * $wgLocaltimezone = 'Europe/Sweden';
- * $wgLocaltimezone = 'CET';
+ * $wgDBerrorLogTZ = 'UTC';
+ * $wgDBerrorLogTZ = 'GMT';
+ * $wgDBerrorLogTZ = 'PST8PDT';
+ * $wgDBerrorLogTZ = 'Europe/Sweden';
+ * $wgDBerrorLogTZ = 'CET';
* @endcode
*
* @since 1.20
@@ -1874,13 +1904,6 @@ $wgDBerrorLog = false;
$wgDBerrorLogTZ = false;
/**
- * Scale load balancer polling time so that under overload conditions, the
- * database server receives a SHOW STATUS query at an average interval of this
- * many microseconds
- */
-$wgDBAvgStatusPoll = 2000;
-
-/**
* Set to true to engage MySQL 4.1/5.0 charset-related features;
* for now will just cause sending of 'SET NAMES=utf8' on connect.
*
@@ -2067,6 +2090,14 @@ $wgMaxArticleSize = 2048;
*/
$wgMemoryLimit = "50M";
+/**
+ * The minimum amount of time that MediaWiki needs for "slow" write request,
+ * particularly ones with multiple non-atomic writes that *should* be as
+ * transactional as possible; MediaWiki will call set_time_limit() if needed.
+ * @since 1.26
+ */
+$wgTransactionalTimeLimit = 120;
+
/** @} */ # end performance hacks }
/************************************************************************//**
@@ -2086,8 +2117,8 @@ $wgCacheDirectory = false;
/**
* Main cache type. This should be a cache with fast access, but it may have
- * limited space. By default, it is disabled, since the database is not fast
- * enough to make it worthwhile.
+ * limited space. By default, it is disabled, since the stock database cache
+ * is not fast enough to make it worthwhile.
*
* The options are:
*
@@ -2157,6 +2188,19 @@ $wgObjectCaches = array(
CACHE_ACCEL => array( 'factory' => 'ObjectCache::newAccelerator' ),
CACHE_MEMCACHED => array( 'factory' => 'ObjectCache::newMemcached', 'loggroup' => 'memcached' ),
+ 'db-replicated' => array(
+ 'class' => 'ReplicatedBagOStuff',
+ 'readFactory' => array(
+ 'class' => 'SqlBagOStuff',
+ 'args' => array( array( 'slaveOnly' => true ) )
+ ),
+ 'writeFactory' => array(
+ 'class' => 'SqlBagOStuff',
+ 'args' => array( array( 'slaveOnly' => false ) )
+ ),
+ 'loggroup' => 'SQLBagOStuff'
+ ),
+
'apc' => array( 'class' => 'APCBagOStuff' ),
'xcache' => array( 'class' => 'XCacheBagOStuff' ),
'wincache' => array( 'class' => 'WinCacheBagOStuff' ),
@@ -2166,6 +2210,71 @@ $wgObjectCaches = array(
);
/**
+ * Main Wide-Area-Network cache type. This should be a cache with fast access,
+ * but it may have limited space. By default, it is disabled, since the basic stock
+ * cache is not fast enough to make it worthwhile. For single data-center setups, this can
+ * simply be pointed to a cache in $wgWANObjectCaches that uses a local $wgObjectCaches
+ * cache with a relayer of type EventRelayerNull.
+ *
+ * The options are:
+ * - false: Configure the cache using $wgMainCacheType, without using
+ * a relayer (only matters if there are multiple data-centers)
+ * - CACHE_NONE: Do not cache
+ * - (other): A string may be used which identifies a cache
+ * configuration in $wgWANObjectCaches
+ * @since 1.26
+ */
+$wgMainWANCache = false;
+
+/**
+ * Advanced WAN object cache configuration.
+ *
+ * Each WAN cache wraps a registered object cache (for the local cluster)
+ * and it must also be configured to point to a PubSub instance. Subscribers
+ * must be configured to relay purges to the actual cache servers.
+ *
+ * The format is an associative array where the key is a cache identifier, and
+ * the value is an associative array of parameters. The "cacheId" parameter is
+ * a cache identifier from $wgObjectCaches. The "relayerConfig" parameter is an
+ * array used to construct an EventRelayer object. The "pool" parameter is a
+ * string that is used as a PubSub channel prefix.
+ *
+ * @since 1.26
+ */
+$wgWANObjectCaches = array(
+ CACHE_NONE => array(
+ 'class' => 'WANObjectCache',
+ 'cacheId' => CACHE_NONE,
+ 'pool' => 'mediawiki-main-none',
+ 'relayerConfig' => array( 'class' => 'EventRelayerNull' )
+ )
+ /* Example of a simple single data-center cache:
+ 'memcached-php' => array(
+ 'class' => 'WANObjectCache',
+ 'cacheId' => 'memcached-php',
+ 'pool' => 'mediawiki-main-memcached',
+ 'relayerConfig' => array( 'class' => 'EventRelayerNull' )
+ )
+ */
+);
+
+/**
+ * Main object stash type. This should be a fast storage system for storing
+ * lightweight data like hit counters and user activity. Sites with multiple
+ * data-centers should have this use a store that replicates all writes. The
+ * store should have enough consistency for CAS operations to be usable.
+ * Reads outside of those needed for merge() may be eventually consistent.
+ *
+ * The options are:
+ * - db: Store cache objects in the DB
+ * - (other): A string may be used which identifies a cache
+ * configuration in $wgObjectCaches
+ *
+ * @since 1.26
+ */
+$wgMainStash = 'db-replicated';
+
+/**
* The expiry time for the parser cache, in seconds.
* The default is 86400 (one day).
*/
@@ -2239,11 +2348,13 @@ $wgAdaptiveMessageCache = false;
* Localisation cache configuration. Associative array with keys:
* class: The class to use. May be overridden by extensions.
*
- * store: The location to store cache data. May be 'files', 'db' or
+ * store: The location to store cache data. May be 'files', 'array', 'db' or
* 'detect'. If set to "files", data will be in CDB files. If set
* to "db", data will be stored to the database. If set to
* "detect", files will be used if $wgCacheDirectory is set,
* otherwise the database will be used.
+ * "array" is an experimental option that uses PHP files that
+ * store static arrays.
*
* storeClass: The class name for the underlying storage. If set to a class
* name, it overrides the "store" setting.
@@ -2311,13 +2422,8 @@ $wgUseFileCache = false;
$wgFileCacheDepth = 2;
/**
- * Keep parsed pages in a cache (objectcache table or memcached)
- * to speed up output of the same page viewed by another user with the
- * same options.
- *
- * This can provide a significant speedup for medium to large pages,
- * so you probably want to keep it on. Extensions that conflict with the
- * parser cache should disable the cache on a per-page basis instead.
+ * Kept for extension compatibility; see $wgParserCacheType
+ * @deprecated 1.26
*/
$wgEnableParserCache = true;
@@ -2447,13 +2553,16 @@ $wgInternalServer = false;
/**
* Cache timeout for the squid, will be sent as s-maxage (without ESI) or
* Surrogate-Control (with ESI). Without ESI, you should strip out s-maxage in
- * the Squid config. 18000 seconds = 5 hours, more cache hits with 2678400 = 31
- * days
+ * the Squid config.
+ *
+* 18000 seconds = 5 hours, more cache hits with 2678400 = 31 days.
*/
$wgSquidMaxage = 18000;
/**
* Default maximum age for raw CSS/JS accesses
+ *
+ * 300 seconds = 5 minutes.
*/
$wgForcedRawSMaxage = 300;
@@ -2742,14 +2851,14 @@ $wgBrowserBlackList = array(
* - Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC)
* - [...]
*
- * @link http://en.wikipedia.org/w/index.php?diff=12356041&oldid=12355864
- * @link http://en.wikipedia.org/wiki/Template%3AOS9
+ * @link https://en.wikipedia.org/w/index.php?diff=12356041&oldid=12355864
+ * @link https://en.wikipedia.org/wiki/Template%3AOS9
*/
'/^Mozilla\/4\.0 \(compatible; MSIE \d+\.\d+; Mac_PowerPC\)/',
/**
* Google wireless transcoder, seems to eat a lot of chars alive
- * http://it.wikipedia.org/w/index.php?title=Luciano_Ligabue&diff=prev&oldid=8857361
+ * https://it.wikipedia.org/w/index.php?title=Luciano_Ligabue&diff=prev&oldid=8857361
*/
'/^Mozilla\/4\.0 \(compatible; MSIE 6.0; Windows NT 5.0; Google Wireless Transcoder;\)/'
);
@@ -3382,8 +3491,8 @@ $wgResourceModuleSkinStyles = array();
$wgResourceLoaderSources = array();
/**
- * Default 'remoteBasePath' value for instances of ResourceLoaderFileModule.
- * If not set, then $wgScriptPath will be used as a fallback.
+ * The default 'remoteBasePath' value for instances of ResourceLoaderFileModule.
+ * Defaults to $wgScriptPath.
*/
$wgResourceBasePath = null;
@@ -3422,13 +3531,6 @@ $wgResourceLoaderMaxage = array(
$wgResourceLoaderDebug = false;
/**
- * Enable embedding of certain resources using Edge Side Includes. This will
- * improve performance but only works if there is something in front of the
- * web server (e..g a Squid or Varnish server) configured to process the ESI.
- */
-$wgResourceLoaderUseESI = false;
-
-/**
* Put each statement on its own line when minifying JavaScript. This makes
* debugging in non-debug mode a bit easier.
*/
@@ -3442,28 +3544,27 @@ $wgResourceLoaderMinifierStatementsOnOwnLine = false;
$wgResourceLoaderMinifierMaxLineLength = 1000;
/**
- * Whether to include the mediawiki.legacy JS library (old wikibits.js), and its
- * dependencies.
+ * Whether to ensure the mediawiki.legacy library is loaded before other modules.
+ *
+ * @deprecated since 1.26: Always declare dependencies.
*/
$wgIncludeLegacyJavaScript = true;
/**
- * Whether to preload the mediawiki.util module as blocking module in the top
- * queue.
+ * Whether to ensure the mediawiki.util is loaded before other modules.
*
- * Before MediaWiki 1.19, modules used to load slower/less asynchronous which
- * allowed modules to lack dependencies on 'popular' modules that were likely
- * loaded already.
+ * Before MediaWiki 1.19, modules used to load less asynchronous which allowed
+ * modules to lack dependencies on 'popular' modules that were likely loaded already.
*
* This setting is to aid scripts during migration by providing mediawiki.util
- * unconditionally (which was the most commonly missed dependency).
- * It doesn't cover all missing dependencies obviously but should fix most of
- * them.
+ * unconditionally (which was the most commonly missed dependency). It doesn't
+ * cover all missing dependencies obviously but should fix most of them.
*
* This should be removed at some point after site/user scripts have been fixed.
* Enable this if your wiki has a large amount of user/site scripts that are
* lacking dependencies.
- * @todo Deprecate
+ *
+ * @deprecated since 1.26: Always declare dependencies.
*/
$wgPreloadJavaScriptMwUtil = false;
@@ -3529,13 +3630,6 @@ $wgResourceLoaderValidateJS = true;
$wgResourceLoaderValidateStaticJS = false;
/**
- * If set to true, asynchronous loading of bottom-queue scripts in the "<head>"
- * will be enabled. This is an experimental feature that's supposed to make
- * JavaScript load faster.
- */
-$wgResourceLoaderExperimentalAsyncLoading = false;
-
-/**
* Global LESS variables. An associative array binding variable names to
* LESS code snippets representing their values.
*
@@ -3561,18 +3655,6 @@ $wgResourceLoaderExperimentalAsyncLoading = false;
$wgResourceLoaderLESSVars = array();
/**
- * Custom LESS functions. An associative array mapping function name to PHP
- * callable.
- *
- * Changes to LESS functions do not trigger cache invalidation.
- *
- * @since 1.22
- * @deprecated since 1.24 Questionable usefulness and problematic to support,
- * will be removed in the future.
- */
-$wgResourceLoaderLESSFunctions = array();
-
-/**
* Default import paths for LESS modules. LESS files referenced in @import
* statements will be looked up here first, and relative to the importing file
* second. To avoid collisions, it's important for the LESS files in these
@@ -3881,6 +3963,15 @@ $wgTrackingCategories = array();
$wgContentNamespaces = array( NS_MAIN );
/**
+ * Array of namespaces, in addition to the talk namespaces, where signatures
+ * (~~~~) are likely to be used. This determines whether to display the
+ * Signature button on the edit toolbar, and may also be used by extensions.
+ * For example, "traditional" style wikis, where content and discussion are
+ * intermixed, could place NS_MAIN and NS_PROJECT namespaces in this array.
+ */
+$wgExtraSignatureNamespaces = array();
+
+/**
* Max number of redirects to follow when resolving redirects.
* 1 means only the first redirect is followed (default behavior).
* 0 or less means no redirects are followed.
@@ -4031,44 +4122,55 @@ $wgEnableImageWhitelist = true;
$wgAllowImageTag = false;
/**
- * $wgUseTidy: use tidy to make sure HTML output is sane.
- * Tidy is a free tool that fixes broken HTML.
- * See http://www.w3.org/People/Raggett/tidy/
+ * Configuration for HTML postprocessing tool. Set this to a configuration
+ * array to enable an external tool. Dave Raggett's "HTML Tidy" is typically
+ * used. See http://www.w3.org/People/Raggett/tidy/
*
- * - $wgTidyBin should be set to the path of the binary and
- * - $wgTidyConf to the path of the configuration file.
- * - $wgTidyOpts can include any number of parameters.
- * - $wgTidyInternal controls the use of the PECL extension or the
- * libtidy (PHP >= 5) extension to use an in-process tidy library instead
- * of spawning a separate program.
- * Normally you shouldn't need to override the setting except for
- * debugging. To install, use 'pear install tidy' and add a line
- * 'extension=tidy.so' to php.ini.
+ * If this is null and $wgUseTidy is true, the deprecated configuration
+ * parameters will be used instead.
+ *
+ * If this is null and $wgUseTidy is false, a pure PHP fallback will be used.
+ *
+ * Keys are:
+ * - driver: May be:
+ * - RaggettInternalHHVM: Use the limited-functionality HHVM extension
+ * - RaggettInternalPHP: Use the PECL extension
+ * - RaggettExternal: Shell out to an external binary (tidyBin)
+ *
+ * - tidyConfigFile: Path to configuration file for any of the Raggett drivers
+ * - debugComment: True to add a comment to the output with warning messages
+ * - tidyBin: For RaggettExternal, the path to the tidy binary.
+ * - tidyCommandLine: For RaggettExternal, additional command line options.
*/
-$wgUseTidy = false;
+$wgTidyConfig = null;
/**
- * @see $wgUseTidy
+ * Set this to true to use the deprecated tidy configuration parameters.
+ * @deprecated use $wgTidyConfig
*/
-$wgAlwaysUseTidy = false;
+$wgUseTidy = false;
/**
- * @see $wgUseTidy
+ * The path to the tidy binary.
+ * @deprecated Use $wgTidyConfig['tidyBin']
*/
$wgTidyBin = 'tidy';
/**
- * @see $wgUseTidy
+ * The path to the tidy config file
+ * @deprecated Use $wgTidyConfig['tidyConfigFile']
*/
-$wgTidyConf = $IP . '/includes/tidy.conf';
+$wgTidyConf = $IP . '/includes/tidy/tidy.conf';
/**
- * @see $wgUseTidy
+ * The command line options to the tidy binary
+ * @deprecated Use $wgTidyConfig['tidyCommandLine']
*/
$wgTidyOpts = '';
/**
- * @see $wgUseTidy
+ * Set this to true to use the tidy extension
+ * @deprecated Use $wgTidyConfig['driver']
*/
$wgTidyInternal = extension_loaded( 'tidy' );
@@ -4198,6 +4300,59 @@ $wgActiveUserDays = 30;
*/
/**
+ * Password policy for local wiki users. A user's effective policy
+ * is the superset of all policy statements from the policies for the
+ * groups where the user is a member. If more than one group policy
+ * include the same policy statement, the value is the max() of the
+ * values. Note true > false. The 'default' policy group is required,
+ * and serves as the minimum policy for all users. New statements can
+ * be added by appending to $wgPasswordPolicy['checks'].
+ * Statements:
+ * - MinimalPasswordLength - minimum length a user can set
+ * - MinimumPasswordLengthToLogin - passwords shorter than this will
+ * not be allowed to login, regardless if it is correct.
+ * - MaximalPasswordLength - maximum length password a user is allowed
+ * to attempt. Prevents DoS attacks with pbkdf2.
+ * - PasswordCannotMatchUsername - Password cannot match username to
+ * - PasswordCannotMatchBlacklist - Username/password combination cannot
+ * match a specific, hardcoded blacklist.
+ * @since 1.26
+ */
+$wgPasswordPolicy = array(
+ 'policies' => array(
+ 'bureaucrat' => array(
+ 'MinimalPasswordLength' => 8,
+ 'MinimumPasswordLengthToLogin' => 1,
+ 'PasswordCannotMatchUsername' => true,
+ ),
+ 'sysop' => array(
+ 'MinimalPasswordLength' => 8,
+ 'MinimumPasswordLengthToLogin' => 1,
+ 'PasswordCannotMatchUsername' => true,
+ ),
+ 'bot' => array(
+ 'MinimalPasswordLength' => 8,
+ 'MinimumPasswordLengthToLogin' => 1,
+ 'PasswordCannotMatchUsername' => true,
+ ),
+ 'default' => array(
+ 'MinimalPasswordLength' => 1,
+ 'PasswordCannotMatchUsername' => true,
+ 'PasswordCannotMatchBlacklist' => true,
+ 'MaximalPasswordLength' => 4096,
+ ),
+ ),
+ 'checks' => array(
+ 'MinimalPasswordLength' => 'PasswordPolicyChecks::checkMinimalPasswordLength',
+ 'MinimumPasswordLengthToLogin' => 'PasswordPolicyChecks::checkMinimumPasswordLengthToLogin',
+ 'PasswordCannotMatchUsername' => 'PasswordPolicyChecks::checkPasswordCannotMatchUsername',
+ 'PasswordCannotMatchBlacklist' => 'PasswordPolicyChecks::checkPasswordCannotMatchBlacklist',
+ 'MaximalPasswordLength' => 'PasswordPolicyChecks::checkMaximalPasswordLength',
+ ),
+);
+
+
+/**
* For compatibility with old installations set to false
* @deprecated since 1.24 will be removed in future
*/
@@ -4206,8 +4361,9 @@ $wgPasswordSalt = true;
/**
* Specifies the minimal length of a user password. If set to 0, empty pass-
* words are allowed.
+ * @deprecated since 1.26, use $wgPasswordPolicy's MinimalPasswordLength.
*/
-$wgMinimalPasswordLength = 1;
+$wgMinimalPasswordLength = false;
/**
* Specifies the maximal length of a user password (T64685).
@@ -4218,8 +4374,9 @@ $wgMinimalPasswordLength = 1;
*
* @warning Unlike other password settings, user with passwords greater than
* the maximum will not be able to log in.
+ * @deprecated since 1.26, use $wgPasswordPolicy's MaximalPasswordLength.
*/
-$wgMaximalPasswordLength = 4096;
+$wgMaximalPasswordLength = false;
/**
* Specifies if users should be sent to a password-reset form on login, if their
@@ -4295,7 +4452,7 @@ $wgPasswordConfig = array(
*/
$wgPasswordResetRoutes = array(
'username' => true,
- 'email' => false,
+ 'email' => true,
);
/**
@@ -4322,6 +4479,7 @@ $wgReservedUsernames = array(
'msg:double-redirect-fixer', // Automatic double redirect fix
'msg:usermessage-editor', // Default user for leaving user messages
'msg:proxyblocker', // For $wgProxyList and Special:Blockme (removed in 1.22)
+ 'msg:spambot_username', // Used by cleanupSpam.php
);
/**
@@ -4397,7 +4555,7 @@ $wgHiddenPrefs = array();
* This is used in a regular expression character class during
* registration (regex metacharacters like / are escaped).
*/
-$wgInvalidUsernameCharacters = '@';
+$wgInvalidUsernameCharacters = '@:';
/**
* Character used as a delimiter when testing for interwiki userrights
@@ -4413,7 +4571,7 @@ $wgUserrightsInterwikiDelimiter = '@';
/**
* This is to let user authenticate using https when they come from http.
* Based on an idea by George Herbert on wikitech-l:
- * http://lists.wikimedia.org/pipermail/wikitech-l/2010-October/050039.html
+ * https://lists.wikimedia.org/pipermail/wikitech-l/2010-October/050039.html
* @since 1.17
*/
$wgSecureLogin = false;
@@ -4433,7 +4591,7 @@ $wgAutoblockExpiry = 86400;
/**
* Set this to true to allow blocked users to edit their own user talk page.
*/
-$wgBlockAllowsUTEdit = false;
+$wgBlockAllowsUTEdit = true;
/**
* Allow sysops to ban users from accessing Emailuser
@@ -4940,7 +5098,7 @@ $wgAccountCreationThrottle = 0;
* There's no administrator override on-wiki, so be careful what you set. :)
* May be an array of regexes or a single string for backwards compatibility.
*
- * @see http://en.wikipedia.org/wiki/Regular_expression
+ * @see https://en.wikipedia.org/wiki/Regular_expression
*
* @note Each regex needs a beginning/end delimiter, eg: # or /
*/
@@ -5145,6 +5303,22 @@ $wgProxyList = array();
$wgCookieExpiration = 180 * 86400;
/**
+ * The identifiers of the login cookies that can have their lifetimes
+ * extended independently of all other login cookies.
+ *
+ * @var string[]
+ */
+$wgExtendedLoginCookies = array( 'UserID', 'Token' );
+
+/**
+ * Default login cookie lifetime, in seconds. Setting
+ * $wgExtendLoginCookieExpiration to null will use $wgCookieExpiration to
+ * calculate the cookie lifetime. As with $wgCookieExpiration, 0 will make
+ * login cookies session-only.
+ */
+$wgExtendedLoginCookieExpiration = null;
+
+/**
* Set to set an explicit domain on the login cookies eg, "justthis.domain.org"
* or ".any.subdomain.net"
*/
@@ -5282,6 +5456,36 @@ $wgDebugDumpSql = false;
$wgDebugDumpSqlLength = 500;
/**
+ * Performance expectations for DB usage
+ *
+ * @since 1.26
+ */
+$wgTrxProfilerLimits = array(
+ // Basic GET and POST requests
+ 'GET' => array(
+ 'masterConns' => 0,
+ 'writes' => 0,
+ 'readQueryTime' => 5
+ ),
+ 'POST' => array(
+ 'readQueryTime' => 5,
+ 'writeQueryTime' => 1,
+ 'maxAffected' => 500
+ ),
+ // Background job runner
+ 'JobRunner' => array(
+ 'readQueryTime' => 30,
+ 'writeQueryTime' => 5,
+ 'maxAffected' => 500
+ ),
+ // Command-line scripts
+ 'Maintenance' => array(
+ 'writeQueryTime' => 5,
+ 'maxAffected' => 1000
+ )
+);
+
+/**
* Map of string log group names to log destinations.
*
* If set, wfDebugLog() output for that group will go to that file instead
@@ -5447,7 +5651,7 @@ $wgProfilePerHost = null;
*
* The host should be running a daemon which can be obtained from MediaWiki
* Git at:
- * http://git.wikimedia.org/tree/operations%2Fsoftware.git/master/udpprofile
+ * https://git.wikimedia.org/tree/operations%2Fsoftware.git/master/udpprofile
*
* @deprecated set $wgProfiler['udphost'] instead
*/
@@ -5504,6 +5708,29 @@ $wgAggregateStatsID = false;
$wgStatsFormatString = "stats/%s - %s 1 1 1 1 %s\n";
/**
+ * Destination of statsd metrics.
+ *
+ * A host or host:port of a statsd server. Port defaults to 8125.
+ *
+ * If not set, statsd metrics will not be collected.
+ *
+ * @see wfLogProfilingData
+ * @since 1.25
+ */
+$wgStatsdServer = false;
+
+/**
+ * Prefix for metric names sent to wgStatsdServer.
+ *
+ * Defaults to "MediaWiki".
+ *
+ * @see RequestContext::getStats
+ * @see BufferingStatsdDataFactory
+ * @since 1.25
+ */
+$wgStatsdMetricPrefix = false;
+
+/**
* InfoAction retrieves a list of transclusion links (both to and from).
* This number puts a limit on that query in the case of highly transcluded
* templates.
@@ -5836,6 +6063,21 @@ $wgGitRepositoryViewers = array(
$wgRCMaxAge = 90 * 24 * 3600;
/**
+ * Page watchers inactive for more than this many seconds are considered inactive.
+ * Used mainly by action=info. Default: 180 days = about six months.
+ * @since 1.26
+ */
+$wgWatchersMaxAge = 180 * 24 * 3600;
+
+/**
+ * If active watchers (per above) are this number or less, do not disclose it.
+ * Left to 1, prevents unprivileged users from knowing for sure that there are 0.
+ * Set to -1 if you want to always complement watchers count with this info.
+ * @since 1.26
+ */
+$wgUnwatchedPageSecret = 1;
+
+/**
* Filter $wgRCLinkDays by $wgRCMaxAge to avoid showing links for numbers
* higher than what will be stored. Note that this is disabled by default
* because we sometimes do have RC data which is beyond the limit for some
@@ -6453,6 +6695,7 @@ $wgJobClasses = array(
'ThumbnailRender' => 'ThumbnailRenderJob',
'recentChangesUpdate' => 'RecentChangesUpdateJob',
'refreshLinksPrioritized' => 'RefreshLinksJob', // for cascading protection
+ 'activityUpdateJob' => 'ActivityUpdateJob',
'enqueue' => 'EnqueueJob', // local queue for multi-DC setups
'null' => 'NullJob'
);
@@ -6482,13 +6725,28 @@ $wgJobTypesExcludedFromDefaultQueue = array( 'AssembleUploadChunks', 'PublishSta
$wgJobBackoffThrottling = array();
/**
+ * Make job runners commit changes for slave-lag prone jobs one job at a time.
+ * This is useful if there are many job workers that race on slave lag checks.
+ * If set, jobs taking this many seconds of DB write time have serialized commits.
+ *
+ * Note that affected jobs may have worse lock contention. Also, if they affect
+ * several DBs at once they may have a smaller chance of being atomic due to the
+ * possibility of connection loss while queueing up to commit. Affected jobs may
+ * also fail due to the commit lock acquisition timeout.
+ *
+ * @var float|bool
+ * @since 1.26
+ */
+$wgJobSerialCommitThreshold = false;
+
+/**
* Map of job types to configuration arrays.
* This determines which queue class and storage system is used for each job type.
* Job types that do not have explicit configuration will use the 'default' config.
* These settings should be global to all wikis.
*/
$wgJobTypeConf = array(
- 'default' => array( 'class' => 'JobQueueDB', 'order' => 'random' ),
+ 'default' => array( 'class' => 'JobQueueDB', 'order' => 'random', 'claimTTL' => 3600 ),
);
/**
@@ -6604,6 +6862,7 @@ $wgLogTypes = array(
'suppress',
'tag',
'managetags',
+ 'contentmodel',
);
/**
@@ -6679,15 +6938,15 @@ $wgLogNames = array(
$wgLogHeaders = array(
'' => 'alllogstext',
'block' => 'blocklogtext',
- 'protect' => 'protectlogtext',
- 'rights' => 'rightslogtext',
'delete' => 'dellogpagetext',
- 'upload' => 'uploadlogpagetext',
- 'move' => 'movelogpagetext',
'import' => 'importlogpagetext',
- 'patrol' => 'patrol-log-header',
'merge' => 'mergelogpagetext',
+ 'move' => 'movelogpagetext',
+ 'patrol' => 'patrol-log-header',
+ 'protect' => 'protectlogtext',
+ 'rights' => 'rightslogtext',
'suppress' => 'suppressionlogtext',
+ 'upload' => 'uploadlogpagetext',
);
/**
@@ -6697,10 +6956,9 @@ $wgLogHeaders = array(
* Extensions with custom log types may add to this array.
*/
$wgLogActions = array(
- 'protect/protect' => 'protectedarticle',
'protect/modify' => 'modifiedarticleprotection',
+ 'protect/protect' => 'protectedarticle',
'protect/unprotect' => 'unprotectedarticle',
- 'protect/move_prot' => 'movedarticleprotection',
);
/**
@@ -6710,34 +6968,36 @@ $wgLogActions = array(
* @see LogFormatter
*/
$wgLogActionsHandlers = array(
- 'move/move' => 'MoveLogFormatter',
- 'move/move_redir' => 'MoveLogFormatter',
+ 'block/block' => 'BlockLogFormatter',
+ 'block/reblock' => 'BlockLogFormatter',
+ 'block/unblock' => 'BlockLogFormatter',
+ 'contentmodel/change' => 'ContentModelLogFormatter',
'delete/delete' => 'DeleteLogFormatter',
+ 'delete/event' => 'DeleteLogFormatter',
'delete/restore' => 'DeleteLogFormatter',
'delete/revision' => 'DeleteLogFormatter',
- 'delete/event' => 'DeleteLogFormatter',
- 'suppress/revision' => 'DeleteLogFormatter',
- 'suppress/event' => 'DeleteLogFormatter',
- 'suppress/delete' => 'DeleteLogFormatter',
- 'patrol/patrol' => 'PatrolLogFormatter',
- 'rights/rights' => 'RightsLogFormatter',
- 'rights/autopromote' => 'RightsLogFormatter',
- 'upload/upload' => 'UploadLogFormatter',
- 'upload/overwrite' => 'UploadLogFormatter',
- 'upload/revert' => 'UploadLogFormatter',
- 'merge/merge' => 'MergeLogFormatter',
- 'tag/update' => 'TagLogFormatter',
- 'managetags/create' => 'LogFormatter',
- 'managetags/delete' => 'LogFormatter',
+ 'import/interwiki' => 'LogFormatter',
+ 'import/upload' => 'LogFormatter',
'managetags/activate' => 'LogFormatter',
+ 'managetags/create' => 'LogFormatter',
'managetags/deactivate' => 'LogFormatter',
- 'block/block' => 'BlockLogFormatter',
- 'block/unblock' => 'BlockLogFormatter',
- 'block/reblock' => 'BlockLogFormatter',
+ 'managetags/delete' => 'LogFormatter',
+ 'merge/merge' => 'MergeLogFormatter',
+ 'move/move' => 'MoveLogFormatter',
+ 'move/move_redir' => 'MoveLogFormatter',
+ 'patrol/patrol' => 'PatrolLogFormatter',
+ 'protect/move_prot' => 'ProtectLogFormatter',
+ 'rights/autopromote' => 'RightsLogFormatter',
+ 'rights/rights' => 'RightsLogFormatter',
'suppress/block' => 'BlockLogFormatter',
+ 'suppress/delete' => 'DeleteLogFormatter',
+ 'suppress/event' => 'DeleteLogFormatter',
'suppress/reblock' => 'BlockLogFormatter',
- 'import/upload' => 'LogFormatter',
- 'import/interwiki' => 'LogFormatter',
+ 'suppress/revision' => 'DeleteLogFormatter',
+ 'tag/update' => 'TagLogFormatter',
+ 'upload/overwrite' => 'UploadLogFormatter',
+ 'upload/revert' => 'UploadLogFormatter',
+ 'upload/upload' => 'UploadLogFormatter',
);
/**
@@ -6764,14 +7024,6 @@ $wgAllowSpecialInclusion = true;
$wgDisableQueryPageUpdate = false;
/**
- * List of special pages, followed by what subtitle they should go under
- * at Special:SpecialPages
- *
- * @deprecated since 1.21 Override SpecialPage::getGroupName instead
- */
-$wgSpecialPageGroups = array();
-
-/**
* On Special:Unusedimages, consider images "used", if they are put
* into a category. Default (false) is not to count those as used.
*/
@@ -7009,12 +7261,6 @@ $wgAPIPropModules = array();
$wgAPIListModules = array();
/**
- * This variable is ignored. To add your module to the API, please add it to $wgAPI*Modules
- * @deprecated since 1.21
- */
-$wgAPIGeneratorModules = array();
-
-/**
* Maximum amount of rows to scan in a DB query in the API
* The default value is generally fine
*/
@@ -7464,6 +7710,7 @@ $wgUseLinkNamespaceDBFields = true;
* $wgVirtualRestConfig['modules']['parsoid'] = array(
* 'url' => 'http://localhost:8000',
* 'prefix' => 'enwiki',
+ * 'domain' => 'en.wikipedia.org',
* );
*
* @var array
@@ -7474,12 +7721,22 @@ $wgVirtualRestConfig = array(
'global' => array(
# Timeout in seconds
'timeout' => 360,
+ # 'domain' is set to $wgCanonicalServer in Setup.php
'forwardCookies' => false,
'HTTPProxy' => null
)
);
/**
+ * Controls whether zero-result search queries with suggestions should display results for
+ * these suggestions.
+ *
+ * @var bool
+ * @since 1.26
+ */
+$wgSearchRunSuggestedQuery = true;
+
+/**
* For really cool vim folding this needs to be at the end:
* vim: foldmarker=@{,@} foldmethod=marker
* @}
diff --git a/includes/Defines.php b/includes/Defines.php
index c9263da9..d55bbcf8 100644
--- a/includes/Defines.php
+++ b/includes/Defines.php
@@ -24,11 +24,6 @@
* @defgroup Constants MediaWiki constants
*/
-/**
- * Version constants for the benefit of extensions
- */
-define( 'MW_SPECIALPAGE_VERSION', 2 );
-
/**@{
* Database related constants
*/
@@ -203,7 +198,7 @@ define( 'LIST_OR', 4 );
/**
* Unicode and normalisation related
*/
-require_once __DIR__ . '/libs/normal/UtfNormalDefines.php';
+require_once __DIR__ . '/compat/normal/UtfNormalDefines.php';
/**@{
* Hook support constants
diff --git a/includes/EditPage.php b/includes/EditPage.php
index 8d27eac8..05e0ac0e 100644
--- a/includes/EditPage.php
+++ b/includes/EditPage.php
@@ -168,6 +168,12 @@ class EditPage {
const AS_PARSE_ERROR = 240;
/**
+ * Status: when changing the content model is disallowed due to
+ * $wgContentHandlerUseDB being false
+ */
+ const AS_CANNOT_USE_CUSTOM_MODEL = 241;
+
+ /**
* HTML id and name for the beginning of the edit form.
*/
const EDITFORM_ID = 'editform';
@@ -380,13 +386,15 @@ class EditPage {
public $suppressIntro = false;
- /** @var bool Set to true to allow editing of non-text content types. */
- public $allowNonTextContent = false;
-
/** @var bool */
protected $edit;
/**
+ * @var bool Set in ApiEditPage, based on ContentHandler::allowsDirectApiEditing
+ */
+ private $enableApiEditOverride = false;
+
+ /**
* @param Article $article
*/
public function __construct( Article $article ) {
@@ -447,8 +455,18 @@ class EditPage {
* @throws MWException If $modelId has no known handler
*/
public function isSupportedContentModel( $modelId ) {
- return $this->allowNonTextContent ||
- ContentHandler::getForModelID( $modelId ) instanceof TextContentHandler;
+ return $this->enableApiEditOverride === true ||
+ ContentHandler::getForModelID( $modelId )->supportsDirectEditing();
+ }
+
+ /**
+ * Allow editing of content that supports API direct editing, but not general
+ * direct editing. Set to false by default.
+ *
+ * @param bool $enableOverride
+ */
+ public function setApiEditOverride( $enableOverride ) {
+ $this->enableApiEditOverride = $enableOverride;
}
function submit() {
@@ -509,7 +527,10 @@ class EditPage {
if ( $permErrors ) {
wfDebug( __METHOD__ . ": User can't edit\n" );
// Auto-block user's IP if the account was "hard" blocked
- $wgUser->spreadAnyEditBlock();
+ $user = $wgUser;
+ DeferredUpdates::addCallableUpdate( function() use ( $user ) {
+ $user->spreadAnyEditBlock();
+ } );
$this->displayPermissionsError( $permErrors );
@@ -634,6 +655,9 @@ class EditPage {
$this->getContextTitle()->getPrefixedText()
) );
$wgOut->addBacklinkSubtitle( $this->getContextTitle() );
+ $wgOut->addHTML( $this->editFormPageTop );
+ $wgOut->addHTML( $this->editFormTextTop );
+
$wgOut->addWikiText( $wgOut->formatPermissionsErrorMessage( $permErrors, 'edit' ) );
$wgOut->addHTML( "<hr />\n" );
@@ -647,13 +671,16 @@ class EditPage {
$wgOut->addWikiMsg( 'viewsourcetext' );
}
+ $wgOut->addHTML( $this->editFormTextBeforeContent );
$this->showTextbox( $text, 'wpTextbox1', array( 'readonly' ) );
+ $wgOut->addHTML( $this->editFormTextAfterContent );
$wgOut->addHTML( Html::rawElement( 'div', array( 'class' => 'templatesUsed' ),
Linker::formatTemplates( $this->getTemplates() ) ) );
$wgOut->addModules( 'mediawiki.action.edit.collapsibleFooter' );
+ $wgOut->addHTML( $this->editFormTextBottom );
if ( $this->mTitle->exists() ) {
$wgOut->returnToMain( null, $this->mTitle );
}
@@ -1025,7 +1052,6 @@ class EditPage {
$undo = $wgRequest->getInt( 'undo' );
if ( $undo > 0 && $undoafter > 0 ) {
-
$undorev = Revision::newFromId( $undo );
$oldrev = Revision::newFromId( $undoafter );
@@ -1034,8 +1060,8 @@ class EditPage {
# Otherwise, $content will be left as-is.
if ( !is_null( $undorev ) && !is_null( $oldrev ) &&
!$undorev->isDeleted( Revision::DELETED_TEXT ) &&
- !$oldrev->isDeleted( Revision::DELETED_TEXT ) ) {
-
+ !$oldrev->isDeleted( Revision::DELETED_TEXT )
+ ) {
$content = $this->mArticle->getUndoContent( $undorev, $oldrev );
if ( $content === false ) {
@@ -1230,9 +1256,9 @@ class EditPage {
if ( !$converted ) {
//TODO: somehow show a warning to the user!
- wfDebug( "Attempt to preload incompatible content: "
- . "can't convert " . $content->getModel()
- . " to " . $handler->getModelID() );
+ wfDebug( "Attempt to preload incompatible content: " .
+ "can't convert " . $content->getModel() .
+ " to " . $handler->getModelID() );
return $handler->makeEmptyContent();
}
@@ -1350,6 +1376,7 @@ class EditPage {
case self::AS_HOOK_ERROR:
return false;
+ case self::AS_CANNOT_USE_CUSTOM_MODEL:
case self::AS_PARSE_ERROR:
$wgOut->addWikiText( '<div class="error">' . $status->getWikiText() . '</div>' );
return true;
@@ -1532,6 +1559,7 @@ class EditPage {
*/
function internalAttemptSave( &$result, $bot = false ) {
global $wgUser, $wgRequest, $wgParser, $wgMaxArticleSize;
+ global $wgContentHandlerUseDB;
$status = Status::newGood();
@@ -1652,11 +1680,19 @@ class EditPage {
}
}
- if ( $this->contentModel !== $this->mTitle->getContentModel()
- && !$wgUser->isAllowed( 'editcontentmodel' )
- ) {
- $status->setResult( false, self::AS_NO_CHANGE_CONTENT_MODEL );
- return $status;
+ $changingContentModel = false;
+ if ( $this->contentModel !== $this->mTitle->getContentModel() ) {
+ if ( !$wgContentHandlerUseDB ) {
+ $status->fatal( 'editpage-cannot-use-custom-model' );
+ $status->value = self::AS_CANNOT_USE_CUSTOM_MODEL;
+ return $status;
+ } elseif ( !$wgUser->isAllowed( 'editcontentmodel' ) ) {
+ $status->setResult( false, self::AS_NO_CHANGE_CONTENT_MODEL );
+ return $status;
+
+ }
+ $changingContentModel = true;
+ $oldContentModel = $this->mTitle->getContentModel();
}
if ( $this->changeTags ) {
@@ -1916,7 +1952,7 @@ class EditPage {
$this->summary,
$flags,
false,
- null,
+ $wgUser,
$content->getDefaultFormat()
);
@@ -1946,10 +1982,22 @@ class EditPage {
if ( $this->changeTags && isset( $doEditStatus->value['revision'] ) ) {
// If a revision was created, apply any change tags that were requested
- ChangeTags::addTags(
- $this->changeTags,
- isset( $doEditStatus->value['rc'] ) ? $doEditStatus->value['rc']->mAttribs['rc_id'] : null,
- $doEditStatus->value['revision']->getId()
+ $addTags = $this->changeTags;
+ $revId = $doEditStatus->value['revision']->getId();
+ // Defer this both for performance and so that addTags() sees the rc_id
+ // since the recentchange entry addition is deferred first (bug T100248)
+ DeferredUpdates::addCallableUpdate( function() use ( $addTags, $revId ) {
+ ChangeTags::addTags( $addTags, null, $revId );
+ } );
+ }
+
+ // If the content model changed, add a log entry
+ if ( $changingContentModel ) {
+ $this->addContentModelChangeLogEntry(
+ $wgUser,
+ $oldContentModel,
+ $this->contentModel,
+ $this->summary
);
}
@@ -1957,6 +2005,26 @@ class EditPage {
}
/**
+ * @param Title $title
+ * @param string $oldModel
+ * @param string $newModel
+ * @param string $reason
+ */
+ protected function addContentModelChangeLogEntry( User $user, $oldModel, $newModel, $reason ) {
+ $log = new ManualLogEntry( 'contentmodel', 'change' );
+ $log->setPerformer( $user );
+ $log->setTarget( $this->mTitle );
+ $log->setComment( $reason );
+ $log->setParameters( array(
+ '4::oldmodel' => $oldModel,
+ '5::newmodel' => $newModel
+ ) );
+ $logid = $log->insert();
+ $log->publish( $logid );
+ }
+
+
+ /**
* Register the change of watch status
*/
protected function updateWatchlist() {
@@ -2486,7 +2554,7 @@ class EditPage {
$wgOut->addHTML( $this->editFormTextBeforeContent );
if ( !$this->isCssJsSubpage && $showToolbar && $wgUser->getOption( 'showtoolbar' ) ) {
- $wgOut->addHTML( EditPage::getEditToolbar() );
+ $wgOut->addHTML( EditPage::getEditToolbar( $this->mTitle ) );
}
if ( $this->blankArticle ) {
@@ -3386,7 +3454,7 @@ HTML
$this->deletedSinceEdit = false;
- if ( $this->mTitle->isDeletedQuick() ) {
+ if ( !$this->mTitle->exists() && $this->mTitle->isDeletedQuick() ) {
$this->lastDelete = $this->getLastDelete();
if ( $this->lastDelete ) {
$deleteTime = wfTimestamp( TS_MW, $this->lastDelete->log_timestamp );
@@ -3450,6 +3518,8 @@ HTML
global $wgOut, $wgUser, $wgRawHtml, $wgLang;
global $wgAllowUserCss, $wgAllowUserJs;
+ $stats = $wgOut->getContext()->getStats();
+
if ( $wgRawHtml && !$this->mTokenOk ) {
// Could be an offsite preview attempt. This is very unsafe if
// HTML is enabled, as it could be an attack.
@@ -3461,6 +3531,7 @@ HTML
$parsedNote = $wgOut->parse( "<div class='previewnote'>" .
wfMessage( 'session_fail_preview_html' )->text() . "</div>", true, /* interface */true );
}
+ $stats->increment( 'edit.failures.session_loss' );
return $parsedNote;
}
@@ -3484,11 +3555,16 @@ HTML
if ( $this->mTriedSave && !$this->mTokenOk ) {
if ( $this->mTokenOkExceptSuffix ) {
$note = wfMessage( 'token_suffix_mismatch' )->plain();
+ $stats->increment( 'edit.failures.bad_token' );
} else {
$note = wfMessage( 'session_fail_preview' )->plain();
+ $stats->increment( 'edit.failures.session_loss' );
}
} elseif ( $this->incompleteForm ) {
$note = wfMessage( 'edit_form_incomplete' )->plain();
+ if ( $this->mTriedSave ) {
+ $stats->increment( 'edit.failures.incomplete_form' );
+ }
} else {
$note = wfMessage( 'previewnote' )->plain() . ' ' . $continueEditing;
}
@@ -3619,13 +3695,18 @@ HTML
* Shows a bulletin board style toolbar for common editing functions.
* It can be disabled in the user preferences.
*
+ * @param $title Title object for the page being edited (optional)
* @return string
*/
- static function getEditToolbar() {
+ static function getEditToolbar( $title = null ) {
global $wgContLang, $wgOut;
global $wgEnableUploads, $wgForeignFileRepos;
$imagesAvailable = $wgEnableUploads || count( $wgForeignFileRepos );
+ $showSignature = true;
+ if ( $title ) {
+ $showSignature = MWNamespace::wantSignatures( $title->getNamespace() );
+ }
/**
* $toolarray is an array of arrays each of which includes the
@@ -3693,13 +3774,13 @@ HTML
'sample' => wfMessage( 'nowiki_sample' )->text(),
'tip' => wfMessage( 'nowiki_tip' )->text(),
),
- array(
+ $showSignature ? array(
'id' => 'mw-editbutton-signature',
'open' => '--~~~~',
'close' => '',
'sample' => '',
'tip' => wfMessage( 'sig_tip' )->text(),
- ),
+ ) : false,
array(
'id' => 'mw-editbutton-hr',
'open' => "\n----\n",
@@ -3737,7 +3818,7 @@ HTML
}
$script .= '});';
- $wgOut->addScript( Html::inlineScript( ResourceLoader::makeLoaderConditionalScript( $script ) ) );
+ $wgOut->addScript( ResourceLoader::makeInlineScript( $script ) );
$toolbar = '<div id="toolbar"></div>';
diff --git a/includes/Export.php b/includes/Export.php
index 4600feb5..adab21c3 100644
--- a/includes/Export.php
+++ b/includes/Export.php
@@ -874,7 +874,7 @@ class XmlDumpWriter {
}
global $wgContLang;
- $prefix = str_replace( '_', ' ', $wgContLang->getNsText( $title->getNamespace() ) );
+ $prefix = $wgContLang->getFormattedNsText( $title->getNamespace() );
if ( $prefix !== '' ) {
$prefix .= ':';
@@ -1191,7 +1191,7 @@ class Dump7ZipOutput extends DumpPipeOutput {
* @return string
*/
function setup7zCommand( $file ) {
- $command = "7za a -bd -si " . wfEscapeShellArg( $file );
+ $command = "7za a -bd -si -mx=4 " . wfEscapeShellArg( $file );
// Suppress annoying useless crap from p7zip
// Unfortunately this could suppress real error messages too
$command .= ' >' . wfGetNull() . ' 2>&1';
diff --git a/includes/FileDeleteForm.php b/includes/FileDeleteForm.php
index c1d14db0..bcd6db20 100644
--- a/includes/FileDeleteForm.php
+++ b/includes/FileDeleteForm.php
@@ -296,8 +296,8 @@ class FileDeleteForm {
Xml::closeElement( 'form' );
if ( $wgUser->isAllowed( 'editinterface' ) ) {
- $title = Title::makeTitle( NS_MEDIAWIKI, 'Filedelete-reason-dropdown' );
- $link = Linker::link(
+ $title = wfMessage( 'filedelete-reason-dropdown' )->inContentLanguage()->getTitle();
+ $link = Linker::linkKnown(
$title,
wfMessage( 'filedelete-edit-reasonlist' )->escaped(),
array(),
diff --git a/includes/GitInfo.php b/includes/GitInfo.php
index fb298cfe..7f05bb0f 100644
--- a/includes/GitInfo.php
+++ b/includes/GitInfo.php
@@ -281,9 +281,9 @@ class GitInfo {
$config = "{$this->basedir}/config";
$url = false;
if ( is_readable( $config ) ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$configArray = parse_ini_file( $config, true );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
$remote = false;
// Use the "origin" remote repo if available or any other repo if not.
diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php
index ab3f019f..64aa87ec 100644
--- a/includes/GlobalFunctions.php
+++ b/includes/GlobalFunctions.php
@@ -24,7 +24,6 @@ if ( !defined( 'MEDIAWIKI' ) ) {
die( "This file is part of MediaWiki, it is not a valid entry point" );
}
-use Liuggio\StatsdClient\StatsdClient;
use Liuggio\StatsdClient\Sender\SocketSender;
use MediaWiki\Logger\LoggerFactory;
@@ -172,6 +171,7 @@ if ( !function_exists( 'hash_equals' ) ) {
*
* @param string $ext Name of the extension to load
* @param string|null $path Absolute path of where to find the extension.json file
+ * @since 1.25
*/
function wfLoadExtension( $ext, $path = null ) {
if ( !$path ) {
@@ -192,6 +192,7 @@ function wfLoadExtension( $ext, $path = null ) {
*
* @see wfLoadExtension
* @param string[] $exts Array of extension names to load
+ * @since 1.25
*/
function wfLoadExtensions( array $exts ) {
global $wgExtensionDirectory;
@@ -207,6 +208,7 @@ function wfLoadExtensions( array $exts ) {
* @see wfLoadExtension
* @param string $skin Name of the extension to load
* @param string|null $path Absolute path of where to find the skin.json file
+ * @since 1.25
*/
function wfLoadSkin( $skin, $path = null ) {
if ( !$path ) {
@@ -221,6 +223,7 @@ function wfLoadSkin( $skin, $path = null ) {
*
* @see wfLoadExtensions
* @param string[] $skins Array of extension names to load
+ * @since 1.25
*/
function wfLoadSkins( array $skins ) {
global $wgStyleDirectory;
@@ -402,12 +405,17 @@ function wfRandomString( $length = 32 ) {
*
* ;:@&=$-_.+!*'(),
*
+ * RFC 1738 says ~ is unsafe, however RFC 3986 considers it an unreserved
+ * character which should not be encoded. More importantly, google chrome
+ * always converts %7E back to ~, and converting it in this function can
+ * cause a redirect loop (T105265).
+ *
* But + is not safe because it's used to indicate a space; &= are only safe in
* paths and not in queries (and we don't distinguish here); ' seems kind of
* scary; and urlencode() doesn't touch -_. to begin with. Plus, although /
* is reserved, we don't care. So the list we unescape is:
*
- * ;:@$!*(),/
+ * ;:@$!*(),/~
*
* However, IIS7 redirects fail when the url contains a colon (Bug 22709),
* so no fancy : for IIS7.
@@ -426,7 +434,7 @@ function wfUrlencode( $s ) {
}
if ( is_null( $needle ) ) {
- $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F' );
+ $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F', '%7E' );
if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) ||
( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false )
) {
@@ -437,7 +445,7 @@ function wfUrlencode( $s ) {
$s = urlencode( $s );
$s = str_ireplace(
$needle,
- array( ';', '@', '$', '!', '*', '(', ')', ',', '/', ':' ),
+ array( ';', '@', '$', '!', '*', '(', ')', ',', '/', '~', ':' ),
$s
);
@@ -860,9 +868,9 @@ function wfParseUrl( $url ) {
if ( $wasRelative ) {
$url = "http:$url";
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$bits = parse_url( $url );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
// parse_url() returns an array without scheme for some invalid URLs, e.g.
// parse_url("%0Ahttp://example.com") == array( 'host' => '%0Ahttp', 'path' => 'example.com' )
if ( !$bits || !isset( $bits['scheme'] ) ) {
@@ -1248,13 +1256,17 @@ function wfLogProfilingData() {
$profiler->logData();
$config = $context->getConfig();
- if ( $config->has( 'StatsdServer' ) ) {
- $statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
- $statsdHost = $statsdServer[0];
- $statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
- $statsdSender = new SocketSender( $statsdHost, $statsdPort );
- $statsdClient = new StatsdClient( $statsdSender );
- $statsdClient->send( $context->getStats()->getBuffer() );
+ if ( $config->get( 'StatsdServer' ) ) {
+ 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->send( $context->getStats()->getBuffer() );
+ } catch ( Exception $ex ) {
+ MWExceptionHandler::logException( $ex );
+ }
}
# Profiling must actually be enabled...
@@ -1344,6 +1356,17 @@ function wfReadOnlyReason() {
} else {
$wgReadOnly = false;
}
+ // Callers use this method to be aware that data presented to a user
+ // may be very stale and thus allowing submissions can be problematic.
+ try {
+ if ( $wgReadOnly === false && wfGetLB()->getLaggedSlaveMode() ) {
+ $wgReadOnly = 'The database has been automatically locked ' .
+ 'while the slave database servers catch up to the master';
+ }
+ } catch ( DBConnectionError $e ) {
+ $wgReadOnly = 'The database has been automatically locked ' .
+ 'until the slave database servers become available';
+ }
}
return $wgReadOnly;
@@ -1405,7 +1428,7 @@ function wfGetLangObj( $langcode = false ) {
*
* This function replaces all old wfMsg* functions.
*
- * @param string|string[] $key Message key, or array of keys
+ * @param string|string[]|MessageSpecifier $key Message key, or array of keys, or a MessageSpecifier
* @param mixed $params,... Normal message parameters
* @return Message
*
@@ -1745,7 +1768,7 @@ function wfMsgExt( $key, $options ) {
}
if ( in_array( 'escape', $options, true ) ) {
- $string = htmlspecialchars ( $string );
+ $string = htmlspecialchars( $string );
} elseif ( in_array( 'escapenoentities', $options, true ) ) {
$string = Sanitizer::escapeHtmlAllowEntities( $string );
}
@@ -2118,15 +2141,14 @@ function wfVarDump( $var ) {
*/
function wfHttpError( $code, $label, $desc ) {
global $wgOut;
- header( "HTTP/1.0 $code $label" );
- header( "Status: $code $label" );
+ HttpStatus::header( $code );
if ( $wgOut ) {
$wgOut->disable();
$wgOut->sendCacheControl();
}
header( 'Content-type: text/html; charset=utf-8' );
- print "<!doctype html>" .
+ print '<!DOCTYPE html>' .
'<html><head><title>' .
htmlspecialchars( $label ) .
'</title></head><body><h1>' .
@@ -2161,14 +2183,24 @@ function wfResetOutputBuffers( $resetGzipEncoding = true ) {
$wgDisableOutputCompression = true;
}
while ( $status = ob_get_status() ) {
- if ( $status['type'] == 0 /* PHP_OUTPUT_HANDLER_INTERNAL */ ) {
- // Probably from zlib.output_compression or other
- // PHP-internal setting which can't be removed.
- //
+ if ( isset( $status['flags'] ) ) {
+ $flags = PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_REMOVABLE;
+ $deleteable = ( $status['flags'] & $flags ) === $flags;
+ } elseif ( isset( $status['del'] ) ) {
+ $deleteable = $status['del'];
+ } else {
+ // Guess that any PHP-internal setting can't be removed.
+ $deleteable = $status['type'] !== 0; /* PHP_OUTPUT_HANDLER_INTERNAL */
+ }
+ if ( !$deleteable ) {
// Give up, and hope the result doesn't break
// output behavior.
break;
}
+ if ( $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier' ) {
+ // Unit testing barrier to prevent this function from breaking PHPUnit.
+ break;
+ }
if ( !ob_end_clean() ) {
// Could not remove output buffer handler; abort now
// to avoid getting in some kind of infinite loop.
@@ -2312,40 +2344,19 @@ function wfNegotiateType( $cprefs, $sprefs ) {
/**
* Reference-counted warning suppression
*
+ * @deprecated since 1.26, use MediaWiki\suppressWarnings() directly
* @param bool $end
*/
function wfSuppressWarnings( $end = false ) {
- static $suppressCount = 0;
- static $originalLevel = false;
-
- if ( $end ) {
- if ( $suppressCount ) {
- --$suppressCount;
- if ( !$suppressCount ) {
- error_reporting( $originalLevel );
- }
- }
- } else {
- if ( !$suppressCount ) {
- $originalLevel = error_reporting( E_ALL & ~(
- E_WARNING |
- E_NOTICE |
- E_USER_WARNING |
- E_USER_NOTICE |
- E_DEPRECATED |
- E_USER_DEPRECATED |
- E_STRICT
- ) );
- }
- ++$suppressCount;
- }
+ MediaWiki\suppressWarnings( $end );
}
/**
+ * @deprecated since 1.26, use MediaWiki\restoreWarnings() directly
* Restore error level to previous value
*/
function wfRestoreWarnings() {
- wfSuppressWarnings( true );
+ MediaWiki\suppressWarnings( true );
}
# Autodetect, convert and provide timestamps of various types
@@ -2453,7 +2464,7 @@ function wfTimestampNow() {
function wfIsWindows() {
static $isWindows = null;
if ( $isWindows === null ) {
- $isWindows = substr( php_uname(), 0, 7 ) == 'Windows';
+ $isWindows = strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN';
}
return $isWindows;
}
@@ -2515,7 +2526,7 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) {
wfDebug( "$caller: called wfMkdirParents($dir)\n" );
}
- if ( strval( $dir ) === '' || ( file_exists( $dir ) && is_dir( $dir ) ) ) {
+ if ( strval( $dir ) === '' || is_dir( $dir ) ) {
return true;
}
@@ -2526,9 +2537,9 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) {
}
// Turn off the normal warning, we're doing our own below
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = mkdir( $dir, $mode, true ); // PHP5 <3
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$ok ) {
//directory may have been created on another request since we last checked
@@ -2769,7 +2780,7 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(),
$useLogPipe = false;
if ( is_executable( '/bin/bash' ) ) {
- $time = intval ( isset( $limits['time'] ) ? $limits['time'] : $wgMaxShellTime );
+ $time = intval( isset( $limits['time'] ) ? $limits['time'] : $wgMaxShellTime );
if ( isset( $limits['walltime'] ) ) {
$wallTime = intval( $limits['walltime'] );
} elseif ( isset( $limits['time'] ) ) {
@@ -2777,8 +2788,8 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(),
} else {
$wallTime = intval( $wgMaxShellWallClockTime );
}
- $mem = intval ( isset( $limits['memory'] ) ? $limits['memory'] : $wgMaxShellMemory );
- $filesize = intval ( isset( $limits['filesize'] ) ? $limits['filesize'] : $wgMaxShellFileSize );
+ $mem = intval( isset( $limits['memory'] ) ? $limits['memory'] : $wgMaxShellMemory );
+ $filesize = intval( isset( $limits['filesize'] ) ? $limits['filesize'] : $wgMaxShellFileSize );
if ( $time > 0 || $mem > 0 || $filesize > 0 || $wallTime > 0 ) {
$cmd = '/bin/bash ' . escapeshellarg( "$IP/includes/limit.sh" ) . ' ' .
@@ -3023,9 +3034,9 @@ function wfMerge( $old, $mine, $yours, &$result ) {
# This check may also protect against code injection in
# case of broken installations.
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$haveDiff3 ) {
wfDebug( "diff3 not found\n" );
@@ -3102,9 +3113,9 @@ function wfDiff( $before, $after, $params = '-u' ) {
}
global $wgDiff;
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$haveDiff = $wgDiff && file_exists( $wgDiff );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
# This check may also protect against code injection in
# case of broken installations.
@@ -3205,6 +3216,7 @@ function wfUsePHP( $req_ver ) {
*
* @see perldoc -f use
*
+ * @deprecated since 1.26, use the "requires' property of extension.json
* @param string|int|float $req_ver The version to check, can be a string, an integer, or a float
* @throws MWException
*/
@@ -3455,7 +3467,6 @@ function wfResetSessionID() {
$_SESSION = $tmp;
}
$newSessionId = session_id();
- Hooks::run( 'ResetSessionID', array( $oldSessionId, $newSessionId ) );
}
/**
@@ -3464,15 +3475,17 @@ function wfResetSessionID() {
* @param bool $sessionId
*/
function wfSetupSession( $sessionId = false ) {
- global $wgSessionsInMemcached, $wgSessionsInObjectCache, $wgCookiePath, $wgCookieDomain,
- $wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler;
- if ( $wgSessionsInObjectCache || $wgSessionsInMemcached ) {
+ global $wgSessionsInObjectCache, $wgSessionHandler;
+ global $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly;
+
+ if ( $wgSessionsInObjectCache ) {
ObjectCacheSessionHandler::install();
} elseif ( $wgSessionHandler && $wgSessionHandler != ini_get( 'session.save_handler' ) ) {
# Only set this if $wgSessionHandler isn't null and session.save_handler
# hasn't already been set to the desired value (that causes errors)
ini_set( 'session.save_handler', $wgSessionHandler );
}
+
session_set_cookie_params(
0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly );
session_cache_limiter( 'private, must-revalidate' );
@@ -3481,9 +3494,14 @@ function wfSetupSession( $sessionId = false ) {
} else {
wfFixSessionID();
}
- wfSuppressWarnings();
+
+ MediaWiki\suppressWarnings();
session_start();
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
+
+ if ( $wgSessionsInObjectCache ) {
+ ObjectCacheSessionHandler::renewCurrentSession();
+ }
}
/**
@@ -3506,7 +3524,7 @@ function wfGetPrecompiledData( $name ) {
}
/**
- * Get a cache key
+ * Make a cache key for the local wiki.
*
* @param string $args,...
* @return string
@@ -3516,12 +3534,13 @@ function wfMemcKey( /*...*/ ) {
$prefix = $wgCachePrefix === false ? wfWikiID() : $wgCachePrefix;
$args = func_get_args();
$key = $prefix . ':' . implode( ':', $args );
- $key = str_replace( ' ', '_', $key );
- return $key;
+ return strtr( $key, ' ', '_' );
}
/**
- * Get a cache key for a foreign DB
+ * Make a cache key for a foreign DB.
+ *
+ * Must match what wfMemcKey() would produce in context of the foreign wiki.
*
* @param string $db
* @param string $prefix
@@ -3531,11 +3550,29 @@ function wfMemcKey( /*...*/ ) {
function wfForeignMemcKey( $db, $prefix /*...*/ ) {
$args = array_slice( func_get_args(), 2 );
if ( $prefix ) {
+ // Match wfWikiID() logic
$key = "$db-$prefix:" . implode( ':', $args );
} else {
$key = $db . ':' . implode( ':', $args );
}
- return str_replace( ' ', '_', $key );
+ return strtr( $key, ' ', '_' );
+}
+
+/**
+ * Make a cache key with database-agnostic prefix.
+ *
+ * Doesn't have a wiki-specific namespace. Uses a generic 'global' prefix
+ * instead. Must have a prefix as otherwise keys that use a database name
+ * in the first segment will clash with wfMemcKey/wfForeignMemcKey.
+ *
+ * @since 1.26
+ * @param string $args,...
+ * @return string
+ */
+function wfGlobalCacheKey( /*...*/ ) {
+ $args = func_get_args();
+ $key = 'global:' . implode( ':', $args );
+ return strtr( $key, ' ', '_' );
}
/**
@@ -3744,6 +3781,7 @@ function wfWaitForSlaves(
}
// Figure out which clusters need to be checked
+ /** @var LoadBalancer[] $lbs */
$lbs = array();
if ( $cluster === '*' ) {
wfGetLBFactory()->forEachLB( function ( LoadBalancer $lb ) use ( &$lbs ) {
@@ -3760,20 +3798,14 @@ function wfWaitForSlaves(
// time needed to wait on the next clusters.
$masterPositions = array_fill( 0, count( $lbs ), false );
foreach ( $lbs as $i => $lb ) {
- // bug 27975 - Don't try to wait for slaves if there are none
- // Prevents permission error when getting master position
- if ( $lb->getServerCount() > 1 ) {
- if ( $ifWritesSince && !$lb->hasMasterConnection() ) {
- continue; // assume no writes done
- }
- // Use the empty string to not trigger selectDB() since the connection
- // may have been to a server that does not have a DB for the current wiki.
- $dbw = $lb->getConnection( DB_MASTER, array(), '' );
- if ( $ifWritesSince && $dbw->lastDoneWrites() < $ifWritesSince ) {
- continue; // no writes since the last wait
- }
- $masterPositions[$i] = $dbw->getMasterPos();
+ if ( $lb->getServerCount() <= 1 ) {
+ // Bug 27975 - Don't try to wait for slaves if there are none
+ // Prevents permission error when getting master position
+ continue;
+ } elseif ( $ifWritesSince && $lb->lastMasterChangeTimestamp() < $ifWritesSince ) {
+ continue; // no writes since the last wait
}
+ $masterPositions[$i] = $lb->getMasterPos();
}
$ok = true;
@@ -3830,9 +3862,9 @@ function wfStripIllegalFilenameChars( $name ) {
}
/**
- * Set PHP's memory limit to the larger of php.ini or $wgMemoryLimit;
+ * Set PHP's memory limit to the larger of php.ini or $wgMemoryLimit
*
- * @return int Value the memory limit was set to.
+ * @return int Resulting value of the memory limit.
*/
function wfMemoryLimit() {
global $wgMemoryLimit;
@@ -3841,15 +3873,15 @@ function wfMemoryLimit() {
$conflimit = wfShorthandToInteger( $wgMemoryLimit );
if ( $conflimit == -1 ) {
wfDebug( "Removing PHP's memory limit\n" );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
ini_set( 'memory_limit', $conflimit );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $conflimit;
} elseif ( $conflimit > $memlimit ) {
wfDebug( "Raising PHP's memory limit to $conflimit bytes\n" );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
ini_set( 'memory_limit', $conflimit );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $conflimit;
}
}
@@ -3857,6 +3889,26 @@ function wfMemoryLimit() {
}
/**
+ * Set PHP's time limit to the larger of php.ini or $wgTransactionalTimeLimit
+ *
+ * @return int Prior time limit
+ * @since 1.26
+ */
+function wfTransactionalTimeLimit() {
+ global $wgTransactionalTimeLimit;
+
+ $timeLimit = ini_get( 'max_execution_time' );
+ // Note that CLI scripts use 0
+ if ( $timeLimit > 0 && $wgTransactionalTimeLimit > $timeLimit ) {
+ set_time_limit( $wgTransactionalTimeLimit );
+ }
+
+ ignore_user_abort( true ); // ignore client disconnects
+
+ return $timeLimit;
+}
+
+/**
* Converts shorthand byte notation to integer form
*
* @param string $string
@@ -3917,13 +3969,13 @@ function wfBCP47( $code ) {
}
/**
- * Get a cache object.
+ * Get a specific cache object.
*
- * @param int $inputType Cache type, one of the CACHE_* constants.
+ * @param int|string $cacheType A CACHE_* constants, or other key in $wgObjectCaches
* @return BagOStuff
*/
-function wfGetCache( $inputType ) {
- return ObjectCache::getInstance( $inputType );
+function wfGetCache( $cacheType ) {
+ return ObjectCache::getInstance( $cacheType );
}
/**
@@ -3995,9 +4047,9 @@ function wfUnpack( $format, $data, $length = false ) {
}
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$result = unpack( $format, $data );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $result === false ) {
// If it cannot extract the packed data.
@@ -4236,3 +4288,28 @@ function wfThumbIsStandard( File $file, array $params ) {
return true;
}
+
+/**
+ * Merges two (possibly) 2 dimensional arrays into the target array ($baseArray).
+ *
+ * Values that exist in both values will be combined with += (all values of the array
+ * of $newValues will be added to the values of the array of $baseArray, while values,
+ * that exists in both, the value of $baseArray will be used).
+ *
+ * @param array $baseArray The array where you want to add the values of $newValues to
+ * @param array $newValues An array with new values
+ * @return array The combined array
+ * @since 1.26
+ */
+function wfArrayPlus2d( array $baseArray, array $newValues ) {
+ // First merge items that are in both arrays
+ foreach ( $baseArray as $name => &$groupVal ) {
+ if ( isset( $newValues[$name] ) ) {
+ $groupVal += $newValues[$name];
+ }
+ }
+ // Now add items that didn't exist yet
+ $baseArray += $newValues;
+
+ return $baseArray;
+}
diff --git a/includes/HistoryBlob.php b/includes/HistoryBlob.php
index 69f1120d..494cbfaf 100644
--- a/includes/HistoryBlob.php
+++ b/includes/HistoryBlob.php
@@ -522,9 +522,9 @@ class DiffHistoryBlob implements HistoryBlob {
function diff( $t1, $t2 ) {
# Need to do a null concatenation with warnings off, due to bugs in the current version of xdiff
# "String is not zero-terminated"
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$diff = xdiff_string_rabdiff( $t1, $t2 ) . '';
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $diff;
}
@@ -535,9 +535,9 @@ class DiffHistoryBlob implements HistoryBlob {
*/
function patch( $base, $diff ) {
if ( function_exists( 'xdiff_string_bpatch' ) ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$text = xdiff_string_bpatch( $base, $diff ) . '';
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $text;
}
diff --git a/includes/Hooks.php b/includes/Hooks.php
index dffc7bcf..a4145624 100644
--- a/includes/Hooks.php
+++ b/includes/Hooks.php
@@ -135,9 +135,6 @@ class Hooks {
* returning null) is equivalent to returning true.
*/
public static function run( $event, array $args = array(), $deprecatedVersion = null ) {
- $profiler = Profiler::instance();
- $eventPS = $profiler->scopedProfileIn( 'hook: ' . $event );
-
foreach ( self::getHandlers( $event ) as $hook ) {
// Turn non-array values into an array. (Can't use casting because of objects.)
if ( !is_array( $hook ) ) {
@@ -196,8 +193,6 @@ class Hooks {
$badhookmsg = null;
$hook_args = array_merge( $hook, $args );
- // Profile first in case the Profiler causes errors
- $funcPS = $profiler->scopedProfileIn( $func );
set_error_handler( 'Hooks::hookErrorHandler' );
// mark hook as deprecated, if deprecation version is specified
@@ -215,7 +210,6 @@ class Hooks {
}
restore_error_handler();
- $profiler->scopedProfileOut( $funcPS );
// Process the return value.
if ( is_string( $retval ) ) {
@@ -237,22 +231,25 @@ class Hooks {
}
/**
- * Handle PHP errors issued inside a hook. Catch errors that have to do with
- * a function expecting a reference, and let all others pass through.
- *
- * This REALLY should be protected... but it's public for compatibility
+ * Handle PHP errors issued inside a hook. Catch errors that have to do
+ * with a function expecting a reference, and pass all others through to
+ * MWExceptionHandler::handleError() for default processing.
*
* @since 1.18
*
* @param int $errno Error number (unused)
* @param string $errstr Error message
* @throws MWHookException If the error has to do with the function signature
- * @return bool Always returns false
+ * @return bool
*/
public static function hookErrorHandler( $errno, $errstr ) {
if ( strpos( $errstr, 'expected to be a reference, value given' ) !== false ) {
throw new MWHookException( $errstr, $errno );
}
- return false;
+
+ // Delegate unhandled errors to the default MW handler
+ return call_user_func_array(
+ 'MWExceptionHandler::handleError', func_get_args()
+ );
}
}
diff --git a/includes/Html.php b/includes/Html.php
index d312e0a6..62ae0b85 100644
--- a/includes/Html.php
+++ b/includes/Html.php
@@ -104,27 +104,26 @@ class Html {
/**
* Modifies a set of attributes meant for button elements
* and apply a set of default attributes when $wgUseMediaWikiUIEverywhere enabled.
- * @param array $attrs
- * @param string[] $modifiers to add to the button
+ * @param array $attrs HTML attributes in an associative array
+ * @param string[] $modifiers classes to add to the button
* @see https://tools.wmflabs.org/styleguide/desktop/index.html for guidance on available modifiers
* @return array $attrs A modified attribute array
*/
- public static function buttonAttributes( $attrs, $modifiers = array() ) {
+ public static function buttonAttributes( array $attrs, array $modifiers = array() ) {
global $wgUseMediaWikiUIEverywhere;
if ( $wgUseMediaWikiUIEverywhere ) {
if ( isset( $attrs['class'] ) ) {
if ( is_array( $attrs['class'] ) ) {
$attrs['class'][] = 'mw-ui-button';
- $attrs = array_merge( $attrs, $modifiers );
+ $attrs['class'] = array_merge( $attrs['class'], $modifiers );
// ensure compatibility with Xml
$attrs['class'] = implode( ' ', $attrs['class'] );
} else {
$attrs['class'] .= ' mw-ui-button ' . implode( ' ', $modifiers );
}
} else {
- $attrs['class'] = array( 'mw-ui-button' );
// ensure compatibility with Xml
- $attrs['class'] = implode( ' ', array_merge( $attrs['class'], $modifiers ) );
+ $attrs['class'] = 'mw-ui-button ' . implode( ' ', $modifiers );
}
}
return $attrs;
@@ -137,11 +136,8 @@ class Html {
* @param array $attrs An attribute array.
* @return array $attrs A modified attribute array
*/
- public static function getTextInputAttributes( $attrs ) {
+ public static function getTextInputAttributes( array $attrs ) {
global $wgUseMediaWikiUIEverywhere;
- if ( !$attrs ) {
- $attrs = array();
- }
if ( $wgUseMediaWikiUIEverywhere ) {
if ( isset( $attrs['class'] ) ) {
if ( is_array( $attrs['class'] ) ) {
@@ -165,11 +161,11 @@ class Html {
* @param array $attrs Associative array of attributes, e.g., array(
* 'href' => 'http://www.mediawiki.org/' ). See expandAttributes() for
* further documentation.
- * @param string[] $modifiers to add to the button
+ * @param string[] $modifiers classes to add to the button
* @see http://tools.wmflabs.org/styleguide/desktop/index.html for guidance on available modifiers
* @return string Raw HTML
*/
- public static function linkButton( $contents, $attrs, $modifiers = array() ) {
+ public static function linkButton( $contents, array $attrs, array $modifiers = array() ) {
return self::element( 'a',
self::buttonAttributes( $attrs, $modifiers ),
$contents
@@ -185,11 +181,11 @@ class Html {
* @param array $attrs Associative array of attributes, e.g., array(
* 'href' => 'http://www.mediawiki.org/' ). See expandAttributes() for
* further documentation.
- * @param string[] $modifiers to add to the button
+ * @param string[] $modifiers classes to add to the button
* @see http://tools.wmflabs.org/styleguide/desktop/index.html for guidance on available modifiers
* @return string Raw HTML
*/
- public static function submitButton( $contents, $attrs, $modifiers = array() ) {
+ public static function submitButton( $contents, array $attrs, array $modifiers = array() ) {
$attrs['type'] = 'submit';
$attrs['value'] = $contents;
return self::element( 'input', self::buttonAttributes( $attrs, $modifiers ) );
@@ -337,8 +333,7 @@ class Html {
* further documentation.
* @return array An array of attributes functionally identical to $attribs
*/
- private static function dropDefaults( $element, $attribs ) {
-
+ private static function dropDefaults( $element, array $attribs ) {
// Whenever altering this array, please provide a covering test case
// in HtmlTest::provideElementsWithAttributesHavingDefaultValues
static $attribDefaults = array(
@@ -485,11 +480,10 @@ class Html {
* @return string HTML fragment that goes between element name and '>'
* (starting with a space if at least one attribute is output)
*/
- public static function expandAttributes( $attribs ) {
+ public static function expandAttributes( array $attribs ) {
global $wgWellFormedXml;
$ret = '';
- $attribs = (array)$attribs;
foreach ( $attribs as $key => $value ) {
// Support intuitive array( 'checked' => true/false ) form
if ( $value === false || is_null( $value ) ) {
@@ -714,13 +708,16 @@ class Html {
* attributes, passed to Html::element()
* @return string Raw HTML
*/
- public static function input( $name, $value = '', $type = 'text', $attribs = array() ) {
+ public static function input( $name, $value = '', $type = 'text', array $attribs = array() ) {
$attribs['type'] = $type;
$attribs['value'] = $value;
$attribs['name'] = $name;
if ( in_array( $type, array( 'text', 'search', 'email', 'password', 'number' ) ) ) {
$attribs = self::getTextInputAttributes( $attribs );
}
+ if ( in_array( $type, array( 'button', 'reset', 'submit' ) ) ) {
+ $attribs = self::buttonAttributes( $attribs );
+ }
return self::element( 'input', $attribs );
}
@@ -794,7 +791,7 @@ class Html {
* attributes, passed to Html::element()
* @return string Raw HTML
*/
- public static function hidden( $name, $value, $attribs = array() ) {
+ public static function hidden( $name, $value, array $attribs = array() ) {
return self::input( $name, $value, 'hidden', $attribs );
}
@@ -810,7 +807,7 @@ class Html {
* attributes, passed to Html::element()
* @return string Raw HTML
*/
- public static function textarea( $name, $value = '', $attribs = array() ) {
+ public static function textarea( $name, $value = '', array $attribs = array() ) {
$attribs['name'] = $name;
if ( substr( $value, 0, 1 ) == "\n" ) {
@@ -826,6 +823,47 @@ class Html {
}
/**
+ * Helper for Html::namespaceSelector().
+ * @param array $params See Html::namespaceSelector()
+ * @return array
+ */
+ public static function namespaceSelectorOptions( array $params = array() ) {
+ global $wgContLang;
+
+ $options = array();
+
+ if ( !isset( $params['exclude'] ) || !is_array( $params['exclude'] ) ) {
+ $params['exclude'] = array();
+ }
+
+ if ( isset( $params['all'] ) ) {
+ // add an option that would let the user select all namespaces.
+ // Value is provided by user, the name shown is localized for the user.
+ $options[$params['all']] = wfMessage( 'namespacesall' )->text();
+ }
+ // Add all namespaces as options (in the content language)
+ $options += $wgContLang->getFormattedNamespaces();
+
+ $optionsOut = array();
+ // Filter out namespaces below 0 and massage labels
+ foreach ( $options as $nsId => $nsName ) {
+ if ( $nsId < NS_MAIN || in_array( $nsId, $params['exclude'] ) ) {
+ continue;
+ }
+ if ( $nsId === NS_MAIN ) {
+ // For other namespaces use the namespace prefix as label, but for
+ // main we don't use "" but the user message describing it (e.g. "(Main)" or "(Article)")
+ $nsName = wfMessage( 'blanknamespace' )->text();
+ } elseif ( is_int( $nsId ) ) {
+ $nsName = $wgContLang->convertNamespace( $nsId );
+ }
+ $optionsOut[ $nsId ] = $nsName;
+ }
+
+ return $optionsOut;
+ }
+
+ /**
* Build a drop-down box for selecting a namespace
*
* @param array $params Params to set.
@@ -844,8 +882,6 @@ class Html {
public static function namespaceSelector( array $params = array(),
array $selectAttribs = array()
) {
- global $wgContLang;
-
ksort( $selectAttribs );
// Is a namespace selected?
@@ -862,37 +898,16 @@ class Html {
$params['selected'] = '';
}
- if ( !isset( $params['exclude'] ) || !is_array( $params['exclude'] ) ) {
- $params['exclude'] = array();
- }
if ( !isset( $params['disable'] ) || !is_array( $params['disable'] ) ) {
$params['disable'] = array();
}
// Associative array between option-values and option-labels
- $options = array();
-
- if ( isset( $params['all'] ) ) {
- // add an option that would let the user select all namespaces.
- // Value is provided by user, the name shown is localized for the user.
- $options[$params['all']] = wfMessage( 'namespacesall' )->text();
- }
- // Add all namespaces as options (in the content language)
- $options += $wgContLang->getFormattedNamespaces();
+ $options = self::namespaceSelectorOptions( $params );
- // Convert $options to HTML and filter out namespaces below 0
+ // Convert $options to HTML
$optionsHtml = array();
foreach ( $options as $nsId => $nsName ) {
- if ( $nsId < NS_MAIN || in_array( $nsId, $params['exclude'] ) ) {
- continue;
- }
- if ( $nsId === NS_MAIN ) {
- // For other namespaces use the namespace prefix as label, but for
- // main we don't use "" but the user message describing it (e.g. "(Main)" or "(Article)")
- $nsName = wfMessage( 'blanknamespace' )->text();
- } elseif ( is_int( $nsId ) ) {
- $nsName = $wgContLang->convertNamespace( $nsId );
- }
$optionsHtml[] = self::element(
'option', array(
'disabled' => in_array( $nsId, $params['disable'] ),
@@ -937,7 +952,7 @@ class Html {
* attributes, passed to Html::element() of html tag.
* @return string Raw HTML
*/
- public static function htmlHeader( $attribs = array() ) {
+ public static function htmlHeader( array $attribs = array() ) {
$ret = '';
global $wgHtml5Version, $wgMimeType, $wgXhtmlNamespaces;
@@ -1047,7 +1062,7 @@ class Html {
* @param string[] $urls
* @return string
*/
- static function srcSet( $urls ) {
+ static function srcSet( array $urls ) {
$candidates = array();
foreach ( $urls as $density => $url ) {
// Cast density to float to strip 'x'.
diff --git a/includes/HttpFunctions.php b/includes/HttpFunctions.php
index fa54487a..bc5a9570 100644
--- a/includes/HttpFunctions.php
+++ b/includes/HttpFunctions.php
@@ -257,7 +257,7 @@ class MWHttpRequest {
$this->parsedUrl = wfParseUrl( $this->url );
if ( !$this->parsedUrl || !Http::isValidURI( $this->url ) ) {
- $this->status = Status::newFatal( 'http-invalid-url' );
+ $this->status = Status::newFatal( 'http-invalid-url', $url );
} else {
$this->status = Status::newGood( 100 ); // continue
}
@@ -797,14 +797,14 @@ class CurlHttpRequest extends MWHttpRequest {
}
if ( $this->followRedirects && $this->canFollowRedirects() ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
if ( !curl_setopt( $curlHandle, CURLOPT_FOLLOWLOCATION, true ) ) {
wfDebug( __METHOD__ . ": Couldn't set CURLOPT_FOLLOWLOCATION. " .
"Probably safe_mode or open_basedir is set.\n" );
// Continue the processing. If it were in curl_setopt_array,
// processing would have halted on its entry
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
if ( $this->profiler ) {
diff --git a/includes/Import.php b/includes/Import.php
index d31be43b..6a0bfd09 100644
--- a/includes/Import.php
+++ b/includes/Import.php
@@ -34,7 +34,7 @@ class WikiImporter {
private $reader = null;
private $foreignNamespaces = null;
private $mLogItemCallback, $mUploadCallback, $mRevisionCallback, $mPageCallback;
- private $mSiteInfoCallback, $mTargetNamespace, $mPageOutCallback;
+ private $mSiteInfoCallback, $mPageOutCallback;
private $mNoticeCallback, $mDebug;
private $mImportUploads, $mImageBasePath;
private $mNoUpdates = false;
@@ -49,8 +49,13 @@ class WikiImporter {
* Creates an ImportXMLReader drawing from the source provided
* @param ImportSource $source
* @param Config $config
+ * @throws Exception
*/
function __construct( ImportSource $source, Config $config = null ) {
+ if ( !class_exists( 'XMLReader' ) ) {
+ throw new Exception( 'Import requires PHP to have been compiled with libxml support' );
+ }
+
$this->reader = new XMLReader();
if ( !$config ) {
wfDeprecated( __METHOD__ . ' without a Config instance', '1.25' );
@@ -62,11 +67,22 @@ class WikiImporter {
stream_wrapper_register( 'uploadsource', 'UploadSourceAdapter' );
}
$id = UploadSourceAdapter::registerSource( $source );
+
+ // Enable the entity loader, as it is needed for loading external URLs via
+ // XMLReader::open (T86036)
+ $oldDisable = libxml_disable_entity_loader( false );
if ( defined( 'LIBXML_PARSEHUGE' ) ) {
- $this->reader->open( "uploadsource://$id", null, LIBXML_PARSEHUGE );
+ $status = $this->reader->open( "uploadsource://$id", null, LIBXML_PARSEHUGE );
} else {
- $this->reader->open( "uploadsource://$id" );
+ $status = $this->reader->open( "uploadsource://$id" );
}
+ if ( !$status ) {
+ $error = libxml_get_last_error();
+ libxml_disable_entity_loader( $oldDisable );
+ throw new MWException( 'Encountered an internal error while initializing WikiImporter object: ' .
+ $error->message );
+ }
+ libxml_disable_entity_loader( $oldDisable );
// Default callbacks
$this->setPageCallback( array( $this, 'beforeImportPage' ) );
@@ -224,7 +240,6 @@ class WikiImporter {
public function setTargetNamespace( $namespace ) {
if ( is_null( $namespace ) ) {
// Don't override namespaces
- $this->mTargetNamespace = null;
$this->setImportTitleFactory( new NaiveImportTitleFactory() );
return true;
} elseif (
@@ -232,7 +247,6 @@ class WikiImporter {
MWNamespace::exists( intval( $namespace ) )
) {
$namespace = intval( $namespace );
- $this->mTargetNamespace = $namespace;
$this->setImportTitleFactory( new NamespaceImportTitleFactory( $namespace ) );
return true;
} else {
@@ -252,10 +266,7 @@ class WikiImporter {
$this->setImportTitleFactory( new NaiveImportTitleFactory() );
} elseif ( $rootpage !== '' ) {
$rootpage = rtrim( $rootpage, '/' ); //avoid double slashes
- $title = Title::newFromText( $rootpage, !is_null( $this->mTargetNamespace )
- ? $this->mTargetNamespace
- : NS_MAIN
- );
+ $title = Title::newFromText( $rootpage );
if ( !$title || $title->isExternal() ) {
$status->fatal( 'import-rootpage-invalid' );
@@ -383,9 +394,9 @@ class WikiImporter {
$countKey = 'title_' . $title->getPrefixedText();
$countable = $page->isCountable( $editInfo );
if ( array_key_exists( $countKey, $this->countableCache ) &&
- $countable != $this->countableCache[ $countKey ] ) {
+ $countable != $this->countableCache[$countKey] ) {
DeferredUpdates::addUpdate( SiteStatsUpdate::factory( array(
- 'articles' => ( (int)$countable - (int)$this->countableCache[ $countKey ] )
+ 'articles' => ( (int)$countable - (int)$this->countableCache[$countKey] )
) ) );
}
}
@@ -528,10 +539,10 @@ class WikiImporter {
$oldDisable = libxml_disable_entity_loader( true );
$this->reader->read();
- if ( $this->reader->name != 'mediawiki' ) {
+ if ( $this->reader->localName != 'mediawiki' ) {
libxml_disable_entity_loader( $oldDisable );
throw new MWException( "Expected <mediawiki> tag, got " .
- $this->reader->name );
+ $this->reader->localName );
}
$this->debug( "<mediawiki> tag is correct." );
@@ -542,7 +553,7 @@ class WikiImporter {
$rethrow = null;
try {
while ( $keepReading ) {
- $tag = $this->reader->name;
+ $tag = $this->reader->localName;
$type = $this->reader->nodeType;
if ( !Hooks::run( 'ImportHandleToplevelXMLTag', array( $this ) ) ) {
@@ -593,14 +604,14 @@ class WikiImporter {
while ( $this->reader->read() ) {
if ( $this->reader->nodeType == XmlReader::END_ELEMENT &&
- $this->reader->name == 'siteinfo' ) {
+ $this->reader->localName == 'siteinfo' ) {
break;
}
- $tag = $this->reader->name;
+ $tag = $this->reader->localName;
if ( $tag == 'namespace' ) {
- $this->foreignNamespaces[ $this->nodeAttribute( 'key' ) ] =
+ $this->foreignNamespaces[$this->nodeAttribute( 'key' )] =
$this->nodeContents();
} elseif ( in_array( $tag, $normalFields ) ) {
$siteInfo[$tag] = $this->nodeContents();
@@ -621,11 +632,11 @@ class WikiImporter {
while ( $this->reader->read() ) {
if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
- $this->reader->name == 'logitem' ) {
+ $this->reader->localName == 'logitem' ) {
break;
}
- $tag = $this->reader->name;
+ $tag = $this->reader->localName;
if ( !Hooks::run( 'ImportHandleLogItemXMLTag', array(
$this, $logInfo
@@ -685,13 +696,13 @@ class WikiImporter {
while ( $skip ? $this->reader->next() : $this->reader->read() ) {
if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
- $this->reader->name == 'page' ) {
+ $this->reader->localName == 'page' ) {
break;
}
$skip = false;
- $tag = $this->reader->name;
+ $tag = $this->reader->localName;
if ( $badTitle ) {
// The title is invalid, bail out of this page
@@ -758,11 +769,11 @@ class WikiImporter {
while ( $skip ? $this->reader->next() : $this->reader->read() ) {
if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
- $this->reader->name == 'revision' ) {
+ $this->reader->localName == 'revision' ) {
break;
}
- $tag = $this->reader->name;
+ $tag = $this->reader->localName;
if ( !Hooks::run( 'ImportHandleRevisionXMLTag', array(
$this, $pageInfo, $revisionInfo
@@ -850,11 +861,11 @@ class WikiImporter {
while ( $skip ? $this->reader->next() : $this->reader->read() ) {
if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
- $this->reader->name == 'upload' ) {
+ $this->reader->localName == 'upload' ) {
break;
}
- $tag = $this->reader->name;
+ $tag = $this->reader->localName;
if ( !Hooks::run( 'ImportHandleUploadXMLTag', array(
$this, $pageInfo
@@ -948,11 +959,11 @@ class WikiImporter {
while ( $this->reader->read() ) {
if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
- $this->reader->name == 'contributor' ) {
+ $this->reader->localName == 'contributor' ) {
break;
}
- $tag = $this->reader->name;
+ $tag = $this->reader->localName;
if ( in_array( $tag, $fields ) ) {
$info[$tag] = $this->nodeContents();
@@ -1846,9 +1857,9 @@ class ImportStreamSource implements ImportSource {
* @return Status
*/
static function newFromFile( $filename ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$file = fopen( $filename, 'rt' );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$file ) {
return Status::newFatal( "importcantopen" );
}
diff --git a/includes/Linker.php b/includes/Linker.php
index b58dabab..9b5ff27b 100644
--- a/includes/Linker.php
+++ b/includes/Linker.php
@@ -77,7 +77,7 @@ class Linker {
wfDeprecated( __METHOD__, '1.25' );
$title = urldecode( $title );
- $title = str_replace( '_', ' ', $title );
+ $title = strtr( $title, '_', ' ' );
return self::getLinkAttributesInternal( $title, $class );
}
@@ -1276,9 +1276,11 @@ class Linker {
* @param string $comment
* @param Title|null $title Title object (to generate link to the section in autocomment) or null
* @param bool $local Whether section links should refer to local page
+ * @param string|null $wikiId Id (as used by WikiMap) of the wiki to generate links to. For use with external changes.
+ *
* @return mixed|string
*/
- public static function formatComment( $comment, $title = null, $local = false ) {
+ public static function formatComment( $comment, $title = null, $local = false, $wikiId = null ) {
# Sanitize text a bit:
$comment = str_replace( "\n", " ", $comment );
@@ -1286,8 +1288,8 @@ class Linker {
$comment = Sanitizer::escapeHtmlAllowEntities( $comment );
# Render autocomments and make links:
- $comment = self::formatAutocomments( $comment, $title, $local );
- $comment = self::formatLinksInComment( $comment, $title, $local );
+ $comment = self::formatAutocomments( $comment, $title, $local, $wikiId );
+ $comment = self::formatLinksInComment( $comment, $title, $local, $wikiId );
return $comment;
}
@@ -1304,9 +1306,11 @@ class Linker {
* @param string $comment Comment text
* @param Title|null $title An optional title object used to links to sections
* @param bool $local Whether section links should refer to local page
- * @return string Formatted comment
+ * @param string|null $wikiId Id of the wiki to link to (if not the local wiki), as used by WikiMap.
+ *
+ * @return string Formatted comment (wikitext)
*/
- private static function formatAutocomments( $comment, $title = null, $local = false ) {
+ private static function formatAutocomments( $comment, $title = null, $local = false, $wikiId = null ) {
// @todo $append here is something of a hack to preserve the status
// quo. Someone who knows more about bidi and such should decide
// (1) what sane rendering even *is* for an LTR edit summary on an RTL
@@ -1320,7 +1324,7 @@ class Linker {
// zero-width assertions optional, so wrap them in a non-capturing
// group.
'!(?:(?<=(.)))?/\*\s*(.*?)\s*\*/(?:(?=(.)))?!',
- function ( $match ) use ( $title, $local, &$append ) {
+ function ( $match ) use ( $title, $local, $wikiId, &$append ) {
global $wgLang;
// Ensure all match positions are defined
@@ -1330,7 +1334,7 @@ class Linker {
$auto = $match[2];
$post = $match[3] !== '';
$comment = null;
- Hooks::run( 'FormatAutocomments', array( &$comment, $pre, $auto, $post, $title, $local ) );
+ Hooks::run( 'FormatAutocomments', array( &$comment, $pre, $auto, $post, $title, $local, $wikiId ) );
if ( $comment === null ) {
$link = '';
if ( $title ) {
@@ -1349,9 +1353,7 @@ class Linker {
$title->getDBkey(), $section );
}
if ( $sectionTitle ) {
- $link = Linker::link( $sectionTitle,
- $wgLang->getArrow(), array(), array(),
- 'noclasses' );
+ $link = Linker::makeCommentLink( $sectionTitle, $wgLang->getArrow(), $wikiId, 'noclasses' );
} else {
$link = '';
}
@@ -1384,7 +1386,7 @@ class Linker {
* @param string $comment Text to format links in
* @param Title|null $title An optional title object used to links to sections
* @param bool $local Whether section links should refer to local page
- * @param string|null $wikiId Id of the wiki to link to (if not the local wiki), as used by WikiMap
+ * @param string|null $wikiId Id of the wiki to link to (if not the local wiki), as used by WikiMap.
*
* @return string
*/
@@ -1414,10 +1416,9 @@ class Linker {
# fix up urlencoded title texts (copied from Parser::replaceInternalLinks)
if ( strpos( $match[1], '%' ) !== false ) {
- $match[1] = str_replace(
- array( '<', '>' ),
- array( '&lt;', '&gt;' ),
- rawurldecode( $match[1] )
+ $match[1] = strtr(
+ rawurldecode( $match[1] ),
+ array( '<' => '&lt;', '>' => '&gt;' )
);
}
@@ -1460,22 +1461,9 @@ class Linker {
$newTarget = clone ( $title );
$newTarget->setFragment( '#' . $target->getFragment() );
$target = $newTarget;
-
- }
-
- if ( $wikiId !== null ) {
- $thelink = Linker::makeExternalLink(
- WikiMap::getForeignURL( $wikiId, $target->getFullText() ),
- $linkText . $inside,
- /* escape = */ false // Already escaped
- ) . $trail;
- } else {
- $thelink = Linker::link(
- $target,
- $linkText . $inside
- ) . $trail;
}
+ $thelink = Linker::makeCommentLink( $target, $linkText . $inside, $wikiId ) . $trail;
}
}
if ( $thelink ) {
@@ -1495,6 +1483,32 @@ class Linker {
}
/**
+ * Generates a link to the given Title
+ *
+ * @note This is only public for technical reasons. It's not intended for use outside Linker.
+ *
+ * @param Title $title
+ * @param string $text
+ * @param string|null $wikiId Id of the wiki to link to (if not the local wiki), as used by WikiMap.
+ * @param string|string[] $options See the $options parameter in Linker::link.
+ *
+ * @return string HTML link
+ */
+ public static function makeCommentLink( Title $title, $text, $wikiId = null, $options = array() ) {
+ if ( $wikiId !== null && !$title->isExternal() ) {
+ $link = Linker::makeExternalLink(
+ WikiMap::getForeignURL( $wikiId, $title->getPrefixedText(), $title->getFragment() ),
+ $text,
+ /* escape = */ false // Already escaped
+ );
+ } else {
+ $link = Linker::link( $title, $text, array(), array(), $options );
+ }
+
+ return $link;
+ }
+
+ /**
* @param Title $contextTitle
* @param string $target
* @param string $text
@@ -1580,17 +1594,18 @@ class Linker {
* @param string $comment
* @param Title|null $title Title object (to generate link to section in autocomment) or null
* @param bool $local Whether section links should refer to local page
+ * @param string|null $wikiId Id (as used by WikiMap) of the wiki to generate links to. For use with external changes.
*
* @return string
*/
- public static function commentBlock( $comment, $title = null, $local = false ) {
+ public static function commentBlock( $comment, $title = null, $local = false, $wikiId = null ) {
// '*' used to be the comment inserted by the software way back
// in antiquity in case none was provided, here for backwards
// compatibility, acc. to brion -ævar
if ( $comment == '' || $comment == '*' ) {
return '';
} else {
- $formatted = self::formatComment( $comment, $title, $local );
+ $formatted = self::formatComment( $comment, $title, $local, $wikiId );
$formatted = wfMessage( 'parentheses' )->rawParams( $formatted )->escaped();
return " <span class=\"comment\">$formatted</span>";
}
@@ -1705,13 +1720,13 @@ class Linker {
}
/**
- * Generate a table of contents from a section tree
- * Currently unused.
+ * Generate a table of contents from a section tree.
*
* @param array $tree Return value of ParserOutput::getSections()
+ * @param string|Language|bool $lang Language for the toc title, defaults to user language
* @return string HTML fragment
*/
- public static function generateTOC( $tree ) {
+ public static function generateTOC( $tree, $lang = false ) {
$toc = '';
$lastLevel = 0;
foreach ( $tree as $section ) {
@@ -1730,7 +1745,7 @@ class Linker {
$lastLevel = $section['toclevel'];
}
$toc .= self::tocLineEnd();
- return self::tocList( $toc );
+ return self::tocList( $toc, $lang );
}
/**
@@ -2383,6 +2398,7 @@ class Linker {
'title' => $tooltip
) );
}
+
}
/**
diff --git a/includes/MWNamespace.php b/includes/MWNamespace.php
index e370bf10..8ca205ab 100644
--- a/includes/MWNamespace.php
+++ b/includes/MWNamespace.php
@@ -299,6 +299,18 @@ class MWNamespace {
}
/**
+ * Might pages in this namespace require the use of the Signature button on
+ * the edit toolbar?
+ *
+ * @param int $index Index to check
+ * @return bool
+ */
+ public static function wantSignatures( $index ) {
+ global $wgExtraSignatureNamespaces;
+ return self::isTalk( $index ) || in_array( $index, $wgExtraSignatureNamespaces );
+ }
+
+ /**
* Can pages in a namespace be watched?
*
* @param int $index
diff --git a/includes/MWTimestamp.php b/includes/MWTimestamp.php
index ea91470e..d28f88e5 100644
--- a/includes/MWTimestamp.php
+++ b/includes/MWTimestamp.php
@@ -56,7 +56,7 @@ class MWTimestamp {
*
* @since 1.20
*
- * @param bool|string $timestamp Timestamp to set, or false for current time
+ * @param bool|string|int|float $timestamp Timestamp to set, or false for current time
*/
public function __construct( $timestamp = false ) {
$this->setTimestamp( $timestamp );
@@ -74,6 +74,7 @@ class MWTimestamp {
* @throws TimestampException
*/
public function setTimestamp( $ts = false ) {
+ $m = array();
$da = array();
$strtime = '';
@@ -87,9 +88,9 @@ class MWTimestamp {
# TS_EXIF
} elseif ( preg_match( '/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/D', $ts, $da ) ) {
# TS_MW
- } elseif ( preg_match( '/^-?\d{1,13}$/D', $ts ) ) {
+ } elseif ( preg_match( '/^(-?\d{1,13})(\.\d+)?$/D', $ts, $m ) ) {
# TS_UNIX
- $strtime = "@$ts"; // http://php.net/manual/en/datetime.formats.compound.php
+ $strtime = "@{$m[1]}"; // http://php.net/manual/en/datetime.formats.compound.php
} elseif ( preg_match( '/^\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}.\d{6}$/', $ts ) ) {
# TS_ORACLE // session altered to DD-MM-YYYY HH24:MI:SS.FF6
$strtime = preg_replace( '/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
@@ -199,42 +200,19 @@ class MWTimestamp {
*
* @since 1.20
* @since 1.22 Uses Language::getHumanTimestamp to produce the timestamp
+ * @deprecated since 1.26 Use Language::getHumanTimestamp directly
*
- * @param MWTimestamp|null $relativeTo The base timestamp to compare to
- * (defaults to now).
- * @param User|null $user User the timestamp is being generated for (or null
- * to use main context's user).
- * @param Language|null $lang Language to use to make the human timestamp
- * (or null to use main context's language).
+ * @param MWTimestamp|null $relativeTo The base timestamp to compare to (defaults to now)
+ * @param User|null $user User the timestamp is being generated for (or null to use main context's user)
+ * @param Language|null $lang Language to use to make the human timestamp (or null to use main context's language)
* @return string Formatted timestamp
*/
- public function getHumanTimestamp( MWTimestamp $relativeTo = null,
- User $user = null, Language $lang = null
- ) {
- if ( $relativeTo === null ) {
- $relativeTo = new self();
- }
- if ( $user === null ) {
- $user = RequestContext::getMain()->getUser();
- }
+ public function getHumanTimestamp( MWTimestamp $relativeTo = null, User $user = null, Language $lang = null ) {
if ( $lang === null ) {
$lang = RequestContext::getMain()->getLanguage();
}
- // Adjust for the user's timezone.
- $offsetThis = $this->offsetForUser( $user );
- $offsetRel = $relativeTo->offsetForUser( $user );
-
- $ts = '';
- if ( Hooks::run( 'GetHumanTimestamp', array( &$ts, $this, $relativeTo, $user, $lang ) ) ) {
- $ts = $lang->getHumanTimestamp( $this, $relativeTo, $user );
- }
-
- // Reset the timezone on the objects.
- $this->timestamp->sub( $offsetThis );
- $relativeTo->timestamp->sub( $offsetRel );
-
- return $ts;
+ return $lang->getHumanTimestamp( $this, $relativeTo, $user );
}
/**
diff --git a/includes/MagicWord.php b/includes/MagicWord.php
index 186821de..2c7ba91b 100644
--- a/includes/MagicWord.php
+++ b/includes/MagicWord.php
@@ -718,9 +718,6 @@ class MagicWordArray {
private $regex;
- /** @todo Unused? */
- private $matches;
-
/**
* @param array $names
*/
@@ -953,10 +950,12 @@ class MagicWordArray {
if ( $regex === '' ) {
continue;
}
- preg_match_all( $regex, $text, $matches, PREG_SET_ORDER );
- foreach ( $matches as $m ) {
- list( $name, $param ) = $this->parseMatch( $m );
- $found[$name] = $param;
+ $matches = array();
+ if ( preg_match_all( $regex, $text, $matches, PREG_SET_ORDER ) ) {
+ foreach ( $matches as $m ) {
+ list( $name, $param ) = $this->parseMatch( $m );
+ $found[$name] = $param;
+ }
}
$text = preg_replace( $regex, '', $text );
}
diff --git a/includes/MediaWiki.php b/includes/MediaWiki.php
index ec2f40f6..fbacb250 100644
--- a/includes/MediaWiki.php
+++ b/includes/MediaWiki.php
@@ -51,6 +51,7 @@ class MediaWiki {
/**
* Parse the request to get the Title object
*
+ * @throws MalformedTitleException If a title has been provided by the user, but is invalid.
* @return Title Title object to be $wgTitle
*/
private function parseTitle() {
@@ -110,7 +111,10 @@ class MediaWiki {
}
if ( $ret === null || ( $ret->getDBkey() == '' && !$ret->isExternal() ) ) {
- $ret = SpecialPage::getTitleFor( 'Badtitle' );
+ // If we get here, we definitely don't have a valid title; throw an exception.
+ // Try to get detailed invalid title exception first, fall back to MalformedTitleException.
+ Title::newFromTextThrow( $title );
+ throw new MalformedTitleException( 'badtitletext', $title );
}
return $ret;
@@ -122,7 +126,11 @@ class MediaWiki {
*/
public function getTitle() {
if ( !$this->context->hasTitle() ) {
- $this->context->setTitle( $this->parseTitle() );
+ try {
+ $this->context->setTitle( $this->parseTitle() );
+ } catch ( MalformedTitleException $ex ) {
+ $this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) );
+ }
}
return $this->context->getTitle();
}
@@ -174,6 +182,11 @@ class MediaWiki {
|| $title->isSpecial( 'Badtitle' )
) {
$this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) );
+ try {
+ $this->parseTitle();
+ } catch ( MalformedTitleException $ex ) {
+ throw new BadTitleError( $ex );
+ }
throw new BadTitleError();
}
@@ -219,65 +232,116 @@ class MediaWiki {
$output->redirect( $url, 301 );
} else {
$this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) );
- throw new BadTitleError();
- }
- // Redirect loops, no title in URL, $wgUsePathInfo URLs, and URLs with a variant
- } elseif ( $request->getVal( 'action', 'view' ) == 'view' && !$request->wasPosted()
- && ( $request->getVal( 'title' ) === null
- || $title->getPrefixedDBkey() != $request->getVal( 'title' ) )
- && !count( $request->getValueNames( array( 'action', 'title' ) ) )
- && Hooks::run( 'TestCanonicalRedirect', array( $request, $title, $output ) )
- ) {
- if ( $title->isSpecialPage() ) {
- list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
- if ( $name ) {
- $title = SpecialPage::getTitleFor( $name, $subpage );
+ try {
+ $this->parseTitle();
+ } catch ( MalformedTitleException $ex ) {
+ throw new BadTitleError( $ex );
}
+ throw new BadTitleError();
}
- $targetUrl = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
- // Redirect to canonical url, make it a 301 to allow caching
- if ( $targetUrl == $request->getFullRequestURL() ) {
- $message = "Redirect loop detected!\n\n" .
- "This means the wiki got confused about what page was " .
- "requested; this sometimes happens when moving a wiki " .
- "to a new server or changing the server configuration.\n\n";
-
- if ( $this->config->get( 'UsePathInfo' ) ) {
- $message .= "The wiki is trying to interpret the page " .
- "title from the URL path portion (PATH_INFO), which " .
- "sometimes fails depending on the web server. Try " .
- "setting \"\$wgUsePathInfo = false;\" in your " .
- "LocalSettings.php, or check that \$wgArticlePath " .
- "is correct.";
+ // Handle any other redirects.
+ // Redirect loops, titleless URL, $wgUsePathInfo URLs, and URLs with a variant
+ } elseif ( !$this->tryNormaliseRedirect( $title ) ) {
+
+ // Special pages
+ if ( NS_SPECIAL == $title->getNamespace() ) {
+ // Actions that need to be made when we have a special pages
+ SpecialPageFactory::executePath( $title, $this->context );
+ } else {
+ // ...otherwise treat it as an article view. The article
+ // may still be a wikipage redirect to another article or URL.
+ $article = $this->initializeArticle();
+ if ( is_object( $article ) ) {
+ $this->performAction( $article, $requestTitle );
+ } elseif ( is_string( $article ) ) {
+ $output->redirect( $article );
} else {
- $message .= "Your web server was detected as possibly not " .
- "supporting URL path components (PATH_INFO) correctly; " .
- "check your LocalSettings.php for a customized " .
- "\$wgArticlePath setting and/or toggle \$wgUsePathInfo " .
- "to true.";
+ throw new MWException( "Shouldn't happen: MediaWiki::initializeArticle()"
+ . " returned neither an object nor a URL" );
}
- throw new HttpError( 500, $message );
- } else {
- $output->setSquidMaxage( 1200 );
- $output->redirect( $targetUrl, '301' );
}
- // Special pages
- } elseif ( NS_SPECIAL == $title->getNamespace() ) {
- // Actions that need to be made when we have a special pages
- SpecialPageFactory::executePath( $title, $this->context );
- } else {
- // ...otherwise treat it as an article view. The article
- // may be a redirect to another article or URL.
- $article = $this->initializeArticle();
- if ( is_object( $article ) ) {
- $this->performAction( $article, $requestTitle );
- } elseif ( is_string( $article ) ) {
- $output->redirect( $article );
+ }
+ }
+
+ /**
+ * Handle redirects for uncanonical title requests.
+ *
+ * Handles:
+ * - Redirect loops.
+ * - No title in URL.
+ * - $wgUsePathInfo URLs.
+ * - URLs with a variant.
+ * - Other non-standard URLs (as long as they have no extra query parameters).
+ *
+ * Behaviour:
+ * - Normalise title values:
+ * /wiki/Foo%20Bar -> /wiki/Foo_Bar
+ * - Normalise empty title:
+ * /wiki/ -> /wiki/Main
+ * /w/index.php?title= -> /wiki/Main
+ * - Normalise non-standard title urls:
+ * /w/index.php?title=Foo_Bar -> /wiki/Foo_Bar
+ * - Don't redirect anything with query parameters other than 'title' or 'action=view'.
+ *
+ * @param Title $title
+ * @return bool True if a redirect was set.
+ * @throws HttpError
+ */
+ private function tryNormaliseRedirect( Title $title ) {
+ $request = $this->context->getRequest();
+ $output = $this->context->getOutput();
+
+ if ( $request->getVal( 'action', 'view' ) != 'view'
+ || $request->wasPosted()
+ || count( $request->getValueNames( array( 'action', 'title' ) ) )
+ || !Hooks::run( 'TestCanonicalRedirect', array( $request, $title, $output ) )
+ ) {
+ return false;
+ }
+
+ if ( $title->isSpecialPage() ) {
+ list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
+ if ( $name ) {
+ $title = SpecialPage::getTitleFor( $name, $subpage );
+ }
+ }
+ // Redirect to canonical url, make it a 301 to allow caching
+ $targetUrl = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
+
+ if ( $targetUrl != $request->getFullRequestURL() ) {
+ $output->setSquidMaxage( 1200 );
+ $output->redirect( $targetUrl, '301' );
+ return true;
+ }
+
+ // If there is no title, or the title is in a non-standard encoding, we demand
+ // a redirect. If cgi somehow changed the 'title' query to be non-standard while
+ // the url is standard, the server is misconfigured.
+ if ( $request->getVal( 'title' ) === null
+ || $title->getPrefixedDBkey() != $request->getVal( 'title' )
+ ) {
+ $message = "Redirect loop detected!\n\n" .
+ "This means the wiki got confused about what page was " .
+ "requested; this sometimes happens when moving a wiki " .
+ "to a new server or changing the server configuration.\n\n";
+
+ if ( $this->config->get( 'UsePathInfo' ) ) {
+ $message .= "The wiki is trying to interpret the page " .
+ "title from the URL path portion (PATH_INFO), which " .
+ "sometimes fails depending on the web server. Try " .
+ "setting \"\$wgUsePathInfo = false;\" in your " .
+ "LocalSettings.php, or check that \$wgArticlePath " .
+ "is correct.";
} else {
- throw new MWException( "Shouldn't happen: MediaWiki::initializeArticle()"
- . " returned neither an object nor a URL" );
+ $message .= "Your web server was detected as possibly not " .
+ "supporting URL path components (PATH_INFO) correctly; " .
+ "check your LocalSettings.php for a customized " .
+ "\$wgArticlePath setting and/or toggle \$wgUsePathInfo " .
+ "to true.";
}
+ throw new HttpError( 500, $message );
}
+ return false;
}
/**
@@ -301,9 +365,8 @@ class MediaWiki {
$this->context->setWikiPage( $article->getPage() );
}
- // NS_MEDIAWIKI has no redirects.
- // It is also used for CSS/JS, so performance matters here...
- if ( $title->getNamespace() == NS_MEDIAWIKI ) {
+ // Skip some unnecessary code if the content model doesn't support redirects
+ if ( !ContentHandler::getForTitle( $title )->supportsRedirects() ) {
return $article;
}
@@ -404,8 +467,7 @@ class MediaWiki {
}
/**
- * Run the current MediaWiki instance
- * index.php just calls this
+ * Run the current MediaWiki instance; index.php just calls this
*/
public function run() {
try {
@@ -416,16 +478,71 @@ class MediaWiki {
// Bug 62091: while exceptions are convenient to bubble up GUI errors,
// they are not internal application faults. As with normal requests, this
// should commit, print the output, do deferred updates, jobs, and profiling.
- wfGetLBFactory()->commitMasterChanges();
+ $this->doPreOutputCommit();
$e->report(); // display the GUI error
}
+ } catch ( Exception $e ) {
+ MWExceptionHandler::handleException( $e );
+ }
+
+ $this->doPostOutputShutdown( 'normal' );
+ }
+
+ /**
+ * This function commits all DB changes as needed before
+ * the user can receive a response (in case commit fails)
+ *
+ * @since 1.26
+ */
+ public function doPreOutputCommit() {
+ // Either all DBs should commit or none
+ ignore_user_abort( true );
+
+ // Commit all changes and record ChronologyProtector positions
+ $factory = wfGetLBFactory();
+ $factory->commitMasterChanges();
+ $factory->shutdown();
+
+ wfDebug( __METHOD__ . ' completed; all transactions committed' );
+ }
+
+ /**
+ * This function does work that can be done *after* the
+ * user gets the HTTP response so they don't block on it
+ *
+ * This manages deferred updates, job insertion,
+ * final commit, and the logging of profiling data
+ *
+ * @param string $mode Use 'fast' to always skip job running
+ * @since 1.26
+ */
+ public function doPostOutputShutdown( $mode = 'normal' ) {
+ // Show visible profiling data if enabled (which cannot be post-send)
+ Profiler::instance()->logDataPageOutputOnly();
+
+ $that = $this;
+ $callback = function () use ( $that, $mode ) {
+ try {
+ $that->restInPeace( $mode );
+ } catch ( Exception $e ) {
+ MWExceptionHandler::handleException( $e );
+ }
+ };
+
+ // Defer everything else...
+ if ( function_exists( 'register_postsend_function' ) ) {
+ // https://github.com/facebook/hhvm/issues/1230
+ register_postsend_function( $callback );
+ } else {
if ( function_exists( 'fastcgi_finish_request' ) ) {
fastcgi_finish_request();
+ } else {
+ // Either all DB and deferred updates should happen or none.
+ // The later should not be cancelled due to client disconnect.
+ ignore_user_abort( true );
}
- $this->triggerJobs();
- $this->restInPeace();
- } catch ( Exception $e ) {
- MWExceptionHandler::handleException( $e );
+
+ $callback();
}
}
@@ -440,7 +557,7 @@ class MediaWiki {
list( $host, $lag ) = wfGetLB()->getMaxLag();
if ( $lag > $maxLag ) {
$resp = $this->context->getRequest()->response();
- $resp->header( 'HTTP/1.1 503 Service Unavailable' );
+ $resp->statusHeader( 503 );
$resp->header( 'Retry-After: ' . max( intval( $maxLag ), 5 ) );
$resp->header( 'X-Database-Lag: ' . intval( $lag ) );
$resp->header( 'Content-Type: text/plain' );
@@ -457,7 +574,7 @@ class MediaWiki {
}
private function main() {
- global $wgTitle;
+ global $wgTitle, $wgTrxProfilerLimits;
$request = $this->context->getRequest();
@@ -489,10 +606,9 @@ class MediaWiki {
if ( !$request->wasPosted()
&& in_array( $action, array( 'view', 'edit', 'history' ) )
) {
- $trxProfiler->setExpectation( 'masterConns', 0, __METHOD__ );
- $trxProfiler->setExpectation( 'writes', 0, __METHOD__ );
+ $trxProfiler->setExpectations( $wgTrxProfilerLimits['GET'], __METHOD__ );
} else {
- $trxProfiler->setExpectation( 'maxAffected', 500, __METHOD__ );
+ $trxProfiler->setExpectations( $wgTrxProfilerLimits['POST'], __METHOD__ );
}
// If the user has forceHTTPS set to true, or if the user
@@ -565,22 +681,23 @@ class MediaWiki {
// Actually do the work of the request and build up any output
$this->performRequest();
- // Either all DB and deferred updates should happen or none.
- // The later should not be cancelled due to client disconnect.
- ignore_user_abort( true );
// Now commit any transactions, so that unreported errors after
- // output() don't roll back the whole DB transaction
- wfGetLBFactory()->commitMasterChanges();
+ // output() don't roll back the whole DB transaction and so that
+ // we avoid having both success and error text in the response
+ $this->doPreOutputCommit();
// Output everything!
$this->context->getOutput()->output();
-
}
/**
* Ends this task peacefully
+ * @param string $mode Use 'fast' to always skip job running
*/
- public function restInPeace() {
+ public function restInPeace( $mode = 'fast' ) {
+ // Assure deferred updates are not in the main transaction
+ wfGetLBFactory()->commitMasterChanges();
+
// Ignore things like master queries/connections on GET requests
// as long as they are in deferred updates (which catch errors).
Profiler::instance()->getTransactionProfiler()->resetExpectations();
@@ -588,6 +705,15 @@ class MediaWiki {
// Do any deferred jobs
DeferredUpdates::doUpdates( 'commit' );
+ // Make sure any lazy jobs are pushed
+ JobQueueGroup::pushLazyJobs();
+
+ // Now that everything specific to this request is done,
+ // try to occasionally run jobs (if enabled) from the queues
+ if ( $mode === 'normal' ) {
+ $this->triggerJobs();
+ }
+
// Log profiling data, e.g. in the database or UDP
wfLogProfilingData();
@@ -604,7 +730,7 @@ class MediaWiki {
* to run a specified number of jobs. This registers a callback to cleanup
* the socket once it's done.
*/
- protected function triggerJobs() {
+ public function triggerJobs() {
$jobRunRate = $this->config->get( 'JobRunRate' );
if ( $jobRunRate <= 0 || wfReadOnly() ) {
return;
@@ -647,7 +773,7 @@ class MediaWiki {
$errno = $errstr = null;
$info = wfParseUrl( $this->config->get( 'Server' ) );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$sock = fsockopen(
$info['host'],
isset( $info['port'] ) ? $info['port'] : 80,
@@ -657,7 +783,7 @@ class MediaWiki {
// is a problem elsewhere.
0.1
);
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$sock ) {
$runJobsLogger->error( "Failed to start cron API (socket error $errno): $errstr" );
// Fall back to running the job here while the user waits
diff --git a/includes/Message.php b/includes/Message.php
index 134af0ed..54abfd15 100644
--- a/includes/Message.php
+++ b/includes/Message.php
@@ -156,7 +156,7 @@
*
* @since 1.17
*/
-class Message implements MessageSpecifier {
+class Message implements MessageSpecifier, Serializable {
/**
* In which language to get this message. True, which is the default,
@@ -226,8 +226,9 @@ class Message implements MessageSpecifier {
/**
* @since 1.17
*
- * @param string|string[] $key Message key or array of message keys to try and use the first
- * non-empty message for.
+ * @param string|string[]|MessageSpecifier $key Message key, or array of
+ * message keys to try and use the first non-empty message for, or a
+ * MessageSpecifier to copy from.
* @param array $params Message parameters.
* @param Language $language Optional language of the message, defaults to $wgLang.
*
@@ -236,6 +237,16 @@ class Message implements MessageSpecifier {
public function __construct( $key, $params = array(), Language $language = null ) {
global $wgLang;
+ if ( $key instanceof MessageSpecifier ) {
+ if ( $params ) {
+ throw new InvalidArgumentException(
+ '$params must be empty if $key is a MessageSpecifier'
+ );
+ }
+ $params = $key->getParams();
+ $key = $key->getKey();
+ }
+
if ( !is_string( $key ) && !is_array( $key ) ) {
throw new InvalidArgumentException( '$key must be a string or an array' );
}
@@ -253,6 +264,41 @@ class Message implements MessageSpecifier {
}
/**
+ * @see Serializable::serialize()
+ * @since 1.26
+ * @return string
+ */
+ public function serialize() {
+ return serialize( array(
+ 'interface' => $this->interface,
+ 'language' => $this->language->getCode(),
+ 'key' => $this->key,
+ 'keysToTry' => $this->keysToTry,
+ 'parameters' => $this->parameters,
+ 'format' => $this->format,
+ 'useDatabase' => $this->useDatabase,
+ 'title' => $this->title,
+ ) );
+ }
+
+ /**
+ * @see Serializable::unserialize()
+ * @since 1.26
+ * @param string $serialized
+ */
+ public function unserialize( $serialized ) {
+ $data = unserialize( $serialized );
+ $this->interface = $data['interface'];
+ $this->key = $data['key'];
+ $this->keysToTry = $data['keysToTry'];
+ $this->parameters = $data['parameters'];
+ $this->format = $data['format'];
+ $this->useDatabase = $data['useDatabase'];
+ $this->language = Language::factory( $data['language'] );
+ $this->title = $data['title'];
+ }
+
+ /**
* @since 1.24
*
* @return bool True if this is a multi-key message, that is, if the key provided to the
@@ -327,7 +373,7 @@ class Message implements MessageSpecifier {
*
* @since 1.17
*
- * @param string|string[] $key Message key or array of keys.
+ * @param string|string[]|MessageSpecifier $key
* @param mixed $param,... Parameters as strings.
*
* @return Message
@@ -365,6 +411,31 @@ class Message implements MessageSpecifier {
}
/**
+ * Get a title object for a mediawiki message, where it can be found in the mediawiki namespace.
+ * The title will be for the current language, if the message key is in
+ * $wgForceUIMsgAsContentMsg it will be append with the language code (except content
+ * language), because Message::inContentLanguage will also return in user language.
+ *
+ * @see $wgForceUIMsgAsContentMsg
+ * @return Title
+ * @since 1.26
+ */
+ public function getTitle() {
+ global $wgContLang, $wgForceUIMsgAsContentMsg;
+
+ $code = $this->language->getCode();
+ $title = $this->key;
+ if (
+ $wgContLang->getCode() !== $code
+ && in_array( $this->key, (array)$wgForceUIMsgAsContentMsg )
+ ) {
+ $title .= '/' . $code;
+ }
+
+ return Title::makeTitle( NS_MEDIAWIKI, $wgContLang->ucfirst( strtr( $title, ' ', '_' ) ) );
+ }
+
+ /**
* Adds parameters to the parameter list of this message.
*
* @since 1.17
@@ -597,7 +668,7 @@ class Message implements MessageSpecifier {
if ( $lang instanceof Language || $lang instanceof StubUserLang ) {
$this->language = $lang;
} elseif ( is_string( $lang ) ) {
- if ( $this->language->getCode() != $lang ) {
+ if ( !$this->language instanceof Language || $this->language->getCode() != $lang ) {
$this->language = Language::factory( $lang );
}
} else {
diff --git a/includes/MimeMagic.php b/includes/MimeMagic.php
index ebe98a3c..2b240c3b 100644
--- a/includes/MimeMagic.php
+++ b/includes/MimeMagic.php
@@ -617,16 +617,18 @@ class MimeMagic {
/**
* Guess the MIME type from the file contents.
*
+ * @todo Remove $ext param
+ *
* @param string $file
* @param mixed $ext
* @return bool|string
* @throws MWException
*/
- private function doGuessMimeType( $file, $ext ) { // TODO: remove $ext param
+ private function doGuessMimeType( $file, $ext ) {
// Read a chunk of the file
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$f = fopen( $file, 'rb' );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$f ) {
return 'unknown/unknown';
@@ -693,7 +695,7 @@ class MimeMagic {
}
/* Look for WebP */
- if ( strncmp( $head, "RIFF", 4 ) == 0 && strncmp( substr( $head, 8, 8 ), "WEBPVP8 ", 8 ) == 0 ) {
+ if ( strncmp( $head, "RIFF", 4 ) == 0 && strncmp( substr( $head, 8, 7 ), "WEBPVP8", 7 ) == 0 ) {
wfDebug( __METHOD__ . ": recognized file as image/webp\n" );
return "image/webp";
}
@@ -780,9 +782,9 @@ class MimeMagic {
return $this->detectZipType( $head, $tail, $ext );
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$gis = getimagesize( $file );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $gis && isset( $gis['mime'] ) ) {
$mime = $gis['mime'];
diff --git a/includes/MovePage.php b/includes/MovePage.php
index de7da3f9..2cd9698c 100644
--- a/includes/MovePage.php
+++ b/includes/MovePage.php
@@ -64,21 +64,9 @@ class MovePage {
$status->fatal( 'spamprotectiontext' );
}
- # The move is allowed only if (1) the target doesn't exist, or
- # (2) the target is a redirect to the source, and has no history
- # (so we can undo bad moves right after they're done).
-
- if ( $this->newTitle->getArticleID() ) { # Target exists; check for validity
- if ( !$this->isValidMoveTarget() ) {
- $status->fatal( 'articleexists' );
- }
- } else {
- $tp = $this->newTitle->getTitleProtection();
- if ( $tp !== false ) {
- if ( !$user->isAllowed( $tp['permission'] ) ) {
- $status->fatal( 'cantmove-titleprotected' );
- }
- }
+ $tp = $this->newTitle->getTitleProtection();
+ if ( $tp !== false && !$user->isAllowed( $tp['permission'] ) ) {
+ $status->fatal( 'cantmove-titleprotected' );
}
Hooks::run( 'MovePageCheckPermissions',
@@ -125,6 +113,13 @@ class MovePage {
$status->fatal( 'badarticleerror' );
}
+ # The move is allowed only if (1) the target doesn't exist, or
+ # (2) the target is a redirect to the source, and has no history
+ # (so we can undo bad moves right after they're done).
+ if ( $this->newTitle->getArticleID() && !$this->isValidMoveTarget() ) {
+ $status->fatal( 'articleexists' );
+ }
+
// Content model checks
if ( !$wgContentHandlerUseDB &&
$this->oldTitle->getContentModel() !== $this->newTitle->getContentModel() ) {
@@ -310,8 +305,8 @@ class MovePage {
__METHOD__,
array( 'IGNORE' )
);
- # Update the protection log
- $log = new LogPage( 'protect' );
+
+ // Build comment for log
$comment = wfMessage(
'prot_1movedto2',
$this->oldTitle->getPrefixedText(),
@@ -320,14 +315,6 @@ class MovePage {
if ( $reason ) {
$comment .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $reason;
}
- // @todo FIXME: $params?
- $logId = $log->addEntry(
- 'move_prot',
- $this->newTitle,
- $comment,
- array( $this->oldTitle->getPrefixedText() ),
- $user
- );
// reread inserted pr_ids for log relation
$insertedPrIds = $dbw->select(
@@ -340,7 +327,18 @@ class MovePage {
foreach ( $insertedPrIds as $prid ) {
$logRelationsValues[] = $prid->pr_id;
}
- $log->addRelations( 'pr_id', $logRelationsValues, $logId );
+
+ // Update the protection log
+ $logEntry = new ManualLogEntry( 'protect', 'move_prot' );
+ $logEntry->setTarget( $this->newTitle );
+ $logEntry->setComment( $comment );
+ $logEntry->setPerformer( $user );
+ $logEntry->setParameters( array(
+ '4::oldtitle' => $this->oldTitle->getPrefixedText(),
+ ) );
+ $logEntry->setRelations( array( 'pr_id' => $logRelationsValues ) );
+ $logId = $logEntry->insert();
+ $logEntry->publish( $logId );
}
// Update *_from_namespace fields as needed
@@ -421,6 +419,13 @@ class MovePage {
$redirectContent = null;
}
+ // Figure out whether the content model is no longer the default
+ $oldDefault = ContentHandler::getDefaultModelFor( $this->oldTitle );
+ $contentModel = $this->oldTitle->getContentModel();
+ $newDefault = ContentHandler::getDefaultModelFor( $nt );
+ $defaultContentModelChanging = ( $oldDefault !== $newDefault
+ && $oldDefault === $contentModel );
+
// bug 57084: log_page should be the ID of the *moved* page
$oldid = $this->oldTitle->getArticleID();
$logTitle = clone $this->oldTitle;
@@ -498,6 +503,16 @@ class MovePage {
$newpage->doEditUpdates( $nullRevision, $user,
array( 'changed' => false, 'moved' => true, 'oldcountable' => $oldcountable ) );
+ // If the default content model changes, we need to populate rev_content_model
+ if ( $defaultContentModelChanging ) {
+ $dbw->update(
+ 'revision',
+ array( 'rev_content_model' => $contentModel ),
+ array( 'rev_page' => $nt->getArticleID(), 'rev_content_model IS NULL' ),
+ __METHOD__
+ );
+ }
+
if ( !$moveOverRedirect ) {
WikiPage::onArticleCreate( $nt );
}
diff --git a/includes/OutputPage.php b/includes/OutputPage.php
index 7e671878..552e1815 100644
--- a/includes/OutputPage.php
+++ b/includes/OutputPage.php
@@ -20,6 +20,9 @@
* @file
*/
+use MediaWiki\Logger\LoggerFactory;
+use WrappedString\WrappedString;
+
/**
* This class should be covered by a general architecture document which does
* not exist as of January 2011. This is one of the Core classes and should
@@ -139,9 +142,6 @@ class OutputPage extends ContextSource {
/** @var string Inline CSS styles. Use addInlineStyle() sparingly */
protected $mInlineStyles = '';
- /** @todo Unused? */
- private $mLinkColours;
-
/**
* @var string Used by skin template.
* Example: $tpl->set( 'displaytitle', $out->mPageLinkTitle );
@@ -162,9 +162,6 @@ class OutputPage extends ContextSource {
/** @var array */
protected $mModuleStyles = array();
- /** @var array */
- protected $mModuleMessages = array();
-
/** @var ResourceLoader */
protected $mResourceLoader;
@@ -306,6 +303,11 @@ class OutputPage extends ContextSource {
private $mEnableSectionEditLinks = true;
/**
+ * @var string|null The URL to send in a <link> element with rel=copyright
+ */
+ private $copyrightUrl;
+
+ /**
* Constructor for OutputPage. This should not be called directly.
* Instead a new RequestContext should be created and it will implicitly create
* a OutputPage tied to that context.
@@ -342,6 +344,18 @@ class OutputPage extends ContextSource {
}
/**
+ * Set the copyright URL to send with the output.
+ * Empty string to omit, null to reset.
+ *
+ * @since 1.26
+ *
+ * @param string|null $url
+ */
+ public function setCopyrightUrl( $url ) {
+ $this->copyrightUrl = $url;
+ }
+
+ /**
* Set the HTTP status code to send with the output.
*
* @param int $statusCode
@@ -594,6 +608,20 @@ class OutputPage extends ContextSource {
* @return array Array of module names
*/
public function getModuleStyles( $filter = false, $position = null ) {
+ // T97420
+ $resourceLoader = $this->getResourceLoader();
+
+ foreach ( $this->mModuleStyles as $val ) {
+ $module = $resourceLoader->getModule( $val );
+
+ if ( $module instanceof ResourceLoaderModule && $module->isPositionDefault() ) {
+ $warning = __METHOD__ . ': style module should define its position explicitly: ' .
+ $val . ' ' . get_class( $module );
+ wfDebugLog( 'resourceloader', $warning );
+ wfLogWarning( $warning );
+ }
+ }
+
return $this->getModules( $filter, $position, 'mModuleStyles' );
}
@@ -613,24 +641,24 @@ class OutputPage extends ContextSource {
/**
* Get the list of module messages to include on this page
*
+ * @deprecated since 1.26 Obsolete
* @param bool $filter
* @param string|null $position
- *
* @return array Array of module names
*/
public function getModuleMessages( $filter = false, $position = null ) {
- return $this->getModules( $filter, $position, 'mModuleMessages' );
+ wfDeprecated( __METHOD__, '1.26' );
+ return array();
}
/**
- * Add only messages of one or more modules recognized by the resource loader.
- * Module messages added through this function will be loaded by the resource
- * loader when the page loads.
+ * Load messages of one or more ResourceLoader modules.
*
+ * @deprecated since 1.26 Use addModules() instead
* @param string|array $modules Module name (string) or array of module names
*/
public function addModuleMessages( $modules ) {
- $this->mModuleMessages = array_merge( $this->mModuleMessages, (array)$modules );
+ wfDeprecated( __METHOD__, '1.26' );
}
/**
@@ -797,9 +825,9 @@ class OutputPage extends ContextSource {
# this breaks strtotime().
$clientHeader = preg_replace( '/;.*$/', '', $clientHeader );
- wfSuppressWarnings(); // E_STRICT system time bitching
+ MediaWiki\suppressWarnings(); // E_STRICT system time bitching
$clientHeaderTime = strtotime( $clientHeader );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$clientHeaderTime ) {
wfDebug( __METHOD__
. ": unable to parse the client's If-Modified-Since header: $clientHeader\n" );
@@ -826,10 +854,10 @@ class OutputPage extends ContextSource {
}
# Not modified
- # Give a 304 response code and disable body output
+ # Give a 304 Not Modified response code and disable body output
wfDebug( __METHOD__ . ": NOT MODIFIED, $info\n", 'log' );
ini_set( 'zlib.output_compression', 0 );
- $this->getRequest()->response()->header( "HTTP/1.1 304 Not Modified" );
+ $this->getRequest()->response()->statusHeader( 304 );
$this->sendCacheControl();
$this->disable();
@@ -1761,7 +1789,6 @@ class OutputPage extends ContextSource {
$this->addModules( $parserOutput->getModules() );
$this->addModuleScripts( $parserOutput->getModuleScripts() );
$this->addModuleStyles( $parserOutput->getModuleStyles() );
- $this->addModuleMessages( $parserOutput->getModuleMessages() );
$this->addJsConfigVars( $parserOutput->getJsConfigVars() );
$this->mPreventClickjacking = $this->mPreventClickjacking
|| $parserOutput->preventClickjacking();
@@ -1788,6 +1815,11 @@ class OutputPage extends ContextSource {
}
}
+ // enable OOUI if requested via ParserOutput
+ if ( $parserOutput->getEnableOOUI() ) {
+ $this->enableOOUI();
+ }
+
// Link flags are ignored for now, but may in the future be
// used to mark individual language links.
$linkFlags = array();
@@ -1808,7 +1840,6 @@ class OutputPage extends ContextSource {
$this->addModules( $parserOutput->getModules() );
$this->addModuleScripts( $parserOutput->getModuleScripts() );
$this->addModuleStyles( $parserOutput->getModuleStyles() );
- $this->addModuleMessages( $parserOutput->getModuleMessages() );
$this->addJsConfigVars( $parserOutput->getJsConfigVars() );
}
@@ -1978,21 +2009,20 @@ class OutputPage extends ContextSource {
* Add an HTTP header that will influence on the cache
*
* @param string $header Header name
- * @param array|null $option
- * @todo FIXME: Document the $option parameter; it appears to be for
- * X-Vary-Options but what format is acceptable?
+ * @param string[]|null $option Options for X-Vary-Options. Possible options are:
+ * - "string-contains=$XXX" varies on whether the header value as a string
+ * contains $XXX as a substring.
+ * - "list-contains=$XXX" varies on whether the header value as a
+ * comma-separated list contains $XXX as one of the list items.
*/
- public function addVaryHeader( $header, $option = null ) {
+ public function addVaryHeader( $header, array $option = null ) {
if ( !array_key_exists( $header, $this->mVaryHeader ) ) {
- $this->mVaryHeader[$header] = (array)$option;
- } elseif ( is_array( $option ) ) {
- if ( is_array( $this->mVaryHeader[$header] ) ) {
- $this->mVaryHeader[$header] = array_merge( $this->mVaryHeader[$header], $option );
- } else {
- $this->mVaryHeader[$header] = $option;
- }
+ $this->mVaryHeader[$header] = array();
}
- $this->mVaryHeader[$header] = array_unique( (array)$this->mVaryHeader[$header] );
+ if ( !is_array( $option ) ) {
+ $option = array();
+ }
+ $this->mVaryHeader[$header] = array_unique( array_merge( $this->mVaryHeader[$header], $option ) );
}
/**
@@ -2210,8 +2240,7 @@ class OutputPage extends ContextSource {
if ( Hooks::run( "BeforePageRedirect", array( $this, &$redirect, &$code ) ) ) {
if ( $code == '301' || $code == '303' ) {
if ( !$config->get( 'DebugRedirects' ) ) {
- $message = HttpStatus::getMessage( $code );
- $response->header( "HTTP/1.1 $code $message" );
+ $response->statusHeader( $code );
}
$this->mLastModified = wfTimestamp( TS_RFC2822 );
}
@@ -2233,10 +2262,7 @@ class OutputPage extends ContextSource {
return;
} elseif ( $this->mStatusCode ) {
- $message = HttpStatus::getMessage( $this->mStatusCode );
- if ( $message ) {
- $response->header( 'HTTP/1.1 ' . $this->mStatusCode . ' ' . $message );
- }
+ $response->statusHeader( $this->mStatusCode );
}
# Buffer output; final headers may depend on later processing
@@ -2258,14 +2284,14 @@ class OutputPage extends ContextSource {
if ( $this->mArticleBodyOnly ) {
echo $this->mBodytext;
} else {
-
$sk = $this->getSkin();
// add skin specific modules
$modules = $sk->getDefaultModules();
- // enforce various default modules for all skins
+ // Enforce various default modules for all skins
$coreModules = array(
- // keep this list as small as possible
+ // Keep this list as small as possible
+ 'site',
'mediawiki.page.startup',
'mediawiki.user',
);
@@ -2672,16 +2698,14 @@ class OutputPage extends ContextSource {
}
$ret .= Html::element( 'title', null, $this->getHTMLTitle() ) . "\n";
+ $ret .= $this->getInlineHeadScripts() . "\n";
+ $ret .= $this->buildCssLinks() . "\n";
+ $ret .= $this->getExternalHeadScripts() . "\n";
foreach ( $this->getHeadLinksArray() as $item ) {
$ret .= $item . "\n";
}
- // No newline after buildCssLinks since makeResourceLoaderLink did that already
- $ret .= $this->buildCssLinks();
-
- $ret .= $this->getHeadScripts() . "\n";
-
foreach ( $this->mHeadItems as $item ) {
$ret .= $item . "\n";
}
@@ -2729,29 +2753,31 @@ class OutputPage extends ContextSource {
*/
public function getResourceLoader() {
if ( is_null( $this->mResourceLoader ) ) {
- $this->mResourceLoader = new ResourceLoader( $this->getConfig() );
+ $this->mResourceLoader = new ResourceLoader(
+ $this->getConfig(),
+ LoggerFactory::getInstance( 'resourceloader' )
+ );
}
return $this->mResourceLoader;
}
/**
- * @todo Document
+ * Construct neccecary html and loader preset states to load modules on a page.
+ *
+ * Use getHtmlFromLoaderLinks() to convert this array to HTML.
+ *
* @param array|string $modules One or more module names
* @param string $only ResourceLoaderModule TYPE_ class constant
- * @param bool $useESI
- * @param array $extraQuery Array with extra query parameters to add to each
- * request. array( param => value ).
- * @param bool $loadCall If true, output an (asynchronous) mw.loader.load()
- * call rather than a "<script src='...'>" tag.
- * @return string The html "<script>", "<link>" and "<style>" tags
- */
- public function makeResourceLoaderLink( $modules, $only, $useESI = false,
- array $extraQuery = array(), $loadCall = false
- ) {
+ * @param array $extraQuery [optional] Array with extra query parameters for the request
+ * @return array A list of HTML strings and array of client loader preset states
+ */
+ public function makeResourceLoaderLink( $modules, $only, array $extraQuery = array() ) {
$modules = (array)$modules;
$links = array(
- 'html' => '',
+ // List of html strings
+ 'html' => array(),
+ // Associative array of module names and their states
'states' => array(),
);
@@ -2768,8 +2794,8 @@ class OutputPage extends ContextSource {
if ( ResourceLoader::inDebugMode() ) {
// Recursively call us for every item
foreach ( $modules as $name ) {
- $link = $this->makeResourceLoaderLink( $name, $only, $useESI );
- $links['html'] .= $link['html'];
+ $link = $this->makeResourceLoaderLink( $name, $only, $extraQuery );
+ $links['html'] = array_merge( $links['html'], $link['html'] );
$links['states'] += $link['states'];
}
return $links;
@@ -2783,7 +2809,6 @@ class OutputPage extends ContextSource {
// Create keyed-by-source and then keyed-by-group list of module objects from modules list
$sortedModules = array();
$resourceLoader = $this->getResourceLoader();
- $resourceLoaderUseESI = $this->getConfig()->get( 'ResourceLoaderUseESI' );
foreach ( $modules as $name ) {
$module = $resourceLoader->getModule( $name );
# Check that we're allowed to include this module on this page
@@ -2849,21 +2874,18 @@ class OutputPage extends ContextSource {
// Inline private modules. These can't be loaded through load.php for security
// reasons, see bug 34907. Note that these modules should be loaded from
- // getHeadScripts() before the first loader call. Otherwise other modules can't
+ // getExternalHeadScripts() before the first loader call. Otherwise other modules can't
// properly use them as dependencies (bug 30914)
if ( $group === 'private' ) {
if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
- $links['html'] .= Html::inlineStyle(
+ $links['html'][] = Html::inlineStyle(
$resourceLoader->makeModuleResponse( $context, $grpModules )
);
} else {
- $links['html'] .= Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- $resourceLoader->makeModuleResponse( $context, $grpModules )
- )
+ $links['html'][] = ResourceLoader::makeInlineScript(
+ $resourceLoader->makeModuleResponse( $context, $grpModules )
);
}
- $links['html'] .= "\n";
continue;
}
@@ -2874,65 +2896,44 @@ class OutputPage extends ContextSource {
// and we shouldn't be putting timestamps in Squid-cached HTML
$version = null;
if ( $group === 'user' ) {
- // Get the maximum timestamp
- $timestamp = 1;
- foreach ( $grpModules as $module ) {
- $timestamp = max( $timestamp, $module->getModifiedTime( $context ) );
- }
- // Add a version parameter so cache will break when things change
- $query['version'] = wfTimestamp( TS_ISO_8601_BASIC, $timestamp );
+ $query['version'] = $resourceLoader->getCombinedVersion( $context, array_keys( $grpModules ) );
}
$query['modules'] = ResourceLoader::makePackedModulesString( array_keys( $grpModules ) );
$moduleContext = new ResourceLoaderContext( $resourceLoader, new FauxRequest( $query ) );
$url = $resourceLoader->createLoaderURL( $source, $moduleContext, $extraQuery );
- if ( $useESI && $resourceLoaderUseESI ) {
- $esi = Xml::element( 'esi:include', array( 'src' => $url ) );
- if ( $only == ResourceLoaderModule::TYPE_STYLES ) {
- $link = Html::inlineStyle( $esi );
- } else {
- $link = Html::inlineScript( $esi );
- }
+ // Automatically select style/script elements
+ if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
+ $link = Html::linkedStyle( $url );
} else {
- // Automatically select style/script elements
- if ( $only === ResourceLoaderModule::TYPE_STYLES ) {
- $link = Html::linkedStyle( $url );
- } elseif ( $loadCall ) {
- $link = Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- Xml::encodeJsCall( 'mw.loader.load', array( $url, 'text/javascript', true ) )
- )
- );
+ if ( $context->getRaw() || $isRaw ) {
+ // Startup module can't load itself, needs to use <script> instead of mw.loader.load
+ $link = Html::element( 'script', array(
+ // In SpecialJavaScriptTest, QUnit must load synchronous
+ 'async' => !isset( $extraQuery['sync'] ),
+ 'src' => $url
+ ) );
} else {
- $link = Html::linkedScript( $url );
- if ( !$context->getRaw() && !$isRaw ) {
- // Wrap only=script / only=combined requests in a conditional as
- // browsers not supported by the startup module would unconditionally
- // execute this module. Otherwise users will get "ReferenceError: mw is
- // undefined" or "jQuery is undefined" from e.g. a "site" module.
- $link = Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- Xml::encodeJsCall( 'document.write', array( $link ) )
- )
- );
- }
+ $link = ResourceLoader::makeInlineScript(
+ Xml::encodeJsCall( 'mw.loader.load', array( $url ) )
+ );
+ }
- // For modules requested directly in the html via <link> or <script>,
- // tell mw.loader they are being loading to prevent duplicate requests.
- foreach ( $grpModules as $key => $module ) {
- // Don't output state=loading for the startup module..
- if ( $key !== 'startup' ) {
- $links['states'][$key] = 'loading';
- }
+ // For modules requested directly in the html via <script> or mw.loader.load
+ // tell mw.loader they are being loading to prevent duplicate requests.
+ foreach ( $grpModules as $key => $module ) {
+ // Don't output state=loading for the startup module.
+ if ( $key !== 'startup' ) {
+ $links['states'][$key] = 'loading';
}
}
}
if ( $group == 'noscript' ) {
- $links['html'] .= Html::rawElement( 'noscript', array(), $link ) . "\n";
+ $links['html'][] = Html::rawElement( 'noscript', array(), $link );
} else {
- $links['html'] .= $link . "\n";
+ $links['html'][] = $link;
}
}
}
@@ -2946,26 +2947,26 @@ class OutputPage extends ContextSource {
* @return string HTML
*/
protected static function getHtmlFromLoaderLinks( array $links ) {
- $html = '';
+ $html = array();
$states = array();
foreach ( $links as $link ) {
if ( !is_array( $link ) ) {
- $html .= $link;
+ $html[] = $link;
} else {
- $html .= $link['html'];
+ $html = array_merge( $html, $link['html'] );
$states += $link['states'];
}
}
+ // Filter out empty values
+ $html = array_filter( $html, 'strlen' );
if ( count( $states ) ) {
- $html = Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- ResourceLoader::makeLoaderStateScript( $states )
- )
- ) . "\n" . $html;
+ array_unshift( $html, ResourceLoader::makeInlineScript(
+ ResourceLoader::makeLoaderStateScript( $states )
+ ) );
}
- return $html;
+ return WrappedString::join( "\n", $html );
}
/**
@@ -2975,127 +2976,149 @@ class OutputPage extends ContextSource {
* @return string HTML fragment
*/
function getHeadScripts() {
- // Startup - this will immediately load jquery and mediawiki modules
+ return $this->getInlineHeadScripts() . "\n" . $this->getExternalHeadScripts();
+ }
+
+ /**
+ * <script src="..."> tags for "<head>". This is the startup module
+ * and other modules marked with position 'top'.
+ *
+ * @return string HTML fragment
+ */
+ function getExternalHeadScripts() {
$links = array();
- $links[] = $this->makeResourceLoaderLink( 'startup', ResourceLoaderModule::TYPE_SCRIPTS, true );
- // Load config before anything else
+ // Startup - this provides the client with the module manifest and loads jquery and mediawiki base modules
+ $links[] = $this->makeResourceLoaderLink( 'startup', ResourceLoaderModule::TYPE_SCRIPTS );
+
+ return self::getHtmlFromLoaderLinks( $links );
+ }
+
+ /**
+ * <script>...</script> tags to put in "<head>".
+ *
+ * @return string HTML fragment
+ */
+ function getInlineHeadScripts() {
+ $links = array();
+
+ // Client profile classes for <html>. Allows for easy hiding/showing of UI components.
+ // Must be done synchronously on every page to avoid flashes of wrong content.
+ // Note: This class distinguishes MediaWiki-supported JavaScript from the rest.
+ // The "rest" includes browsers that support JavaScript but not supported by our runtime.
+ // For the performance benefit of the majority, this is added unconditionally here and is
+ // then fixed up by the startup module for unsupported browsers.
$links[] = Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- ResourceLoader::makeConfigSetScript( $this->getJSVars() )
- )
+ 'document.documentElement.className = document.documentElement.className'
+ . '.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );'
+ );
+
+ // Load config before anything else
+ $links[] = ResourceLoader::makeInlineScript(
+ ResourceLoader::makeConfigSetScript( $this->getJSVars() )
);
// Load embeddable private modules before any loader links
// This needs to be TYPE_COMBINED so these modules are properly wrapped
// in mw.loader.implement() calls and deferred until mw.user is available
- $embedScripts = array( 'user.options', 'user.tokens' );
+ $embedScripts = array( 'user.options' );
$links[] = $this->makeResourceLoaderLink( $embedScripts, ResourceLoaderModule::TYPE_COMBINED );
-
- // Scripts and messages "only" requests marked for top inclusion
- // Messages should go first
- $links[] = $this->makeResourceLoaderLink(
- $this->getModuleMessages( true, 'top' ),
- ResourceLoaderModule::TYPE_MESSAGES
- );
- $links[] = $this->makeResourceLoaderLink(
- $this->getModuleScripts( true, 'top' ),
- ResourceLoaderModule::TYPE_SCRIPTS
- );
+ // Separate user.tokens as otherwise caching will be allowed (T84960)
+ $links[] = $this->makeResourceLoaderLink( 'user.tokens', ResourceLoaderModule::TYPE_COMBINED );
// Modules requests - let the client calculate dependencies and batch requests as it likes
// Only load modules that have marked themselves for loading at the top
$modules = $this->getModules( true, 'top' );
if ( $modules ) {
- $links[] = Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- Xml::encodeJsCall( 'mw.loader.load', array( $modules ) )
- )
+ $links[] = ResourceLoader::makeInlineScript(
+ Xml::encodeJsCall( 'mw.loader.load', array( $modules ) )
);
}
- if ( $this->getConfig()->get( 'ResourceLoaderExperimentalAsyncLoading' ) ) {
- $links[] = $this->getScriptsForBottomQueue( true );
- }
+ // "Scripts only" modules marked for top inclusion
+ $links[] = $this->makeResourceLoaderLink(
+ $this->getModuleScripts( true, 'top' ),
+ ResourceLoaderModule::TYPE_SCRIPTS
+ );
return self::getHtmlFromLoaderLinks( $links );
}
/**
- * JS stuff to put at the 'bottom', which can either be the bottom of the
- * "<body>" or the bottom of the "<head>" depending on
- * $wgResourceLoaderExperimentalAsyncLoading: modules marked with position
- * 'bottom', legacy scripts ($this->mScripts), user preferences, site JS
- * and user JS.
+ * JS stuff to put at the 'bottom', which goes at the bottom of the `<body>`.
+ * These are modules marked with position 'bottom', legacy scripts ($this->mScripts),
+ * site JS, and user JS.
*
- * @param bool $inHead If true, this HTML goes into the "<head>",
- * if false it goes into the "<body>".
+ * @param bool $unused Previously used to let this method change its output based
+ * on whether it was called by getExternalHeadScripts() or getBottomScripts().
* @return string
*/
- function getScriptsForBottomQueue( $inHead ) {
- // Scripts and messages "only" requests marked for bottom inclusion
+ function getScriptsForBottomQueue( $unused = null ) {
+ // Scripts "only" requests marked for bottom inclusion
// If we're in the <head>, use load() calls rather than <script src="..."> tags
- // Messages should go first
$links = array();
- $links[] = $this->makeResourceLoaderLink( $this->getModuleMessages( true, 'bottom' ),
- ResourceLoaderModule::TYPE_MESSAGES, /* $useESI = */ false, /* $extraQuery = */ array(),
- /* $loadCall = */ $inHead
- );
+
$links[] = $this->makeResourceLoaderLink( $this->getModuleScripts( true, 'bottom' ),
- ResourceLoaderModule::TYPE_SCRIPTS, /* $useESI = */ false, /* $extraQuery = */ array(),
- /* $loadCall = */ $inHead
+ ResourceLoaderModule::TYPE_SCRIPTS
+ );
+
+ $links[] = $this->makeResourceLoaderLink( $this->getModuleStyles( true, 'bottom' ),
+ ResourceLoaderModule::TYPE_STYLES
);
// Modules requests - let the client calculate dependencies and batch requests as it likes
// Only load modules that have marked themselves for loading at the bottom
$modules = $this->getModules( true, 'bottom' );
if ( $modules ) {
- $links[] = Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- Xml::encodeJsCall( 'mw.loader.load', array( $modules, null, true ) )
- )
+ $links[] = ResourceLoader::makeInlineScript(
+ Xml::encodeJsCall( 'mw.loader.load', array( $modules ) )
);
}
// Legacy Scripts
- $links[] = "\n" . $this->mScripts;
-
- // Add site JS if enabled
- $links[] = $this->makeResourceLoaderLink( 'site', ResourceLoaderModule::TYPE_SCRIPTS,
- /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
- );
+ $links[] = $this->mScripts;
// Add user JS if enabled
+ // This must use TYPE_COMBINED instead of only=scripts so that its request is handled by
+ // mw.loader.implement() which ensures that execution is scheduled after the "site" module.
if ( $this->getConfig()->get( 'AllowUserJs' )
&& $this->getUser()->isLoggedIn()
&& $this->getTitle()
&& $this->getTitle()->isJsSubpage()
&& $this->userCanPreview()
) {
- # XXX: additional security check/prompt?
- // We're on a preview of a JS subpage
- // Exclude this page from the user module in case it's in there (bug 26283)
- $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS, false,
- array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() ), $inHead
+ // We're on a preview of a JS subpage. Exclude this page from the user module (T28283)
+ // and include the draft contents as a raw script instead.
+ $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED,
+ array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() )
);
// Load the previewed JS
- $links[] = Html::inlineScript( "\n"
- . $this->getRequest()->getText( 'wpTextbox1' ) . "\n" ) . "\n";
+ $links[] = ResourceLoader::makeInlineScript(
+ Xml::encodeJsCall( 'mw.loader.using', array(
+ array( 'user', 'site' ),
+ new XmlJsCode(
+ 'function () {'
+ . Xml::encodeJsCall( '$.globalEval', array(
+ $this->getRequest()->getText( 'wpTextbox1' )
+ ) )
+ . '}'
+ )
+ ) )
+ );
// FIXME: If the user is previewing, say, ./vector.js, his ./common.js will be loaded
// asynchronously and may arrive *after* the inline script here. So the previewed code
- // may execute before ./common.js runs. Normally, ./common.js runs before ./vector.js...
+ // may execute before ./common.js runs. Normally, ./common.js runs before ./vector.js.
+ // Similarly, when previewing ./common.js and the user module does arrive first, it will
+ // arrive without common.js and the inline script runs after. Thus running common after
+ // the excluded subpage.
} else {
// Include the user module normally, i.e., raw to avoid it being wrapped in a closure.
- $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_SCRIPTS,
- /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
- );
+ $links[] = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_COMBINED );
}
// Group JS is only enabled if site JS is enabled.
- $links[] = $this->makeResourceLoaderLink( 'user.groups', ResourceLoaderModule::TYPE_COMBINED,
- /* $useESI = */ false, /* $extraQuery = */ array(), /* $loadCall = */ $inHead
- );
+ $links[] = $this->makeResourceLoaderLink( 'user.groups', ResourceLoaderModule::TYPE_COMBINED );
return self::getHtmlFromLoaderLinks( $links );
}
@@ -3105,17 +3128,10 @@ class OutputPage extends ContextSource {
* @return string
*/
function getBottomScripts() {
- // Optimise jQuery ready event cross-browser.
- // This also enforces $.isReady to be true at </body> which fixes the
- // mw.loader bug in Firefox with using document.write between </body>
- // and the DOMContentReady event (bug 47457).
- $html = Html::inlineScript( 'if(window.jQuery)jQuery.ready();' );
-
- if ( !$this->getConfig()->get( 'ResourceLoaderExperimentalAsyncLoading' ) ) {
- $html .= $this->getScriptsForBottomQueue( false );
- }
+ // In case the skin wants to add bottom CSS
+ $this->getSkin()->setupSkinUserCss( $this );
- return $html;
+ return $this->getScriptsForBottomQueue();
}
/**
@@ -3426,33 +3442,37 @@ class OutputPage extends ContextSource {
$lang = $this->getTitle()->getPageLanguage();
if ( $lang->hasVariants() ) {
$variants = $lang->getVariants();
- foreach ( $variants as $_v ) {
- $tags["variant-$_v"] = Html::element( 'link', array(
+ foreach ( $variants as $variant ) {
+ $tags["variant-$variant"] = Html::element( 'link', array(
'rel' => 'alternate',
- 'hreflang' => wfBCP47( $_v ),
- 'href' => $this->getTitle()->getLocalURL( array( 'variant' => $_v ) ) )
+ 'hreflang' => wfBCP47( $variant ),
+ 'href' => $this->getTitle()->getLocalURL( array( 'variant' => $variant ) ) )
);
}
+ # x-default link per https://support.google.com/webmasters/answer/189077?hl=en
+ $tags["variant-x-default"] = Html::element( 'link', array(
+ 'rel' => 'alternate',
+ 'hreflang' => 'x-default',
+ 'href' => $this->getTitle()->getLocalURL() ) );
}
- # x-default link per https://support.google.com/webmasters/answer/189077?hl=en
- $tags["variant-x-default"] = Html::element( 'link', array(
- 'rel' => 'alternate',
- 'hreflang' => 'x-default',
- 'href' => $this->getTitle()->getLocalURL() ) );
}
# Copyright
- $copyright = '';
- if ( $config->get( 'RightsPage' ) ) {
- $copy = Title::newFromText( $config->get( 'RightsPage' ) );
+ if ( $this->copyrightUrl !== null ) {
+ $copyright = $this->copyrightUrl;
+ } else {
+ $copyright = '';
+ if ( $config->get( 'RightsPage' ) ) {
+ $copy = Title::newFromText( $config->get( 'RightsPage' ) );
- if ( $copy ) {
- $copyright = $copy->getLocalURL();
+ if ( $copy ) {
+ $copyright = $copy->getLocalURL();
+ }
}
- }
- if ( !$copyright && $config->get( 'RightsUrl' ) ) {
- $copyright = $config->get( 'RightsUrl' );
+ if ( !$copyright && $config->get( 'RightsUrl' ) ) {
+ $copyright = $config->get( 'RightsUrl' );
+ }
}
if ( $copyright ) {
@@ -3513,8 +3533,25 @@ class OutputPage extends ContextSource {
if ( $canonicalUrl !== false ) {
$canonicalUrl = wfExpandUrl( $canonicalUrl, PROTO_CANONICAL );
} else {
- $reqUrl = $this->getRequest()->getRequestURL();
- $canonicalUrl = wfExpandUrl( $reqUrl, PROTO_CANONICAL );
+ if ( $this->isArticleRelated() ) {
+ // This affects all requests where "setArticleRelated" is true. This is
+ // typically all requests that show content (query title, curid, oldid, diff),
+ // and all wikipage actions (edit, delete, purge, info, history etc.).
+ // It does not apply to File pages and Special pages.
+ // 'history' and 'info' actions address page metadata rather than the page
+ // content itself, so they may not be canonicalized to the view page url.
+ // TODO: this ought to be better encapsulated in the Action class.
+ $action = Action::getActionName( $this->getContext() );
+ if ( in_array( $action, array( 'history', 'info' ) ) ) {
+ $query = "action={$action}";
+ } else {
+ $query = '';
+ }
+ $canonicalUrl = $this->getTitle()->getCanonicalURL( $query );
+ } else {
+ $reqUrl = $this->getRequest()->getRequestURL();
+ $canonicalUrl = wfExpandUrl( $reqUrl, PROTO_CANONICAL );
+ }
}
}
if ( $canonicalUrl !== false ) {
@@ -3613,10 +3650,10 @@ class OutputPage extends ContextSource {
'noscript' => array()
);
$links = array();
- $otherTags = ''; // Tags to append after the normal <link> tags
+ $otherTags = array(); // Tags to append after the normal <link> tags
$resourceLoader = $this->getResourceLoader();
- $moduleStyles = $this->getModuleStyles();
+ $moduleStyles = $this->getModuleStyles( true, 'top' );
// Per-site custom styles
$moduleStyles[] = 'site';
@@ -3629,10 +3666,10 @@ class OutputPage extends ContextSource {
) {
// We're on a preview of a CSS subpage
// Exclude this page from the user module in case it's in there (bug 26283)
- $link = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_STYLES, false,
+ $link = $this->makeResourceLoaderLink( 'user', ResourceLoaderModule::TYPE_STYLES,
array( 'excludepage' => $this->getTitle()->getPrefixedDBkey() )
);
- $otherTags .= $link['html'];
+ $otherTags = array_merge( $otherTags, $link['html'] );
// Load the previewed CSS
// If needed, Janus it first. This is user-supplied CSS, so it's
@@ -3641,7 +3678,7 @@ class OutputPage extends ContextSource {
if ( $this->getLanguage()->getDir() !== $wgContLang->getDir() ) {
$previewedCSS = CSSJanus::transform( $previewedCSS, true, false );
}
- $otherTags .= Html::inlineStyle( $previewedCSS ) . "\n";
+ $otherTags[] = Html::inlineStyle( $previewedCSS ) . "\n";
} else {
// Load the user styles normally
$moduleStyles[] = 'user';
@@ -3655,9 +3692,17 @@ class OutputPage extends ContextSource {
if ( !$module ) {
continue;
}
+ if ( $name === 'site' ) {
+ // HACK: The site module shouldn't be fragmented with a cache group and
+ // http request. But in order to ensure its styles are separated and after the
+ // ResourceLoaderDynamicStyles marker, pretend it is in a group called 'site'.
+ // The scripts remain ungrouped and rides the bottom queue.
+ $styles['site'][] = $name;
+ continue;
+ }
$group = $module->getGroup();
- // Modules in groups different than the ones listed on top (see $styles assignment)
- // will be placed in the "other" group
+ // Modules in groups other than the ones needing special treatment (see $styles assignment)
+ // will be placed in the "other" style category.
$styles[isset( $styles[$group] ) ? $group : 'other'][] = $name;
}
@@ -3674,9 +3719,9 @@ class OutputPage extends ContextSource {
$links[] = Html::element(
'meta',
array( 'name' => 'ResourceLoaderDynamicStyles', 'content' => '' )
- ) . "\n";
+ );
- // Add site, private and user styles
+ // Add site-specific and user-specific styles
// 'private' at present only contains user.options, so put that before 'user'
// Any future private modules will likely have a similar user-specific character
foreach ( array( 'site', 'noscript', 'private', 'user' ) as $group ) {
@@ -3686,7 +3731,7 @@ class OutputPage extends ContextSource {
}
// Add stuff in $otherTags (previewed user CSS if applicable)
- return self::getHtmlFromLoaderLinks( $links ) . $otherTags;
+ return self::getHtmlFromLoaderLinks( $links ) . implode( '', $otherTags );
}
/**
@@ -3918,14 +3963,40 @@ class OutputPage extends ContextSource {
}
/**
+ * Helper function to setup the PHP implementation of OOUI to use in this request.
+ *
+ * @since 1.26
+ * @param String $skinName The Skin name to determine the correct OOUI theme
+ * @param String $dir Language direction
+ */
+ public static function setupOOUI( $skinName = '', $dir = 'ltr' ) {
+ $themes = ExtensionRegistry::getInstance()->getAttribute( 'SkinOOUIThemes' );
+ // Make keys (skin names) lowercase for case-insensitive matching.
+ $themes = array_change_key_case( $themes, CASE_LOWER );
+ $theme = isset( $themes[ $skinName ] ) ? $themes[ $skinName ] : 'MediaWiki';
+ // For example, 'OOUI\MediaWikiTheme'.
+ $themeClass = "OOUI\\{$theme}Theme";
+ OOUI\Theme::setSingleton( new $themeClass() );
+ OOUI\Element::setDefaultDir( $dir );
+ }
+
+ /**
* Add ResourceLoader module styles for OOUI and set up the PHP implementation of it for use with
* MediaWiki and this OutputPage instance.
*
* @since 1.25
*/
public function enableOOUI() {
- OOUI\Theme::setSingleton( new OOUI\MediaWikiTheme() );
- OOUI\Element::setDefaultDir( $this->getLanguage()->getDir() );
- $this->addModuleStyles( 'oojs-ui.styles' );
+ self::setupOOUI(
+ strtolower( $this->getSkin()->getSkinName() ),
+ $this->getLanguage()->getDir()
+ );
+ $this->addModuleStyles( array(
+ 'oojs-ui.styles',
+ 'oojs-ui.styles.icons',
+ 'oojs-ui.styles.indicators',
+ 'oojs-ui.styles.textures',
+ 'mediawiki.widgets.styles',
+ ) );
}
}
diff --git a/includes/PHPVersionCheck.php b/includes/PHPVersionCheck.php
index eee9aa9c..ba3ff1ab 100644
--- a/includes/PHPVersionCheck.php
+++ b/includes/PHPVersionCheck.php
@@ -25,13 +25,23 @@
/**
* Check php version and that external dependencies are installed, and
* display an informative error if either condition is not satisfied.
+ *
+ * @note Since we can't rely on anything, the minimum PHP versions and MW current
+ * version are hardcoded here
*/
function wfEntryPointCheck( $entryPoint ) {
+ $mwVersion = '1.26';
+ $minimumVersionPHP = '5.3.3';
+ $phpVersion = PHP_VERSION;
+
if ( !function_exists( 'version_compare' )
- || version_compare( PHP_VERSION, '5.3.3' ) < 0
- || !file_exists( dirname( __FILE__ ) . '/../vendor/autoload.php' )
+ || version_compare( $phpVersion, $minimumVersionPHP ) < 0
) {
- wfPHPVersionError( $entryPoint );
+ wfPHPVersionError( $entryPoint, $mwVersion, $minimumVersionPHP, $phpVersion );
+ }
+
+ if ( !file_exists( dirname( __FILE__ ) . '/../vendor/autoload.php' ) ) {
+ wfMissingVendorError( $entryPoint, $mwVersion );
}
}
@@ -49,47 +59,39 @@ function wfEntryPointCheck( $entryPoint ) {
* - api.php
* - mw-config/index.php
* - cli
- *
- * @note Since we can't rely on anything, the minimum PHP versions and MW current
- * version are hardcoded here
+ * @param string $mwVersion The number of the MediaWiki version used
+ * @param string $title HTML code to be put within an <h2> tag
+ * @param string $shortText
+ * @param string $longText
+ * @param string $longHtml
*/
-function wfPHPVersionError( $type ) {
- $mwVersion = '1.25';
- $minimumVersionPHP = '5.3.3';
-
- $phpVersion = PHP_VERSION;
+function wfGenericError( $type, $mwVersion, $title, $shortText, $longText, $longHtml ) {
$protocol = isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';
- $message = "MediaWiki $mwVersion requires at least "
- . "PHP version $minimumVersionPHP, you are using PHP $phpVersion. Installing some "
- . " external dependencies (e.g. via composer) is also required.";
if ( $type == 'cli' ) {
- $finalOutput = "Error: You are missing some external dependencies or are using on older PHP version. \n"
- . "MediaWiki $mwVersion needs PHP $minimumVersionPHP or higher.\n\n"
- . "Check if you have a newer php executable with a different name, such as php5.\n\n"
- . "MediaWiki now also has some external dependencies that need to be installed\n"
- . "via composer or from a separate git repo. Please see\n"
- . "https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries\n"
- . "for help on installing the required components.";
- } elseif ( $type == 'index.php' || $type == 'mw-config/index.php' ) {
- $pathinfo = pathinfo( $_SERVER['SCRIPT_NAME'] );
- if ( $type == 'mw-config/index.php' ) {
- $dirname = dirname( $pathinfo['dirname'] );
- } else {
- $dirname = $pathinfo['dirname'];
- }
- $encLogo = htmlspecialchars(
- str_replace( '//', '/', $dirname . '/' ) .
- 'resources/assets/mediawiki.png'
- );
-
+ $finalOutput = $longText;
+ } else {
header( "$protocol 500 MediaWiki configuration Error" );
- header( 'Content-type: text/html; charset=UTF-8' );
// Don't cache error pages! They cause no end of trouble...
header( 'Cache-control: none' );
header( 'Pragma: no-cache' );
- $finalOutput = <<<HTML
+ if ( $type == 'index.php' || $type == 'mw-config/index.php' ) {
+ $pathinfo = pathinfo( $_SERVER['SCRIPT_NAME'] );
+ if ( $type == 'mw-config/index.php' ) {
+ $dirname = dirname( $pathinfo['dirname'] );
+ } else {
+ $dirname = $pathinfo['dirname'];
+ }
+ $encLogo = htmlspecialchars(
+ str_replace( '//', '/', $dirname . '/' ) .
+ 'resources/assets/mediawiki.png'
+ );
+ $shortHtml = htmlspecialchars( $shortText );
+
+ header( 'Content-type: text/html; charset=UTF-8' );
+
+ $finalOutput = <<<HTML
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
@@ -120,10 +122,43 @@ function wfPHPVersionError( $type ) {
<h1>MediaWiki {$mwVersion} internal error</h1>
<div class='error'>
<p>
- {$message}
+ {$shortHtml}
</p>
- <h2>Supported PHP versions</h2>
+ <h2>{$title}</h2>
<p>
+ {$longHtml}
+ </p>
+ </div>
+ </body>
+</html>
+HTML;
+ // Handle everything that's not index.php
+ } else {
+ // So nothing thinks this is JS or CSS
+ $finalOutput = ( $type == 'load.php' ) ? "/* $shortText */" : $shortText;
+ }
+ }
+ echo "$finalOutput\n";
+ die( 1 );
+}
+
+/**
+ * Display an error for the minimum PHP version requirement not being satisfied.
+ *
+ * @param string $type See wfGenericError
+ * @param string $mwVersion See wfGenericError
+ * @param string $minimumVersionPHP The minimum PHP version supported by MediaWiki
+ * @param string $phpVersion The current PHP version
+ */
+function wfPHPVersionError( $type, $mwVersion, $minimumVersionPHP, $phpVersion ) {
+ $shortText = "MediaWiki $mwVersion requires at least "
+ . "PHP version $minimumVersionPHP, you are using PHP $phpVersion.";
+
+ $longText = "Error: You might be using on older PHP version. \n"
+ . "MediaWiki $mwVersion needs PHP $minimumVersionPHP or higher.\n\n"
+ . "Check if you have a newer php executable with a different name, such as php5.\n\n";
+
+ $longHtml = <<<HTML
Please consider <a href="http://www.php.net/downloads.php">upgrading your copy of PHP</a>.
PHP versions less than 5.3.0 are no longer supported by the PHP Group and will not receive
security or bugfix updates.
@@ -134,24 +169,31 @@ function wfPHPVersionError( $type ) {
of MediaWiki from our website. 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 PHP.
- </p>
- <h2>External dependencies</h2>
- <p>
+HTML;
+ wfGenericError( $type, $mwVersion, 'Supported PHP versions', $shortText, $longText, $longHtml );
+}
+
+/**
+ * Display an error for the vendor/autoload.php file not being found.
+ *
+ * @param string $type See wfGenericError
+ * @param string $mwVersion See wfGenericError
+ */
+function wfMissingVendorError( $type, $mwVersion ) {
+ $shortText = "Installing some external dependencies (e.g. via composer) is required.";
+
+ $longText = "Error: You are missing some external dependencies. \n"
+ . "MediaWiki now also has some external dependencies that need to be installed\n"
+ . "via composer or from a separate git repo. Please see\n"
+ . "https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries\n"
+ . "for help on installing the required components.";
+
+ $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.
- </p>
- </div>
- </body>
-</html>
HTML;
- // Handle everything that's not index.php
- } else {
- // So nothing thinks this is JS or CSS
- $finalOutput = ( $type == 'load.php' ) ? "/* $message */" : $message;
- header( "$protocol 500 MediaWiki configuration Error" );
- }
- echo "$finalOutput\n";
- die( 1 );
+
+ wfGenericError( $type, $mwVersion, 'External dependencies', $shortText, $longText, $longHtml );
}
diff --git a/includes/Preferences.php b/includes/Preferences.php
index a5239331..d0475c17 100644
--- a/includes/Preferences.php
+++ b/includes/Preferences.php
@@ -124,6 +124,7 @@ class Preferences {
$disable = !$user->isAllowed( 'editmyoptions' );
+ $defaultOptions = User::getDefaultOptions();
## Prod in defaults from the user
foreach ( $defaultPreferences as $name => &$info ) {
$prefFromUser = self::getOptionFromUser( $name, $info, $user );
@@ -131,7 +132,6 @@ class Preferences {
$info['disabled'] = 'disabled';
}
$field = HTMLForm::loadInputFromParameters( $name, $info, $dummyForm ); // For validation
- $defaultOptions = User::getDefaultOptions();
$globalDefault = isset( $defaultOptions[$name] )
? $defaultOptions[$name]
: null;
@@ -657,8 +657,9 @@ class Preferences {
$now = wfTimestampNow();
$lang = $context->getLanguage();
$nowlocal = Xml::element( 'span', array( 'id' => 'wpLocalTime' ),
- $lang->time( $now, true ) );
- $nowserver = $lang->time( $now, false ) .
+ $lang->userTime( $now, $user ) );
+ $nowserver = $lang->userTime( $now, $user,
+ array( 'format' => false, 'timecorrection' => false ) ) .
Html::hidden( 'wpServerTime', (int)substr( $now, 8, 2 ) * 60 + (int)substr( $now, 10, 2 ) );
$defaultPreferences['nowserver'] = array(
@@ -750,7 +751,11 @@ class Preferences {
'type' => 'select',
'section' => 'rendering/advancedrendering',
'options' => $stubThresholdOptions,
- 'label-raw' => $context->msg( 'stub-threshold' )->text(), // Raw HTML message. Yay?
+ // This is not a raw HTML message; label-raw is needed for the manual <a></a>
+ 'label-raw' => $context->msg( 'stub-threshold' )->rawParams(
+ '<a href="#" class="stub">' .
+ $context->msg( 'stub-threshold-sample-link' )->parse() .
+ '</a>' )->parse(),
);
$defaultPreferences['showhiddencats'] = array(
@@ -1293,12 +1298,19 @@ class Preferences {
$opt = array();
$localTZoffset = $context->getConfig()->get( 'LocalTZoffset' );
+ $timeZoneList = self::getTimeZoneList( $context->getLanguage() );
+
$timestamp = MWTimestamp::getLocalInstance();
// Check that the LocalTZoffset is the same as the local time zone offset
if ( $localTZoffset == $timestamp->format( 'Z' ) / 60 ) {
+ $timezoneName = $timestamp->getTimezone()->getName();
+ // Localize timezone
+ if ( isset( $timeZoneList[$timezoneName] ) ) {
+ $timezoneName = $timeZoneList[$timezoneName]['name'];
+ }
$server_tz_msg = $context->msg(
'timezoneuseserverdefault',
- $timestamp->getTimezone()->getName()
+ $timezoneName
)->text();
} else {
$tzstring = sprintf(
@@ -1312,49 +1324,12 @@ class Preferences {
$opt[$context->msg( 'timezoneuseoffset' )->text()] = 'other';
$opt[$context->msg( 'guesstimezone' )->text()] = 'guess';
- if ( function_exists( 'timezone_identifiers_list' ) ) {
- # Read timezone list
- $tzs = timezone_identifiers_list();
- sort( $tzs );
-
- $tzRegions = array();
- $tzRegions['Africa'] = $context->msg( 'timezoneregion-africa' )->text();
- $tzRegions['America'] = $context->msg( 'timezoneregion-america' )->text();
- $tzRegions['Antarctica'] = $context->msg( 'timezoneregion-antarctica' )->text();
- $tzRegions['Arctic'] = $context->msg( 'timezoneregion-arctic' )->text();
- $tzRegions['Asia'] = $context->msg( 'timezoneregion-asia' )->text();
- $tzRegions['Atlantic'] = $context->msg( 'timezoneregion-atlantic' )->text();
- $tzRegions['Australia'] = $context->msg( 'timezoneregion-australia' )->text();
- $tzRegions['Europe'] = $context->msg( 'timezoneregion-europe' )->text();
- $tzRegions['Indian'] = $context->msg( 'timezoneregion-indian' )->text();
- $tzRegions['Pacific'] = $context->msg( 'timezoneregion-pacific' )->text();
- asort( $tzRegions );
-
- $prefill = array_fill_keys( array_values( $tzRegions ), array() );
- $opt = array_merge( $opt, $prefill );
-
- $now = date_create( 'now' );
-
- foreach ( $tzs as $tz ) {
- $z = explode( '/', $tz, 2 );
-
- # timezone_identifiers_list() returns a number of
- # backwards-compatibility entries. This filters them out of the
- # list presented to the user.
- if ( count( $z ) != 2 || !array_key_exists( $z[0], $tzRegions ) ) {
- continue;
- }
-
- # Localize region
- $z[0] = $tzRegions[$z[0]];
-
- $minDiff = floor( timezone_offset_get( timezone_open( $tz ), $now ) / 60 );
-
- $display = str_replace( '_', ' ', $z[0] . '/' . $z[1] );
- $value = "ZoneInfo|$minDiff|$tz";
-
- $opt[$z[0]][$display] = $value;
+ foreach ( $timeZoneList as $timeZoneInfo ) {
+ $region = $timeZoneInfo['region'];
+ if ( !isset( $opt[$region] ) ) {
+ $opt[$region] = array();
}
+ $opt[$region][$timeZoneInfo['name']] = $timeZoneInfo['timecorrection'];
}
return $opt;
}
@@ -1393,7 +1368,7 @@ class Preferences {
}
# Max is +14:00 and min is -12:00, see:
- # http://en.wikipedia.org/wiki/Timezone
+ # https://en.wikipedia.org/wiki/Timezone
$minDiff = min( $minDiff, 840 ); # 14:00
$minDiff = max( $minDiff, - 720 ); # -12:00
return 'Offset|' . $minDiff;
@@ -1458,10 +1433,10 @@ class Preferences {
}
Hooks::run( 'PreferencesFormPreSave', array( $formData, $form, $user, &$result ) );
- $user->saveSettings();
}
$wgAuth->updateExternalDB( $user );
+ $user->saveSettings();
return $result;
}
@@ -1490,6 +1465,68 @@ class Preferences {
return Status::newGood();
}
+
+ /**
+ * Get a list of all time zones
+ * @param Language $language Language used for the localized names
+ * @return array A list of all time zones. The system name of the time zone is used as key and
+ * the value is an array which contains localized name, the timecorrection value used for
+ * preferences and the region
+ * @since 1.26
+ */
+ public static function getTimeZoneList( Language $language ) {
+ $identifiers = DateTimeZone::listIdentifiers();
+ if ( $identifiers === false ) {
+ return array();
+ }
+ sort( $identifiers );
+
+ $tzRegions = array(
+ 'Africa' => wfMessage( 'timezoneregion-africa' )->inLanguage( $language )->text(),
+ 'America' => wfMessage( 'timezoneregion-america' )->inLanguage( $language )->text(),
+ 'Antarctica' => wfMessage( 'timezoneregion-antarctica' )->inLanguage( $language )->text(),
+ 'Arctic' => wfMessage( 'timezoneregion-arctic' )->inLanguage( $language )->text(),
+ 'Asia' => wfMessage( 'timezoneregion-asia' )->inLanguage( $language )->text(),
+ 'Atlantic' => wfMessage( 'timezoneregion-atlantic' )->inLanguage( $language )->text(),
+ 'Australia' => wfMessage( 'timezoneregion-australia' )->inLanguage( $language )->text(),
+ 'Europe' => wfMessage( 'timezoneregion-europe' )->inLanguage( $language )->text(),
+ 'Indian' => wfMessage( 'timezoneregion-indian' )->inLanguage( $language )->text(),
+ 'Pacific' => wfMessage( 'timezoneregion-pacific' )->inLanguage( $language )->text(),
+ );
+ asort( $tzRegions );
+
+ $timeZoneList = array();
+
+ $now = new DateTime();
+
+ foreach ( $identifiers as $identifier ) {
+ $parts = explode( '/', $identifier, 2 );
+
+ // DateTimeZone::listIdentifiers() returns a number of
+ // backwards-compatibility entries. This filters them out of the
+ // list presented to the user.
+ if ( count( $parts ) !== 2 || !array_key_exists( $parts[0], $tzRegions ) ) {
+ continue;
+ }
+
+ // Localize region
+ $parts[0] = $tzRegions[$parts[0]];
+
+ $dateTimeZone = new DateTimeZone( $identifier );
+ $minDiff = floor( $dateTimeZone->getOffset( $now ) / 60 );
+
+ $display = str_replace( '_', ' ', $parts[0] . '/' . $parts[1] );
+ $value = "ZoneInfo|$minDiff|$identifier";
+
+ $timeZoneList[$identifier] = array(
+ 'name' => $display,
+ 'timecorrection' => $value,
+ 'region' => $parts[0],
+ );
+ }
+
+ return $timeZoneList;
+ }
}
/** Some tweaks to allow js prefs to work */
diff --git a/includes/PrefixSearch.php b/includes/PrefixSearch.php
index 55a4f49b..430b4b89 100644
--- a/includes/PrefixSearch.php
+++ b/includes/PrefixSearch.php
@@ -362,7 +362,11 @@ abstract class PrefixSearch {
$ns = NS_MAIN; // if searching on many always default to main
}
- $t = Title::newFromText( $search, $ns );
+ $t = null;
+ if ( is_string( $search ) ) {
+ $t = Title::newFromText( $search, $ns );
+ }
+
$prefix = $t ? $t->getDBkey() : '';
$dbr = wfGetDB( DB_SLAVE );
$res = $dbr->select( 'page',
diff --git a/includes/ProtectionForm.php b/includes/ProtectionForm.php
index 1219da51..4cad7b74 100644
--- a/includes/ProtectionForm.php
+++ b/includes/ProtectionForm.php
@@ -157,7 +157,7 @@ class ProtectionForm {
$value = $this->mExpirySelection[$action];
}
if ( wfIsInfinity( $value ) ) {
- $time = wfGetDB( DB_SLAVE )->getInfinity();
+ $time = 'infinity';
} else {
$unix = strtotime( $value );
@@ -384,7 +384,12 @@ class ProtectionForm {
"mwProtect-$action-expires"
);
- $expiryFormOptions = '';
+ $expiryFormOptions = new XmlSelect( "wpProtectExpirySelection-$action", "mwProtectExpirySelection-$action", $this->mExpirySelection[$action] );
+ $expiryFormOptions->setAttribute( 'tabindex', '2' );
+ if ( $this->disabled ) {
+ $expiryFormOptions->setAttribute( 'disabled', 'disabled' );
+ }
+
if ( $this->mExistingExpiry[$action] ) {
if ( $this->mExistingExpiry[$action] == 'infinity' ) {
$existingExpiryMessage = $context->msg( 'protect-existing-expiry-infinity' );
@@ -394,29 +399,17 @@ class ProtectionForm {
$t = $lang->userTime( $this->mExistingExpiry[$action], $user );
$existingExpiryMessage = $context->msg( 'protect-existing-expiry', $timestamp, $d, $t );
}
- $expiryFormOptions .=
- Xml::option(
- $existingExpiryMessage->text(),
- 'existing',
- $this->mExpirySelection[$action] == 'existing'
- ) . "\n";
+ $expiryFormOptions->addOption( $existingExpiryMessage->text(), 'existing' );
}
- $expiryFormOptions .= Xml::option(
- $context->msg( 'protect-othertime-op' )->text(),
- "othertime"
- ) . "\n";
+ $expiryFormOptions->addOption( $context->msg( 'protect-othertime-op' )->text(), 'othertime' );
foreach ( explode( ',', $scExpiryOptions ) as $option ) {
if ( strpos( $option, ":" ) === false ) {
$show = $value = $option;
} else {
list( $show, $value ) = explode( ":", $option );
}
- $expiryFormOptions .= Xml::option(
- $show,
- htmlspecialchars( $value ),
- $this->mExpirySelection[$action] === $value
- ) . "\n";
+ $expiryFormOptions->addOption( $show, htmlspecialchars( $value ) );
}
# Add expiry dropdown
if ( $showProtectOptions && !$this->disabled ) {
@@ -426,12 +419,7 @@ class ProtectionForm {
{$mProtectexpiry}
</td>
<td class='mw-input'>" .
- Xml::tags( 'select',
- array(
- 'id' => "mwProtectExpirySelection-$action",
- 'name' => "wpProtectExpirySelection-$action",
- 'tabindex' => '2' ) + $this->disabledAttrib,
- $expiryFormOptions ) .
+ $expiryFormOptions->getHTML() .
"</td>
</tr></table>";
}
@@ -541,9 +529,8 @@ class ProtectionForm {
$out .= Xml::closeElement( 'fieldset' );
if ( $user->isAllowed( 'editinterface' ) ) {
- $title = Title::makeTitle( NS_MEDIAWIKI, 'Protect-dropdown' );
- $link = Linker::link(
- $title,
+ $link = Linker::linkKnown(
+ $context->msg( 'protect-dropdown' )->inContentLanguage()->getTitle(),
$context->msg( 'protect-edit-reasonlist' )->escaped(),
array(),
array( 'action' => 'edit' )
@@ -577,18 +564,18 @@ class ProtectionForm {
);
$id = 'mwProtect-level-' . $action;
- $attribs = array(
- 'id' => $id,
- 'name' => $id,
- 'size' => count( $levels ),
- ) + $this->disabledAttrib;
- $out = Xml::openElement( 'select', $attribs );
+ $select = new XmlSelect( $id, $id, $selected );
+ $select->setAttribute( 'size', count( $levels ) );
+ if ( $this->disabled ) {
+ $select->setAttribute( 'disabled', 'disabled' );
+ }
+
foreach ( $levels as $key ) {
- $out .= Xml::option( $this->getOptionLabel( $key ), $key, $key == $selected );
+ $select->addOption( $this->getOptionLabel( $key ), $key );
}
- $out .= Xml::closeElement( 'select' );
- return $out;
+
+ return $select->getHTML();
}
/**
diff --git a/includes/Revision.php b/includes/Revision.php
index 3ba6157c..32ee259f 100644
--- a/includes/Revision.php
+++ b/includes/Revision.php
@@ -194,8 +194,8 @@ class Revision implements IDBAccessObject {
if ( !isset( $attribs['title'] )
&& isset( $row->ar_namespace )
- && isset( $row->ar_title ) ) {
-
+ && isset( $row->ar_title )
+ ) {
$attribs['title'] = Title::makeTitle( $row->ar_namespace, $row->ar_title );
}
@@ -1087,7 +1087,7 @@ class Revision implements IDBAccessObject {
/**
* Returns the content model for this revision.
*
- * If no content model was stored in the database, $this->getTitle()->getContentModel() is
+ * 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.
*
@@ -1097,7 +1097,11 @@ class Revision implements IDBAccessObject {
public function getContentModel() {
if ( !$this->mContentModel ) {
$title = $this->getTitle();
- $this->mContentModel = ( $title ? $title->getContentModel() : CONTENT_MODEL_WIKITEXT );
+ if ( $title ) {
+ $this->mContentModel = ContentHandler::getDefaultModelFor( $title );
+ } else {
+ $this->mContentModel = CONTENT_MODEL_WIKITEXT;
+ }
assert( !empty( $this->mContentModel ) );
}
@@ -1284,8 +1288,14 @@ class Revision implements IDBAccessObject {
if ( $wgCompressRevisions ) {
if ( function_exists( 'gzdeflate' ) ) {
- $text = gzdeflate( $text );
- $flags[] = 'gzip';
+ $deflated = gzdeflate( $text );
+
+ if ( $deflated === false ) {
+ wfLogWarning( __METHOD__ . ': gzdeflate() failed' );
+ } else {
+ $text = $deflated;
+ $flags[] = 'gzip';
+ }
} else {
wfDebug( __METHOD__ . " -- no zlib support, not compressing\n" );
}
@@ -1306,6 +1316,11 @@ class Revision implements IDBAccessObject {
# 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 ) ) {
@@ -1626,8 +1641,9 @@ class Revision implements IDBAccessObject {
$row['content_format'] = $current->rev_content_format;
}
+ $row['title'] = Title::makeTitle( $current->page_namespace, $current->page_title );
+
$revision = new Revision( $row );
- $revision->setTitle( Title::makeTitle( $current->page_namespace, $current->page_title ) );
} else {
$revision = null;
}
diff --git a/includes/RevisionList.php b/includes/RevisionList.php
index 6844dadc..e4174730 100644
--- a/includes/RevisionList.php
+++ b/includes/RevisionList.php
@@ -30,6 +30,7 @@ abstract class RevisionListBase extends ContextSource {
/** @var array */
protected $ids;
+ /** @var ResultWrapper|bool */
protected $res;
/** @var bool|object */
@@ -340,7 +341,8 @@ class RevisionItem extends RevisionItemBase {
* @return string
*/
protected function getRevisionLink() {
- $date = $this->list->getLanguage()->timeanddate( $this->revision->getTimestamp(), true );
+ $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate(
+ $this->revision->getTimestamp(), $this->list->getUser() ) );
if ( $this->isDeleted() && !$this->canViewContent() ) {
return $date;
diff --git a/includes/Sanitizer.php b/includes/Sanitizer.php
index 96193a74..de63af79 100644
--- a/includes/Sanitizer.php
+++ b/includes/Sanitizer.php
@@ -346,12 +346,9 @@ class Sanitizer {
($space*=$space*
(?:
# The attribute value: quoted or alone
- \"([^<\"]*)\"
- | '([^<']*)'
+ \"([^<\"]*)(?:\"|\$)
+ | '([^<']*)(?:'|\$)
| ([a-zA-Z0-9!#$%&()*,\\-.\\/:;<>?@[\\]^_`{|}~]+)
- | (\#[0-9a-fA-F]+) # Technically wrong, but lots of
- # colors are specified like this.
- # We'll be normalizing it.
)
)?(?=$space|\$)/sx";
}
@@ -359,20 +356,13 @@ class Sanitizer {
}
/**
- * Cleans up HTML, removes dangerous tags and attributes, and
- * removes HTML comments
- * @param string $text
- * @param callable $processCallback Callback to do any variable or parameter
- * replacements in HTML attribute values
- * @param array|bool $args Arguments for the processing callback
+ * Return the various lists of recognized tags
* @param array $extratags For any extra tags to include
* @param array $removetags For any tags (default or extra) to exclude
- * @return string
+ * @return array
*/
- public static function removeHTMLtags( $text, $processCallback = null,
- $args = array(), $extratags = array(), $removetags = array()
- ) {
- global $wgUseTidy, $wgAllowMicrodataAttributes, $wgAllowImageTag;
+ public static function getRecognizedTagData( $extratags = array(), $removetags = array() ) {
+ global $wgAllowMicrodataAttributes, $wgAllowImageTag;
static $htmlpairsStatic, $htmlsingle, $htmlsingleonly, $htmlnest, $tabletags,
$htmllist, $listtags, $htmlsingleallowed, $htmlelementsStatic, $staticInitialised;
@@ -381,7 +371,6 @@ class Sanitizer {
// are changed (like in the screwed up test system) we will re-initialise the settings.
$globalContext = implode( '-', compact( 'wgAllowMicrodataAttributes', 'wgAllowImageTag' ) );
if ( !$staticInitialised || $staticInitialised != $globalContext ) {
-
$htmlpairsStatic = array( # Tags that must be closed
'b', 'bdi', 'del', 'i', 'ins', 'u', 'font', 'big', 'small', 'sub', 'sup', 'h1',
'h2', 'h3', 'h4', 'h5', 'h6', 'cite', 'code', 'em', 's',
@@ -431,17 +420,47 @@ class Sanitizer {
}
$staticInitialised = $globalContext;
}
+
# Populate $htmlpairs and $htmlelements with the $extratags and $removetags arrays
$extratags = array_flip( $extratags );
$removetags = array_flip( $removetags );
$htmlpairs = array_merge( $extratags, $htmlpairsStatic );
$htmlelements = array_diff_key( array_merge( $extratags, $htmlelementsStatic ), $removetags );
+ return array(
+ 'htmlpairs' => $htmlpairs,
+ 'htmlsingle' => $htmlsingle,
+ 'htmlsingleonly' => $htmlsingleonly,
+ 'htmlnest' => $htmlnest,
+ 'tabletags' => $tabletags,
+ 'htmllist' => $htmllist,
+ 'listtags' => $listtags,
+ 'htmlsingleallowed' => $htmlsingleallowed,
+ 'htmlelements' => $htmlelements,
+ );
+ }
+
+ /**
+ * Cleans up HTML, removes dangerous tags and attributes, and
+ * removes HTML comments
+ * @param string $text
+ * @param callable $processCallback Callback to do any variable or parameter
+ * replacements in HTML attribute values
+ * @param array|bool $args Arguments for the processing callback
+ * @param array $extratags For any extra tags to include
+ * @param array $removetags For any tags (default or extra) to exclude
+ * @return string
+ */
+ public static function removeHTMLtags( $text, $processCallback = null,
+ $args = array(), $extratags = array(), $removetags = array()
+ ) {
+ extract( self::getRecognizedTagData( $extratags, $removetags ) );
+
# Remove HTML comments
$text = Sanitizer::removeHTMLcomments( $text );
$bits = explode( '<', $text );
$text = str_replace( '>', '&gt;', array_shift( $bits ) );
- if ( !$wgUseTidy ) {
+ if ( !MWTidy::isEnabled() ) {
$tagstack = $tablestack = array();
foreach ( $bits as $x ) {
$regs = array();
@@ -463,9 +482,9 @@ class Sanitizer {
$badtag = true;
} elseif ( $slash ) {
# Closing a tag... is it the one we just opened?
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ot = array_pop( $tagstack );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $ot != $t ) {
if ( isset( $htmlsingleallowed[$ot] ) ) {
@@ -473,32 +492,32 @@ class Sanitizer {
# and see if we find a match below them
$optstack = array();
array_push( $optstack, $ot );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ot = array_pop( $tagstack );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
while ( $ot != $t && isset( $htmlsingleallowed[$ot] ) ) {
array_push( $optstack, $ot );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ot = array_pop( $tagstack );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
if ( $t != $ot ) {
# No match. Push the optional elements back again
$badtag = true;
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ot = array_pop( $optstack );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
while ( $ot ) {
array_push( $tagstack, $ot );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ot = array_pop( $optstack );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
}
} else {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
array_push( $tagstack, $ot );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
# <li> can be nested in <ul> or <ol>, skip those cases:
if ( !isset( $htmllist[$ot] ) || !isset( $listtags[$t] ) ) {
@@ -729,7 +748,7 @@ class Sanitizer {
}
# Allow any attribute beginning with "data-"
- if ( !preg_match( '/^data-/i', $attribute ) && !isset( $whitelist[$attribute] ) ) {
+ if ( !preg_match( '/^data-(?!ooui)/i', $attribute ) && !isset( $whitelist[$attribute] ) ) {
continue;
}
@@ -942,7 +961,8 @@ class Sanitizer {
$value = self::normalizeCss( $value );
// Reject problematic keywords and control characters
- if ( preg_match( '/[\000-\010\013\016-\037\177]/', $value ) ) {
+ if ( preg_match( '/[\000-\010\013\016-\037\177]/', $value ) ||
+ strpos( $value, UtfNormal\Constants::UTF8_REPLACEMENT ) !== false ) {
return '/* invalid control char */';
} elseif ( preg_match(
'! expression
@@ -1239,10 +1259,7 @@ class Sanitizer {
* @return string
*/
private static function getTagAttributeCallback( $set ) {
- if ( isset( $set[6] ) ) {
- # Illegal #XXXXXX color with no quotes.
- return $set[6];
- } elseif ( isset( $set[5] ) ) {
+ if ( isset( $set[5] ) ) {
# No quotes.
return $set[5];
} elseif ( isset( $set[4] ) ) {
@@ -1252,9 +1269,10 @@ class Sanitizer {
# Double-quoted
return $set[3];
} elseif ( !isset( $set[2] ) ) {
- # In XHTML, attributes must have a value.
- # For 'reduced' form, return explicitly the attribute name here.
- return $set[1];
+ # In XHTML, attributes must have a value so return an empty string.
+ # See "Empty attribute syntax",
+ # http://www.w3.org/TR/html5/syntax.html#syntax-attribute-name
+ return "";
} else {
throw new MWException( "Tag conditions not met. This should never happen and is a bug." );
}
@@ -1374,15 +1392,19 @@ class Sanitizer {
}
/**
- * Returns true if a given Unicode codepoint is a valid character in XML.
+ * Returns true if a given Unicode codepoint is a valid character in
+ * both HTML5 and XML.
* @param int $codepoint
* @return bool
*/
private static function validateCodepoint( $codepoint ) {
+ # U+000C is valid in HTML5 but not allowed in XML.
+ # U+000D is valid in XML but not allowed in HTML5.
+ # U+007F - U+009F are disallowed in HTML5 (control characters).
return $codepoint == 0x09
|| $codepoint == 0x0a
- || $codepoint == 0x0d
- || ( $codepoint >= 0x20 && $codepoint <= 0xd7ff )
+ || ( $codepoint >= 0x20 && $codepoint <= 0x7e )
+ || ( $codepoint >= 0xa0 && $codepoint <= 0xd7ff )
|| ( $codepoint >= 0xe000 && $codepoint <= 0xfffd )
|| ( $codepoint >= 0x10000 && $codepoint <= 0x10ffff );
}
@@ -1784,6 +1806,11 @@ class Sanitizer {
$host = preg_replace( $strip, '', $host );
+ // IPv6 host names are bracketed with []. Url-decode these.
+ if ( substr_compare( "//%5B", $host, 0, 5 ) === 0 && preg_match( '!^//%5B([0-9A-Fa-f:.]+)%5D((:\d+)?)$!', $host, $matches ) ) {
+ $host = '//[' . $matches[1] . ']' . $matches[2];
+ }
+
// @todo FIXME: Validate hostnames here
return $protocol . $host . $rest;
diff --git a/includes/Setup.php b/includes/Setup.php
index 1b6d66c0..70e8cde4 100644
--- a/includes/Setup.php
+++ b/includes/Setup.php
@@ -68,17 +68,18 @@ if ( !empty( $wgActionPaths ) && !isset( $wgActionPaths['view'] ) ) {
$wgActionPaths['view'] = $wgArticlePath;
}
+if ( $wgResourceBasePath === null ) {
+ $wgResourceBasePath = $wgScriptPath;
+}
if ( $wgStylePath === false ) {
- $wgStylePath = "$wgScriptPath/skins";
+ $wgStylePath = "$wgResourceBasePath/skins";
}
if ( $wgLocalStylePath === false ) {
+ // Avoid wgResourceBasePath here since that may point to a different domain (e.g. CDN)
$wgLocalStylePath = "$wgScriptPath/skins";
}
if ( $wgExtensionAssetsPath === false ) {
- $wgExtensionAssetsPath = "$wgScriptPath/extensions";
-}
-if ( $wgResourceBasePath === null ) {
- $wgResourceBasePath = $wgScriptPath;
+ $wgExtensionAssetsPath = "$wgResourceBasePath/extensions";
}
if ( $wgLogo === false ) {
@@ -105,6 +106,10 @@ if ( $wgGitInfoCacheDirectory === false && $wgCacheDirectory !== false ) {
$wgGitInfoCacheDirectory = "{$wgCacheDirectory}/gitinfo";
}
+if ( $wgEnableParserCache === false ) {
+ $wgParserCacheType = CACHE_NONE;
+}
+
// Fix path to icon images after they were moved in 1.24
if ( $wgRightsIcon ) {
$wgRightsIcon = str_replace(
@@ -359,13 +364,13 @@ if ( $wgMetaNamespace === false ) {
// Default value is 2000 or the suhosin limit if it is between 1 and 2000
if ( $wgResourceLoaderMaxQueryLength === false ) {
- $suhosinMaxValueLength = (int) ini_get( 'suhosin.get.max_value_length' );
+ $suhosinMaxValueLength = (int)ini_get( 'suhosin.get.max_value_length' );
if ( $suhosinMaxValueLength > 0 && $suhosinMaxValueLength < 2000 ) {
$wgResourceLoaderMaxQueryLength = $suhosinMaxValueLength;
} else {
$wgResourceLoaderMaxQueryLength = 2000;
}
- unset($suhosinMaxValueLength);
+ unset( $suhosinMaxValueLength );
}
// Ensure the minimum chunk size is less than PHP upload limits or the maximum
@@ -434,12 +439,12 @@ if ( !$wgHtml5Version && $wgAllowRdfaAttributes ) {
}
// Blacklisted file extensions shouldn't appear on the "allowed" list
-$wgFileExtensions = array_values( array_diff ( $wgFileExtensions, $wgFileBlacklist ) );
+$wgFileExtensions = array_values( array_diff( $wgFileExtensions, $wgFileBlacklist ) );
if ( $wgInvalidateCacheOnLocalSettingsChange ) {
- // @codingStandardsIgnoreStart Generic.PHP.NoSilencedErrors.Discouraged - No GlobalFunction here yet.
- $wgCacheEpoch = max( $wgCacheEpoch, gmdate( 'YmdHis', @filemtime( "$IP/LocalSettings.php" ) ) );
- // @codingStandardsIgnoreEnd
+ MediaWiki\suppressWarnings();
+ $wgCacheEpoch = max( $wgCacheEpoch, gmdate( 'YmdHis', filemtime( "$IP/LocalSettings.php" ) ) );
+ MediaWiki\restoreWarnings();
}
if ( $wgNewUserLog ) {
@@ -473,6 +478,21 @@ if ( $wgProfileOnly ) {
$wgDebugLogFile = '';
}
+// Backwards compatibility with old password limits
+if ( $wgMinimalPasswordLength !== false ) {
+ $wgPasswordPolicy['policies']['default']['MinimalPasswordLength'] = $wgMinimalPasswordLength;
+}
+
+if ( $wgMaximalPasswordLength !== false ) {
+ $wgPasswordPolicy['policies']['default']['MaximalPasswordLength'] = $wgMaximalPasswordLength;
+}
+
+// Backwards compatibility with deprecated alias
+// Must be before call to wfSetupSession()
+if ( $wgSessionsInMemcached ) {
+ $wgSessionsInObjectCache = true;
+}
+
Profiler::instance()->scopedProfileOut( $ps_default );
// Disable MWDebug for command line mode, this prevents MWDebug from eating up
@@ -488,7 +508,7 @@ if ( !class_exists( 'AutoLoader' ) ) {
MWExceptionHandler::installHandler();
-require_once "$IP/includes/libs/normal/UtfNormalUtil.php";
+require_once "$IP/includes/compat/normal/UtfNormalUtil.php";
$ps_default2 = Profiler::instance()->scopedProfileIn( $fname . '-defaults2' );
@@ -525,11 +545,11 @@ if ( $wgSecureLogin && substr( $wgServer, 0, 2 ) !== '//' ) {
. 'HTTP or HTTPS. Disabling secure login.' );
}
+$wgVirtualRestConfig['global']['domain'] = $wgCanonicalServer;
+
// Now that GlobalFunctions is loaded, set defaults that depend on it.
if ( $wgTmpDirectory === false ) {
- $ps_tmpdir = Profiler::instance()->scopedProfileIn( $fname . '-tempDir' );
$wgTmpDirectory = wfTempDir();
- Profiler::instance()->scopedProfileOut( $ps_tmpdir );
}
// We don't use counters anymore. Left here for extensions still
@@ -538,6 +558,18 @@ if ( !isset( $wgDisableCounters ) ) {
$wgDisableCounters = true;
}
+if ( $wgMainWANCache === false ) {
+ // Setup a WAN cache from $wgMainCacheType with no relayer.
+ // Sites using multiple datacenters can configure a relayer.
+ $wgMainWANCache = 'mediawiki-main-default';
+ $wgWANObjectCaches[$wgMainWANCache] = array(
+ 'class' => 'WANObjectCache',
+ 'cacheId' => $wgMainCacheType,
+ 'pool' => 'mediawiki-main-default',
+ 'relayerConfig' => array( 'class' => 'EventRelayerNull' )
+ );
+}
+
Profiler::instance()->scopedProfileOut( $ps_default2 );
$ps_misc = Profiler::instance()->scopedProfileIn( $fname . '-misc1' );
@@ -551,9 +583,9 @@ wfMemoryLimit();
* explicitly set. Inspired by phpMyAdmin's treatment of the problem.
*/
if ( is_null( $wgLocaltimezone ) ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$wgLocaltimezone = date_default_timezone_get();
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
date_default_timezone_set( $wgLocaltimezone );
@@ -561,6 +593,10 @@ if ( is_null( $wgLocalTZoffset ) ) {
$wgLocalTZoffset = date( 'Z' ) / 60;
}
+if ( !$wgDBerrorLogTZ ) {
+ $wgDBerrorLogTZ = $wgLocaltimezone;
+}
+
// Useful debug output
if ( $wgCommandLineMode ) {
$wgRequest = new FauxRequest( array() );
@@ -654,12 +690,6 @@ if ( !is_object( $wgAuth ) ) {
*/
$wgTitle = null;
-/**
- * @deprecated since 1.24 Use DeferredUpdates::addUpdate instead
- * @var array
- */
-$wgDeferredUpdateList = array();
-
Profiler::instance()->scopedProfileOut( $ps_globals );
$ps_extensions = Profiler::instance()->scopedProfileIn( $fname . '-extensions' );
diff --git a/includes/SiteStats.php b/includes/SiteStats.php
index 15c18f35..81172a14 100644
--- a/includes/SiteStats.php
+++ b/includes/SiteStats.php
@@ -68,6 +68,8 @@ class SiteStats {
* @return bool|ResultWrapper
*/
static function loadAndLazyInit() {
+ global $wgMiserMode;
+
wfDebug( __METHOD__ . ": reading site_stats from slave\n" );
$row = self::doLoad( wfGetDB( DB_SLAVE ) );
@@ -77,7 +79,7 @@ class SiteStats {
$row = self::doLoad( wfGetDB( DB_MASTER ) );
}
- if ( !self::isSane( $row ) ) {
+ if ( !$wgMiserMode && !self::isSane( $row ) ) {
// Normally the site_stats table is initialized at install time.
// Some manual construction scenarios may leave the table empty or
// broken, however, for instance when importing from a dump into a
diff --git a/includes/SquidPurgeClient.php b/includes/SquidPurgeClient.php
index 824dd06b..ca8f11ae 100644
--- a/includes/SquidPurgeClient.php
+++ b/includes/SquidPurgeClient.php
@@ -95,9 +95,9 @@ class SquidPurgeClient {
}
$this->socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
socket_set_nonblock( $this->socket );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = socket_connect( $this->socket, $ip, $this->port );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$ok ) {
$error = socket_last_error( $this->socket );
if ( $error !== self::EINPROGRESS ) {
@@ -153,12 +153,12 @@ class SquidPurgeClient {
} elseif ( IP::isIPv6( $this->host ) ) {
throw new MWException( '$wgSquidServers does not support IPv6' );
} else {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$this->ip = gethostbyname( $this->host );
if ( $this->ip === $this->host ) {
$this->ip = false;
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
}
return $this->ip;
@@ -178,11 +178,11 @@ class SquidPurgeClient {
*/
public function close() {
if ( $this->socket ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
socket_set_block( $this->socket );
socket_shutdown( $this->socket );
socket_close( $this->socket );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
$this->socket = null;
$this->readBuffer = '';
@@ -252,9 +252,9 @@ class SquidPurgeClient {
$buf = substr( $this->writeBuffer, 0, self::BUFFER_SIZE );
$flags = 0;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$bytesSent = socket_send( $socket, $buf, strlen( $buf ), $flags );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $bytesSent === false ) {
$error = socket_last_error( $socket );
@@ -278,9 +278,9 @@ class SquidPurgeClient {
}
$buf = '';
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$bytesRead = socket_recv( $socket, $buf, self::BUFFER_SIZE, 0 );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $bytesRead === false ) {
$error = socket_last_error( $socket );
if ( $error != self::EAGAIN && $error != self::EINTR ) {
@@ -442,9 +442,9 @@ class SquidPurgeClientPool {
}
$exceptSockets = null;
$timeout = min( $startTime + $this->timeout - microtime( true ), 1 );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$numReady = socket_select( $readSockets, $writeSockets, $exceptSockets, $timeout );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $numReady === false ) {
wfDebugLog( 'squid', __METHOD__ . ': Error in stream_select: ' .
socket_strerror( socket_last_error() ) . "\n" );
diff --git a/includes/Status.php b/includes/Status.php
index cd10258d..28af7f53 100644
--- a/includes/Status.php
+++ b/includes/Status.php
@@ -69,9 +69,9 @@ class Status {
* Succinct helper method to wrap a StatusValue
*
* This is is useful when formatting StatusValue objects:
- * <code>
+ * @code
* $this->getOutput()->addHtml( Status::wrap( $sv )->getHTML() );
- * </code>
+ * @endcode
*
* @param StatusValue|Status $sv
* @return Status
@@ -281,7 +281,7 @@ class Status {
* Otherwise, if its an array, just use the first value as the
* message and the remaining items as the params.
*
- * @return string
+ * @return Message
*/
protected function getErrorMessage( $error ) {
if ( is_array( $error ) ) {
@@ -316,9 +316,9 @@ class Status {
}
/**
- * Return an array with the wikitext for each item in the array.
+ * Return an array with a Message object for each error.
* @param array $errors
- * @return array
+ * @return Message[]
*/
protected function getErrorMessageArray( $errors ) {
return array_map( array( $this, 'getErrorMessage' ), $errors );
diff --git a/includes/StreamFile.php b/includes/StreamFile.php
index a52b25b0..3f73ae3c 100644
--- a/includes/StreamFile.php
+++ b/includes/StreamFile.php
@@ -44,9 +44,9 @@ class StreamFile {
throw new MWException( __FUNCTION__ . " given storage path '$fname'." );
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$stat = stat( $fname );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
$res = self::prepareForStream( $fname, $stat, $headers, $sendErrors );
if ( $res == self::NOT_MODIFIED ) {
@@ -78,7 +78,7 @@ class StreamFile {
) {
if ( !is_array( $info ) ) {
if ( $sendErrors ) {
- header( 'HTTP/1.0 404 Not Found' );
+ HttpStatus::header( 404 );
header( 'Cache-Control: no-cache' );
header( 'Content-Type: text/html; charset=utf-8' );
$encFile = htmlspecialchars( $path );
@@ -126,7 +126,7 @@ class StreamFile {
$modsince = preg_replace( '/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
if ( wfTimestamp( TS_UNIX, $info['mtime'] ) <= strtotime( $modsince ) ) {
ini_set( 'zlib.output_compression', 0 );
- header( "HTTP/1.0 304 Not Modified" );
+ HttpStatus::header( 304 );
return self::NOT_MODIFIED; // ok
}
}
diff --git a/includes/StubObject.php b/includes/StubObject.php
index 2dfcdc2f..49155d6d 100644
--- a/includes/StubObject.php
+++ b/includes/StubObject.php
@@ -194,7 +194,7 @@ class StubUserLang extends StubObject {
public function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) {
global $wgLang;
$this->_unstub( 'findVariantLink', 3 );
- return $wgLang->findVariantLink( $link, $nt, $ignoreOtherCond );
+ $wgLang->findVariantLink( $link, $nt, $ignoreOtherCond );
}
/**
diff --git a/includes/TemplateParser.php b/includes/TemplateParser.php
index 3de70fa2..d6b101b2 100644
--- a/includes/TemplateParser.php
+++ b/includes/TemplateParser.php
@@ -103,7 +103,7 @@ class TemplateParser {
// See if the compiled PHP code is stored in cache.
// CACHE_ACCEL throws an exception if no suitable object cache is present, so fall
// back to CACHE_ANYTHING.
- $cache = ObjectCache::newAccelerator( array(), CACHE_ANYTHING );
+ $cache = ObjectCache::newAccelerator( CACHE_ANYTHING );
$key = wfMemcKey( 'template', $templateName, $fastHash );
$code = $this->forceRecompile ? null : $cache->get( $key );
@@ -130,7 +130,8 @@ class TemplateParser {
if ( !is_callable( $renderer ) ) {
throw new RuntimeException( "Requested template, {$templateName}, is not callable" );
}
- return $this->renderers[$templateName] = $renderer;
+ $this->renderers[$templateName] = $renderer;
+ return $renderer;
}
/**
@@ -172,7 +173,9 @@ class TemplateParser {
array(
// Do not add more flags here without discussion.
// If you do add more flags, be sure to update unit tests as well.
- 'flags' => LightnCandy::FLAG_ERROR_EXCEPTION
+ 'flags' => LightnCandy::FLAG_ERROR_EXCEPTION,
+ 'basedir' => $this->templateDir,
+ 'fileext' => '.mustache',
)
);
}
diff --git a/includes/Title.php b/includes/Title.php
index d8976635..b347edbb 100644
--- a/includes/Title.php
+++ b/includes/Title.php
@@ -96,7 +96,7 @@ class Title {
/** @var array Array of groups allowed to edit this article */
public $mRestrictions = array();
- /** @var bool */
+ /** @var string|bool */
protected $mOldRestrictions = false;
/** @var bool Cascade restrictions on this page to included templates and images? */
@@ -225,9 +225,11 @@ class Title {
public static function newFromDBkey( $key ) {
$t = new Title();
$t->mDbkeyform = $key;
- if ( $t->secureAndSplit() ) {
+
+ try {
+ $t->secureAndSplit();
return $t;
- } else {
+ } catch ( MalformedTitleException $ex ) {
return null;
}
}
@@ -263,7 +265,34 @@ class Title {
if ( is_object( $text ) ) {
throw new InvalidArgumentException( '$text must be a string.' );
} elseif ( !is_string( $text ) ) {
- wfWarn( __METHOD__ . ': $text must be a string. This will throw an InvalidArgumentException in future.' );
+ wfDebugLog( 'T76305', wfGetAllCallers( 5 ) );
+ wfWarn( __METHOD__ . ': $text must be a string. This will throw an InvalidArgumentException in future.', 2 );
+ }
+
+ try {
+ return Title::newFromTextThrow( $text, $defaultNamespace );
+ } catch ( MalformedTitleException $ex ) {
+ return null;
+ }
+ }
+
+ /**
+ * Like Title::newFromText(), but throws MalformedTitleException when the title is invalid,
+ * rather than returning null.
+ *
+ * The exception subclasses encode detailed information about why the title is invalid.
+ *
+ * @see Title::newFromText
+ *
+ * @since 1.25
+ * @param string $text Title text to check
+ * @param int $defaultNamespace
+ * @throws MalformedTitleException If the title is invalid
+ * @return Title
+ */
+ public static function newFromTextThrow( $text, $defaultNamespace = NS_MAIN ) {
+ if ( is_object( $text ) ) {
+ throw new MWException( 'Title::newFromTextThrow given an object' );
}
$cache = self::getTitleCache();
@@ -284,17 +313,14 @@ class Title {
$filteredText = Sanitizer::decodeCharReferencesAndNormalize( $text );
$t = new Title();
- $t->mDbkeyform = str_replace( ' ', '_', $filteredText );
+ $t->mDbkeyform = strtr( $filteredText, ' ', '_' );
$t->mDefaultNamespace = intval( $defaultNamespace );
- if ( $t->secureAndSplit() ) {
- if ( $defaultNamespace == NS_MAIN ) {
- $cache->set( $text, $t );
- }
- return $t;
- } else {
- return null;
+ $t->secureAndSplit();
+ if ( $defaultNamespace == NS_MAIN ) {
+ $cache->set( $text, $t );
}
+ return $t;
}
/**
@@ -319,13 +345,15 @@ class Title {
# but some URLs used it as a space replacement and they still come
# from some external search tools.
if ( strpos( self::legalChars(), '+' ) === false ) {
- $url = str_replace( '+', ' ', $url );
+ $url = strtr( $url, '+', ' ' );
}
- $t->mDbkeyform = str_replace( ' ', '_', $url );
- if ( $t->secureAndSplit() ) {
+ $t->mDbkeyform = strtr( $url, ' ', '_' );
+
+ try {
+ $t->secureAndSplit();
return $t;
- } else {
+ } catch ( MalformedTitleException $ex ) {
return null;
}
}
@@ -451,6 +479,9 @@ class Title {
if ( isset( $row->page_lang ) ) {
$this->mDbPageLanguage = (string)$row->page_lang;
}
+ if ( isset( $row->page_restrictions ) ) {
+ $this->mOldRestrictions = $row->page_restrictions;
+ }
} else { // page not found
$this->mArticleID = 0;
$this->mLength = 0;
@@ -478,10 +509,10 @@ class Title {
$t->mInterwiki = $interwiki;
$t->mFragment = $fragment;
$t->mNamespace = $ns = intval( $ns );
- $t->mDbkeyform = str_replace( ' ', '_', $title );
+ $t->mDbkeyform = strtr( $title, ' ', '_' );
$t->mArticleID = ( $ns >= 0 ) ? -1 : 0;
$t->mUrlform = wfUrlencode( $t->mDbkeyform );
- $t->mTextform = str_replace( '_', ' ', $title );
+ $t->mTextform = strtr( $title, '_', ' ' );
$t->mContentModel = false; # initialized lazily in getContentModel()
return $t;
}
@@ -504,9 +535,11 @@ class Title {
$t = new Title();
$t->mDbkeyform = Title::makeName( $ns, $title, $fragment, $interwiki, true );
- if ( $t->secureAndSplit() ) {
+
+ try {
+ $t->secureAndSplit();
return $t;
- } else {
+ } catch ( MalformedTitleException $ex ) {
return null;
}
}
@@ -937,7 +970,6 @@ class Title {
/**
* Get the page's content model id, see the CONTENT_MODEL_XXX constants.
*
- * @throws MWException
* @param int $flags A bit field; may be Title::GAID_FOR_UPDATE to select for update
* @return string Content model id
*/
@@ -952,10 +984,6 @@ class Title {
$this->mContentModel = ContentHandler::getDefaultModelFor( $this );
}
- if ( !$this->mContentModel ) {
- throw new MWException( 'Failed to determine content model!' );
- }
-
return $this->mContentModel;
}
@@ -1391,7 +1419,7 @@ class Title {
* @param string $fragment Text
*/
public function setFragment( $fragment ) {
- $this->mFragment = str_replace( '_', ' ', substr( $fragment, 1 ) );
+ $this->mFragment = strtr( substr( $fragment, 1 ), '_', ' ' );
}
/**
@@ -1421,7 +1449,7 @@ class Title {
*/
public function getPrefixedDBkey() {
$s = $this->prefix( $this->mDbkeyform );
- $s = str_replace( ' ', '_', $s );
+ $s = strtr( $s, ' ', '_' );
return $s;
}
@@ -1434,7 +1462,7 @@ class Title {
public function getPrefixedText() {
if ( $this->mPrefixedText === null ) {
$s = $this->prefix( $this->mTextform );
- $s = str_replace( '_', ' ', $s );
+ $s = strtr( $s, '_', ' ' );
$this->mPrefixedText = $s;
}
return $this->mPrefixedText;
@@ -1582,7 +1610,7 @@ class Title {
*/
public function getSubpageUrlForm() {
$text = $this->getSubpageText();
- $text = wfUrlencode( str_replace( ' ', '_', $text ) );
+ $text = wfUrlencode( strtr( $text, ' ', '_' ) );
return $text;
}
@@ -1593,7 +1621,7 @@ class Title {
*/
public function getPrefixedURL() {
$s = $this->prefix( $this->mDbkeyform );
- $s = wfUrlencode( str_replace( ' ', '_', $s ) );
+ $s = wfUrlencode( strtr( $s, ' ', '_' ) );
return $s;
}
@@ -1911,7 +1939,6 @@ class Title {
* - quick : does cheap permission checks from slaves (usable for GUI creation)
* - full : does cheap and expensive checks possibly from a slave
* - secure : does cheap and expensive checks, using the master as needed
- * @param bool $short Set this to true to stop after the first permission error.
* @param array $ignoreErrors Array of Strings Set this to a list of message keys
* whose corresponding errors may be ignored.
* @return array Array of arguments to wfMessage to explain permissions problems.
@@ -2574,6 +2601,7 @@ class Title {
if ( $row['permission'] == 'autoconfirmed' ) {
$row['permission'] = 'editsemiprotected'; // B/C
}
+ $row['expiry'] = $dbr->decodeExpiry( $row['expiry'] );
}
$this->mTitleProtection = $row;
}
@@ -2711,7 +2739,6 @@ class Title {
* false.
*/
public function getCascadeProtectionSources( $getPages = true ) {
- global $wgContLang;
$pagerestrictions = array();
if ( $this->mCascadeSources !== null && $getPages ) {
@@ -2754,7 +2781,7 @@ class Title {
$now = wfTimestampNow();
foreach ( $res as $row ) {
- $expiry = $wgContLang->formatExpiry( $row->pr_expiry, TS_MW );
+ $expiry = $dbr->decodeExpiry( $row->pr_expiry );
if ( $expiry > $now ) {
if ( $getPages ) {
$page_id = $row->pr_page;
@@ -2887,28 +2914,29 @@ class Title {
* restrictions from page table (pre 1.10)
*/
public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
- global $wgContLang;
$dbr = wfGetDB( DB_SLAVE );
$restrictionTypes = $this->getRestrictionTypes();
foreach ( $restrictionTypes as $type ) {
$this->mRestrictions[$type] = array();
- $this->mRestrictionsExpiry[$type] = $wgContLang->formatExpiry( '', TS_MW );
+ $this->mRestrictionsExpiry[$type] = 'infinity';
}
$this->mCascadeRestriction = false;
# Backwards-compatibility: also load the restrictions from the page record (old format).
+ if ( $oldFashionedRestrictions !== null ) {
+ $this->mOldRestrictions = $oldFashionedRestrictions;
+ }
- if ( $oldFashionedRestrictions === null ) {
- $oldFashionedRestrictions = $dbr->selectField( 'page', 'page_restrictions',
+ if ( $this->mOldRestrictions === false ) {
+ $this->mOldRestrictions = $dbr->selectField( 'page', 'page_restrictions',
array( 'page_id' => $this->getArticleID() ), __METHOD__ );
}
- if ( $oldFashionedRestrictions != '' ) {
-
- foreach ( explode( ':', trim( $oldFashionedRestrictions ) ) as $restrict ) {
+ if ( $this->mOldRestrictions != '' ) {
+ foreach ( explode( ':', trim( $this->mOldRestrictions ) ) as $restrict ) {
$temp = explode( '=', trim( $restrict ) );
if ( count( $temp ) == 1 ) {
// old old format should be treated as edit/move restriction
@@ -2921,9 +2949,6 @@ class Title {
}
}
}
-
- $this->mOldRestrictions = true;
-
}
if ( count( $rows ) ) {
@@ -2940,7 +2965,7 @@ class Title {
// This code should be refactored, now that it's being used more generally,
// But I don't really see any harm in leaving it in Block for now -werdna
- $expiry = $wgContLang->formatExpiry( $row->pr_expiry, TS_MW );
+ $expiry = $dbr->decodeExpiry( $row->pr_expiry );
// Only apply the restrictions if they haven't expired!
if ( !$expiry || $expiry > $now ) {
@@ -2962,11 +2987,9 @@ class Title {
* restrictions from page table (pre 1.10)
*/
public function loadRestrictions( $oldFashionedRestrictions = null ) {
- global $wgContLang;
if ( !$this->mRestrictionsLoaded ) {
+ $dbr = wfGetDB( DB_SLAVE );
if ( $this->exists() ) {
- $dbr = wfGetDB( DB_SLAVE );
-
$res = $dbr->select(
'page_restrictions',
array( 'pr_type', 'pr_expiry', 'pr_level', 'pr_cascade' ),
@@ -2980,7 +3003,7 @@ class Title {
if ( $title_protection ) {
$now = wfTimestampNow();
- $expiry = $wgContLang->formatExpiry( $title_protection['expiry'], TS_MW );
+ $expiry = $dbr->decodeExpiry( $title_protection['expiry'] );
if ( !$expiry || $expiry > $now ) {
// Apply the restrictions
@@ -2990,7 +3013,7 @@ class Title {
$this->mTitleProtection = false;
}
} else {
- $this->mRestrictionsExpiry['create'] = $wgContLang->formatExpiry( '', TS_MW );
+ $this->mRestrictionsExpiry['create'] = 'infinity';
}
$this->mRestrictionsLoaded = true;
}
@@ -3274,6 +3297,7 @@ class Title {
}
$this->mRestrictionsLoaded = false;
$this->mRestrictions = array();
+ $this->mOldRestrictions = false;
$this->mRedirect = null;
$this->mLength = -1;
$this->mLatestID = false;
@@ -3318,6 +3342,7 @@ class Title {
* namespace prefixes, sets the other forms, and canonicalizes
* everything.
*
+ * @throws MalformedTitleException On invalid titles
* @return bool True on success
*/
private function secureAndSplit() {
@@ -3328,15 +3353,12 @@ class Title {
$dbkey = $this->mDbkeyform;
- try {
- // @note: splitTitleString() is a temporary hack to allow MediaWikiTitleCodec to share
- // the parsing code with Title, while avoiding massive refactoring.
- // @todo: get rid of secureAndSplit, refactor parsing code.
- $titleParser = self::getTitleParser();
- $parts = $titleParser->splitTitleString( $dbkey, $this->getDefaultNamespace() );
- } catch ( MalformedTitleException $ex ) {
- return false;
- }
+ // @note: splitTitleString() is a temporary hack to allow MediaWikiTitleCodec to share
+ // the parsing code with Title, while avoiding massive refactoring.
+ // @todo: get rid of secureAndSplit, refactor parsing code.
+ $titleParser = self::getTitleParser();
+ // MalformedTitleException can be thrown here
+ $parts = $titleParser->splitTitleString( $dbkey, $this->getDefaultNamespace() );
# Fill fields
$this->setFragment( '#' . $parts['fragment'] );
@@ -3347,7 +3369,7 @@ class Title {
$this->mDbkeyform = $parts['dbkey'];
$this->mUrlform = wfUrlencode( $this->mDbkeyform );
- $this->mTextform = str_replace( '_', ' ', $this->mDbkeyform );
+ $this->mTextform = strtr( $this->mDbkeyform, '_', ' ' );
# We already know that some pages won't be in the database!
if ( $this->isExternal() || $this->mNamespace == NS_SPECIAL ) {
@@ -3428,8 +3450,6 @@ class Title {
* @return array Array of Title objects linking here
*/
public function getLinksFrom( $options = array(), $table = 'pagelinks', $prefix = 'pl' ) {
- global $wgContentHandlerUseDB;
-
$id = $this->getArticleID();
# If the page doesn't exist; there can't be any link from this page
@@ -3443,49 +3463,36 @@ class Title {
$db = wfGetDB( DB_SLAVE );
}
- $namespaceFiled = "{$prefix}_namespace";
- $titleField = "{$prefix}_title";
-
- $fields = array(
- $namespaceFiled,
- $titleField,
- 'page_id',
- 'page_len',
- 'page_is_redirect',
- 'page_latest'
- );
-
- if ( $wgContentHandlerUseDB ) {
- $fields[] = 'page_content_model';
- }
+ $blNamespace = "{$prefix}_namespace";
+ $blTitle = "{$prefix}_title";
$res = $db->select(
array( $table, 'page' ),
- $fields,
+ array_merge(
+ array( $blNamespace, $blTitle ),
+ WikiPage::selectFields()
+ ),
array( "{$prefix}_from" => $id ),
__METHOD__,
$options,
array( 'page' => array(
'LEFT JOIN',
- array( "page_namespace=$namespaceFiled", "page_title=$titleField" )
+ array( "page_namespace=$blNamespace", "page_title=$blTitle" )
) )
);
$retVal = array();
- if ( $res->numRows() ) {
- $linkCache = LinkCache::singleton();
- foreach ( $res as $row ) {
- $titleObj = Title::makeTitle( $row->$namespaceFiled, $row->$titleField );
- if ( $titleObj ) {
- if ( $row->page_id ) {
- $linkCache->addGoodLinkObjFromRow( $titleObj, $row );
- } else {
- $linkCache->addBadLinkObj( $titleObj );
- }
- $retVal[] = $titleObj;
- }
+ $linkCache = LinkCache::singleton();
+ foreach ( $res as $row ) {
+ if ( $row->page_id ) {
+ $titleObj = Title::newFromRow( $row );
+ } else {
+ $titleObj = Title::makeTitle( $row->$blNamespace, $row->$blTitle );
+ $linkCache->addBadLinkObj( $titleObj );
}
+ $retVal[] = $titleObj;
}
+
return $retVal;
}
@@ -3624,7 +3631,7 @@ class Title {
);
}
- return $errors ? : true;
+ return $errors ?: true;
}
/**
@@ -4236,10 +4243,12 @@ class Title {
* If you want to know if a title can be meaningfully viewed, you should
* probably call the isKnown() method instead.
*
+ * @param int $flags An optional bit field; may be Title::GAID_FOR_UPDATE to check
+ * from master/for update
* @return bool
*/
- public function exists() {
- $exists = $this->getArticleID() != 0;
+ public function exists( $flags = 0 ) {
+ $exists = $this->getArticleID( $flags ) != 0;
Hooks::run( 'TitleExists', array( $this, &$exists ) );
return $exists;
}
@@ -4370,9 +4379,10 @@ class Title {
/**
* Updates page_touched for this page; called from LinksUpdate.php
*
+ * @param integer $purgeTime TS_MW timestamp [optional]
* @return bool True if the update succeeded
*/
- public function invalidateCache() {
+ public function invalidateCache( $purgeTime = null ) {
if ( wfReadOnly() ) {
return false;
}
@@ -4384,11 +4394,13 @@ class Title {
$method = __METHOD__;
$dbw = wfGetDB( DB_MASTER );
$conds = $this->pageCond();
- $dbw->onTransactionIdle( function () use ( $dbw, $conds, $method ) {
+ $dbw->onTransactionIdle( function () use ( $dbw, $conds, $method, $purgeTime ) {
+ $dbTimestamp = $dbw->timestamp( $purgeTime ?: time() );
+
$dbw->update(
'page',
- array( 'page_touched' => $dbw->timestamp() ),
- $conds,
+ array( 'page_touched' => $dbTimestamp ),
+ $conds + array( 'page_touched < ' . $dbw->addQuotes( $dbTimestamp ) ),
$method
);
} );
@@ -4432,35 +4444,29 @@ class Title {
* @return string|null
*/
public function getNotificationTimestamp( $user = null ) {
- global $wgUser, $wgShowUpdatedMarker;
+ global $wgUser;
+
// Assume current user if none given
if ( !$user ) {
$user = $wgUser;
}
// Check cache first
$uid = $user->getId();
+ if ( !$uid ) {
+ return false;
+ }
// avoid isset here, as it'll return false for null entries
if ( array_key_exists( $uid, $this->mNotificationTimestamp ) ) {
return $this->mNotificationTimestamp[$uid];
}
- if ( !$uid || !$wgShowUpdatedMarker || !$user->isAllowed( 'viewmywatchlist' ) ) {
- $this->mNotificationTimestamp[$uid] = false;
- return $this->mNotificationTimestamp[$uid];
- }
// Don't cache too much!
if ( count( $this->mNotificationTimestamp ) >= self::CACHE_MAX ) {
$this->mNotificationTimestamp = array();
}
- $dbr = wfGetDB( DB_SLAVE );
- $this->mNotificationTimestamp[$uid] = $dbr->selectField( 'watchlist',
- 'wl_notificationtimestamp',
- array(
- 'wl_user' => $user->getId(),
- 'wl_namespace' => $this->getNamespace(),
- 'wl_title' => $this->getDBkey(),
- ),
- __METHOD__
- );
+
+ $watchedItem = WatchedItem::fromUserTitle( $user, $this );
+ $this->mNotificationTimestamp[$uid] = $watchedItem->getNotificationTimestamp();
+
return $this->mNotificationTimestamp[$uid];
}
@@ -4540,15 +4546,17 @@ class Title {
public function isValidRedirectTarget() {
global $wgInvalidRedirectTargets;
- // invalid redirect targets are stored in a global array, but explicitly disallow Userlogout here
- if ( $this->isSpecial( 'Userlogout' ) ) {
- return false;
- }
-
- foreach ( $wgInvalidRedirectTargets as $target ) {
- if ( $this->isSpecial( $target ) ) {
+ if ( $this->isSpecialPage() ) {
+ // invalid redirect targets are stored in a global array, but explicitly disallow Userlogout here
+ if ( $this->isSpecial( 'Userlogout' ) ) {
return false;
}
+
+ foreach ( $wgInvalidRedirectTargets as $target ) {
+ if ( $this->isSpecial( $target ) ) {
+ return false;
+ }
+ }
}
return true;
@@ -4731,7 +4739,7 @@ class Title {
}
} else {
// Even if there are no subpages in namespace, we still don't want "/" in MediaWiki message keys
- $editnoticeText = $editnotice_ns . '-' . str_replace( '/', '-', $this->getDBkey() );
+ $editnoticeText = $editnotice_ns . '-' . strtr( $this->getDBkey(), '/', '-' );
$msg = wfMessage( $editnoticeText );
if ( $msg->exists() ) {
$html = $msg->parseAsBlock();
@@ -4752,4 +4760,26 @@ class Title {
Hooks::run( 'TitleGetEditNotices', array( $this, $oldid, &$notices ) );
return $notices;
}
+
+ /**
+ * @return array
+ */
+ public function __sleep() {
+ return array(
+ 'mNamespace',
+ 'mDbkeyform',
+ 'mFragment',
+ 'mInterwiki',
+ 'mLocalInterwiki',
+ 'mUserCaseDBKey',
+ 'mDefaultNamespace',
+ );
+ }
+
+ public function __wakeup() {
+ $this->mArticleID = ( $this->mNamespace >= 0 ) ? -1 : 0;
+ $this->mUrlform = wfUrlencode( $this->mDbkeyform );
+ $this->mTextform = strtr( $this->mDbkeyform, '_', ' ' );
+ }
+
}
diff --git a/includes/User.php b/includes/User.php
index 663a80b7..22c90cdd 100644
--- a/includes/User.php
+++ b/includes/User.php
@@ -183,50 +183,50 @@ class User implements IDBAccessObject {
*/
protected static $mAllRights = false;
- /** @name Cache variables */
+ /** Cache variables */
//@{
public $mId;
-
+ /** @var string */
public $mName;
-
+ /** @var string */
public $mRealName;
-
/**
* @todo Make this actually private
* @private
+ * @var Password
*/
public $mPassword;
-
/**
* @todo Make this actually private
* @private
+ * @var Password
*/
public $mNewpassword;
-
+ /** @var string */
public $mNewpassTime;
-
+ /** @var string */
public $mEmail;
/** @var string TS_MW timestamp from the DB */
public $mTouched;
/** @var string TS_MW timestamp from cache */
protected $mQuickTouched;
-
+ /** @var string */
protected $mToken;
-
+ /** @var string */
public $mEmailAuthenticated;
-
+ /** @var string */
protected $mEmailToken;
-
+ /** @var string */
protected $mEmailTokenExpires;
-
+ /** @var string */
protected $mRegistration;
-
+ /** @var int */
protected $mEditCount;
-
+ /** @var array */
public $mGroups;
-
+ /** @var array */
protected $mOptionOverrides;
-
+ /** @var string */
protected $mPasswordExpires;
//@}
@@ -257,29 +257,29 @@ class User implements IDBAccessObject {
* Lazy-initialized variables, invalidated with clearInstanceCache
*/
protected $mNewtalk;
-
+ /** @var string */
protected $mDatePreference;
-
+ /** @var string */
public $mBlockedby;
-
+ /** @var string */
protected $mHash;
-
+ /** @var array */
public $mRights;
-
+ /** @var string */
protected $mBlockreason;
-
+ /** @var array */
protected $mEffectiveGroups;
-
+ /** @var array */
protected $mImplicitGroups;
-
+ /** @var array */
protected $mFormerGroups;
-
+ /** @var bool */
protected $mBlockedGlobally;
-
+ /** @var bool */
protected $mLocked;
-
+ /** @var bool */
public $mHideName;
-
+ /** @var array */
public $mOptions;
/**
@@ -330,7 +330,7 @@ class User implements IDBAccessObject {
*
* @param integer $flags User::READ_* constant bitfield
*/
- public function load( $flags = self::READ_LATEST ) {
+ public function load( $flags = self::READ_NORMAL ) {
if ( $this->mLoadedItems === true ) {
return;
}
@@ -344,9 +344,13 @@ class User implements IDBAccessObject {
$this->loadDefaults();
break;
case 'name':
- // @TODO: this gets the ID from a slave, assuming renames
- // are rare. This should be controllable and more consistent.
- $this->mId = self::idFromName( $this->mName );
+ // Make sure this thread sees its own changes
+ if ( wfGetLB()->hasOrMadeRecentMasterChanges() ) {
+ $flags |= self::READ_LATEST;
+ $this->queryFlagsUsed = $flags;
+ }
+
+ $this->mId = self::idFromName( $this->mName, $flags );
if ( !$this->mId ) {
// Nonexistent user placeholder object
$this->loadDefaults( $this->mName );
@@ -365,7 +369,8 @@ class User implements IDBAccessObject {
Hooks::run( 'UserLoadAfterLoadFromSession', array( $this ) );
break;
default:
- throw new MWException( "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
+ throw new UnexpectedValueException(
+ "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
}
}
@@ -374,27 +379,26 @@ class User implements IDBAccessObject {
* @param integer $flags User::READ_* constant bitfield
* @return bool False if the ID does not exist, true otherwise
*/
- public function loadFromId( $flags = self::READ_LATEST ) {
+ public function loadFromId( $flags = self::READ_NORMAL ) {
if ( $this->mId == 0 ) {
$this->loadDefaults();
return false;
}
- // Try cache
- $cache = $this->loadFromCache();
- if ( !$cache ) {
+ // Try cache (unless this needs to lock the DB).
+ // NOTE: if this thread called saveSettings(), the cache was cleared.
+ $locking = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING );
+ if ( $locking || !$this->loadFromCache() ) {
wfDebug( "User: cache miss for user {$this->mId}\n" );
- // Load from DB
+ // Load from DB (make sure this thread sees its own changes)
+ if ( wfGetLB()->hasOrMadeRecentMasterChanges() ) {
+ $flags |= self::READ_LATEST;
+ }
if ( !$this->loadFromDatabase( $flags ) ) {
// Can't load from ID, user is anonymous
return false;
}
- if ( $flags & self::READ_LATEST ) {
- // Only save master data back to the cache to keep it consistent.
- // @TODO: save it anyway and have callers specifiy $flags and have
- // load() called as needed. That requires updating MANY callers...
- $this->saveToCache();
- }
+ $this->saveToCache();
}
$this->mLoadedItems = true;
@@ -410,15 +414,13 @@ class User implements IDBAccessObject {
* @since 1.25
*/
protected function loadFromCache() {
- global $wgMemc;
-
if ( $this->mId == 0 ) {
$this->loadDefaults();
return false;
}
$key = wfMemcKey( 'user', 'id', $this->mId );
- $data = $wgMemc->get( $key );
+ $data = ObjectCache::getMainWANInstance()->get( $key );
if ( !is_array( $data ) || $data['mVersion'] < self::VERSION ) {
// Object is expired
return false;
@@ -440,8 +442,6 @@ class User implements IDBAccessObject {
* This method should not be called outside the User class
*/
public function saveToCache() {
- global $wgMemc;
-
$this->load();
$this->loadGroups();
$this->loadOptions();
@@ -451,13 +451,6 @@ class User implements IDBAccessObject {
return;
}
- // The cache needs good consistency due to its high TTL, so the user
- // should have been loaded from the master to avoid lag amplification.
- if ( !( $this->queryFlagsUsed & self::READ_LATEST ) ) {
- wfWarn( "Cannot cache slave-loaded User object with ID '{$this->mId}'." );
- return;
- }
-
$data = array();
foreach ( self::$mCacheVars as $name ) {
$data[$name] = $this->$name;
@@ -465,7 +458,7 @@ class User implements IDBAccessObject {
$data['mVersion'] = self::VERSION;
$key = wfMemcKey( 'user', 'id', $this->mId );
- $wgMemc->set( $key, $data );
+ ObjectCache::getMainWANInstance()->set( $key, $data, 3600 );
}
/** @name newFrom*() static factory methods */
@@ -604,9 +597,10 @@ class User implements IDBAccessObject {
/**
* Get database id given a user name
* @param string $name Username
+ * @param integer $flags User::READ_* constant bitfield
* @return int|null The corresponding user's ID, or null if user is nonexistent
*/
- public static function idFromName( $name ) {
+ public static function idFromName( $name, $flags = self::READ_NORMAL ) {
$nt = Title::makeTitleSafe( NS_USER, $name );
if ( is_null( $nt ) ) {
// Illegal name
@@ -617,8 +611,11 @@ class User implements IDBAccessObject {
return self::$idCacheByName[$name];
}
- $dbr = wfGetDB( DB_SLAVE );
- $s = $dbr->selectRow(
+ $db = ( $flags & self::READ_LATEST )
+ ? wfGetDB( DB_MASTER )
+ : wfGetDB( DB_SLAVE );
+
+ $s = $db->selectRow(
'user',
array( 'user_id' ),
array( 'user_name' => $nt->getText() ),
@@ -846,19 +843,19 @@ class User implements IDBAccessObject {
* able to set their password to this.
*
* @param string $password Desired password
+ * @param string $purpose one of 'login', 'create', 'reset'
* @return Status
* @since 1.23
*/
- public function checkPasswordValidity( $password ) {
- global $wgMinimalPasswordLength, $wgMaximalPasswordLength, $wgContLang;
+ public function checkPasswordValidity( $password, $purpose = 'login' ) {
+ global $wgPasswordPolicy;
- static $blockedLogins = array(
- 'Useruser' => 'Passpass', 'Useruser1' => 'Passpass1', # r75589
- 'Apitestsysop' => 'testpass', 'Apitestuser' => 'testpass' # r75605
+ $upp = new UserPasswordPolicy(
+ $wgPasswordPolicy['policies'],
+ $wgPasswordPolicy['checks']
);
$status = Status::newGood();
-
$result = false; //init $result to false for the internal checks
if ( !Hooks::run( 'isValidPassword', array( $password, &$result, $this ) ) ) {
@@ -867,28 +864,8 @@ class User implements IDBAccessObject {
}
if ( $result === false ) {
- if ( strlen( $password ) < $wgMinimalPasswordLength ) {
- $status->error( 'passwordtooshort', $wgMinimalPasswordLength );
- return $status;
- } elseif ( strlen( $password ) > $wgMaximalPasswordLength ) {
- // T64685: Password too long, might cause DoS attack
- $status->fatal( 'passwordtoolong', $wgMaximalPasswordLength );
- return $status;
- } elseif ( $wgContLang->lc( $password ) == $wgContLang->lc( $this->mName ) ) {
- $status->error( 'password-name-match' );
- return $status;
- } elseif ( isset( $blockedLogins[$this->getName()] )
- && $password == $blockedLogins[$this->getName()]
- ) {
- $status->error( 'password-login-forbidden' );
- return $status;
- } else {
- //it seems weird returning a Good status here, but this is because of the
- //initialization of $result to false above. If the hook is never run or it
- //doesn't modify $result, then we will likely get down into this if with
- //a valid password.
- return $status;
- }
+ $status->merge( $upp->checkUserPassword( $this, $password, $purpose ) );
+ return $status;
} elseif ( $result === true ) {
return $status;
} else {
@@ -974,7 +951,7 @@ class User implements IDBAccessObject {
* - 'usable' Valid for batch processes and login
* - 'creatable' Valid for batch processes, login and account creation
*
- * @throws MWException
+ * @throws InvalidArgumentException
* @return bool|string
*/
public static function getCanonicalName( $name, $validate = 'valid' ) {
@@ -1021,7 +998,8 @@ class User implements IDBAccessObject {
}
break;
default:
- throw new MWException( 'Invalid parameter value for $validate in ' . __METHOD__ );
+ throw new InvalidArgumentException(
+ 'Invalid parameter value for $validate in ' . __METHOD__ );
}
return $name;
}
@@ -1168,7 +1146,6 @@ class User implements IDBAccessObject {
}
$proposedUser = User::newFromId( $sId );
- $proposedUser->load( self::READ_LATEST );
if ( !$proposedUser->isLoggedIn() ) {
// Not a valid ID
return false;
@@ -1235,7 +1212,7 @@ class User implements IDBAccessObject {
self::selectFields(),
array( 'user_id' => $this->mId ),
__METHOD__,
- ( $flags & self::READ_LOCKING == self::READ_LOCKING )
+ ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
? array( 'LOCK IN SHARE MODE' )
: array()
);
@@ -1436,38 +1413,86 @@ class User implements IDBAccessObject {
public function addAutopromoteOnceGroups( $event ) {
global $wgAutopromoteOnceLogInRC, $wgAuth;
- $toPromote = array();
- if ( !wfReadOnly() && $this->getId() ) {
- $toPromote = Autopromote::getAutopromoteOnceGroups( $this, $event );
- if ( count( $toPromote ) ) {
- $oldGroups = $this->getGroups(); // previous groups
+ if ( wfReadOnly() || !$this->getId() ) {
+ return array();
+ }
- foreach ( $toPromote as $group ) {
- $this->addGroup( $group );
- }
- // update groups in external authentication database
- $wgAuth->updateExternalDBGroups( $this, $toPromote );
+ $toPromote = Autopromote::getAutopromoteOnceGroups( $this, $event );
+ if ( !count( $toPromote ) ) {
+ return array();
+ }
- $newGroups = array_merge( $oldGroups, $toPromote ); // all groups
+ if ( !$this->checkAndSetTouched() ) {
+ return array(); // raced out (bug T48834)
+ }
- $logEntry = new ManualLogEntry( 'rights', 'autopromote' );
- $logEntry->setPerformer( $this );
- $logEntry->setTarget( $this->getUserPage() );
- $logEntry->setParameters( array(
- '4::oldgroups' => $oldGroups,
- '5::newgroups' => $newGroups,
- ) );
- $logid = $logEntry->insert();
- if ( $wgAutopromoteOnceLogInRC ) {
- $logEntry->publish( $logid );
- }
- }
+ $oldGroups = $this->getGroups(); // previous groups
+ foreach ( $toPromote as $group ) {
+ $this->addGroup( $group );
+ }
+ // update groups in external authentication database
+ Hooks::run( 'UserGroupsChanged', array( $this, $toPromote, array(), false ) );
+ $wgAuth->updateExternalDBGroups( $this, $toPromote );
+
+ $newGroups = array_merge( $oldGroups, $toPromote ); // all groups
+
+ $logEntry = new ManualLogEntry( 'rights', 'autopromote' );
+ $logEntry->setPerformer( $this );
+ $logEntry->setTarget( $this->getUserPage() );
+ $logEntry->setParameters( array(
+ '4::oldgroups' => $oldGroups,
+ '5::newgroups' => $newGroups,
+ ) );
+ $logid = $logEntry->insert();
+ if ( $wgAutopromoteOnceLogInRC ) {
+ $logEntry->publish( $logid );
}
return $toPromote;
}
/**
+ * Bump user_touched if it didn't change since this object was loaded
+ *
+ * On success, the mTouched field is updated.
+ * The user serialization cache is always cleared.
+ *
+ * @return bool Whether user_touched was actually updated
+ * @since 1.26
+ */
+ protected function checkAndSetTouched() {
+ $this->load();
+
+ if ( !$this->mId ) {
+ return false; // anon
+ }
+
+ // Get a new user_touched that is higher than the old one
+ $oldTouched = $this->mTouched;
+ $newTouched = $this->newTouchedTimestamp();
+
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update( 'user',
+ array( 'user_touched' => $dbw->timestamp( $newTouched ) ),
+ array(
+ 'user_id' => $this->mId,
+ 'user_touched' => $dbw->timestamp( $oldTouched ) // CAS check
+ ),
+ __METHOD__
+ );
+ $success = ( $dbw->affectedRows() > 0 );
+
+ if ( $success ) {
+ $this->mTouched = $newTouched;
+ }
+
+ // Clears on failure too since that is desired if the cache is stale
+ $this->clearSharedCache();
+
+ return $success;
+ }
+
+ /**
* Clear various cached data stored in this object. The cache of the user table
* data (i.e. self::$mCacheVars) is not cleared unless $reloadFrom is given.
*
@@ -1566,7 +1591,7 @@ class User implements IDBAccessObject {
# We only need to worry about passing the IP address to the Block generator if the
# user is not immune to autoblocks/hardblocks, and they are the current user so we
# know which IP address they're actually coming from
- if ( !$this->isAllowed( 'ipblock-exempt' ) && $this->getID() == $wgUser->getID() ) {
+ if ( !$this->isAllowed( 'ipblock-exempt' ) && $this->equals( $wgUser ) ) {
$ip = $this->getRequest()->getIP();
} else {
$ip = null;
@@ -1968,6 +1993,7 @@ class User implements IDBAccessObject {
global $wgAuth;
$authUser = $wgAuth->getUserInstance( $this );
$this->mLocked = (bool)$authUser->isLocked();
+ Hooks::run( 'UserIsLocked', array( $this, &$this->mLocked ) );
return $this->mLocked;
}
@@ -1985,6 +2011,7 @@ class User implements IDBAccessObject {
global $wgAuth;
$authUser = $wgAuth->getUserInstance( $this );
$this->mHideName = (bool)$authUser->isHidden();
+ Hooks::run( 'UserIsHidden', array( $this, &$this->mHideName ) );
}
return $this->mHideName;
}
@@ -2133,6 +2160,7 @@ class User implements IDBAccessObject {
&& $newMessageLinks[0]['wiki'] === wfWikiID()
&& $newMessageLinks[0]['rev']
) {
+ /** @var Revision $newMessageRevision */
$newMessageRevision = $newMessageLinks[0]['rev'];
$newMessageRevisionId = $newMessageRevision->getId();
}
@@ -2209,8 +2237,6 @@ class User implements IDBAccessObject {
* page. Ignored if null or !$val.
*/
public function setNewtalk( $val, $curRev = null ) {
- global $wgMemc;
-
if ( wfReadOnly() ) {
return;
}
@@ -2232,12 +2258,6 @@ class User implements IDBAccessObject {
$changed = $this->deleteNewtalk( $field, $id );
}
- if ( $this->isAnon() ) {
- // Anons have a separate memcached space, since
- // user records aren't kept for them.
- $key = wfMemcKey( 'newtalk', 'ip', $id );
- $wgMemc->set( $key, $val ? 1 : 0, 1800 );
- }
if ( $changed ) {
$this->invalidateCache();
}
@@ -2267,11 +2287,10 @@ class User implements IDBAccessObject {
* Called implicitly from invalidateCache() and saveSettings().
*/
public function clearSharedCache() {
- global $wgMemc;
-
- $this->load();
- if ( $this->mId ) {
- $wgMemc->delete( wfMemcKey( 'user', 'id', $this->mId ) );
+ $id = $this->getId();
+ if ( $id ) {
+ $key = wfMemcKey( 'user', 'id', $id );
+ ObjectCache::getMainWANInstance()->delete( $key );
}
}
@@ -2298,15 +2317,11 @@ class User implements IDBAccessObject {
* @since 1.25
*/
public function touch() {
- global $wgMemc;
-
- $this->load();
-
- if ( $this->mId ) {
- $key = wfMemcKey( 'user-quicktouched', 'id', $this->mId );
- $timestamp = $this->newTouchedTimestamp();
- $wgMemc->set( $key, $timestamp );
- $this->mQuickTouched = $timestamp;
+ $id = $this->getId();
+ if ( $id ) {
+ $key = wfMemcKey( 'user-quicktouched', 'id', $id );
+ ObjectCache::getMainWANInstance()->touchCheckKey( $key );
+ $this->mQuickTouched = null;
}
}
@@ -2321,23 +2336,21 @@ class User implements IDBAccessObject {
/**
* Get the user touched timestamp
+ *
+ * Use this value only to validate caches via inequalities
+ * such as in the case of HTTP If-Modified-Since response logic
+ *
* @return string TS_MW Timestamp
*/
public function getTouched() {
- global $wgMemc;
-
$this->load();
if ( $this->mId ) {
if ( $this->mQuickTouched === null ) {
$key = wfMemcKey( 'user-quicktouched', 'id', $this->mId );
- $timestamp = $wgMemc->get( $key );
- if ( $timestamp ) {
- $this->mQuickTouched = $timestamp;
- } else {
- # Set the timestamp to get HTTP 304 cache hits
- $this->touch();
- }
+ $cache = ObjectCache::getMainWANInstance();
+
+ $this->mQuickTouched = wfTimestamp( TS_MW, $cache->getCheckKeyTime( $key ) );
}
return max( $this->mTouched, $this->mQuickTouched );
@@ -2347,6 +2360,17 @@ class User implements IDBAccessObject {
}
/**
+ * Get the user_touched timestamp field (time of last DB updates)
+ * @return string TS_MW Timestamp
+ * @since 1.26
+ */
+ public function getDBTouched() {
+ $this->load();
+
+ return $this->mTouched;
+ }
+
+ /**
* @return Password
* @since 1.24
*/
@@ -2416,6 +2440,7 @@ class User implements IDBAccessObject {
*/
public function setInternalPassword( $str ) {
$this->setToken();
+ $this->setOption( 'watchlisttoken', false );
$passwordFactory = self::getPasswordFactory();
$this->mPassword = $passwordFactory->newFromPlaintext( $str );
@@ -2693,20 +2718,24 @@ class User implements IDBAccessObject {
* @return string|bool User's current value for the option, or false if this option is disabled.
* @see resetTokenFromOption()
* @see getOption()
+ * @deprecated 1.26 Applications should use the OAuth extension
*/
public function getTokenFromOption( $oname ) {
global $wgHiddenPrefs;
- if ( in_array( $oname, $wgHiddenPrefs ) ) {
+
+ $id = $this->getId();
+ if ( !$id || in_array( $oname, $wgHiddenPrefs ) ) {
return false;
}
$token = $this->getOption( $oname );
if ( !$token ) {
- $token = $this->resetTokenFromOption( $oname );
- if ( !wfReadOnly() ) {
- $this->saveSettings();
- }
+ // Default to a value based on the user token to avoid space
+ // wasted on storing tokens for all users. When this option
+ // is set manually by the user, only then is it stored.
+ $token = hash_hmac( 'sha1', "$oname:$id", $this->getToken() );
}
+
return $token;
}
@@ -3186,10 +3215,10 @@ class User implements IDBAccessObject {
/**
* Check if user is allowed to access a feature / make an action
*
- * @param string $permissions,... Permissions to test
+ * @param string ... Permissions to test
* @return bool True if user is allowed to perform *any* of the given actions
*/
- public function isAllowedAny( /*...*/ ) {
+ public function isAllowedAny() {
$permissions = func_get_args();
foreach ( $permissions as $permission ) {
if ( $this->isAllowed( $permission ) ) {
@@ -3201,10 +3230,10 @@ class User implements IDBAccessObject {
/**
*
- * @param string $permissions,... Permissions to test
+ * @param string ... Permissions to test
* @return bool True if the user is allowed to perform *all* of the given actions
*/
- public function isAllowedAll( /*...*/ ) {
+ public function isAllowedAll() {
$permissions = func_get_args();
foreach ( $permissions as $permission ) {
if ( !$this->isAllowed( $permission ) ) {
@@ -3368,19 +3397,24 @@ class User implements IDBAccessObject {
return;
}
- $nextid = $oldid ? $title->getNextRevisionID( $oldid ) : null;
+ $that = $this;
+ // Try to update the DB post-send and only if needed...
+ DeferredUpdates::addCallableUpdate( function() use ( $that, $title, $oldid ) {
+ if ( !$that->getNewtalk() ) {
+ return; // no notifications to clear
+ }
- if ( !$oldid || !$nextid ) {
- // If we're looking at the latest revision, we should definitely clear it
- $this->setNewtalk( false );
- } else {
- // Otherwise we should update its revision, if it's present
- if ( $this->getNewtalk() ) {
- // Naturally the other one won't clear by itself
- $this->setNewtalk( false );
- $this->setNewtalk( true, Revision::newFromId( $nextid ) );
+ // Delete the last notifications (they stack up)
+ $that->setNewtalk( false );
+
+ // If there is a new, unseen, revision, use its timestamp
+ $nextid = $oldid
+ ? $title->getNextRevisionID( $oldid, Title::GAID_FOR_UPDATE )
+ : null;
+ if ( $nextid ) {
+ $that->setNewtalk( true, Revision::newFromId( $nextid ) );
}
- }
+ } );
}
if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
@@ -3401,7 +3435,9 @@ class User implements IDBAccessObject {
$force = 'force';
}
- $this->getWatchedItem( $title )->resetNotificationTimestamp( $force, $oldid );
+ $this->getWatchedItem( $title )->resetNotificationTimestamp(
+ $force, $oldid, WatchedItem::DEFERRED
+ );
}
/**
@@ -3430,7 +3466,7 @@ class User implements IDBAccessObject {
$dbw = wfGetDB( DB_MASTER );
$dbw->update( 'watchlist',
array( /* SET */ 'wl_notificationtimestamp' => null ),
- array( /* WHERE */ 'wl_user' => $id ),
+ array( /* WHERE */ 'wl_user' => $id, 'wl_notificationtimestamp IS NOT NULL' ),
__METHOD__
);
// We also need to clear here the "you have new message" notification for the own user_talk page;
@@ -3477,6 +3513,31 @@ class User implements IDBAccessObject {
}
/**
+ * Set an extended login cookie on the user's client. The expiry of the cookie
+ * is controlled by the $wgExtendedLoginCookieExpiration configuration
+ * variable.
+ *
+ * @see User::setCookie
+ *
+ * @param string $name Name of the cookie to set
+ * @param string $value Value to set
+ * @param bool $secure
+ * true: Force setting the secure attribute when setting the cookie
+ * false: Force NOT setting the secure attribute when setting the cookie
+ * null (default): Use the default ($wgCookieSecure) to set the secure attribute
+ */
+ protected function setExtendedLoginCookie( $name, $value, $secure ) {
+ global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
+
+ $exp = time();
+ $exp += $wgExtendedLoginCookieExpiration !== null
+ ? $wgExtendedLoginCookieExpiration
+ : $wgCookieExpiration;
+
+ $this->setCookie( $name, $value, $exp, $secure );
+ }
+
+ /**
* Set the default cookies for this session on the user's client.
*
* @param WebRequest|null $request WebRequest object to use; $wgRequest will be used if null
@@ -3485,6 +3546,8 @@ class User implements IDBAccessObject {
* @param bool $rememberMe Whether to add a Token cookie for elongated sessions
*/
public function setCookies( $request = null, $secure = null, $rememberMe = false ) {
+ global $wgExtendedLoginCookies;
+
if ( $request === null ) {
$request = $this->getRequest();
}
@@ -3526,6 +3589,8 @@ class User implements IDBAccessObject {
foreach ( $cookies as $name => $value ) {
if ( $value === false ) {
$this->clearCookie( $name );
+ } elseif ( $rememberMe && in_array( $name, $wgExtendedLoginCookies ) ) {
+ $this->setExtendedLoginCookie( $name, $value, $secure );
} else {
$this->setCookie( $name, $value, 0, $secure, array(), $request );
}
@@ -3598,17 +3663,11 @@ class User implements IDBAccessObject {
return; // anon
}
- // This method is for updating existing users, so the user should
- // have been loaded from the master to begin with to avoid problems.
- if ( !( $this->queryFlagsUsed & self::READ_LATEST ) ) {
- wfWarn( "Attempting to save slave-loaded User object with ID '{$this->mId}'." );
- }
-
// Get a new user_touched that is higher than the old one.
// This will be used for a CAS check as a last-resort safety
// check against race conditions and slave lag.
$oldTouched = $this->mTouched;
- $this->mTouched = $this->newTouchedTimestamp();
+ $newTouched = $this->newTouchedTimestamp();
if ( !$wgAuth->allowSetLocalPassword() ) {
$this->mPassword = self::getPasswordFactory()->newFromCiphertext( null );
@@ -3624,7 +3683,7 @@ class User implements IDBAccessObject {
'user_real_name' => $this->mRealName,
'user_email' => $this->mEmail,
'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
- 'user_touched' => $dbw->timestamp( $this->mTouched ),
+ 'user_touched' => $dbw->timestamp( $newTouched ),
'user_token' => strval( $this->mToken ),
'user_email_token' => $this->mEmailToken,
'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
@@ -3636,16 +3695,17 @@ class User implements IDBAccessObject {
);
if ( !$dbw->affectedRows() ) {
- // User was changed in the meantime or loaded with stale data
- MWExceptionHandler::logException( new MWException(
- "CAS update failed on user_touched for user ID '{$this->mId}'."
- ) );
// Maybe the problem was a missed cache update; clear it to be safe
$this->clearSharedCache();
-
- return;
+ // User was changed in the meantime or loaded with stale data
+ $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'master' : 'slave';
+ throw new MWException(
+ "CAS update failed on user_touched for user ID '{$this->mId}' (read from $from);" .
+ " the version of the user to be saved is older than the current version."
+ );
}
+ $this->mTouched = $newTouched;
$this->saveOptions();
Hooks::run( 'UserSaveSettings', array( $this ) );
@@ -3655,20 +3715,28 @@ class User implements IDBAccessObject {
/**
* If only this user's username is known, and it exists, return the user ID.
+ *
+ * @param int $flags Bitfield of User:READ_* constants; useful for existence checks
* @return int
*/
- public function idForName() {
+ public function idForName( $flags = 0 ) {
$s = trim( $this->getName() );
if ( $s === '' ) {
return 0;
}
- $dbr = wfGetDB( DB_SLAVE );
- $id = $dbr->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__ );
- if ( $id === false ) {
- $id = 0;
- }
- return $id;
+ $db = ( ( $flags & self::READ_LATEST ) == self::READ_LATEST )
+ ? wfGetDB( DB_MASTER )
+ : wfGetDB( DB_SLAVE );
+
+ $options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
+ ? array( 'LOCK IN SHARE MODE' )
+ : array();
+
+ $id = $db->selectField( 'user',
+ 'user_id', array( 'user_name' => $s ), __METHOD__, $options );
+
+ return (int)$id;
}
/**
@@ -4172,22 +4240,25 @@ class User implements IDBAccessObject {
*
* @param string $subject Message subject
* @param string $body Message body
- * @param string $from Optional From address; if unspecified, default
+ * @param User|null $from Optional sending user; if unspecified, default
* $wgPasswordSender will be used.
* @param string $replyto Reply-To address
* @return Status
*/
public function sendMail( $subject, $body, $from = null, $replyto = null ) {
- if ( is_null( $from ) ) {
- global $wgPasswordSender;
+ global $wgPasswordSender;
+
+ if ( $from instanceof User ) {
+ $sender = MailAddress::newFromUser( $from );
+ } else {
$sender = new MailAddress( $wgPasswordSender,
wfMessage( 'emailsender' )->inContentLanguage()->text() );
- } else {
- $sender = MailAddress::newFromUser( $from );
}
-
$to = MailAddress::newFromUser( $this );
- return UserMailer::send( $to, $sender, $subject, $body, $replyto );
+
+ return UserMailer::send( $to, $sender, $subject, $body, array(
+ 'replyTo' => $replyto,
+ ) );
}
/**
@@ -4745,37 +4816,50 @@ class User implements IDBAccessObject {
}
/**
+ * Deferred version of incEditCountImmediate()
+ */
+ public function incEditCount() {
+ $that = $this;
+ wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $that ) {
+ $that->incEditCountImmediate();
+ } );
+ }
+
+ /**
* Increment the user's edit-count field.
* Will have no effect for anonymous users.
+ * @since 1.26
*/
- public function incEditCount() {
- if ( !$this->isAnon() ) {
- $dbw = wfGetDB( DB_MASTER );
- $dbw->update(
- 'user',
- array( 'user_editcount=user_editcount+1' ),
- array( 'user_id' => $this->getId() ),
- __METHOD__
- );
+ public function incEditCountImmediate() {
+ if ( $this->isAnon() ) {
+ return;
+ }
- // Lazy initialization check...
- if ( $dbw->affectedRows() == 0 ) {
- // Now here's a goddamn hack...
- $dbr = wfGetDB( DB_SLAVE );
- if ( $dbr !== $dbw ) {
- // If we actually have a slave server, the count is
- // at least one behind because the current transaction
- // has not been committed and replicated.
- $this->initEditCount( 1 );
- } else {
- // But if DB_SLAVE is selecting the master, then the
- // count we just read includes the revision that was
- // just added in the working transaction.
- $this->initEditCount();
- }
+ $dbw = wfGetDB( DB_MASTER );
+ // No rows will be "affected" if user_editcount is NULL
+ $dbw->update(
+ 'user',
+ array( 'user_editcount=user_editcount+1' ),
+ array( 'user_id' => $this->getId() ),
+ __METHOD__
+ );
+ // Lazy initialization check...
+ if ( $dbw->affectedRows() == 0 ) {
+ // Now here's a goddamn hack...
+ $dbr = wfGetDB( DB_SLAVE );
+ if ( $dbr !== $dbw ) {
+ // If we actually have a slave server, the count is
+ // at least one behind because the current transaction
+ // has not been committed and replicated.
+ $this->initEditCount( 1 );
+ } else {
+ // But if DB_SLAVE is selecting the master, then the
+ // count we just read includes the revision that was
+ // just added in the working transaction.
+ $this->initEditCount();
}
}
- // edit count in user cache too
+ // Edit count in user cache too
$this->invalidateCache();
}
diff --git a/includes/UserRightsProxy.php b/includes/UserRightsProxy.php
index 1b9e4b69..a19f6984 100644
--- a/includes/UserRightsProxy.php
+++ b/includes/UserRightsProxy.php
@@ -278,8 +278,8 @@ class UserRightsProxy {
array( 'user_id' => $this->id ),
__METHOD__ );
- global $wgMemc;
+ $cache = ObjectCache::getMainWANInstance();
$key = wfForeignMemcKey( $this->database, false, 'user', 'id', $this->id );
- $wgMemc->delete( $key );
+ $cache->delete( $key );
}
}
diff --git a/includes/WatchedItem.php b/includes/WatchedItem.php
index 4d226924..adee1264 100644
--- a/includes/WatchedItem.php
+++ b/includes/WatchedItem.php
@@ -27,20 +27,6 @@
* @ingroup Watchlist
*/
class WatchedItem {
- /**
- * Constant to specify that user rights 'editmywatchlist' and
- * 'viewmywatchlist' should not be checked.
- * @since 1.22
- */
- const IGNORE_USER_RIGHTS = 0;
-
- /**
- * Constant to specify that user rights 'editmywatchlist' and
- * 'viewmywatchlist' should be checked.
- * @since 1.22
- */
- const CHECK_USER_RIGHTS = 1;
-
/** @var Title */
public $mTitle;
@@ -60,6 +46,31 @@ class WatchedItem {
private $timestamp;
/**
+ * Constant to specify that user rights 'editmywatchlist' and
+ * 'viewmywatchlist' should not be checked.
+ * @since 1.22
+ */
+ const IGNORE_USER_RIGHTS = 0;
+
+ /**
+ * Constant to specify that user rights 'editmywatchlist' and
+ * 'viewmywatchlist' should be checked.
+ * @since 1.22
+ */
+ const CHECK_USER_RIGHTS = 1;
+
+ /**
+ * Do DB master updates right now
+ * @since 1.26
+ */
+ const IMMEDIATE = 0;
+ /**
+ * Do DB master updates via the job queue
+ * @since 1.26
+ */
+ const DEFERRED = 1;
+
+ /**
* Create a WatchedItem object with the given user and title
* @since 1.22 $checkRights parameter added
* @param User $user The user to use for (un)watching
@@ -208,8 +219,11 @@ class WatchedItem {
* @param bool $force Whether to force the write query to be executed even if the
* page is not watched or the notification timestamp is already NULL.
* @param int $oldid The revision id being viewed. If not given or 0, latest revision is assumed.
+ * @mode int $mode WatchedItem::DEFERRED/IMMEDIATE
*/
- public function resetNotificationTimestamp( $force = '', $oldid = 0 ) {
+ public function resetNotificationTimestamp(
+ $force = '', $oldid = 0, $mode = self::IMMEDIATE
+ ) {
// Only loggedin user can have a watchlist
if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
return;
@@ -240,11 +254,7 @@ class WatchedItem {
} else {
// Oldid given and isn't the latest; update the timestamp.
// This will result in no further notification emails being sent!
- $dbr = wfGetDB( DB_SLAVE );
- $notificationTimestamp = $dbr->selectField(
- 'revision', 'rev_timestamp',
- array( 'rev_page' => $title->getArticleID(), 'rev_id' => $oldid )
- );
+ $notificationTimestamp = Revision::getTimestampFromId( $title, $oldid );
// We need to go one second to the future because of various strict comparisons
// throughout the codebase
$ts = new MWTimestamp( $notificationTimestamp );
@@ -262,11 +272,30 @@ class WatchedItem {
}
}
- // If the page is watched by the user (or may be watched), update the timestamp on any
- // any matching rows
- $dbw = wfGetDB( DB_MASTER );
- $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => $notificationTimestamp ),
- $this->dbCond(), __METHOD__ );
+ // If the page is watched by the user (or may be watched), update the timestamp
+ if ( $mode === self::DEFERRED ) {
+ $job = new ActivityUpdateJob(
+ $title,
+ array(
+ 'type' => 'updateWatchlistNotification',
+ 'userid' => $this->getUserId(),
+ 'notifTime' => $notificationTimestamp,
+ 'curTime' => time()
+ )
+ );
+ // Try to run this post-send
+ DeferredUpdates::addCallableUpdate( function() use ( $job ) {
+ $job->run();
+ } );
+ } else {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update( 'watchlist',
+ array( 'wl_notificationtimestamp' => $notificationTimestamp ),
+ $this->dbCond(),
+ __METHOD__
+ );
+ }
+
$this->timestamp = null;
}
diff --git a/includes/WebRequest.php b/includes/WebRequest.php
index 054eceb9..b4b8be9b 100644
--- a/includes/WebRequest.php
+++ b/includes/WebRequest.php
@@ -39,6 +39,12 @@ class WebRequest {
protected $data, $headers = array();
/**
+ * Flag to make WebRequest::getHeader return an array of values.
+ * @since 1.26
+ */
+ const GETHEADER_LIST = 1;
+
+ /**
* Lazy-init response object
* @var WebResponse
*/
@@ -98,9 +104,9 @@ class WebRequest {
if ( !preg_match( '!^https?://!', $url ) ) {
$url = 'http://unused' . $url;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$a = parse_url( $url );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $a ) {
$path = isset( $a['path'] ) ? $a['path'] : '';
@@ -170,6 +176,8 @@ class WebRequest {
* @return string
*/
public static function detectServer() {
+ global $wgAssumeProxiesUseDefaultProtocolPorts;
+
$proto = self::detectProtocol();
$stdPort = $proto === 'https' ? 443 : 80;
@@ -180,13 +188,15 @@ class WebRequest {
if ( !isset( $_SERVER[$varName] ) ) {
continue;
}
+
$parts = IP::splitHostAndPort( $_SERVER[$varName] );
if ( !$parts ) {
// Invalid, do not use
continue;
}
+
$host = $parts[0];
- if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
+ if ( $wgAssumeProxiesUseDefaultProtocolPorts && isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
// Bug 70021: Assume that upstream proxy is running on the default
// port based on the protocol. We have no reliable way to determine
// the actual port in use upstream.
@@ -685,7 +695,7 @@ class WebRequest {
// This shouldn't happen!
throw new MWException( "Web server doesn't provide either " .
"REQUEST_URI, HTTP_X_ORIGINAL_URL or SCRIPT_NAME. Report details " .
- "of your web server configuration to http://bugzilla.wikimedia.org/" );
+ "of your web server configuration to https://phabricator.wikimedia.org/" );
}
// User-agents should not send a fragment with the URI, but
// if they do, and the web server passes it on to us, we
@@ -768,7 +778,7 @@ class WebRequest {
*
* @param int $deflimit Limit to use if no input and the user hasn't set the option.
* @param string $optionname To specify an option other than rclimit to pull from.
- * @return array First element is limit, second is offset
+ * @return int[] First element is limit, second is offset
*/
public function getLimitOffset( $deflimit = 50, $optionname = 'rclimit' ) {
global $wgUser;
@@ -861,7 +871,7 @@ class WebRequest {
/**
* Initialise the header list
*/
- private function initHeaders() {
+ protected function initHeaders() {
if ( count( $this->headers ) ) {
return;
}
@@ -894,19 +904,28 @@ class WebRequest {
}
/**
- * Get a request header, or false if it isn't set
- * @param string $name Case-insensitive header name
+ * Get a request header, or false if it isn't set.
*
- * @return string|bool False on failure
- */
- public function getHeader( $name ) {
+ * @param string $name Case-insensitive header name
+ * @param int $flags Bitwise combination of:
+ * WebRequest::GETHEADER_LIST Treat the header as a comma-separated list
+ * of values, as described in RFC 2616 § 4.2.
+ * (since 1.26).
+ * @return string|array|bool False if header is unset; otherwise the
+ * header value(s) as either a string (the default) or an array, if
+ * WebRequest::GETHEADER_LIST flag was set.
+ */
+ public function getHeader( $name, $flags = 0 ) {
$this->initHeaders();
$name = strtoupper( $name );
- if ( isset( $this->headers[$name] ) ) {
- return $this->headers[$name];
- } else {
+ if ( !isset( $this->headers[$name] ) ) {
return false;
}
+ $value = $this->headers[$name];
+ if ( $flags & self::GETHEADER_LIST ) {
+ $value = array_map( 'trim', explode( ',', $value ) );
+ }
+ return $value;
}
/**
@@ -1278,6 +1297,7 @@ class FauxRequest extends WebRequest {
private $wasPosted = false;
private $session = array();
private $requestUrl;
+ protected $cookies = array();
/**
* @param array $data Array of *non*-urlencoded key => value pairs, the
@@ -1305,11 +1325,10 @@ class FauxRequest extends WebRequest {
}
/**
- * @param string $method
- * @throws MWException
+ * Initialise the header list
*/
- private function notImplemented( $method ) {
- throw new MWException( "{$method}() not implemented" );
+ protected function initHeaders() {
+ // Nothing to init
}
/**
@@ -1352,7 +1371,38 @@ class FauxRequest extends WebRequest {
}
public function getCookie( $key, $prefix = null, $default = null ) {
- return $default;
+ if ( $prefix === null ) {
+ global $wgCookiePrefix;
+ $prefix = $wgCookiePrefix;
+ }
+ $name = $prefix . $key;
+ return isset( $this->cookies[$name] ) ? $this->cookies[$name] : $default;
+ }
+
+ /**
+ * @since 1.26
+ * @param string $name Unprefixed name of the cookie to set
+ * @param string|null $value Value of the cookie to set
+ * @param string|null $prefix Cookie prefix. Defaults to $wgCookiePrefix
+ */
+ public function setCookie( $key, $value, $prefix = null ) {
+ $this->setCookies( array( $key => $value ), $prefix );
+ }
+
+ /**
+ * @since 1.26
+ * @param array $cookies
+ * @param string|null $prefix Cookie prefix. Defaults to $wgCookiePrefix
+ */
+ public function setCookies( $cookies, $prefix = null ) {
+ if ( $prefix === null ) {
+ global $wgCookiePrefix;
+ $prefix = $wgCookiePrefix;
+ }
+ foreach ( $cookies as $key => $value ) {
+ $name = $prefix . $key;
+ $this->cookies[$name] = $value;
+ }
}
public function checkSessionCookie() {
@@ -1375,21 +1425,22 @@ class FauxRequest extends WebRequest {
}
/**
- * @param string $name The name of the header to get (case insensitive).
- * @return bool|string
+ * @param string $name
+ * @param string $val
*/
- public function getHeader( $name ) {
- $name = strtoupper( $name );
- return isset( $this->headers[$name] ) ? $this->headers[$name] : false;
+ public function setHeader( $name, $val ) {
+ $this->setHeaders( array( $name => $val ) );
}
/**
- * @param string $name
- * @param string $val
+ * @since 1.26
+ * @param array $headers
*/
- public function setHeader( $name, $val ) {
- $name = strtoupper( $name );
- $this->headers[$name] = $val;
+ public function setHeaders( $headers ) {
+ foreach ( $headers as $name => $val ) {
+ $name = strtoupper( $name );
+ $this->headers[$name] = $val;
+ }
}
/**
@@ -1488,8 +1539,8 @@ class DerivativeRequest extends FauxRequest {
return $this->base->checkSessionCookie();
}
- public function getHeader( $name ) {
- return $this->base->getHeader( $name );
+ public function getHeader( $name, $flags = 0 ) {
+ return $this->base->getHeader( $name, $flags );
}
public function getAllHeaders() {
diff --git a/includes/WebResponse.php b/includes/WebResponse.php
index ab34931c..1b6947cd 100644
--- a/includes/WebResponse.php
+++ b/includes/WebResponse.php
@@ -28,7 +28,7 @@
class WebResponse {
/**
- * Output a HTTP header, wrapper for PHP's header()
+ * Output an HTTP header, wrapper for PHP's header()
* @param string $string Header to output
* @param bool $replace Replace current similar header
* @param null|int $http_response_code Forces the HTTP response code to the specified value.
@@ -54,6 +54,15 @@ class WebResponse {
}
/**
+ * Output an HTTP status code header
+ * @since 1.26
+ * @param int $code Status code
+ */
+ public function statusHeader( $code ) {
+ HttpStatus::header( $code );
+ }
+
+ /**
* Set the browser cookie
* @param string $name The name of the cookie.
* @param string $value The value to be stored in the cookie.
@@ -163,6 +172,14 @@ class FauxResponse extends WebResponse {
}
/**
+ * @since 1.26
+ * @param int $code Status code
+ */
+ public function statusHeader( $code ) {
+ $this->code = intval( $code );
+ }
+
+ /**
* @param string $key The name of the header to get (case insensitive).
* @return string|null The header value (if set); null otherwise.
*/
diff --git a/includes/WebStart.php b/includes/WebStart.php
index 9c71f3e1..f5a4f93b 100644
--- a/includes/WebStart.php
+++ b/includes/WebStart.php
@@ -78,7 +78,6 @@ if ( $IP === false ) {
# Grab profiling functions
require_once "$IP/includes/profiler/ProfilerFunctions.php";
-$wgRUstart = wfGetRusage() ?: array();
# Start the autoloader, so that extensions can derive classes from core files
require_once "$IP/includes/AutoLoader.php";
@@ -137,3 +136,8 @@ if ( ob_get_level() == 0 ) {
if ( !defined( 'MW_NO_SETUP' ) ) {
require_once "$IP/includes/Setup.php";
}
+
+# Multiple DBs or commits might be used; keep the request as transactional as possible
+if ( isset( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] === 'POST' ) {
+ ignore_user_abort( true );
+}
diff --git a/includes/WikiMap.php b/includes/WikiMap.php
index f16f5aa7..027ff72f 100644
--- a/includes/WikiMap.php
+++ b/includes/WikiMap.php
@@ -108,13 +108,15 @@ class WikiMap {
*
* @param string $wikiID Wiki'd id (generally database name)
* @param string $page Page name (must be normalised before calling this function!)
+ * @param string|null $fragmentId
+ *
* @return string|bool URL or false if the wiki was not found
*/
- public static function getForeignURL( $wikiID, $page ) {
+ public static function getForeignURL( $wikiID, $page, $fragmentId = null ) {
$wiki = WikiMap::getWiki( $wikiID );
if ( $wiki ) {
- return $wiki->getFullUrl( $page );
+ return $wiki->getFullUrl( $page, $fragmentId );
}
return false;
@@ -147,33 +149,18 @@ class WikiReference {
}
/**
- * @return string
- * @throws MWException
- */
- public function getHostname() {
- $prefixes = array( 'http://', 'https://' );
- foreach ( $prefixes as $prefix ) {
- if ( substr( $this->mCanonicalServer, 0, strlen( $prefix ) ) ) {
- return substr( $this->mCanonicalServer, strlen( $prefix ) );
- }
- }
- throw new MWException( "Invalid hostname for wiki {$this->mMinor}.{$this->mMajor}" );
- }
-
- /**
* Get the URL in a way to be displayed to the user
* More or less Wikimedia specific
*
* @return string
*/
public function getDisplayName() {
- $url = $this->getUrl( '' );
- $parsed = wfParseUrl( $url );
+ $parsed = wfParseUrl( $this->mCanonicalServer );
if ( $parsed ) {
return $parsed['host'];
} else {
- // Invalid URL. There's no sane thing to do here, so just return it
- return $url;
+ // Invalid server spec. There's no sane thing to do here, so just return the canonical server name in full
+ return $this->mCanonicalServer;
}
}
@@ -181,21 +168,32 @@ class WikiReference {
* Helper function for getUrl()
*
* @todo FIXME: This may be generalized...
- * @param string $page Page name (must be normalised before calling this function!)
- * @return string Url fragment
+ *
+ * @param string $page Page name (must be normalised before calling this function! May contain a section part.)
+ * @param string|null $fragmentId
+ *
+ * @return string relative URL, without the server part.
*/
- private function getLocalUrl( $page ) {
- return str_replace( '$1', wfUrlEncode( str_replace( ' ', '_', $page ) ), $this->mPath );
+ private function getLocalUrl( $page, $fragmentId = null ) {
+ $page = wfUrlEncode( str_replace( ' ', '_', $page ) );
+
+ if ( is_string( $fragmentId ) && $fragmentId !== '' ) {
+ $page .= '#' . wfUrlEncode( $fragmentId );
+ }
+
+ return str_replace( '$1', $page, $this->mPath );
}
/**
* Get a canonical (i.e. based on $wgCanonicalServer) URL to a page on this foreign wiki
*
* @param string $page Page name (must be normalised before calling this function!)
+ * @param string|null $fragmentId
+ *
* @return string Url
*/
- public function getCanonicalUrl( $page ) {
- return $this->mCanonicalServer . $this->getLocalUrl( $page );
+ public function getCanonicalUrl( $page, $fragmentId = null ) {
+ return $this->mCanonicalServer . $this->getLocalUrl( $page, $fragmentId );
}
/**
@@ -209,10 +207,12 @@ class WikiReference {
/**
* Alias for getCanonicalUrl(), for backwards compatibility.
* @param string $page
+ * @param string|null $fragmentId
+ *
* @return string
*/
- public function getUrl( $page ) {
- return $this->getCanonicalUrl( $page );
+ public function getUrl( $page, $fragmentId = null ) {
+ return $this->getCanonicalUrl( $page, $fragmentId );
}
/**
@@ -220,10 +220,12 @@ class WikiReference {
* when called locally on the wiki.
*
* @param string $page Page name (must be normalized before calling this function!)
+ * @param string|null $fragmentId
+ *
* @return string URL
*/
- public function getFullUrl( $page ) {
+ public function getFullUrl( $page, $fragmentId = null ) {
return $this->mServer .
- $this->getLocalUrl( $page );
+ $this->getLocalUrl( $page, $fragmentId );
}
}
diff --git a/includes/Xml.php b/includes/Xml.php
index f0bd70b2..37cffdef 100644
--- a/includes/Xml.php
+++ b/includes/Xml.php
@@ -144,26 +144,19 @@ class Xml {
public static function monthSelector( $selected = '', $allmonths = null, $id = 'month' ) {
global $wgLang;
$options = array();
+ $data = new XmlSelect( 'month', $id, $selected );
if ( is_null( $selected ) ) {
$selected = '';
}
if ( !is_null( $allmonths ) ) {
- $options[] = self::option(
- wfMessage( 'monthsall' )->text(),
- $allmonths,
- $selected === $allmonths
- );
+ $options[wfMessage( 'monthsall' )->text()] = $allmonths;
}
for ( $i = 1; $i < 13; $i++ ) {
- $options[] = self::option( $wgLang->getMonthName( $i ), $i, $selected === $i );
+ $options[$wgLang->getMonthName( $i )] = $i;
}
- return self::openElement( 'select', array(
- 'id' => $id,
- 'name' => 'month',
- 'class' => 'mw-month-selector'
- ) )
- . implode( "\n", $options )
- . self::closeElement( 'select' );
+ $data->addOptions( $options );
+ $data->setAttribute( 'class', 'mw-month-selector' );
+ return $data->getHTML();
}
/**
@@ -871,112 +864,6 @@ class Xml {
}
}
-class XmlSelect {
- protected $options = array();
- protected $default = false;
- protected $attributes = array();
-
- public function __construct( $name = false, $id = false, $default = false ) {
- if ( $name ) {
- $this->setAttribute( 'name', $name );
- }
-
- if ( $id ) {
- $this->setAttribute( 'id', $id );
- }
-
- if ( $default !== false ) {
- $this->default = $default;
- }
- }
-
- /**
- * @param string $default
- */
- public function setDefault( $default ) {
- $this->default = $default;
- }
-
- /**
- * @param string $name
- * @param array $value
- */
- public function setAttribute( $name, $value ) {
- $this->attributes[$name] = $value;
- }
-
- /**
- * @param string $name
- * @return array|null
- */
- public function getAttribute( $name ) {
- if ( isset( $this->attributes[$name] ) ) {
- return $this->attributes[$name];
- } else {
- return null;
- }
- }
-
- /**
- * @param string $name
- * @param bool $value
- */
- public function addOption( $name, $value = false ) {
- // Stab stab stab
- $value = $value !== false ? $value : $name;
-
- $this->options[] = array( $name => $value );
- }
-
- /**
- * This accepts an array of form
- * label => value
- * label => ( label => value, label => value )
- *
- * @param array $options
- */
- public function addOptions( $options ) {
- $this->options[] = $options;
- }
-
- /**
- * This accepts an array of form
- * label => value
- * label => ( label => value, label => value )
- *
- * @param array $options
- * @param bool $default
- * @return string
- */
- static function formatOptions( $options, $default = false ) {
- $data = '';
-
- foreach ( $options as $label => $value ) {
- if ( is_array( $value ) ) {
- $contents = self::formatOptions( $value, $default );
- $data .= Html::rawElement( 'optgroup', array( 'label' => $label ), $contents ) . "\n";
- } else {
- $data .= Xml::option( $label, $value, $value === $default ) . "\n";
- }
- }
-
- return $data;
- }
-
- /**
- * @return string
- */
- public function getHTML() {
- $contents = '';
-
- foreach ( $this->options as $options ) {
- $contents .= self::formatOptions( $options, $this->default );
- }
-
- return Html::rawElement( 'select', $this->attributes, rtrim( $contents ) );
- }
-}
-
/**
* A wrapper class which causes Xml::encodeJsVar() and Xml::encodeJsCall() to
* interpret a given string as being a JavaScript expression, instead of string
diff --git a/includes/XmlSelect.php b/includes/XmlSelect.php
new file mode 100644
index 00000000..78f47645
--- /dev/null
+++ b/includes/XmlSelect.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * Class for generating HTML <select> elements.
+ *
+ * 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
+ */
+
+/**
+ * Class for generating HTML <select> elements.
+ */
+class XmlSelect {
+ protected $options = array();
+ protected $default = false;
+ protected $attributes = array();
+
+ public function __construct( $name = false, $id = false, $default = false ) {
+ if ( $name ) {
+ $this->setAttribute( 'name', $name );
+ }
+
+ if ( $id ) {
+ $this->setAttribute( 'id', $id );
+ }
+
+ if ( $default !== false ) {
+ $this->default = $default;
+ }
+ }
+
+ /**
+ * @param string|array $default
+ */
+ public function setDefault( $default ) {
+ $this->default = $default;
+ }
+
+ /**
+ * @param string $name
+ * @param string $value
+ */
+ public function setAttribute( $name, $value ) {
+ $this->attributes[$name] = $value;
+ }
+
+ /**
+ * @param string $name
+ * @return string|null
+ */
+ public function getAttribute( $name ) {
+ if ( isset( $this->attributes[$name] ) ) {
+ return $this->attributes[$name];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @param string $label
+ * @param string $value If not given, assumed equal to $label
+ */
+ public function addOption( $label, $value = false ) {
+ $value = $value !== false ? $value : $label;
+ $this->options[] = array( $label => $value );
+ }
+
+ /**
+ * This accepts an array of form
+ * label => value
+ * label => ( label => value, label => value )
+ *
+ * @param array $options
+ */
+ public function addOptions( $options ) {
+ $this->options[] = $options;
+ }
+
+ /**
+ * This accepts an array of form:
+ * label => value
+ * label => ( label => value, label => value )
+ *
+ * @param array $options
+ * @param string|array $default
+ * @return string
+ */
+ static function formatOptions( $options, $default = false ) {
+ $data = '';
+
+ foreach ( $options as $label => $value ) {
+ if ( is_array( $value ) ) {
+ $contents = self::formatOptions( $value, $default );
+ $data .= Html::rawElement( 'optgroup', array( 'label' => $label ), $contents ) . "\n";
+ } else {
+ // If $default is an array, then the <select> probably has the multiple attribute,
+ // so we should check if each $value is in $default, rather than checking if
+ // $value is equal to $default.
+ $selected = is_array( $default ) ? in_array( $value, $default ) : $value === $default;
+ $data .= Xml::option( $label, $value, $selected ) . "\n";
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * @return string
+ */
+ public function getHTML() {
+ $contents = '';
+
+ foreach ( $this->options as $options ) {
+ $contents .= self::formatOptions( $options, $this->default );
+ }
+
+ return Html::rawElement( 'select', $this->attributes, rtrim( $contents ) );
+ }
+}
diff --git a/includes/ZhConversion.php b/includes/ZhConversion.php
index 4be27513..893ae040 100644
--- a/includes/ZhConversion.php
+++ b/includes/ZhConversion.php
@@ -46,7 +46,6 @@ $zh2Hant = array(
'㱮' => '殨',
'㲿' => '瀇',
'㳔' => '濧',
-'㳕' => '灡',
'㳠' => '澾',
'㳡' => '濄',
'㳢' => '𣾷',
@@ -79,7 +78,6 @@ $zh2Hant = array(
'䍁' => '繸',
'䎬' => '䎱',
'䏝' => '膞',
-'䓕' => '薳',
'䓖' => '藭',
'䗖' => '螮',
'䘛' => '𧝞',
@@ -375,6 +373,7 @@ $zh2Hant = array(
'啰' => '囉',
'啴' => '嘽',
'啸' => '嘯',
+'喂' => '餵',
'喷' => '噴',
'喽' => '嘍',
'喾' => '嚳',
@@ -415,7 +414,6 @@ $zh2Hant = array(
'垭' => '埡',
'垱' => '壋',
'垲' => '塏',
-'垴' => '堖',
'埘' => '塒',
'埙' => '塤',
'埚' => '堝',
@@ -504,7 +502,6 @@ $zh2Hant = array(
'岖' => '嶇',
'岗' => '崗',
'岘' => '峴',
-'岙' => '嶴',
'岚' => '嵐',
'岛' => '島',
'岭' => '嶺',
@@ -1373,6 +1370,7 @@ $zh2Hant = array(
'脶' => '腡',
'脸' => '臉',
'腊' => '臘',
+'腌' => '醃',
'腘' => '膕',
'腭' => '齶',
'腻' => '膩',
@@ -1477,7 +1475,6 @@ $zh2Hant = array(
'虑' => '慮',
'虚' => '虛',
'虫' => '蟲',
-'虬' => '虯',
'虮' => '蟣',
'虽' => '雖',
'虾' => '蝦',
@@ -2889,7 +2886,6 @@ $zh2Hant = array(
'𩧿' => '䮠',
'𩨀' => '騔',
'𩨁' => '䮞',
-'𩨂' => '驄',
'𩨃' => '騝',
'𩨄' => '騪',
'𩨅' => '𩤸',
@@ -3002,8 +2998,8 @@ $zh2Hant = array(
'𫛢' => '鸋',
'𫛶' => '鶒',
'𫛸' => '鶗',
-'0出現' => '0出現',
'0出现' => '0出現',
+'0出現' => '0出現',
'0出線' => '0出線',
'0出线' => '0出線',
'0只支持' => '0只支持',
@@ -3079,6 +3075,8 @@ $zh2Hant = array(
'9余' => '9餘',
'·范' => '·范',
'’s' => '’s',
+'、面点' => '、麵點',
+'。个中' => '。箇中',
'〇周后' => '〇周後',
'〇年' => '〇年',
'〇只' => '〇隻',
@@ -3116,6 +3114,7 @@ $zh2Hant = array(
'一争两丑' => '一爭兩醜',
'一物克一物' => '一物剋一物',
'一目了然' => '一目了然',
+'一碗面' => '一碗麵',
'一扎' => '一紮',
'一冲' => '一衝',
'一厘一毫' => '一釐一毫',
@@ -3188,6 +3187,7 @@ $zh2Hant = array(
'下签' => '下籤',
'下课钟' => '下課鐘',
'不干不净' => '不乾不淨',
+'不干胶' => '不乾膠',
'不克自制' => '不克自制',
'不加自制' => '不加自制',
'不占凶吉' => '不占凶吉',
@@ -3201,26 +3201,11 @@ $zh2Hant = array(
'不好干预' => '不好干預',
'不嫌母丑' => '不嫌母醜',
'不寒而栗' => '不寒而慄',
-'不干事' => '不干事',
-'不干他' => '不干他',
-'不干休' => '不干休',
-'不干你' => '不干你',
-'不干她' => '不干她',
-'不干它' => '不干它',
-'不干我' => '不干我',
-'不干擾' => '不干擾',
-'不干扰' => '不干擾',
-'不干涉' => '不干涉',
-'不干牠' => '不干牠',
-'不干犯' => '不干犯',
-'不干預' => '不干預',
-'不干预' => '不干預',
-'不干' => '不幹',
'不吊' => '不弔',
'不卷' => '不捲',
'不采' => '不採',
-'不斗膽' => '不斗膽',
'不斗胆' => '不斗膽',
+'不斗膽' => '不斗膽',
'不断发' => '不斷發',
'不每只' => '不每只',
'不谷' => '不穀',
@@ -3228,8 +3213,8 @@ $zh2Hant = array(
'不负所托' => '不負所托',
'不通吊庆' => '不通弔慶',
'不丑' => '不醜',
-'不采聲' => '不采聲',
'不采声' => '不采聲',
+'不采聲' => '不采聲',
'不锈钢' => '不鏽鋼',
'不食干腊' => '不食乾腊',
'不斗' => '不鬥',
@@ -3260,6 +3245,7 @@ $zh2Hant = array(
'中型钟表面' => '中型鐘表面',
'中型钟表' => '中型鐘錶',
'中型钟面' => '中型鐘面',
+'中境里' => '中境里',
'中岳' => '中嶽',
'中庄子' => '中庄子',
'中文里' => '中文裡',
@@ -3275,31 +3261,36 @@ $zh2Hant = array(
'中签订' => '中簽訂',
'中签' => '中籤',
'中风后' => '中風後',
-'丰儀' => '丰儀',
'丰仪' => '丰儀',
+'丰儀' => '丰儀',
'丰南' => '丰南',
'丰姿' => '丰姿',
'丰容' => '丰容',
-'丰度' => '丰度',
'丰情' => '丰情',
'丰标' => '丰標',
-'丰標不凡' => '丰標不凡',
'丰标不凡' => '丰標不凡',
+'丰標不凡' => '丰標不凡',
'丰神' => '丰神',
'丰茸' => '丰茸',
'丰采' => '丰采',
-'丰韻' => '丰韻',
'丰韵' => '丰韻',
+'丰韻' => '丰韻',
+'丹棱' => '丹稜',
'主仆' => '主僕',
'主干' => '主幹',
'主钟差' => '主鐘差',
'主钟曲线' => '主鐘曲線',
'乃系' => '乃係',
'么么唱唱' => '么么唱唱',
+'么九' => '么九',
'么儿' => '么兒',
+'么半' => '么半',
'么喝' => '么喝',
+'么女' => '么女',
'么妹' => '么妹',
+'么子' => '么子',
'么弟' => '么弟',
+'么正' => '么正',
'么爷' => '么爺',
'么雞' => '么雞',
'么么小丑' => '么麼小丑',
@@ -3321,12 +3312,8 @@ $zh2Hant = array(
'九扎' => '九紮',
'九只' => '九隻',
'九余' => '九餘',
-'也斗了胆' => '也斗了膽',
-'干上' => '乾上',
'干干' => '乾乾',
-'干干儿的' => '乾乾兒的',
'干干净净' => '乾乾淨淨',
-'干了' => '乾了',
'干井' => '乾井',
'干个够' => '乾個夠',
'干儿' => '乾兒',
@@ -3349,12 +3336,12 @@ $zh2Hant = array(
'干回付' => '乾回付',
'干圆洁净' => '乾圓潔淨',
'干地' => '乾地',
-'干坤' => '乾坤',
'干坞' => '乾塢',
'干女' => '乾女',
'干奴才' => '乾奴才',
'干妹' => '乾妹',
'干姊' => '乾姊',
+'干姐' => '乾姐',
'干娘' => '乾娘',
'干妈' => '乾媽',
'干子' => '乾子',
@@ -3364,7 +3351,6 @@ $zh2Hant = array(
'干巴' => '乾巴',
'干式' => '乾式',
'干弟' => '乾弟',
-'干得' => '乾得',
'干急' => '乾急',
'干性' => '乾性',
'干打雷' => '乾打雷',
@@ -3374,7 +3360,6 @@ $zh2Hant = array(
'干擦' => '乾擦',
'干支剌' => '乾支剌',
'干支支' => '乾支支',
-'干敲梆子不卖油' => '乾敲梆子不賣油',
'干料' => '乾料',
'干旱' => '乾旱',
'干暖' => '乾暖',
@@ -3418,6 +3403,7 @@ $zh2Hant = array(
'干癣' => '乾癬',
'干瘾' => '乾癮',
'干白儿' => '乾白兒',
+'干白葡萄酒' => '乾白葡萄酒',
'干的' => '乾的',
'干眼' => '乾眼',
'干瞪眼' => '乾瞪眼',
@@ -3428,6 +3414,7 @@ $zh2Hant = array(
'干篾片' => '乾篾片',
'干粉' => '乾粉',
'干粮' => '乾糧',
+'干红葡萄酒' => '乾紅葡萄酒',
'干结' => '乾結',
'干丝' => '乾絲',
'干纲' => '乾綱',
@@ -3464,13 +3451,14 @@ $zh2Hant = array(
'干醋' => '乾醋',
'干重' => '乾重',
'干量' => '乾量',
+'干锅' => '乾鍋',
'干阿奶' => '乾阿奶',
-'干隆' => '乾隆',
'干雷' => '乾雷',
'干电' => '乾電',
'干霍乱' => '乾霍亂',
'干颡' => '乾顙',
'干台' => '乾颱',
+'干食' => '乾食',
'干饭' => '乾飯',
'干馆' => '乾館',
'干糇' => '乾餱',
@@ -3481,13 +3469,10 @@ $zh2Hant = array(
'乱发生' => '亂發生',
'乱发脾气' => '亂發脾氣',
'乱发' => '亂髮',
-'乱哄' => '亂鬨',
-'乱哄不过来' => '亂鬨不過來',
+'乱哄哄' => '亂鬨鬨',
'了然后' => '了然後',
-'事情干脆' => '事情干脆',
'事有斗巧' => '事有鬥巧',
'事里' => '事裡',
-'事都干脆' => '事都干脆',
'二不棱登' => '二不稜登',
'二个' => '二個',
'二只得' => '二只得',
@@ -3507,11 +3492,11 @@ $zh2Hant = array(
'于仲文' => '于仲文',
'于佳卉' => '于佳卉',
'于来山' => '于來山',
-'于偉國' => '于偉國',
'于伟国' => '于偉國',
+'于偉國' => '于偉國',
'于光新' => '于光新',
-'于光遠' => '于光遠',
'于光远' => '于光遠',
+'于光遠' => '于光遠',
'于克-兰多县' => '于克-蘭多縣',
'于克-蘭多縣' => '于克-蘭多縣',
'于克勒' => '于克勒',
@@ -3530,12 +3515,12 @@ $zh2Hant = array(
'于吉' => '于吉',
'于和伟' => '于和偉',
'于品海' => '于品海',
-'于國楨' => '于國楨',
'于国桢' => '于國楨',
+'于國楨' => '于國楨',
'于国治' => '于國治',
'于國治' => '于國治',
-'于堅' => '于堅',
'于坚' => '于堅',
+'于堅' => '于堅',
'于大宝' => '于大寶',
'于大寶' => '于大寶',
'于天仁' => '于天仁',
@@ -3558,12 +3543,12 @@ $zh2Hant = array(
'于小惠' => '于小惠',
'于少保' => '于少保',
'于山' => '于山',
-'于山國' => '于山國',
'于山国' => '于山國',
+'于山國' => '于山國',
'于帅' => '于帥',
'于帥' => '于帥',
-'于幼軍' => '于幼軍',
'于幼军' => '于幼軍',
+'于幼軍' => '于幼軍',
'于康震' => '于康震',
'于广洲' => '于廣洲',
'于廣洲' => '于廣洲',
@@ -3571,14 +3556,14 @@ $zh2Hant = array(
'于从濂' => '于從濂',
'于從濂' => '于從濂',
'于德海' => '于德海',
-'于志寧' => '于志寧',
'于志宁' => '于志寧',
+'于志寧' => '于志寧',
'于忠肃集' => '于忠肅集',
'于思' => '于思',
'于慎行' => '于慎行',
'于慧' => '于慧',
-'于成龙' => '于成龍',
'于成龍' => '于成龍',
+'于成龙' => '于成龍',
'于振' => '于振',
'于振武' => '于振武',
'于敏' => '于敏',
@@ -3587,24 +3572,24 @@ $zh2Hant = array(
'于斯塔德' => '于斯塔德',
'于斯納爾斯貝里' => '于斯納爾斯貝里',
'于斯纳尔斯贝里' => '于斯納爾斯貝里',
-'于斯達爾' => '于斯達爾',
'于斯达尔' => '于斯達爾',
-'于明濤' => '于明濤',
+'于斯達爾' => '于斯達爾',
'于明涛' => '于明濤',
+'于明濤' => '于明濤',
'于是之' => '于是之',
'于晨楠' => '于晨楠',
'于晴' => '于晴',
'于会泳' => '于會泳',
'于會泳' => '于會泳',
-'于根偉' => '于根偉',
'于根伟' => '于根偉',
+'于根偉' => '于根偉',
'于格' => '于格',
'于枫' => '于楓',
'于楓' => '于楓',
'于荣光' => '于榮光',
'于樂' => '于樂',
-'于樹潔' => '于樹潔',
'于树洁' => '于樹潔',
+'于樹潔' => '于樹潔',
'于欣' => '于欣',
'于欣源' => '于欣源',
'于正昇' => '于正昇',
@@ -3615,18 +3600,18 @@ $zh2Hant = array(
'于江震' => '于江震',
'于波' => '于波',
'于洋' => '于洋',
-'于洪區' => '于洪區',
'于洪区' => '于洪區',
+'于洪區' => '于洪區',
'于浩威' => '于浩威',
'于海' => '于海',
'于海洋' => '于海洋',
-'于湘蘭' => '于湘蘭',
'于湘兰' => '于湘蘭',
-'于漢超' => '于漢超',
+'于湘蘭' => '于湘蘭',
'于汉超' => '于漢超',
+'于漢超' => '于漢超',
'于澄' => '于澄',
-'于澤爾' => '于澤爾',
'于泽尔' => '于澤爾',
+'于澤爾' => '于澤爾',
'于涛' => '于濤',
'于濤' => '于濤',
'于熙珍' => '于熙珍',
@@ -3655,10 +3640,9 @@ $zh2Hant = array(
'于谨' => '于謹',
'于貝爾' => '于貝爾',
'于贝尔' => '于貝爾',
-'于赠' => '于贈',
'于贈' => '于贈',
+'于赠' => '于贈',
'于越' => '于越',
-'于军' => '于軍',
'于軍' => '于軍',
'于道泉' => '于道泉',
'于远伟' => '于遠偉',
@@ -3679,23 +3663,23 @@ $zh2Hant = array(
'于非闇' => '于非闇',
'于韋斯屈萊' => '于韋斯屈萊',
'于韦斯屈莱' => '于韋斯屈萊',
-'于风政' => '于風政',
'于風政' => '于風政',
+'于风政' => '于風政',
+'于飛' => '于飛',
'于飞' => '于飛',
-'于飛島' => '于飛島',
-'于飞岛' => '于飛島',
'于余曲折' => '于餘曲折',
'于鬯' => '于鬯',
'于魁智' => '于魁智',
-'于鳳桐' => '于鳳桐',
'于凤桐' => '于鳳桐',
-'于鳳至' => '于鳳至',
+'于鳳桐' => '于鳳桐',
'于凤至' => '于鳳至',
-'于默奧' => '于默奧',
+'于鳳至' => '于鳳至',
'于默奥' => '于默奧',
+'于默奧' => '于默奧',
'云乎' => '云乎',
'云云' => '云云',
'云何' => '云何',
+'云敞' => '云敞',
'云为' => '云為',
'云為' => '云為',
'云然' => '云然',
@@ -3704,6 +3688,7 @@ $zh2Hant = array(
'五个' => '五個',
'五周后' => '五周後',
'五天后' => '五天後',
+'五峰县' => '五峯縣',
'五岳' => '五嶽',
'五年' => '五年',
'五谷' => '五穀',
@@ -3715,7 +3700,6 @@ $zh2Hant = array(
'五只' => '五隻',
'五余' => '五餘',
'井干' => '井幹',
-'井干摧败' => '井榦摧敗',
'井里' => '井裡',
'亚于' => '亞於',
'亚美尼亚历' => '亞美尼亞曆',
@@ -3723,27 +3707,31 @@ $zh2Hant = array(
'交游' => '交遊',
'交哄' => '交鬨',
'亦云' => '亦云',
+'京沈' => '京瀋',
'亮丑' => '亮醜',
'亮钟' => '亮鐘',
'人云' => '人云',
'人如风后入江云' => '人如風後入江雲',
+'人干的' => '人幹的',
'人欲' => '人慾',
'人数只' => '人數只',
'人数里' => '人數裡',
'人物志' => '人物誌',
'人生天里' => '人生天里',
+'人发指' => '人髮指',
'什锦面' => '什錦麵',
'仇仇' => '仇讎',
'介胄' => '介冑',
+'他干的' => '他幹的',
'他钟' => '他鐘',
'付托' => '付託',
'仙后' => '仙后',
'仙后座' => '仙后座',
+'仙游' => '仙遊',
'代数里' => '代數裡',
'代理发行' => '代理發行',
'代码表' => '代碼表',
'代表' => '代表',
-'令人发指' => '令人髮指',
'以自制' => '以自制',
'仲裁制' => '仲裁制',
'件钟' => '件鐘',
@@ -3767,6 +3755,7 @@ $zh2Hant = array(
'伊郁' => '伊鬱',
'伏几' => '伏几',
'伐罪吊民' => '伐罪弔民',
+'休克期' => '休克期',
'休征' => '休徵',
'伙头' => '伙頭',
'伴游' => '伴遊',
@@ -3791,15 +3780,13 @@ $zh2Hant = array(
'佛罗棱萨' => '佛羅稜薩',
'佛钟' => '佛鐘',
'作品里' => '作品裡',
-'作奸犯科' => '作姦犯科',
'作准' => '作準',
-'你斗了胆' => '你斗了膽',
'你夸' => '你誇',
'佣金' => '佣金',
'佣鈿' => '佣鈿',
'佣钿' => '佣鈿',
-'佣钱' => '佣錢',
'佣錢' => '佣錢',
+'佣钱' => '佣錢',
'佳肴' => '佳肴',
'佳里鎮' => '佳里鎮',
'并一不二' => '併一不二',
@@ -3808,7 +3795,7 @@ $zh2Hant = array(
'并到' => '併到',
'并合' => '併合',
'并名' => '併名',
-'并吞' => '併吞',
+'并吞下' => '併吞下',
'并拢' => '併攏',
'并案' => '併案',
'并流' => '併流',
@@ -3834,6 +3821,7 @@ $zh2Hant = array(
'依托' => '依託',
'侵并' => '侵併',
'局促' => '侷促',
+'便于' => '便於',
'系数' => '係數',
'系为' => '係為',
'保险柜' => '保險柜',
@@ -3843,17 +3831,17 @@ $zh2Hant = array(
'修杰麟' => '修杰麟',
'修胡刀' => '修鬍刀',
'俯冲' => '俯衝',
+'个月里' => '個月裡',
'个里' => '個裡',
'个钟' => '個鐘',
'个钟表' => '個鐘錶',
-'们斗了胆' => '們斗了膽',
+'们干的' => '們幹的',
'幸免' => '倖免',
'幸存' => '倖存',
'幸幸' => '倖幸',
'候复' => '候覆',
'倚闲' => '倚閑',
'倛丑' => '倛醜',
-'借听于聋' => '借聽於聾',
'借鉴' => '借鑑',
'倦游' => '倦遊',
'假里' => '假裡',
@@ -3870,11 +3858,12 @@ $zh2Hant = array(
'佣仆' => '傭僕',
'傲游' => '傲遊',
'傲霜斗雪' => '傲霜鬥雪',
-'傳位于四太子' => '傳位于四太子',
'传位于四太子' => '傳位于四太子',
+'傳位于四太子' => '傳位于四太子',
'传于' => '傳於',
'债累累' => '債纍纍',
'傻里傻气' => '傻裡傻氣',
+'仅余' => '僅餘',
'仆人' => '僕人',
'仆使' => '僕使',
'仆仆' => '僕僕',
@@ -3956,14 +3945,15 @@ $zh2Hant = array(
'凶险' => '兇險',
'先采' => '先採',
'光致致' => '光緻緻',
+'克期间' => '克期間',
'免征' => '免徵',
'党太尉' => '党太尉',
'党姓' => '党姓',
'党家' => '党家',
'党怀英' => '党懷英',
'党进' => '党進',
-'党项' => '党項',
'党項' => '党項',
+'党项' => '党項',
'内脏' => '內臟',
'内制' => '內製',
'内面包' => '內面包',
@@ -3971,8 +3961,6 @@ $zh2Hant = array(
'内斗' => '內鬥',
'内哄' => '內鬨',
'全干' => '全乾',
-'全面包围' => '全面包圍',
-'全面包裹' => '全面包裹',
'两个' => '兩個',
'两周后' => '兩周後',
'两天后' => '兩天後',
@@ -4032,10 +4020,10 @@ $zh2Hant = array(
'冷面相' => '冷面相',
'冷面' => '冷麵',
'准三后' => '准三后',
-'准保護' => '准保護',
'准保护' => '准保護',
-'准保釋' => '准保釋',
+'准保護' => '准保護',
'准保释' => '准保釋',
+'准保釋' => '准保釋',
'凌蒙初' => '凌濛初',
'凝炼' => '凝鍊',
'几上' => '几上',
@@ -4065,8 +4053,8 @@ $zh2Hant = array(
'分子钟' => '分子鐘',
'分子云' => '分子雲',
'分布于' => '分布於',
-'分散于' => '分散於',
'分钟' => '分鐘',
+'分钟里' => '分鐘裡',
'刑余' => '刑餘',
'划一桨' => '划一槳',
'划上' => '划上',
@@ -4074,8 +4062,8 @@ $zh2Hant = array(
'划不來' => '划不來',
'划不来' => '划不來',
'划了一会' => '划了一會',
-'划来划去' => '划來划去',
'划來划去' => '划來划去',
+'划来划去' => '划來划去',
'划具' => '划具',
'划到岸' => '划到岸',
'划到江心' => '划到江心',
@@ -4086,29 +4074,30 @@ $zh2Hant = array(
'划得來' => '划得來',
'划得来' => '划得來',
'划拳' => '划拳',
-'划槳' => '划槳',
'划桨' => '划槳',
+'划槳' => '划槳',
'划水' => '划水',
+'划着独木舟' => '划着獨木舟',
+'划着竹筏' => '划着竹筏',
+'划着船' => '划着船',
'划算' => '划算',
'划船' => '划船',
'划艇' => '划艇',
-'划著' => '划著',
'划行' => '划行',
'划走' => '划走',
'划起' => '划起',
-'划進' => '划進',
'划进' => '划進',
+'划進' => '划進',
'划过' => '划過',
'划過' => '划過',
-'划龙舟' => '划龍舟',
'划龍舟' => '划龍舟',
+'划龙舟' => '划龍舟',
'判断发' => '判斷發',
'别辟' => '別闢',
'利欲' => '利慾',
'利于' => '利於',
'刮来刮去' => '刮來刮去',
'刮起来' => '刮起來',
-'刮风下雪倒便宜' => '刮風下雪倒便宜',
'刮胡' => '刮鬍',
'到山里' => '到山裡',
'制冷机' => '制冷機',
@@ -4136,7 +4125,6 @@ $zh2Hant = array(
'剥制' => '剝製',
'剩余' => '剩餘',
'剪其发' => '剪其髮',
-'剪牡丹喂牛' => '剪牡丹喂牛',
'剪发' => '剪髮',
'割舍' => '割捨',
'创获' => '創穫',
@@ -4148,8 +4136,9 @@ $zh2Hant = array(
'铲头' => '剷頭',
'划入' => '劃入',
'划为' => '劃為',
-'劉佳怜' => '劉佳怜',
+'划著' => '劃著名',
'刘佳怜' => '劉佳怜',
+'劉佳怜' => '劉佳怜',
'刘芸后' => '劉芸后',
'力拼' => '力拚',
'力拼众敌' => '力拼眾敵',
@@ -4157,7 +4146,6 @@ $zh2Hant = array(
'功勋' => '功勳',
'功致' => '功緻',
'加氢精制' => '加氫精制',
-'加注' => '加註',
'劣于' => '劣於',
'助于' => '助於',
'劫余' => '劫餘',
@@ -4179,6 +4167,7 @@ $zh2Hant = array(
'包扎' => '包紮',
'匏系' => '匏繫',
'北山索面' => '北山索麵',
+'北仑河' => '北崙河',
'北岳' => '北嶽',
'北回线' => '北迴線',
'北回铁路' => '北迴鐵路',
@@ -4214,6 +4203,7 @@ $zh2Hant = array(
'千钧一发' => '千鈞一髮',
'千只' => '千隻',
'千余' => '千餘',
+'升高后' => '升高後',
'半制品' => '半制品',
'半只可' => '半只可',
'半只够' => '半只夠',
@@ -4230,21 +4220,17 @@ $zh2Hant = array(
'南回线' => '南迴線',
'南回铁路' => '南迴鐵路',
'南游' => '南遊',
-'博汇' => '博彙',
'博采' => '博採',
'博尔术' => '博爾朮',
'卜云吉' => '卜云吉',
'占了卜' => '占了卜',
-'占便宜的是呆' => '占便宜的是獃',
'印累绶若' => '印纍綬若',
'印制' => '印製',
'印鉴' => '印鑑',
'危于' => '危於',
'卵与石斗' => '卵與石鬥',
-'卷发' => '卷髮',
'卷须' => '卷鬚',
'厂部' => '厂部',
-'厝薪于火' => '厝薪於火',
'原子钟' => '原子鐘',
'原钟' => '原鐘',
'历物之意' => '厤物之意',
@@ -4254,9 +4240,10 @@ $zh2Hant = array(
'反朴' => '反樸',
'反冲' => '反衝',
'反复制' => '反複製',
-'反覆' => '反覆',
'反复' => '反覆',
+'反覆' => '反覆',
'取舍' => '取捨',
+'取决于' => '取決於',
'受雇' => '受僱',
'受托' => '受託',
'丛林里' => '叢林裡',
@@ -4270,12 +4257,13 @@ $zh2Hant = array(
'口腹之欲' => '口腹之慾',
'口里' => '口裡',
'口钟' => '口鐘',
-'古書云' => '古書云',
+'古人有云' => '古人有云',
'古书云' => '古書云',
+'古書云' => '古書云',
'古柯咸' => '古柯鹹',
'古朴' => '古樸',
-'古语云' => '古語云',
'古語云' => '古語云',
+'古语云' => '古語云',
'古迹' => '古蹟',
'古钟' => '古鐘',
'古钟表' => '古鐘錶',
@@ -4294,8 +4282,8 @@ $zh2Hant = array(
'只身上有' => '只身上有',
'只身上沒' => '只身上沒',
'只身上没' => '只身上沒',
-'只身上無' => '只身上無',
'只身上无' => '只身上無',
+'只身上無' => '只身上無',
'只身上的' => '只身上的',
'只身世' => '只身世',
'只身份' => '只身份',
@@ -4304,19 +4292,19 @@ $zh2Hant = array(
'只身子' => '只身子',
'只身形' => '只身形',
'只身影' => '只身影',
-'只身後' => '只身後',
'只身后' => '只身後',
+'只身後' => '只身後',
'只身心' => '只身心',
'只身旁' => '只身旁',
'只身材' => '只身材',
'只身段' => '只身段',
'只身为' => '只身為',
'只身為' => '只身為',
-'只身邊' => '只身邊',
'只身边' => '只身邊',
+'只身邊' => '只身邊',
'只身首' => '只身首',
-'只身體' => '只身體',
'只身体' => '只身體',
+'只身體' => '只身體',
'只身高' => '只身高',
'只采声' => '只采聲',
'叮叮当当' => '叮叮噹噹',
@@ -4339,9 +4327,11 @@ $zh2Hant = array(
'叶音' => '叶音',
'叶韵' => '叶韻',
'吃板刀面' => '吃板刀麵',
+'吃碗面' => '吃碗麵',
'吃姜' => '吃薑',
'吃里扒外' => '吃裡扒外',
'吃里爬外' => '吃裡爬外',
+'吃面' => '吃麵',
'各辟' => '各闢',
'各类钟' => '各類鐘',
'合伙人' => '合伙人',
@@ -4359,6 +4349,7 @@ $zh2Hant = array(
'同伙' => '同夥',
'同于' => '同於',
'同余' => '同餘',
+'名单于' => '名單於',
'后冠' => '后冠',
'后北街' => '后北街',
'后土' => '后土',
@@ -4369,19 +4360,19 @@ $zh2Hant = array(
'后庄' => '后庄',
'后座' => '后座',
'后母戊' => '后母戊',
-'后海灣' => '后海灣',
'后海湾' => '后海灣',
+'后海灣' => '后海灣',
'后瑞站' => '后瑞站',
'后稷' => '后稷',
'后綜' => '后綜',
'后羿' => '后羿',
'后街' => '后街',
'后角' => '后角',
-'后豐' => '后豐',
'后丰' => '后豐',
+'后豐' => '后豐',
'后里' => '后里',
-'后髮FK型星' => '后髮FK型星',
'后发FK型星' => '后髮FK型星',
+'后髮FK型星' => '后髮FK型星',
'后发座' => '后髮座',
'后髮座' => '后髮座',
'后发星系团' => '后髮星系團',
@@ -4402,19 +4393,21 @@ $zh2Hant = array(
'吾为之范我驰驱' => '吾爲之範我馳驅',
'吕后' => '呂后',
'呂后' => '呂后',
-'呆呆兽' => '呆呆獸',
'呆致致' => '呆緻緻',
'呆里呆气' => '呆裡呆氣',
'告札' => '告劄',
+'呦喂' => '呦喂',
'周后' => '周后',
+'周惠后' => '周惠后',
'周历' => '周曆',
-'周杰倫' => '周杰倫',
-'周杰伦' => '周杰倫',
+'周杰' => '周杰',
'周历史' => '周歷史',
-'周游' => '周遊',
+'周游列国' => '周遊列國',
+'呵喂' => '呵喂',
'呼吁' => '呼籲',
'命中注定' => '命中注定',
'和奸' => '和姦',
+'和制汉' => '和製漢',
'咎征' => '咎徵',
'咕咕钟' => '咕咕鐘',
'咪表' => '咪錶',
@@ -4422,7 +4415,6 @@ $zh2Hant = array(
'咯当' => '咯噹',
'哀吊' => '哀弔',
'哀挽' => '哀輓',
-'品汇' => '品彙',
'品鉴' => '品鑑',
'哄堂大笑' => '哄堂大笑',
'員山庄' => '員山庄',
@@ -4437,9 +4429,14 @@ $zh2Hant = array(
'商历' => '商曆',
'商标准许' => '商標准許',
'商历史' => '商歷史',
+'啊喂' => '啊喂',
'启发式' => '啟發式',
'啷当' => '啷噹',
'喂了一声' => '喂了一聲',
+'喂喂' => '喂喂',
+'喂哟' => '喂喲',
+'喂!' => '喂!',
+'喂,' => '喂,',
'善于' => '善於',
'喜向往' => '喜向往',
'喜欢表' => '喜歡錶',
@@ -4450,11 +4447,13 @@ $zh2Hant = array(
'喧哄' => '喧鬨',
'丧钟' => '喪鐘',
'乔岳' => '喬嶽',
-'單于' => '單于',
'单于' => '單于',
+'單于' => '單于',
'单单于' => '單單於',
'单干' => '單幹',
'单打独斗' => '單打獨鬥',
+'哟喂' => '喲喂',
+'喲喂' => '喲喂',
'嘉谷' => '嘉穀',
'嘉肴' => '嘉肴',
'嘴里' => '嘴裡',
@@ -4507,6 +4506,7 @@ $zh2Hant = array(
'回游' => '回遊',
'因于' => '因於',
'困倦起来' => '困倦起來',
+'困于' => '困於',
'困兽之斗' => '困獸之鬥',
'困兽犹斗' => '困獸猶鬥',
'困斗' => '困鬥',
@@ -4558,6 +4558,7 @@ $zh2Hant = array(
'埃及历史' => '埃及歷史',
'埃及艳后' => '埃及豔后',
'埃荣冲' => '埃榮衝',
+'城市里' => '城市裡',
'城里' => '城裡',
'埔子里' => '埔子里',
'埔里社' => '埔裏社',
@@ -4570,13 +4571,18 @@ $zh2Hant = array(
'堡子里' => '堡子里',
'场里' => '場裡',
'塞耳盗钟' => '塞耳盜鐘',
+'境里' => '境裡',
+'境里程' => '境里程',
'墓志铭' => '墓志銘',
'墓志' => '墓誌',
'增辟' => '增闢',
'墨子里' => '墨子里',
-'墨沈' => '墨沈',
-'墨沈未干' => '墨瀋未乾',
+'墨斗' => '墨斗',
+'墨沈沈' => '墨沈沈',
+'墨沈' => '墨瀋',
'垦辟' => '墾闢',
+'压制出' => '壓製出',
+'压制机' => '壓製機',
'壮游' => '壯遊',
'壮面' => '壯麵',
'壹郁' => '壹鬱',
@@ -4597,16 +4603,16 @@ $zh2Hant = array(
'多只含' => '多只含',
'多只在' => '多只在',
'多只是' => '多只是',
-'多只會' => '多只會',
'多只会' => '多只會',
+'多只會' => '多只會',
'多只有' => '多只有',
'多只比' => '多只比',
'多只用' => '多只用',
'多只能' => '多只能',
'多只限' => '多只限',
'多只需' => '多只需',
-'多只须' => '多只須',
'多只須' => '多只須',
+'多只须' => '多只須',
'多周后' => '多周後',
'多天后' => '多天後',
'多于' => '多於',
@@ -4665,7 +4671,6 @@ $zh2Hant = array(
'大钟' => '大鐘',
'大只' => '大隻',
'大风后' => '大風後',
-'大曲酒' => '大麴酒',
'天克地冲' => '天克地衝',
'天后' => '天后',
'天后宫' => '天后宮',
@@ -4691,15 +4696,10 @@ $zh2Hant = array(
'太后' => '太后',
'太丑' => '太醜',
'太阁' => '太閤',
-'夯干' => '夯幹',
-'夸人' => '夸人',
'夸克' => '夸克',
-'夸姣' => '夸姣',
-'夸容' => '夸容',
'夸父' => '夸父',
'夸特' => '夸特',
'夸脱' => '夸脫',
-'夸丽' => '夸麗',
'奇勋' => '奇勳',
'奇迹' => '奇蹟',
'奇丑' => '奇醜',
@@ -4710,7 +4710,6 @@ $zh2Hant = array(
'女仆' => '女僕',
'奴仆' => '奴僕',
'奸淫掳掠' => '奸淫擄掠',
-'好干' => '好乾',
'好家伙' => '好傢夥',
'好凶' => '好兇',
'好勇斗狠' => '好勇鬥狠',
@@ -4734,7 +4733,6 @@ $zh2Hant = array(
'始于' => '始於',
'委托' => '委託',
'委托书' => '委託書',
-'姜文杰' => '姜文杰',
'奸夫' => '姦夫',
'奸妇' => '姦婦',
'奸宄' => '姦宄',
@@ -4761,11 +4759,12 @@ $zh2Hant = array(
'字汇' => '字彙',
'字码表' => '字碼表',
'字里行间' => '字裡行間',
-'存十一于千百' => '存十一於千百',
'存折' => '存摺',
'存于' => '存於',
'孛里海' => '孛里海',
-'孤寡不谷' => '孤寡不穀',
+'孝惠后' => '孝惠后',
+'孙杰' => '孫杰',
+'孫杰' => '孫杰',
'学家' => '學家',
'学里' => '學裡',
'宇宙志' => '宇宙誌',
@@ -4805,10 +4804,10 @@ $zh2Hant = array(
'实干' => '實幹',
'实累累' => '實纍纍',
'写字台' => '寫字檯',
-'宽宽松松' => '寬寬鬆鬆',
'宽于' => '寬於',
'宽余' => '寬餘',
'宽松' => '寬鬆',
+'宽松松' => '寬鬆鬆',
'寮采' => '寮寀',
'寶山庄' => '寶山庄',
'宝历' => '寶曆',
@@ -4832,6 +4831,7 @@ $zh2Hant = array(
'对准表' => '對準錶',
'对准钟' => '對準鐘',
'对准钟表' => '對準鐘錶',
+'对着干' => '對着幹',
'对华发' => '對華發',
'对表中' => '對表中',
'对表扬' => '對表揚',
@@ -4841,6 +4841,7 @@ $zh2Hant = array(
'对表达' => '對表達',
'导游' => '導遊',
'小丑' => '小丑',
+'小井里' => '小井里',
'小价' => '小价',
'小仆' => '小僕',
'小几' => '小几',
@@ -4856,13 +4857,16 @@ $zh2Hant = array(
'小型钟表面' => '小型鐘表面',
'小型钟表' => '小型鐘錶',
'小型钟面' => '小型鐘面',
+'小时里' => '小時裡',
'小米面' => '小米麵',
'小只' => '小隻',
'少采' => '少採',
'就范' => '就範',
'就里' => '就裡',
'尸位素餐' => '尸位素餐',
+'尸佼' => '尸佼',
'尸利' => '尸利',
+'尸子' => '尸子',
'尸居余气' => '尸居餘氣',
'尸弃佛' => '尸棄佛',
'尸祝' => '尸祝',
@@ -4892,26 +4896,29 @@ $zh2Hant = array(
'山羊胡' => '山羊鬍',
'山里有' => '山裡有',
'山里的' => '山裡的',
-'山谷道' => '山谷道',
+'山谷' => '山谷',
'山重水复' => '山重水複',
+'岫岩' => '岫巖',
'岱岳' => '岱嶽',
'峇里海' => '峇里海',
'峰回' => '峰迴',
'峻岭' => '峻岭',
-'昆剧' => '崑劇',
'崑剧' => '崑劇',
+'昆剧' => '崑劇',
'崑山' => '崑山',
'昆山' => '崑山',
'昆冈' => '崑岡',
'昆仑' => '崑崙',
+'昆嵛' => '崑嵛',
+'昆承湖' => '崑承湖',
'崑曲' => '崑曲',
'昆曲' => '崑曲',
-'昆腔' => '崑腔',
'崑腔' => '崑腔',
-'昆苏' => '崑蘇',
+'昆腔' => '崑腔',
'崑苏' => '崑蘇',
-'昆调' => '崑調',
+'昆苏' => '崑蘇',
'崑调' => '崑調',
+'昆调' => '崑調',
'崖广' => '崖广',
'嶒棱' => '嶒稜',
'岳岳' => '嶽嶽',
@@ -4923,7 +4930,6 @@ $zh2Hant = array(
'工作台' => '工作檯',
'工致' => '工緻',
'左冲右突' => '左衝右突',
-'巧妇做不得无面馎饦' => '巧婦做不得無麵餺飥',
'巧干' => '巧幹',
'巧历' => '巧曆',
'巧历史' => '巧歷史',
@@ -4935,7 +4941,7 @@ $zh2Hant = array(
'已占算' => '已占算',
'巴尔干' => '巴爾幹',
'巷里' => '巷裡',
-'市里' => '市裡',
+'市里的' => '市裡的',
'布谷' => '布穀',
'布谷鸟' => '布穀鳥',
'布谷鸟钟' => '布穀鳥鐘',
@@ -4948,6 +4954,7 @@ $zh2Hant = array(
'师范' => '師範',
'席卷' => '席捲',
'带征' => '帶徵',
+'带余' => '帶餘',
'带发修行' => '帶髮修行',
'幅图里' => '幅圖裡',
'干系' => '干係',
@@ -4960,19 +4967,22 @@ $zh2Hant = array(
'年里' => '年裡',
'年鉴' => '年鑑',
'并力' => '并力',
+'并吞' => '并吞',
'并州' => '并州',
'并日而食' => '并日而食',
'并迭' => '并迭',
'幸免于难' => '幸免於難',
'幸于' => '幸於',
'幸运胡' => '幸運鬍',
+'干上' => '幹上',
'干下去' => '幹下去',
'干不了' => '幹不了',
'干不成' => '幹不成',
+'干了' => '幹了',
'干事' => '幹事',
'干些' => '幹些',
-'干人' => '幹人',
'干什么' => '幹什麼',
+'干仗' => '幹仗',
'干个' => '幹個',
'干劲' => '幹勁',
'干吏' => '幹吏',
@@ -4981,10 +4991,10 @@ $zh2Hant = array(
'干吗' => '幹嗎',
'干嘛' => '幹嘛',
'干坏事' => '幹壞事',
+'干大事' => '幹大事',
'干完' => '幹完',
'干家' => '幹家',
-'干将' => '幹將',
-'干得了' => '幹得了',
+'干得' => '幹得',
'干性油' => '幹性油',
'干才' => '幹才',
'干掉' => '幹掉',
@@ -4999,7 +5009,8 @@ $zh2Hant = array(
'干甚么' => '幹甚麼',
'干略' => '幹略',
'干当' => '幹當',
-'干的停当' => '幹的停當',
+'干的事' => '幹的事',
+'干的好事' => '幹的好事',
'干细胞' => '幹細胞',
'干线' => '幹線',
'干练' => '幹練',
@@ -5010,8 +5021,7 @@ $zh2Hant = array(
'干起来' => '幹起來',
'干路' => '幹路',
'干办' => '幹辦',
-'干这一行' => '幹這一行',
-'干这种事' => '幹這種事',
+'干这' => '幹這',
'干道' => '幹道',
'干部' => '幹部',
'干革命' => '幹革命',
@@ -5027,8 +5037,8 @@ $zh2Hant = array(
'床席' => '床蓆',
'店里' => '店裡',
'府干卿' => '府干卿',
-'府干擾' => '府干擾',
'府干扰' => '府干擾',
+'府干擾' => '府干擾',
'府干政' => '府干政',
'府干涉' => '府干涉',
'府干犯' => '府干犯',
@@ -5041,8 +5051,8 @@ $zh2Hant = array(
'厨余' => '廚餘',
'厮斗' => '廝鬥',
'庙里' => '廟裡',
-'廢后' => '廢后',
'废后' => '廢后',
+'廢后' => '廢后',
'广征' => '廣徵',
'广舍' => '廣捨',
'延历' => '延曆',
@@ -5093,9 +5103,11 @@ $zh2Hant = array(
'弘历史' => '弘歷史',
'弱于' => '弱於',
'弱水三千只取一瓢' => '弱水三千只取一瓢',
-'張三丰' => '張三丰',
'张三丰' => '張三丰',
+'張三丰' => '張三丰',
'张勋' => '張勳',
+'张杰' => '張杰',
+'張杰' => '張杰',
'张乐于张徐' => '張樂于張徐',
'强制作用' => '強制作用',
'强奸' => '強姦',
@@ -5109,13 +5121,9 @@ $zh2Hant = array(
'弹子台' => '彈子檯',
'弹珠台' => '彈珠檯',
'汇刊' => '彙刊',
-'汇报' => '彙報',
-'汇整' => '彙整',
'汇算' => '彙算',
-'汇编' => '彙編',
'汇纂' => '彙纂',
'汇辑' => '彙輯',
-'汇集' => '彙集',
'形单影只' => '形單影隻',
'形于' => '形於',
'彭于晏' => '彭于晏',
@@ -5129,15 +5137,18 @@ $zh2Hant = array(
'很凶' => '很兇',
'很准' => '很準',
'很丑' => '很醜',
+'很松' => '很鬆',
'律历志' => '律曆志',
'后印' => '後印',
'后台老板' => '後台老板',
'后天' => '後天',
+'後庄' => '後庄',
'后面店' => '後面店',
'徐干' => '徐幹',
'徒杠' => '徒杠',
'徒托空言' => '徒託空言',
'得到回复' => '得到回覆',
+'得力干将' => '得力幹將',
'从仆' => '從僕',
'从图里' => '從圖裡',
'从山里' => '從山裡',
@@ -5326,9 +5337,9 @@ $zh2Hant = array(
'忠人之托' => '忠人之托',
'忠仆' => '忠僕',
'忠于' => '忠於',
-'快干' => '快乾',
'快快当当' => '快快當當',
'快冲' => '快衝',
+'怎么干' => '怎麼幹',
'怒于' => '怒於',
'怒气冲天' => '怒氣衝天',
'怒火冲天' => '怒火衝天',
@@ -5343,7 +5354,9 @@ $zh2Hant = array(
'怪里怪气' => '怪裡怪氣',
'怫郁' => '怫鬱',
'恂栗' => '恂慄',
+'恒基' => '恒基',
'恒生' => '恒生',
+'恒隆' => '恒隆',
'恕乏价催' => '恕乏价催',
'息交绝游' => '息交絕遊',
'息谷' => '息穀',
@@ -5381,6 +5394,7 @@ $zh2Hant = array(
'愿而恭' => '愿而恭',
'栗冽' => '慄冽',
'栗栗' => '慄慄',
+'慈溪' => '慈谿',
'慌里慌张' => '慌裡慌張',
'惨淡' => '慘澹',
'庆吊' => '慶弔',
@@ -5406,9 +5420,8 @@ $zh2Hant = array(
'应征' => '應徵',
'应钟' => '應鐘',
'懔栗' => '懍慄',
-'蒙懂' => '懞懂',
-'蒙蒙懂懂' => '懞懞懂懂',
-'蒙直' => '懞直',
+'懞懞懂懂' => '懞懞懂懂',
+'懞直' => '懞直',
'惩忿窒欲' => '懲忿窒欲',
'怀里' => '懷裡',
'怀钟' => '懷鐘',
@@ -5424,6 +5437,7 @@ $zh2Hant = array(
'截发' => '截髮',
'战天斗地' => '戰天鬥地',
'战栗' => '戰慄',
+'战于' => '戰於',
'战斗' => '戰鬥',
'戏里' => '戲裡',
'戲院里' => '戲院里',
@@ -5437,20 +5451,19 @@ $zh2Hant = array(
'所占算' => '所占算',
'所托' => '所託',
'扁拟谷盗虫' => '扁擬穀盜蟲',
-'手冢治虫' => '手塚治虫',
'手塚治虫' => '手塚治虫',
'手折' => '手摺',
-'手表態' => '手表態',
'手表态' => '手表態',
+'手表態' => '手表態',
'手表明' => '手表明',
-'手表決' => '手表決',
'手表决' => '手表決',
+'手表決' => '手表決',
'手表演' => '手表演',
-'手表現' => '手表現',
'手表现' => '手表現',
+'手表現' => '手表現',
'手表示' => '手表示',
-'手表達' => '手表達',
'手表达' => '手表達',
+'手表達' => '手表達',
'手表露' => '手表露',
'手表面' => '手表面',
'手里剑' => '手裏劍',
@@ -5484,7 +5497,6 @@ $zh2Hant = array(
'打斗' => '打鬥',
'托管国' => '托管國',
'扛大梁' => '扛大樑',
-'捍御' => '扞禦',
'扯面' => '扯麵',
'扶余' => '扶餘',
'批准的' => '批准的',
@@ -5492,7 +5504,6 @@ $zh2Hant = array(
'批复' => '批覆',
'批注' => '批註',
'批斗' => '批鬥',
-'承制' => '承製',
'抑制作用' => '抑制作用',
'抑制剂' => '抑制劑',
'抑郁' => '抑鬱',
@@ -5573,6 +5584,7 @@ $zh2Hant = array(
'捉奸党' => '捉奸黨',
'捉奸' => '捉姦',
'捉发' => '捉髮',
+'捍御' => '捍禦',
'捏面人' => '捏麵人',
'舍不得' => '捨不得',
'舍入' => '捨入',
@@ -5620,7 +5632,6 @@ $zh2Hant = array(
'卷纸' => '捲紙',
'卷缩' => '捲縮',
'卷舌' => '捲舌',
-'卷铺盖' => '捲舖蓋',
'卷烟' => '捲菸',
'卷叶蛾' => '捲葉蛾',
'卷袖' => '捲袖',
@@ -5628,9 +5639,10 @@ $zh2Hant = array(
'卷起' => '捲起',
'卷轴' => '捲軸',
'卷逃' => '捲逃',
+'卷铺盖' => '捲鋪蓋',
'卷云' => '捲雲',
'卷风' => '捲風',
-'卷发器' => '捲髮器',
+'卷发' => '捲髮',
'捵面' => '捵麵',
'捶炼' => '捶鍊',
'扫荡' => '掃蕩',
@@ -5686,8 +5698,8 @@ $zh2Hant = array(
'采种' => '採種',
'采空区' => '採空區',
'采空采穗' => '採空採穗',
-'采纳' => '採納',
'采納' => '採納',
+'采纳' => '採納',
'采给' => '採給',
'采花' => '採花',
'采芹人' => '採芹人',
@@ -5697,6 +5709,7 @@ $zh2Hant = array(
'采薇' => '採薇',
'采薪' => '採薪',
'采药' => '採藥',
+'采血' => '採血',
'采行' => '採行',
'采补' => '採補',
'采访' => '採訪',
@@ -5719,11 +5732,11 @@ $zh2Hant = array(
'控制' => '控制',
'推情准理' => '推情準理',
'推托之词' => '推托之詞',
-'推舟于陆' => '推舟於陸',
'推托' => '推託',
'提子干' => '提子乾',
'提心吊胆' => '提心弔膽',
'提摩太后书' => '提摩太後書',
+'提高后' => '提高後',
'插于' => '插於',
'换签' => '換籤',
'换只' => '換隻',
@@ -5734,8 +5747,8 @@ $zh2Hant = array(
'揪发' => '揪髮',
'揪须' => '揪鬚',
'揭丑' => '揭醜',
-'揮手表' => '揮手表',
'挥手表' => '揮手表',
+'揮手表' => '揮手表',
'搋面' => '搋麵',
'损于' => '損於',
'搏斗' => '搏鬥',
@@ -5773,7 +5786,8 @@ $zh2Hant = array(
'撩斗' => '撩鬥',
'播于' => '播於',
'扑冬' => '撲鼕',
-'扑冬冬' => '撲鼕鼕',
+'扑咚' => '撲鼕',
+'扑咚咚' => '撲鼕鼕',
'擀面' => '擀麵',
'击扑' => '擊扑',
'击钟' => '擊鐘',
@@ -5781,7 +5795,6 @@ $zh2Hant = array(
'担仔面' => '擔仔麵',
'担担面' => '擔擔麵',
'据云' => '據云',
-'据干而窥井底' => '據榦而窺井底',
'擢发' => '擢髮',
'擦干' => '擦乾',
'擦干净' => '擦乾淨',
@@ -5791,9 +5804,10 @@ $zh2Hant = array(
'支干' => '支幹',
'支配欲' => '支配慾',
'收获' => '收穫',
+'改制成' => '改制成',
'改征' => '改徵',
'改采' => '改採',
-'放蒙挣' => '放懞掙',
+'放懞挣' => '放懞掙',
'放荡' => '放蕩',
'放松' => '放鬆',
'政斗' => '政鬥',
@@ -5840,14 +5854,15 @@ $zh2Hant = array(
'数与虏确' => '數與虜确',
'数只' => '數隻',
'文丑' => '文丑',
-'文汇报' => '文匯報',
'文学志' => '文學誌',
'文征明' => '文徵明',
'文思泉涌' => '文思泉湧',
+'文杰' => '文杰',
'文采郁郁' => '文采郁郁',
'斗牛星' => '斗牛星',
'斫雕为朴' => '斫雕為樸',
'新井里美' => '新井里美',
+'新干县' => '新幹縣',
'新历' => '新曆',
'新历史' => '新歷史',
'新扎' => '新紮',
@@ -5855,123 +5870,23 @@ $zh2Hant = array(
'断发' => '斷髮',
'断发文身' => '斷髮文身',
'方便面' => '方便麵',
-'方几' => '方几',
'方向往' => '方向往',
'方志恒' => '方志恒',
'方法里' => '方法裡',
'方志' => '方誌',
-'方面' => '方面',
-'于0' => '於0',
-'于1' => '於1',
-'于2' => '於2',
-'于3' => '於3',
-'于4' => '於4',
-'于5' => '於5',
-'于6' => '於6',
-'于7' => '於7',
-'于8' => '於8',
-'于9' => '於9',
-'于一' => '於一',
-'于一役' => '於一役',
-'于七' => '於七',
-'于三' => '於三',
-'于世' => '於世',
-'于之' => '於之',
-'于乎' => '於乎',
-'于九' => '於九',
-'于事' => '於事',
-'于二' => '於二',
-'于五' => '於五',
-'于人' => '於人',
-'于今' => '於今',
-'于他' => '於他',
-'于伏' => '於伏',
-'于何' => '於何',
-'于你' => '於你',
-'于八' => '於八',
-'于六' => '於六',
-'于前' => '於前',
-'于劣' => '於劣',
-'于勤' => '於勤',
-'于十' => '於十',
-'于半' => '於半',
-'于呼哀哉' => '於呼哀哉',
-'于四' => '於四',
-'于国' => '於國',
-'于坏' => '於坏',
-'于垂' => '於垂',
-'于夫罗' => '於夫羅',
-'於夫罗' => '於夫羅',
-'於夫羅' => '於夫羅',
-'于她' => '於她',
-'于好' => '於好',
-'于始' => '於始',
-'於姓' => '於姓',
-'于它' => '於它',
-'于家' => '於家',
-'于密' => '於密',
-'于差' => '於差',
-'于己' => '於己',
-'于市' => '於市',
-'于幕' => '於幕',
-'于弱' => '於弱',
-'于强' => '於強',
'于后' => '於後',
'于征' => '於徵',
-'于心' => '於心',
-'于怀' => '於懷',
-'于我' => '於我',
-'于戏' => '於戲',
-'于敝' => '於敝',
-'于斯' => '於斯',
-'于是' => '於是',
-'于是乎' => '於是乎',
-'于时' => '於時',
-'于梨华' => '於梨華',
-'於梨華' => '於梨華',
-'于乐' => '於樂',
-'于此' => '於此',
-'於氏' => '於氏',
-'于民' => '於民',
-'于水' => '於水',
-'于法' => '於法',
'于海上' => '於海上',
'于海边' => '於海邊',
-'于潜县' => '於潛縣',
-'于火' => '於火',
-'于焉' => '於焉',
-'于墙' => '於牆',
-'于物' => '於物',
-'于毕' => '於畢',
-'于尽' => '於盡',
-'于盲' => '於盲',
-'于祂' => '於祂',
-'于穆' => '於穆',
-'于终' => '於終',
-'于美' => '於美',
-'于色' => '於色',
-'于菟' => '於菟',
-'于蓝' => '於藍',
-'于行' => '於行',
-'于衷' => '於衷',
-'于该' => '於該',
-'于农' => '於農',
-'于途' => '於途',
-'于过' => '於過',
-'于邑' => '於邑',
-'于丑' => '於醜',
-'于野' => '於野',
-'于陆' => '於陸',
'于震中' => '於震中',
'于震前' => '於震前',
-'于震后' => '於震后',
+'于震后' => '於震後',
'施舍' => '施捨',
'施于' => '施於',
'施舍之道' => '施舍之道',
'旁征博引' => '旁徵博引',
'旁注' => '旁註',
'旅游' => '旅遊',
-'旋干转坤' => '旋乾轉坤',
'旋回' => '旋迴',
'族里' => '族裡',
'日心历表' => '日心曆表',
@@ -5991,11 +5906,13 @@ $zh2Hant = array(
'明范' => '明範',
'明鉴' => '明鑑',
'易于' => '易於',
+'昔人有云' => '昔人有云',
'星历' => '星曆',
'星期后' => '星期後',
'星历史' => '星歷史',
'春游' => '春遊',
'春香斗学' => '春香鬥學',
+'昭惠后' => '昭惠后',
'是发小' => '是髮小',
'时钟' => '時鐘',
'时间不准' => '時間不準',
@@ -6004,7 +5921,7 @@ $zh2Hant = array(
'晚钟' => '晚鐘',
'晞发' => '晞髮',
'晨钟' => '晨鐘',
-'普冬冬' => '普鼕鼕',
+'普咚咚' => '普鼕鼕',
'晾干' => '晾乾',
'暗地里' => '暗地裡',
'暗沟里' => '暗溝裡',
@@ -6018,7 +5935,7 @@ $zh2Hant = array(
'历始' => '曆始',
'历室' => '曆室',
'历尾' => '曆尾',
-'历数' => '曆數',
+'历数书' => '曆數書',
'历日' => '曆日',
'历书' => '曆書',
'历本' => '曆本',
@@ -6030,34 +5947,32 @@ $zh2Hant = array(
'晒谷' => '曬穀',
'曰云' => '曰云',
'更仆难数' => '更僕難數',
-'更加注' => '更加注',
'更签' => '更籤',
'更钟' => '更鐘',
'书签' => '書籤',
'书面' => '書面',
'曹子里' => '曹子里',
-'曼谷人' => '曼谷人',
+'曼谷' => '曼谷',
'曾朴' => '曾樸',
'最多' => '最多',
'最多只' => '最多只',
-'會干擾' => '會干擾',
'会干扰' => '會干擾',
+'會干擾' => '會干擾',
'会干' => '會幹',
'会吊' => '會弔',
'会里' => '會裡',
'月历' => '月曆',
'月历史' => '月歷史',
'月球历表' => '月球曆表',
-'月离于毕' => '月離於畢',
+'月里来' => '月裡來',
'月面' => '月面',
-'月丽于箕' => '月麗於箕',
'有事之无范' => '有事之無範',
'有仆' => '有僕',
'有只不' => '有只不',
'有只允' => '有只允',
'有只容' => '有只容',
-'有只采' => '有只採',
'有只採' => '有只採',
+'有只采' => '有只採',
'有只是' => '有只是',
'有只用' => '有只用',
'有回复' => '有回覆',
@@ -6066,8 +5981,8 @@ $zh2Hant = array(
'有征战' => '有征戰',
'有征戰' => '有征戰',
'有征服' => '有征服',
-'有征讨' => '有征討',
'有征討' => '有征討',
+'有征讨' => '有征討',
'有征' => '有徵',
'有恒街' => '有恒街',
'有栖川' => '有栖川',
@@ -6081,6 +5996,7 @@ $zh2Hant = array(
'望后石' => '望后石',
'朝乾夕惕' => '朝乾夕惕',
'朝钟' => '朝鐘',
+'朝鲜于' => '朝鮮於',
'朦胧' => '朦朧',
'蒙胧' => '朦朧',
'木偶戏扎' => '木偶戲紮',
@@ -6093,6 +6009,7 @@ $zh2Hant = array(
'未干涉' => '未干涉',
'未干預' => '未干預',
'未干预' => '未干預',
+'本庄' => '本庄',
'本征' => '本徵',
'本出戏' => '本齣戲',
'术赤' => '朮赤',
@@ -6101,6 +6018,7 @@ $zh2Hant = array(
'朱理安历史' => '朱理安歷史',
'朴子里' => '朴子里',
'李志喜' => '李志喜',
+'李适' => '李适',
'李连杰' => '李連杰',
'李連杰' => '李連杰',
'材干' => '材幹',
@@ -6113,20 +6031,22 @@ $zh2Hant = array(
'束发' => '束髮',
'杠人' => '杠人',
'杠梁' => '杠梁',
-'杠轂' => '杠轂',
'杠毂' => '杠轂',
+'杠轂' => '杠轂',
'杯干' => '杯乾',
'杯面' => '杯麵',
'杰伦' => '杰倫',
-'杰威爾音樂' => '杰威爾音樂',
-'杰威尔音乐' => '杰威爾音樂',
-'杰特' => '杰特',
+'杰倫' => '杰倫',
+'杰威尔' => '杰威爾',
+'杰威爾' => '杰威爾',
'东周钟' => '東周鐘',
'东岳' => '東嶽',
'東湖里' => '東湖里',
'东冲西突' => '東衝西突',
'东游' => '東遊',
+'松口镇' => '松口鎮',
'松山庄' => '松山庄',
+'松溪县' => '松谿縣',
'板荡' => '板蕩',
'林宏岳' => '林宏嶽',
'林杰樑' => '林杰樑',
@@ -6146,7 +6066,9 @@ $zh2Hant = array(
'柜上' => '柜上',
'柜子' => '柜子',
'柜柳' => '柜柳',
+'查封后' => '查封後',
'柱梁' => '柱樑',
+'柳斌杰' => '柳斌杰',
'柳诒征' => '柳詒徵',
'栖栖皇皇' => '栖栖皇皇',
'栗栖溪' => '栗栖溪',
@@ -6160,6 +6082,7 @@ $zh2Hant = array(
'格里高利历' => '格里高利曆',
'格斗' => '格鬥',
'桂圆干' => '桂圓乾',
+'框里' => '框裡',
'桌几' => '桌几',
'桌历' => '桌曆',
'桌历史' => '桌歷史',
@@ -6169,6 +6092,7 @@ $zh2Hant = array(
'杆秤' => '桿秤',
'杆菌' => '桿菌',
'梁上君子' => '梁上君子',
+'梁启超' => '梁啓超',
'条干' => '條幹',
'梨干' => '梨乾',
'梯冲' => '梯衝',
@@ -6185,14 +6109,15 @@ $zh2Hant = array(
'植发' => '植髮',
'椒面' => '椒麵',
'椰枣干' => '椰棗乾',
-'楊雅筑' => '楊雅筑',
'杨雅筑' => '楊雅筑',
+'楊雅筑' => '楊雅筑',
'桢干' => '楨幹',
'业余' => '業餘',
'榨干' => '榨乾',
'枪杆' => '槍桿',
'杠杆' => '槓桿',
'乐器钟' => '樂器鐘',
+'乐游原' => '樂遊原',
'樊于期' => '樊於期',
'梁上' => '樑上',
'梁柱' => '樑柱',
@@ -6208,8 +6133,8 @@ $zh2Hant = array(
'模范14棒' => '模范14棒',
'模范21棒' => '模范21棒',
'模范七棒' => '模范七棒',
-'模范三軍' => '模范三軍',
'模范三军' => '模范三軍',
+'模范三軍' => '模范三軍',
'模范棒棒堂' => '模范棒棒堂',
'模制' => '模製',
'样范' => '樣範',
@@ -6242,6 +6167,7 @@ $zh2Hant = array(
'机械表' => '機械錶',
'机械钟' => '機械鐘',
'机械钟表' => '機械鐘錶',
+'横峰县' => '橫峯縣',
'横征暴敛' => '橫徵暴斂',
'横梁' => '橫樑',
'横冲' => '橫衝',
@@ -6250,6 +6176,7 @@ $zh2Hant = array(
'台灯' => '檯燈',
'台球' => '檯球',
'台面上' => '檯面上',
+'台面化' => '檯面化',
'柜台' => '櫃檯',
'栉发工' => '櫛髮工',
'欲海难填' => '欲海難填',
@@ -6259,6 +6186,7 @@ $zh2Hant = array(
'欧游' => '歐遊',
'止于' => '止於',
'正官庄' => '正官庄',
+'正杰' => '正杰',
'武丑' => '武丑',
'武后' => '武后',
'武斗' => '武鬥',
@@ -6299,6 +6227,7 @@ $zh2Hant = array(
'水来汤里去' => '水來湯裡去',
'水准' => '水準',
'水无怜奈' => '水無怜奈',
+'水表面' => '水表面',
'水里' => '水裡',
'水里商工' => '水里商工',
'水里溪' => '水里溪',
@@ -6312,13 +6241,11 @@ $zh2Hant = array(
'永志不忘' => '永誌不忘',
'求知欲' => '求知慾',
'求签' => '求籤',
-'求道于盲' => '求道於盲',
-'污蔑' => '汙衊',
'池里' => '池裡',
+'污蔑' => '污衊',
'汤卤' => '汤滷',
'汲于' => '汲於',
'决斗' => '決鬥',
-'沈海蓉' => '沈海蓉',
'沈淀' => '沈澱',
'沈郁' => '沈鬱',
'沉淀' => '沉澱',
@@ -6327,15 +6254,14 @@ $zh2Hant = array(
'没事干' => '沒事幹',
'没干' => '沒幹',
'没折至' => '沒摺至',
-'没梢干' => '沒梢幹',
'没样范' => '沒樣範',
'没准' => '沒準',
'冲冠发怒' => '沖冠髮怒',
'冲天' => '沖天',
+'沙琅' => '沙瑯',
'沙羡' => '沙羡',
'沙里淘金' => '沙裡淘金',
'河岳' => '河嶽',
-'河流汇集' => '河流匯集',
'河里' => '河裡',
'油泼面' => '油潑麵',
'油斗' => '油鬥',
@@ -6356,7 +6282,7 @@ $zh2Hant = array(
'泱郁' => '泱鬱',
'泳气钟' => '泳氣鐘',
'洄游' => '洄遊',
-'洋河大曲' => '洋河大麴',
+'洋河大曲' => '洋河大麯',
'洒家' => '洒家',
'洒扫' => '洒掃',
'洒水' => '洒水',
@@ -6371,6 +6297,8 @@ $zh2Hant = array(
'洗发' => '洗髮',
'洛钟东应' => '洛鐘東應',
'洞里' => '洞裡',
+'洞里萨' => '洞里薩',
+'洞里薩' => '洞里薩',
'泄欲' => '洩慾',
'洪范' => '洪範',
'洪谷子' => '洪谷子',
@@ -6391,8 +6319,8 @@ $zh2Hant = array(
'浮夸' => '浮誇',
'浮松' => '浮鬆',
'海干' => '海乾',
-'海淀山後' => '海淀山後',
'海淀山后' => '海淀山後',
+'海淀山後' => '海淀山後',
'浸卤' => '浸滷',
'涂善妮' => '涂善妮',
'涂坤' => '涂坤',
@@ -6413,8 +6341,9 @@ $zh2Hant = array(
'涂醒哲' => '涂醒哲',
'涂長望' => '涂長望',
'涂长望' => '涂長望',
-'涂鸿钦' => '涂鴻欽',
'涂鴻欽' => '涂鴻欽',
+'涂鸿钦' => '涂鴻欽',
+'涌水塘' => '涌水塘',
'涳蒙' => '涳濛',
'涸干' => '涸乾',
'凉席' => '涼蓆',
@@ -6425,7 +6354,6 @@ $zh2Hant = array(
'泪如泉涌' => '淚如泉湧',
'淡于' => '淡於',
'淡蒙蒙' => '淡濛濛',
-'淡朱' => '淡硃',
'净余' => '淨餘',
'净发' => '淨髮',
'淫欲' => '淫慾',
@@ -6442,7 +6370,6 @@ $zh2Hant = array(
'渠冲' => '渠衝',
'测不准' => '測不準',
'港制' => '港製',
-'游牧民族' => '游牧民族',
'游离' => '游離',
'浑朴' => '渾樸',
'浑个' => '渾箇',
@@ -6453,6 +6380,7 @@ $zh2Hant = array(
'涌入' => '湧入',
'涌出' => '湧出',
'涌向' => '湧向',
+'涌水' => '湧水',
'涌泉' => '湧泉',
'涌现' => '湧現',
'涌起' => '湧起',
@@ -6495,13 +6423,17 @@ $zh2Hant = array(
'准军事' => '準軍事',
'准头' => '準頭',
'准点' => '準點',
+'沟大曲' => '溝大麯',
+'沟谷' => '溝谷',
'溟蒙' => '溟濛',
'溢于' => '溢於',
+'温洛克期' => '溫洛克期',
'溲面' => '溲麵',
'溺于' => '溺於',
'滃郁' => '滃鬱',
'滑借' => '滑藉',
'汇丰' => '滙豐',
+'渗漓' => '滲灕',
'卤了' => '滷了',
'卤五花' => '滷五花',
'卤味' => '滷味',
@@ -6542,9 +6474,9 @@ $zh2Hant = array(
'潮涌' => '潮湧',
'溃于' => '潰於',
'涩谷区' => '澀谷區',
+'澄江县' => '澂江縣',
'澄澹精致' => '澄澹精致',
'澒蒙' => '澒濛',
-'泽渗漓而下降' => '澤滲灕而下降',
'淀乃不耕之地' => '澱乃不耕之地',
'淀北片' => '澱北片',
'淀山' => '澱山',
@@ -6560,19 +6492,29 @@ $zh2Hant = array(
'蒙汜' => '濛汜',
'蒙蒙细雨' => '濛濛細雨',
'蒙雾' => '濛霧',
-'蒙松雨' => '濛鬆雨',
'蒙鸿' => '濛鴻',
+'浚州' => '濬州',
+'浚县' => '濬縣',
'滨田里佳子' => '濱田里佳子',
-'沈吉线' => '瀋吉線',
+'沈丹客运' => '瀋丹客運',
+'沈丹线' => '瀋丹線',
+'沈丹铁路' => '瀋丹鐵路',
+'沈北' => '瀋北',
+'沈吉' => '瀋吉',
+'沈大线' => '瀋大線',
+'沈大铁路' => '瀋大鐵路',
+'沈大高速' => '瀋大高速',
'沈山线' => '瀋山線',
+'沈山铁路' => '瀋山鐵路',
'沈州' => '瀋州',
'沈抚' => '瀋撫',
'沈水' => '瀋水',
'沈河' => '瀋河',
-'沈海' => '瀋海',
'沈海铁路' => '瀋海鐵路',
+'沈海高速' => '瀋海高速',
'沈阳' => '瀋陽',
'泸州大曲' => '瀘州大麯',
+'沥干' => '瀝乾',
'潇洒' => '瀟洒',
'弥山遍野' => '瀰山遍野',
'弥漫' => '瀰漫',
@@ -6604,6 +6546,7 @@ $zh2Hant = array(
'烘制' => '烘製',
'烤干' => '烤乾',
'烤卤' => '烤滷',
+'烹制' => '烹製',
'焙干' => '焙乾',
'无征不信' => '無徵不信',
'无业游民' => '無業游民',
@@ -6613,6 +6556,7 @@ $zh2Hant = array(
'炼制' => '煉製',
'煎面' => '煎麵',
'烟卷' => '煙捲',
+'烟台' => '煙臺',
'照入签' => '照入籤',
'照相干片' => '照相乾片',
'煨干' => '煨乾',
@@ -6622,8 +6566,6 @@ $zh2Hant = array(
'燎发' => '燎髮',
'烧干' => '燒乾',
'燕几' => '燕几',
-'燕巢于幕' => '燕巢於幕',
-'燕燕于飞' => '燕燕于飛',
'燕游' => '燕遊',
'烫一个发' => '燙一個髮',
'烫一次发' => '燙一次髮',
@@ -6674,7 +6616,6 @@ $zh2Hant = array(
'犹如表' => '猶如錶',
'犹如钟' => '猶如鐘',
'犹如钟表' => '猶如鐘錶',
-'呆串了皮' => '獃串了皮',
'狱里' => '獄裡',
'奖杯' => '獎盃',
'独裁制' => '獨裁制',
@@ -6687,6 +6628,7 @@ $zh2Hant = array(
'玉米面' => '玉米面',
'王侯后' => '王侯后',
'王后' => '王后',
+'王添灯' => '王添灯',
'王田里' => '王田里',
'王鉴' => '王鑑',
'王余鱼' => '王餘魚',
@@ -6701,6 +6643,7 @@ $zh2Hant = array(
'理次发' => '理次髮',
'理发' => '理髮',
'琴钟' => '琴鐘',
+'珐琅' => '琺瑯',
'瑞城里' => '瑞城里',
'瑞征' => '瑞徵',
'瑶签' => '瑤籤',
@@ -6722,6 +6665,7 @@ $zh2Hant = array(
'生发' => '生髮',
'产卵洄游' => '產卵洄游',
'苏醒' => '甦醒',
+'用于' => '用於',
'用法里' => '用法裡',
'甩发' => '甩髮',
'田子里' => '田子里',
@@ -6732,10 +6676,10 @@ $zh2Hant = array(
'由于' => '由於',
'甲胄' => '甲冑',
'甲后路' => '甲后路',
-'电影后' => '电影後',
'男仆' => '男僕',
'界里' => '界裡',
'畏于' => '畏於',
+'留长发' => '留長髮',
'留发' => '留髮',
'毕于' => '畢於',
'毕业于' => '畢業於',
@@ -6765,13 +6709,11 @@ $zh2Hant = array(
'癸丑' => '癸丑',
'发干' => '發乾',
'发呆' => '發獃',
-'发蒙' => '發矇',
'发签' => '發籤',
'发松' => '發鬆',
'发面' => '發麵',
-'白干' => '白乾',
+'白干儿' => '白乾兒',
'白子里' => '白子里',
-'白干儿' => '白干兒',
'白术' => '白朮',
'白朴' => '白樸',
'白净面皮' => '白淨面皮',
@@ -6785,11 +6727,11 @@ $zh2Hant = array(
'白霉' => '白黴',
'百个' => '百個',
'百只可' => '百只可',
-'百只夠' => '百只夠',
'百只够' => '百只夠',
+'百只夠' => '百只夠',
'百只怕' => '百只怕',
-'百只足夠' => '百只足夠',
'百只足够' => '百只足夠',
+'百只足夠' => '百只足夠',
'百周后' => '百周後',
'百天后' => '百天後',
'百年' => '百年',
@@ -6805,6 +6747,8 @@ $zh2Hant = array(
'的回复' => '的回覆',
'的图里' => '的圖裡',
'的山里' => '的山裡',
+'的干将' => '的幹將',
+'的个中' => '的箇中',
'的钟' => '的鐘',
'的长发' => '的長髮',
'的发小' => '的髮小',
@@ -6857,11 +6801,13 @@ $zh2Hant = array(
'看钟' => '看鐘',
'真凶' => '真兇',
'真个' => '真箇',
+'真丑' => '真醜',
'眼干' => '眼乾',
'眼帘' => '眼帘',
'眼眶里' => '眼眶裡',
'眼睛里' => '眼睛裡',
'眼里' => '眼裡',
+'着眼于' => '着眼於',
'困乏' => '睏乏',
'困了' => '睏了',
'困倦' => '睏倦',
@@ -6877,6 +6823,7 @@ $zh2Hant = array(
'瞳蒙' => '瞳矇',
'蒙事' => '矇事',
'蒙昧无知' => '矇昧無知',
+'蒙松雨' => '矇松雨',
'蒙混' => '矇混',
'蒙瞍' => '矇瞍',
'蒙眬' => '矇矓',
@@ -6887,6 +6834,7 @@ $zh2Hant = array(
'矜夸' => '矜誇',
'短几' => '短几',
'短于' => '短於',
+'短发生' => '短發生',
'短发' => '短髮',
'矮几' => '矮几',
'石几' => '石几',
@@ -6895,20 +6843,14 @@ $zh2Hant = array(
'石英钟' => '石英鐘',
'石英钟表' => '石英鐘錶',
'石钟' => '石鐘',
-'石钟山' => '石鐘山',
'研制' => '研製',
'砰当' => '砰噹',
'破鉴' => '破鑑',
-'朱唇皓齿' => '硃唇皓齒',
-'朱批' => '硃批',
'朱砂' => '硃砂',
-'朱笔' => '硃筆',
-'朱红色' => '硃紅色',
-'朱色' => '硃色',
-'朱谕' => '硃諭',
'硬干' => '硬幹',
'确瘠' => '确瘠',
'碑志' => '碑誌',
+'碗里' => '碗裡',
'碰钟' => '碰鐘',
'确系' => '確係',
'码表' => '碼錶',
@@ -6952,7 +6894,6 @@ $zh2Hant = array(
'私欲' => '私慾',
'私斗' => '私鬥',
'秋游' => '秋遊',
-'秋阴入井干' => '秋陰入井幹',
'秋发' => '秋髮',
'种丹妮' => '种丹妮',
'种师中' => '种師中',
@@ -6965,6 +6906,7 @@ $zh2Hant = array(
'秒表示' => '秒表示',
'秒钟' => '秒鐘',
'秤杆' => '秤桿',
+'秦沈客运' => '秦瀋客運',
'移祸于' => '移禍於',
'稀松' => '稀鬆',
'棱台' => '稜台',
@@ -7006,10 +6948,10 @@ $zh2Hant = array(
'谷草' => '穀草',
'谷贵饿农' => '穀貴餓農',
'谷贱伤农' => '穀賤傷農',
-'谷道' => '穀道',
'谷雨' => '穀雨',
'谷类' => '穀類',
'谷食' => '穀食',
+'穆棱' => '穆稜',
'穆罕默德历' => '穆罕默德曆',
'穆罕默德历史' => '穆罕默德歷史',
'积淀' => '積澱',
@@ -7021,7 +6963,6 @@ $zh2Hant = array(
'空蒙' => '空濛',
'空荡' => '空蕩',
'空荡荡' => '空蕩蕩',
-'空谷回音' => '空谷回音',
'空钟' => '空鐘',
'空余' => '空餘',
'窒欲' => '窒慾',
@@ -7035,7 +6976,6 @@ $zh2Hant = array(
'窃钟掩耳' => '竊鐘掩耳',
'立于' => '立於',
'立范' => '立範',
-'站干岸儿' => '站乾岸兒',
'童仆' => '童僕',
'竞斗' => '競鬥',
'竹几' => '竹几',
@@ -7043,6 +6983,7 @@ $zh2Hant = array(
'竹签' => '竹籤',
'竹席' => '竹蓆',
'竹制' => '竹製',
+'竹溪县' => '竹谿縣',
'笑里藏刀' => '笑裡藏刀',
'第一出现' => '第一出現',
'第一出現' => '第一出現',
@@ -7053,8 +6994,8 @@ $zh2Hant = array(
'第三出局' => '第三出局',
'第三出' => '第三齣',
'第九出' => '第九齣',
-'第二出线' => '第二出線',
'第二出線' => '第二出線',
+'第二出线' => '第二出線',
'第二出' => '第二齣',
'第五出局' => '第五出局',
'第五出' => '第五齣',
@@ -7076,21 +7017,19 @@ $zh2Hant = array(
'筑肥' => '筑肥',
'筑西' => '筑西',
'筑邦' => '筑邦',
-'筑陽' => '筑陽',
'筑阳' => '筑陽',
+'筑陽' => '筑陽',
'答复' => '答覆',
'筵几' => '筵几',
'个中原因' => '箇中原因',
-'个中奥妙' => '箇中奧妙',
-'个中奥秘' => '箇中奧秘',
+'个中奥' => '箇中奧',
'个中好手' => '箇中好手',
'个中强手' => '箇中強手',
-'个中消息' => '箇中消息',
'个中滋味' => '箇中滋味',
'个中玄机' => '箇中玄機',
'个中理由' => '箇中理由',
-'个中讯息' => '箇中訊息',
-'个中资讯' => '箇中資訊',
+'个中翘楚' => '箇中翹楚',
+'个中道理' => '箇中道理',
'个中高手' => '箇中高手',
'个旧' => '箇舊',
'算历' => '算曆',
@@ -7103,6 +7042,7 @@ $zh2Hant = array(
'节欲' => '節慾',
'节目里' => '節目裡',
'节余' => '節餘',
+'范亭' => '範亭',
'范例' => '範例',
'范围' => '範圍',
'范字' => '範字',
@@ -7115,8 +7055,9 @@ $zh2Hant = array(
'范金' => '範金',
'简并' => '簡併',
'简朴' => '簡樸',
-'簡筑翎' => '簡筑翎',
+'简短发' => '簡短發',
'简筑翎' => '簡筑翎',
+'簡筑翎' => '簡筑翎',
'簸荡' => '簸蕩',
'签幐' => '籤幐',
'签押' => '籤押',
@@ -7198,13 +7139,12 @@ $zh2Hant = array(
'绝于' => '絕於',
'绞干' => '絞乾',
'络腮胡' => '絡腮鬍',
-'給我干脆' => '給我干脆',
-'给我干脆' => '給我干脆',
'给于' => '給於',
'丝恩发怨' => '絲恩髮怨',
'丝制' => '絲製',
'丝发' => '絲髮',
'绑扎' => '綁紮',
+'绥棱' => '綏稜',
'捆扎' => '綑紮',
'經有云' => '經有云',
'经有云' => '經有云',
@@ -7213,6 +7153,9 @@ $zh2Hant = array(
'维系' => '維繫',
'绾发' => '綰髮',
'纲鉴' => '綱鑑',
+'網球台' => '網球台',
+'网球台' => '網球台',
+'网站里' => '網站裡',
'网里' => '網裡',
'网志' => '網誌',
'网游' => '網遊',
@@ -7237,6 +7180,7 @@ $zh2Hant = array(
'缝里' => '縫裡',
'缝制' => '縫製',
'缩栗' => '縮慄',
+'缩短发' => '縮短發',
'纵欲' => '縱慾',
'纤夫' => '縴夫',
'纤手' => '縴手',
@@ -7247,7 +7191,6 @@ $zh2Hant = array(
'繁复' => '繁複',
'繁钟' => '繁鐘',
'绷扒吊拷' => '繃扒弔拷',
-'穗帏飘井干' => '繐幃飄井幹',
'绕梁' => '繞樑',
'绘制' => '繪製',
'系上。' => '繫上。',
@@ -7273,11 +7216,11 @@ $zh2Hant = array(
'系紧' => '繫緊',
'系绳' => '繫繩',
'系累' => '繫纍',
+'系舟' => '繫舟',
'系船' => '繫船',
'系辞' => '繫辭',
'系鞋带' => '繫鞋帶',
'系风捕影' => '繫風捕影',
-'继承制' => '繼承制',
'累囚' => '纍囚',
'累堆' => '纍堆',
'累瓦结绳' => '纍瓦結繩',
@@ -7296,7 +7239,6 @@ $zh2Hant = array(
'羁系' => '羈繫',
'美容美发' => '美容美髮',
'美于' => '美於',
-'美制' => '美製',
'美丑' => '美醜',
'美发学' => '美髮學',
'美发师' => '美髮師',
@@ -7317,9 +7259,10 @@ $zh2Hant = array(
'老干' => '老乾',
'老仆' => '老僕',
'老干部' => '老幹部',
-'老蒙' => '老懞',
+'老懞' => '老懞',
'老于' => '老於',
'老爷钟' => '老爺鐘',
+'老白干' => '老白乾',
'老姜' => '老薑',
'老板' => '老闆',
'老面皮' => '老面皮',
@@ -7331,6 +7274,8 @@ $zh2Hant = array(
'聊斋志异' => '聊齋志異',
'圣人历' => '聖人曆',
'圣后' => '聖后',
+'圣马尔谷日' => '聖馬爾谷日',
+'聖馬爾谷日' => '聖馬爾谷日',
'聘雇' => '聘僱',
'聚药雄蕊' => '聚葯雄蕊',
'闻风后' => '聞風後',
@@ -7356,7 +7301,9 @@ $zh2Hant = array(
'胜肽' => '胜肽',
'胜键' => '胜鍵',
'胡云' => '胡云',
+'胡子婴' => '胡子嬰',
'胡子昂' => '胡子昂',
+'胡杰' => '胡杰',
'胡朴安' => '胡樸安',
'胡里胡涂' => '胡裡胡塗',
'胰脏' => '胰臟',
@@ -7380,6 +7327,7 @@ $zh2Hant = array(
'腊味' => '腊味',
'腊毒' => '腊毒',
'腊笔' => '腊筆',
+'腌臜' => '腌臢',
'肾脏' => '腎臟',
'腐干' => '腐乾',
'腐余' => '腐餘',
@@ -7401,6 +7349,7 @@ $zh2Hant = array(
'卧游' => '臥遊',
'臧谷亡羊' => '臧穀亡羊',
'临潼斗宝' => '臨潼鬥寶',
+'自干五' => '自乾五',
'自制一下' => '自制一下',
'自制下来' => '自制下來',
'自制不' => '自制不',
@@ -7419,6 +7368,7 @@ $zh2Hant = array(
'自制能力' => '自制能力',
'自于' => '自於',
'自然数里' => '自然數裡',
+'自由钟' => '自由鐘',
'自制' => '自製',
'自觉自愿' => '自覺自愿',
'自夸' => '自誇',
@@ -7431,8 +7381,8 @@ $zh2Hant = array(
'台静农' => '臺靜農',
'臻于' => '臻於',
'舂谷' => '舂穀',
-'舉手表' => '舉手表',
'举手表' => '舉手表',
+'舉手表' => '舉手表',
'舊庄' => '舊庄',
'旧历' => '舊曆',
'旧历史' => '舊歷史',
@@ -7468,14 +7418,15 @@ $zh2Hant = array(
'苑里' => '苑裡',
'若干' => '若干',
'苦干' => '苦幹',
+'苦于' => '苦於',
'苦里' => '苦裡',
'苦斗' => '苦鬥',
'苎麻' => '苧麻',
'茂都淀' => '茂都澱',
'范文同' => '范文同',
'范文正公' => '范文正公',
-'范文瀾' => '范文瀾',
'范文澜' => '范文瀾',
+'范文瀾' => '范文瀾',
'范文照' => '范文照',
'范文程' => '范文程',
'范文芳' => '范文芳',
@@ -7484,8 +7435,8 @@ $zh2Hant = array(
'范登堡' => '范登堡',
'范賢惠' => '范賢惠',
'范贤惠' => '范賢惠',
-'茅于轼' => '茅于軾',
'茅于軾' => '茅于軾',
+'茅于轼' => '茅于軾',
'茶几' => '茶几',
'茶余' => '茶餘',
'茶面' => '茶麵',
@@ -7502,12 +7453,12 @@ $zh2Hant = array(
'莽荡' => '莽蕩',
'菜干' => '菜乾',
'菜坛' => '菜罈',
-'菜肴' => '菜肴',
+'菜肴' => '菜餚',
'菠棱菜' => '菠稜菜',
'菠萝干' => '菠蘿乾',
'华严钟' => '華嚴鐘',
-'萬一只' => '萬一只',
'万一只' => '萬一只',
+'萬一只' => '萬一只',
'万个' => '萬個',
'万周后' => '萬周後',
'万天后' => '萬天後',
@@ -7521,6 +7472,7 @@ $zh2Hant = array(
'万象' => '萬象',
'万只' => '萬隻',
'万余' => '萬餘',
+'落于' => '落於',
'落腮胡' => '落腮鬍',
'落发' => '落髮',
'叶叶琴' => '葉叶琴',
@@ -7528,6 +7480,7 @@ $zh2Hant = array(
'葡萄干' => '葡萄乾',
'董氏封发' => '董氏封髮',
'葫芦里卖甚么药' => '葫蘆裡賣甚麼藥',
+'葬于' => '葬於',
'蒙雾露' => '蒙霧露',
'蒜发' => '蒜髮',
'蒲席' => '蒲蓆',
@@ -7541,9 +7494,9 @@ $zh2Hant = array(
'蓄须' => '蓄鬚',
'席子' => '蓆子',
'蓊郁' => '蓊鬱',
-'蓬蓬松松' => '蓬蓬鬆鬆',
'蓬发' => '蓬髮',
'蓬松' => '蓬鬆',
+'蓬松松' => '蓬鬆鬆',
'参绥' => '蔘綏',
'葱郁' => '蔥鬱',
'荞麦面' => '蕎麥麵',
@@ -7589,8 +7542,8 @@ $zh2Hant = array(
'熏风' => '薰風',
'熏香' => '薰香',
'苧悴' => '薴悴',
-'薴烯' => '薴烯',
'苧烯' => '薴烯',
+'薴烯' => '薴烯',
'借以' => '藉以',
'借助' => '藉助',
'借口' => '藉口',
@@ -7612,14 +7565,16 @@ $zh2Hant = array(
'藤制' => '藤製',
'药签' => '藥籤',
'药面儿' => '藥麵兒',
-'苏昆' => '蘇崑',
'苏崑' => '蘇崑',
+'苏昆' => '蘇崑',
'苹果' => '蘋果',
'苹果干' => '蘋果乾',
+'兰溪市' => '蘭谿市',
'萝卜' => '蘿蔔',
'萝卜干' => '蘿蔔乾',
'虎须' => '虎鬚',
'虎斗' => '虎鬥',
+'处于' => '處於',
'虚夸' => '虛誇',
'号志' => '號誌',
'虫部' => '虫部',
@@ -7634,6 +7589,7 @@ $zh2Hant = array(
'蝎虎' => '蝎虎',
'蝎蝎螫螫' => '蝎蝎螫螫',
'蝎谮' => '蝎譖',
+'虾面' => '蝦麵',
'虮虱相吊' => '蟣蝨相弔',
'蛏干' => '蟶乾',
'蚁后' => '蟻后',
@@ -7645,8 +7601,8 @@ $zh2Hant = array(
'行事历' => '行事曆',
'行事历史' => '行事歷史',
'行凶' => '行兇',
+'行家里手' => '行家裡手',
'行于' => '行於',
-'行百里者半于九十' => '行百里者半於九十',
'卫后庄公' => '衛後莊公',
'卫星钟' => '衛星鐘',
'冲上' => '衝上',
@@ -7698,6 +7654,7 @@ $zh2Hant = array(
'冲头阵' => '衝頭陣',
'冲风' => '衝風',
'衡鉴' => '衡鑑',
+'表面包' => '表面包',
'衷于' => '衷於',
'袋杆' => '袋桿',
'袋里' => '袋裡',
@@ -7716,9 +7673,9 @@ $zh2Hant = array(
'夹裙' => '袷裙',
'裁并' => '裁併',
'裁制' => '裁製',
-'里手' => '裏手',
'里水镇' => '裏水鎮',
'里海' => '裏海',
+'里运河' => '裏運河',
'补于' => '補於',
'补注' => '補註',
'装折' => '裝摺',
@@ -7771,6 +7728,7 @@ $zh2Hant = array(
'复利' => '複利',
'复印' => '複印',
'复句' => '複句',
+'复合' => '複合',
'复壁' => '複壁',
'复姓' => '複姓',
'复字键' => '複字鍵',
@@ -7780,6 +7738,7 @@ $zh2Hant = array(
'复平面' => '複平面',
'复式' => '複式',
'复数' => '複數',
+'复方' => '複方',
'复本' => '複本',
'复查' => '複查',
'复次' => '複次',
@@ -7813,6 +7772,7 @@ $zh2Hant = array(
'复韵' => '複韻',
'褒赞' => '褒讚',
'衬里' => '襯裡',
+'西井里' => '西井里',
'西周钟' => '西周鐘',
'西昆' => '西崑',
'西岳' => '西嶽',
@@ -7840,12 +7800,14 @@ $zh2Hant = array(
'角落里' => '角落裡',
'觚棱' => '觚稜',
'解雇' => '解僱',
+'解封后' => '解封後',
'解铃仍须系铃人' => '解鈴仍須繫鈴人',
'解铃还须系铃人' => '解鈴還須繫鈴人',
'解发佯狂' => '解髮佯狂',
'触须' => '觸鬚',
'言云' => '言云',
'言大而夸' => '言大而夸',
+'言里' => '言裡',
'言辩而确' => '言辯而确',
'订制' => '訂製',
'计划' => '計劃',
@@ -7855,6 +7817,7 @@ $zh2Hant = array(
'托交' => '託交',
'托人' => '託人',
'托付' => '託付',
+'托克逊' => '託克遜',
'托儿' => '託兒',
'托古讽今' => '託古諷今',
'托名' => '託名',
@@ -7876,9 +7839,10 @@ $zh2Hant = array(
'托辞' => '託辭',
'托运' => '託運',
'托过' => '託過',
+'托里县' => '託里縣',
'托附' => '託附',
'许愿起经' => '許愿起經',
-'许虬' => '許虬',
+'許聖杰' => '許聖杰',
'注上' => '註上',
'注册' => '註冊',
'注失' => '註失',
@@ -7901,7 +7865,6 @@ $zh2Hant = array(
'词汇' => '詞彙',
'词余' => '詞餘',
'询于' => '詢於',
-'询于刍荛' => '詢於芻蕘',
'试制' => '試製',
'詩云' => '詩云',
'诗云' => '詩云',
@@ -7915,6 +7878,7 @@ $zh2Hant = array(
'诔赞' => '誄讚',
'夸下海口' => '誇下海口',
'夸了' => '誇了',
+'夸人' => '誇人',
'夸他' => '誇他',
'夸你' => '誇你',
'夸来夸去' => '誇來誇去',
@@ -7926,7 +7890,9 @@ $zh2Hant = array(
'夸多斗靡' => '誇多鬥靡',
'夸大' => '誇大',
'夸她' => '誇她',
+'夸姣' => '誇姣',
'夸官' => '誇官',
+'夸容' => '誇容',
'夸张' => '誇張',
'夸强说会' => '誇強說會',
'夸得' => '誇得',
@@ -7951,6 +7917,7 @@ $zh2Hant = array(
'夸辩' => '誇辯',
'夸过' => '誇過',
'夸饰' => '誇飾',
+'夸丽' => '誇麗',
'志哀' => '誌哀',
'志喜' => '誌喜',
'志庆' => '誌慶',
@@ -7980,13 +7947,14 @@ $zh2Hant = array(
'咨询' => '諮詢',
'诸余' => '諸餘',
'谋干' => '謀幹',
+'謝杰' => '謝杰',
+'谢杰' => '謝杰',
'谢华后' => '謝華后',
'谬采虚声' => '謬採虛聲',
'谬赞' => '謬讚',
'謷丑' => '謷醜',
'謹愿' => '謹愿',
'谨愿' => '謹愿',
-'谨于心' => '謹於心',
'哗噪' => '譁噪',
'哗嚣' => '譁囂',
'哗然' => '譁然',
@@ -8023,6 +7991,7 @@ $zh2Hant = array(
'豆干' => '豆乾',
'豆腐干' => '豆腐乾',
'竖起脊梁' => '豎起脊梁',
+'丰度' => '豐度',
'丰滨' => '豐濱',
'丰滨乡' => '豐濱鄉',
'丰台' => '豐臺',
@@ -8043,8 +8012,8 @@ $zh2Hant = array(
'賢后' => '賢后',
'贤后' => '賢后',
'卖断发' => '賣斷發',
-'赋范' => '賦范',
'賦范' => '賦范',
+'赋范' => '賦范',
'质数里' => '質數裡',
'质朴' => '質樸',
'赌后' => '賭后',
@@ -8065,6 +8034,7 @@ $zh2Hant = array(
'赵治勋' => '趙治勳',
'趱干' => '趲幹',
'足于' => '足於',
+'足球台' => '足球台',
'跌扑' => '跌扑',
'路图里' => '路圖裡',
'路签' => '路籤',
@@ -8098,8 +8068,8 @@ $zh2Hant = array(
'挽输' => '輓輸',
'挽辞' => '輓辭',
'轻于' => '輕於',
-'轻轻松松' => '輕輕鬆鬆',
'轻松' => '輕鬆',
+'轻松松' => '輕鬆鬆',
'轮奸' => '輪姦',
'轮回' => '輪迴',
'转向往' => '轉向往',
@@ -8112,6 +8082,7 @@ $zh2Hant = array(
'辞汇' => '辭彙',
'辫发' => '辮髮',
'辩斗' => '辯鬥',
+'辰溪县' => '辰谿縣',
'农历' => '農曆',
'农历史' => '農歷史',
'农民历' => '農民曆',
@@ -8122,11 +8093,16 @@ $zh2Hant = array(
'迥然回异' => '迥然迴異',
'迫于' => '迫於',
'回光返照' => '迴光返照',
-'回向' => '迴向',
'回圈' => '迴圈',
'回廊' => '迴廊',
'回形夹' => '迴形夾',
-'回文' => '迴文',
+'回文序列' => '迴文序列',
+'回文数' => '迴文數',
+'回文构词' => '迴文構詞',
+'回文结构' => '迴文結構',
+'回文联' => '迴文聯',
+'回文诗' => '迴文詩',
+'回文锦' => '迴文錦',
'回旋' => '迴旋',
'回环' => '迴環',
'回纹针' => '迴紋針',
@@ -8141,14 +8117,12 @@ $zh2Hant = array(
'回递性' => '迴遞性',
'回避' => '迴避',
'回銮' => '迴鑾',
-'回音' => '迴音',
'回响' => '迴響',
'回风' => '迴風',
'迷于' => '迷於',
'迷蒙' => '迷濛',
'追凶' => '追兇',
'退伙' => '退夥',
-'退藏于密' => '退藏於密',
'逆钟' => '逆鐘',
'逆钟向' => '逆鐘向',
'逆风后' => '逆風後',
@@ -8185,6 +8159,7 @@ $zh2Hant = array(
'这里' => '這裡',
'这钟' => '這鐘',
'这只' => '這隻',
+'这么干' => '這麼幹',
'这出' => '這齣',
'通奸' => '通姦',
'通心面' => '通心麵',
@@ -8196,11 +8171,12 @@ $zh2Hant = array(
'造钟' => '造鐘',
'连三并四' => '連三併四',
'连采' => '連採',
+'连发式' => '連發式',
'连系' => '連繫',
-'周游世界' => '週遊世界',
+'周游' => '週遊',
'进两出' => '進兩出',
-'進制' => '進制',
'进制' => '進制',
+'進制' => '進制',
'逼并' => '逼併',
'遇风后' => '遇風後',
'游了' => '遊了',
@@ -8234,6 +8210,7 @@ $zh2Hant = array(
'游目骋怀' => '遊目騁懷',
'游程' => '遊程',
'游丝' => '遊絲',
+'游美学务' => '遊美學務',
'游兴' => '遊興',
'游船' => '遊船',
'游艇' => '遊艇',
@@ -8259,6 +8236,7 @@ $zh2Hant = array(
'递回' => '遞迴',
'远游' => '遠遊',
'遨游' => '遨遊',
+'适于' => '適於',
'遮丑' => '遮醜',
'迁于' => '遷於',
'选手表明' => '選手表明',
@@ -8301,6 +8279,7 @@ $zh2Hant = array(
'部子里' => '部子里',
'部落发' => '部落發',
'郭后' => '郭后',
+'都市里' => '都市裡',
'都于' => '都於',
'乡愿' => '鄉愿',
'鄉愿' => '鄉愿',
@@ -8308,16 +8287,16 @@ $zh2Hant = array(
'鄭凱云' => '鄭凱云',
'配制饲料' => '配制飼料',
'配图里' => '配圖裡',
-'配水干管' => '配水幹管',
'配制' => '配製',
'酒帘' => '酒帘',
'酒气冲天' => '酒氣衝天',
'酒坛' => '酒罈',
'酒肴' => '酒肴',
-'酒麹' => '酒麴',
'酒曲' => '酒麴',
+'酒麹' => '酒麴',
'酥松' => '酥鬆',
'酸姜' => '酸薑',
+'腌制' => '醃製',
'醇朴' => '醇樸',
'醉于' => '醉於',
'醋坛' => '醋罈',
@@ -8337,7 +8316,6 @@ $zh2Hant = array(
'丑女' => '醜女',
'丑女效颦' => '醜女效顰',
'丑奴儿' => '醜奴兒',
-'丑婆子' => '醜婆子',
'丑妇' => '醜婦',
'丑媳' => '醜媳',
'丑媳妇' => '醜媳婦',
@@ -8417,6 +8395,7 @@ $zh2Hant = array(
'金表露' => '金表露',
'金表面' => '金表面',
'金装玉里' => '金裝玉裡',
+'金溪县' => '金谿縣',
'金链' => '金鍊',
'金钟' => '金鐘',
'金发' => '金髮',
@@ -8511,6 +8490,7 @@ $zh2Hant = array(
'钟罩' => '鐘罩',
'钟声' => '鐘聲',
'钟腰' => '鐘腰',
+'钟花' => '鐘花',
'钟螺' => '鐘螺',
'钟行' => '鐘行',
'钟表面' => '鐘表面',
@@ -8620,8 +8600,10 @@ $zh2Hant = array(
'陳冲' => '陳冲',
'陳士杰' => '陳士杰',
'陈升' => '陳昇',
-'陳有后' => '陳有后',
'陈有后' => '陳有后',
+'陳有后' => '陳有后',
+'陈杰' => '陳杰',
+'陳杰' => '陳杰',
'陈炼' => '陳鍊',
'陆游' => '陸遊',
'阳春面' => '陽春麵',
@@ -8649,7 +8631,6 @@ $zh2Hant = array(
'雕梁画栋' => '雕樑畫棟',
'双折射' => '雙折射',
'双折' => '雙摺',
-'双沟大曲' => '雙溝大麯',
'双胜类' => '雙胜類',
'双雕' => '雙鵰',
'杂合面儿' => '雜合麵兒',
@@ -8671,8 +8652,9 @@ $zh2Hant = array(
'雪里' => '雪裡',
'雪里红' => '雪裡紅',
'雪里蕻' => '雪裡蕻',
-'云吞面' => '雲吞麵',
+'云吞' => '雲吞',
'云笈七签' => '雲笈七籤',
+'云里雾里' => '雲裡霧裡',
'云游' => '雲遊',
'云须' => '雲鬚',
'零个' => '零個',
@@ -8684,16 +8666,22 @@ $zh2Hant = array(
'电子表格' => '電子表格',
'电子钟' => '電子鐘',
'电子钟表' => '電子鐘錶',
+'电影后' => '電影後',
+'电梯里' => '電梯裡',
'电波钟' => '電波鐘',
'电码表' => '電碼表',
'电冲' => '電衝',
+'电视台风' => '電視台風',
'电表' => '電錶',
'电钟' => '電鐘',
'震栗' => '震慄',
'霉气冲天' => '霉氣衝天',
+'沾化' => '霑化',
+'沾益' => '霑益',
'雾里' => '霧裡',
'露丑' => '露醜',
'霁范' => '霽範',
+'灵昆' => '靈崑',
'青山一发' => '青山一髮',
'青霉' => '青黴',
'非常准' => '非常準',
@@ -8710,18 +8698,18 @@ $zh2Hant = array(
'面包管' => '面包管',
'面包扎' => '面包紮',
'面包罗' => '面包羅',
+'面包着' => '面包著',
'面包藏' => '面包藏',
'面包装' => '面包裝',
'面包裹' => '面包裹',
'面包起' => '面包起',
'面包办' => '面包辦',
'面店铺' => '面店鋪',
-'面條目' => '面條目',
'面条目' => '面條目',
+'面條目' => '面條目',
'面粉碎' => '面粉碎',
'面粉红' => '面粉紅',
'面食饭' => '面食飯',
-'面食面' => '面食麵',
'鞋里' => '鞋裡',
'鞣制' => '鞣製',
'秋千' => '鞦韆',
@@ -8737,8 +8725,8 @@ $zh2Hant = array(
'頁面' => '頁面',
'页面' => '頁面',
'顶凶' => '頂兇',
-'顶多' => '頂多',
'頂多' => '頂多',
+'顶多' => '頂多',
'项链' => '項鍊',
'顺于' => '順於',
'顺钟向' => '順鐘向',
@@ -8749,7 +8737,6 @@ $zh2Hant = array(
'预报不准' => '預報不準',
'预制' => '預製',
'领袖欲' => '領袖慾',
-'头儿干' => '頭兒幹',
'头里' => '頭裡',
'头长发' => '頭長髮',
'头发' => '頭髮',
@@ -8783,11 +8770,13 @@ $zh2Hant = array(
'风起云涌' => '風起雲湧',
'風采' => '風采',
'风采' => '風采',
+'风刮' => '風颳',
'台风' => '颱風',
'台风后' => '颱風後',
'刮了' => '颳了',
'刮倒' => '颳倒',
'刮去' => '颳去',
+'刮大风' => '颳大風',
'刮得' => '颳得',
'刮走' => '颳走',
'刮起' => '颳起',
@@ -8797,6 +8786,7 @@ $zh2Hant = array(
'飘荡' => '飄蕩',
'飘游' => '飄遊',
'飘飘荡荡' => '飄飄蕩蕩',
+'飘发自由女神' => '飄髮自由女神',
'飞扎' => '飛紮',
'飞刍挽粟' => '飛芻輓粟',
'飞行钟' => '飛行鐘',
@@ -8854,6 +8844,7 @@ $zh2Hant = array(
'余子' => '餘子',
'余存' => '餘存',
'余孽' => '餘孽',
+'余干' => '餘干',
'余年' => '餘年',
'余式' => '餘式',
'余弦' => '餘弦',
@@ -8876,6 +8867,7 @@ $zh2Hant = array(
'余殃' => '餘殃',
'余毒' => '餘毒',
'余气' => '餘氣',
+'余江' => '餘江',
'余波' => '餘波',
'余温' => '餘溫',
'余泽' => '餘澤',
@@ -8924,7 +8916,6 @@ $zh2Hant = array(
'馄饨面' => '餛飩麵',
'馆谷' => '館穀',
'馆里' => '館裡',
-'餵驴' => '餵驢',
'饥寒' => '饑寒',
'饥民' => '饑民',
'饥渴' => '饑渴',
@@ -8940,13 +8931,14 @@ $zh2Hant = array(
'香山庄' => '香山庄',
'马干' => '馬乾',
'馬占山' => '馬占山',
+'马德钟' => '馬德鐘',
'马斯垂克期' => '馬斯垂克期',
'馬格里布' => '馬格里布',
'马格里布' => '馬格里布',
'驻扎' => '駐紮',
'骀荡' => '駘蕩',
-'騰格里' => '騰格里',
'腾格里' => '騰格里',
+'騰格里' => '騰格里',
'腾涌' => '騰湧',
'腾冲' => '騰衝',
'惊栗' => '驚慄',
@@ -8959,6 +8951,7 @@ $zh2Hant = array(
'体范' => '體範',
'体系' => '體系',
'高几' => '高几',
+'高后' => '高后',
'高干扰' => '高干擾',
'高干预' => '高干預',
'高干' => '高幹',
@@ -8973,6 +8966,7 @@ $zh2Hant = array(
'发乳' => '髮乳',
'发光可鉴' => '髮光可鑑',
'发匪' => '髮匪',
+'发及腰' => '髮及腰',
'发型' => '髮型',
'发夹' => '髮夾',
'发妻' => '髮妻',
@@ -8983,7 +8977,7 @@ $zh2Hant = array(
'发廊' => '髮廊',
'发式' => '髮式',
'发引千钧' => '髮引千鈞',
-'发指' => '髮指',
+'发披肩' => '髮披肩',
'发卷' => '髮捲',
'发根' => '髮根',
'发油' => '髮油',
@@ -9048,7 +9042,7 @@ $zh2Hant = array(
'松通' => '鬆通',
'松开' => '鬆開',
'松饼' => '鬆餅',
-'松松' => '鬆鬆',
+'松松地' => '鬆鬆地',
'鬈发' => '鬈髮',
'胡子' => '鬍子',
'胡梢' => '鬍梢',
@@ -9075,11 +9069,13 @@ $zh2Hant = array(
'斗剑' => '鬥劍',
'斗力' => '鬥力',
'斗劲' => '鬥勁',
+'斗勇' => '鬥勇',
'斗胜' => '鬥勝',
'斗口' => '鬥口',
'斗合' => '鬥合',
'斗嘴' => '鬥嘴',
'斗地主' => '鬥地主',
+'斗垮' => '鬥垮',
'斗士' => '鬥士',
'斗富' => '鬥富',
'斗巧' => '鬥巧',
@@ -9092,9 +9088,11 @@ $zh2Hant = array(
'斗志' => '鬥志',
'斗闷' => '鬥悶',
'斗成' => '鬥成',
+'斗战' => '鬥戰',
'斗打' => '鬥打',
'斗批改' => '鬥批改',
'斗技' => '鬥技',
+'斗败' => '鬥敗',
'斗文' => '鬥文',
'斗智' => '鬥智',
'斗暴' => '鬥暴',
@@ -9110,7 +9108,9 @@ $zh2Hant = array(
'斗牛' => '鬥牛',
'斗犀台' => '鬥犀臺',
'斗犬' => '鬥犬',
+'斗狗' => '鬥狗',
'斗狠' => '鬥狠',
+'斗兽' => '鬥獸',
'斗叠' => '鬥疊',
'斗百草' => '鬥百草',
'斗眼' => '鬥眼',
@@ -9123,6 +9123,7 @@ $zh2Hant = array(
'斗草' => '鬥草',
'斗叶儿' => '鬥葉兒',
'斗叶子' => '鬥葉子',
+'斗蛐' => '鬥蛐',
'斗蟋蟀' => '鬥蟋蟀',
'斗话' => '鬥話',
'斗艳' => '鬥豔',
@@ -9140,6 +9141,7 @@ $zh2Hant = array(
'斗鸭' => '鬥鴨',
'斗鹌鹑' => '鬥鵪鶉',
'斗丽' => '鬥麗',
+'斗龙' => '鬥龍',
'闹表' => '鬧錶',
'闹钟' => '鬧鐘',
'哄动' => '鬨動',
@@ -9189,14 +9191,14 @@ $zh2Hant = array(
'鬼谷子' => '鬼谷子',
'魂牵梦系' => '魂牽夢繫',
'魏征' => '魏徵',
-'魔杰座' => '魔杰座',
'魔表' => '魔錶',
'鱼干' => '魚乾',
'鱼松' => '魚鬆',
-'鲜于枢' => '鮮于樞',
-'鮮于樞' => '鮮于樞',
+'鮮于' => '鮮于',
+'鲜于' => '鮮于',
'鲸须' => '鯨鬚',
-'鳳凰于飛' => '鳳凰于飛',
+'鳥栖' => '鳥栖',
+'鸟栖市' => '鳥栖市',
'凤梨干' => '鳳梨乾',
'鸣钟' => '鳴鐘',
'鸿范' => '鴻範',
@@ -9206,6 +9208,7 @@ $zh2Hant = array(
'雕悍' => '鵰悍',
'雕翎' => '鵰翎',
'雕鹗' => '鵰鶚',
+'鹤峰县' => '鶴峯縣',
'鹤吊' => '鶴弔',
'鹤发' => '鶴髮',
'鸾鉴' => '鸞鑑',
@@ -9230,7 +9233,7 @@ $zh2Hant = array(
'咸菜' => '鹹菜',
'咸菜干' => '鹹菜乾',
'咸蛋' => '鹹蛋',
-'咸猪肉' => '鹹豬肉',
+'咸猪' => '鹹豬',
'咸类' => '鹹類',
'咸食' => '鹹食',
'咸鱼' => '鹹魚',
@@ -9242,16 +9245,17 @@ $zh2Hant = array(
'盐余' => '鹽餘',
'鹿場里' => '鹿場里',
'丽于' => '麗於',
+'麟游' => '麟遊',
+'曲酒' => '麯酒',
'曲尘' => '麴塵',
'曲櫱' => '麴櫱',
'曲秀才' => '麴秀才',
'曲车' => '麴車',
'曲道士' => '麴道士',
'曲钱' => '麴錢',
-'麹霉' => '麴黴',
'曲霉' => '麴黴',
+'麹霉' => '麴黴',
'面人儿' => '麵人兒',
-'面价' => '麵價',
'面包' => '麵包',
'面坊' => '麵坊',
'面坯儿' => '麵坯兒',
@@ -9263,7 +9267,6 @@ $zh2Hant = array(
'面条' => '麵條',
'面汤' => '麵湯',
'面浆' => '麵漿',
-'面灰' => '麵灰',
'面疙瘩' => '麵疙瘩',
'面皮' => '麵皮',
'面码儿' => '麵碼兒',
@@ -9273,15 +9276,23 @@ $zh2Hant = array(
'面团' => '麵糰',
'面缸' => '麵缸',
'面茶' => '麵茶',
+'面制品' => '麵製品',
'面食' => '麵食',
'面饺' => '麵餃',
'面饼' => '麵餅',
'面馆' => '麵館',
+'面点、' => '麵點、',
+'面点师' => '麵點師',
'麻将席' => '麻將蓆',
'麻酱面' => '麻醬麵',
'黄干黑瘦' => '黃乾黑瘦',
+'黄岩区' => '黃巖區',
+'黄岩县' => '黃巖縣',
'黄历' => '黃曆',
+'黃杰' => '黃杰',
+'黄杰' => '黃杰',
'黄历史' => '黃歷史',
+'黄白术' => '黃白術',
'黃詩杰' => '黃詩杰',
'黄诗杰' => '黃詩杰',
'黄金表' => '黃金表',
@@ -9291,14 +9302,18 @@ $zh2Hant = array(
'黄发' => '黃髮',
'黄曲毒素' => '黃麴毒素',
'黎克特制' => '黎克特制',
-'黎吉雲' => '黎吉雲',
'黎吉云' => '黎吉雲',
+'黎吉雲' => '黎吉雲',
'黑奴吁天录' => '黑奴籲天錄',
+'黑干将' => '黑幹將',
+'黑长发' => '黑長髮',
'黑发' => '黑髮',
+'点个赞' => '點個讚',
'点札' => '點劄',
'点半钟' => '點半鐘',
'点多钟' => '點多鐘',
'点里' => '點裡',
+'点赞' => '點讚',
'点里程' => '點里程',
'点钟' => '點鐘',
'霉毒' => '黴毒',
@@ -9309,6 +9324,7 @@ $zh2Hant = array(
'鼓里' => '鼓裡',
'鼓噪' => '鼓譟',
'冬冬鼓' => '鼕鼕鼓',
+'咚咚鼓' => '鼕鼕鼓',
'鼠曲草' => '鼠麴草',
'鼻梁儿' => '鼻梁兒',
'鼻梁' => '鼻樑',
@@ -9318,6 +9334,7 @@ $zh2Hant = array(
'齿落发白' => '齒落髮白',
'齿发' => '齒髮',
'出儿' => '齣兒',
+'龙岩' => '龍巖',
'龙卷' => '龍捲',
'龙眼干' => '龍眼乾',
'龙须' => '龍鬚',
@@ -9325,13 +9342,13 @@ $zh2Hant = array(
'龙斗虎伤' => '龍鬥虎傷',
'龜山庄' => '龜山庄',
'龟鉴' => '龜鑑',
+',个中' => ',箇中',
);
$zh2Hans = array(
'㑯' => '㑔',
'㑳' => '㑇',
'㑶' => '㐹',
-'㑺' => '俊',
'㒓' => '𠉂',
'㒺' => '罔',
'㓂' => '寇',
@@ -9359,10 +9376,8 @@ $zh2Hans = array(
'㢝' => '𢋈',
'㤙' => '恩',
'㥦' => '惬',
-'㥫' => '惇',
'㥮' => '㤘',
'㦎' => '𢛯',
-'㧱' => '拿',
'㨗' => '捷',
'㨪' => '晃',
'㨿' => '据',
@@ -9489,7 +9504,6 @@ $zh2Hans = array(
'來' => '来',
'侖' => '仑',
'侶' => '侣',
-'侷' => '局',
'俁' => '俣',
'係' => '系',
'俔' => '伣',
@@ -9766,7 +9780,6 @@ $zh2Hans = array(
'執' => '执',
'堅' => '坚',
'堊' => '垩',
-'堖' => '垴',
'堝' => '埚',
'堯' => '尧',
'報' => '报',
@@ -9776,7 +9789,6 @@ $zh2Hans = array(
'塏' => '垲',
'塒' => '埘',
'塗' => '涂',
-'塚' => '冢',
'塟' => '葬',
'塢' => '坞',
'塤' => '埙',
@@ -9933,7 +9945,6 @@ $zh2Hans = array(
'嶧' => '峄',
'嶨' => '峃',
'嶮' => '崄',
-'嶴' => '岙',
'嶸' => '嵘',
'嶺' => '岭',
'嶼' => '屿',
@@ -10075,7 +10086,6 @@ $zh2Hans = array(
'應' => '应',
'懌' => '怿',
'懍' => '懔',
-'懞' => '蒙',
'懟' => '怼',
'懣' => '懑',
'懨' => '恹',
@@ -10281,8 +10291,6 @@ $zh2Hans = array(
'棧' => '栈',
'棲' => '栖',
'棶' => '梾',
-'椀' => '碗',
-'椉' => '乘',
'椏' => '桠',
'椗' => '碇',
'椲' => '㭏',
@@ -10446,7 +10454,6 @@ $zh2Hans = array(
'湞' => '浈',
'湧' => '涌',
'湯' => '汤',
-'湻' => '淳',
'湼' => '涅',
'溈' => '沩',
'準' => '准',
@@ -10550,7 +10557,6 @@ $zh2Hans = array(
'灙' => '𣺼',
'灝' => '灏',
'灠' => '漤',
-'灡' => '㳕',
'灣' => '湾',
'灤' => '滦',
'灧' => '滟',
@@ -10794,7 +10800,6 @@ $zh2Hans = array(
'矚' => '瞩',
'矯' => '矫',
'砲' => '炮',
-'硃' => '朱',
'硜' => '硁',
'硤' => '硖',
'硨' => '砗',
@@ -11334,7 +11339,6 @@ $zh2Hans = array(
'薟' => '莶',
'薦' => '荐',
'薩' => '萨',
-'薳' => '䓕',
'薴' => '苧',
'薺' => '荠',
'藍' => '蓝',
@@ -11426,7 +11430,6 @@ $zh2Hans = array(
'衊' => '蔑',
'術' => '术',
'衕' => '同',
-'衖' => '弄',
'衚' => '胡',
'衛' => '卫',
'衝' => '冲',
@@ -11489,7 +11492,6 @@ $zh2Hans = array(
'覽' => '览',
'覿' => '觌',
'觀' => '观',
-'觔' => '斤',
'觝' => '抵',
'觴' => '觞',
'觶' => '觯',
@@ -11920,7 +11922,6 @@ $zh2Hans = array(
'適' => '适',
'遯' => '遁',
'遲' => '迟',
-'遶' => '绕',
'遷' => '迁',
'選' => '选',
'遺' => '遗',
@@ -12023,6 +12024,7 @@ $zh2Hans = array(
'鈿' => '钿',
'鉀' => '钾',
'鉁' => '𨱅',
+'鉄' => '铁',
'鉅' => '钜',
'鉆' => '钻',
'鉈' => '铊',
@@ -12380,7 +12382,6 @@ $zh2Hans = array(
'靭' => '韧',
'靱' => '韧',
'鞀' => '鼗',
-'鞌' => '鞍',
'鞏' => '巩',
'鞝' => '绱',
'鞦' => '秋',
@@ -12528,6 +12529,7 @@ $zh2Hans = array(
'餭' => '𫗮',
'餱' => '糇',
'餳' => '饧',
+'餵' => '喂',
'餶' => '馉',
'餷' => '馇',
'餸' => '𩠌',
@@ -12582,7 +12584,6 @@ $zh2Hans = array(
'駧' => '𩧲',
'駩' => '𩧴',
'駭' => '骇',
-'駮' => '驳',
'駰' => '骃',
'駱' => '骆',
'駶' => '𩧺',
@@ -12621,7 +12622,7 @@ $zh2Hans = array(
'驁' => '骜',
'驂' => '骖',
'驃' => '骠',
-'驄' => '𩨂',
+'驄' => '骢',
'驅' => '驱',
'驊' => '骅',
'驋' => '𩧯',
@@ -12649,10 +12650,8 @@ $zh2Hans = array(
'體' => '体',
'髕' => '髌',
'髖' => '髋',
-'髣' => '仿',
'髥' => '髯',
'髮' => '发',
-'髴' => '佛',
'鬀' => '剃',
'鬆' => '松',
'鬉' => '鬃',
@@ -12665,7 +12664,6 @@ $zh2Hans = array(
'鬨' => '哄',
'鬩' => '阋',
'鬪' => '斗',
-'鬭' => '斗',
'鬮' => '阄',
'鬰' => '郁',
'鬱' => '郁',
@@ -12944,7 +12942,7 @@ $zh2Hans = array(
'鼇' => '鳌',
'鼈' => '鳖',
'鼉' => '鼍',
-'鼕' => '冬',
+'鼕' => '咚',
'鼴' => '鼹',
'齊' => '齐',
'齋' => '斋',
@@ -12977,43 +12975,30 @@ $zh2Hans = array(
'龜' => '龟',
'龭' => '𩨎',
'龯' => '𨱆',
-'𠇮' => '命',
-'𠌂' => '伞',
'𠌥' => '𠆿',
'𠏢' => '𠉗',
'𠕂' => '再',
'𠕅' => '再',
-'𠖇' => '冥',
'𠞆' => '𠛆',
'𠞰' => '剿',
'𠠎' => '𠚳',
-'𠪾' => '历',
-'𠴟' => '咩',
-'𠻳' => '嗽',
'𡄔' => '𠴢',
'𡄣' => '𠵸',
'𡅏' => '𠲥',
-'𡐨' => '野',
'𡑭' => '𡋗',
'𡓾' => '𡋀',
'𡚁' => '弊',
'𡞵' => '㛟',
'𡠹' => '㛿',
'𡢃' => '㛠',
-'𡨘' => '冤',
'𡨥' => '寇',
-'𡬶' => '寻',
'𡮉' => '𡭜',
'𡮣' => '𡭬',
'𡻕' => '岁',
'𡾱' => '㟜',
'𢣚' => '𢘝',
'𢣭' => '𢘞',
-'𢬸' => '括',
-'𢭏' => '捣',
-'𢮥' => '操',
'𢶫' => '𢫞',
-'𢷬' => '捣',
'𢷮' => '𢫊',
'𢹿' => '𢬦',
'𣙎' => '㭣',
@@ -13030,20 +13015,15 @@ $zh2Hans = array(
'𤨏' => '琐',
'𤪺' => '㻘',
'𤫩' => '㻏',
-'𤰜' => '亩',
'𤱈' => '亩',
-'𤱊' => '留',
'𤳸' => '𤳄',
'𤸫' => '𤶧',
'𤺥' => '瘩',
-'𥄨' => '瞅',
'𥌃' => '𥅘',
'𥕥' => '𥐰',
'𥖅' => '𥐯',
'𥢢' => '䅪',
-'𥦗' => '窗',
'𥨐' => '𥧂',
-'𥲻' => '纂',
'𥵃' => '𥱔',
'𥵊' => '𥭉',
'𥸠' => '𥮋',
@@ -13051,16 +13031,12 @@ $zh2Hans = array(
'𥽖' => '𥺇',
'𥿊' => '𦈈',
'𦂅' => '𦈒',
-'𦂳' => '紧',
-'𦃂' => '紧',
'𦃄' => '𦈗',
-'𦉆' => '碴',
'𦊱' => '挂',
'𦍑' => '羌',
'𦕈' => '眇',
'𦢈' => '𣍨',
'𦣎' => '𦟗',
-'𦪙' => '䑽',
'𦪽' => '𦨩',
'𦵏' => '葬',
'𧔥' => '𧒭',
@@ -13182,22 +13158,21 @@ $zh2Hans = array(
'』' => '’',
'「' => '“',
'「' => '“',
-'」' => '”',
'」' => '”',
+'」' => '”',
'。陞' => '。升',
'《易乾' => '《易乾',
'一釐' => '一厘',
-'一口鍾' => '一口钟',
-'一鍾' => '一钟',
'上昇' => '上升',
+'不穀' => '不穀',
'專著' => '专著',
-'世界鍾' => '世界钟',
-'喪鍾' => '丧钟',
'乾一坛' => '乾一坛',
'乾一壇' => '乾一坛',
-'乾一组' => '乾一组',
'乾一組' => '乾一组',
+'乾一组' => '乾一组',
'乾上乾下' => '乾上乾下',
+'乾东' => '乾东',
+'乾東' => '乾东',
'乾為天' => '乾为天',
'乾為陽' => '乾为阳',
'乾九' => '乾九',
@@ -13212,27 +13187,27 @@ $zh2Hans = array(
'乾光' => '乾光',
'乾兴' => '乾兴',
'乾興' => '乾兴',
-'乾岡' => '乾冈',
'乾冈' => '乾冈',
+'乾岡' => '乾冈',
'乾刘' => '乾刘',
'乾劉' => '乾刘',
'乾刚' => '乾刚',
'乾剛' => '乾刚',
-'乾務' => '乾务',
'乾务' => '乾务',
+'乾務' => '乾务',
'乾化' => '乾化',
'乾卦' => '乾卦',
'乾县' => '乾县',
'乾縣' => '乾县',
'乾台' => '乾台',
'乾吉' => '乾吉',
-'乾啟' => '乾启',
'乾启' => '乾启',
+'乾啟' => '乾启',
'乾命' => '乾命',
'乾和' => '乾和',
'乾嘉' => '乾嘉',
-'乾圖' => '乾图',
'乾图' => '乾图',
+'乾圖' => '乾图',
'乾坤' => '乾坤',
'乾城' => '乾城',
'乾基' => '乾基',
@@ -13251,9 +13226,8 @@ $zh2Hans = array(
'乾崗' => '乾岗',
'乾巛' => '乾巛',
'乾州' => '乾州',
-'乾式' => '乾式',
-'乾錄' => '乾录',
'乾录' => '乾录',
+'乾錄' => '乾录',
'乾律' => '乾律',
'乾德' => '乾德',
'乾心' => '乾心',
@@ -13266,17 +13240,17 @@ $zh2Hans = array(
'乾旦' => '乾旦',
'乾明' => '乾明',
'乾昧' => '乾昧',
-'乾暉' => '乾晖',
'乾晖' => '乾晖',
+'乾暉' => '乾晖',
'乾景' => '乾景',
'乾晷' => '乾晷',
'乾曜' => '乾曜',
-'乾構' => '乾构',
'乾构' => '乾构',
+'乾構' => '乾构',
'乾枢' => '乾枢',
'乾樞' => '乾枢',
-'乾棟' => '乾栋',
'乾栋' => '乾栋',
+'乾棟' => '乾栋',
'乾步' => '乾步',
'乾氏' => '乾氏',
'乾沓和' => '乾沓和',
@@ -13288,6 +13262,7 @@ $zh2Hans = array(
'乾潭' => '乾潭',
'乾灵' => '乾灵',
'乾靈' => '乾灵',
+'乾生元' => '乾生元',
'乾男' => '乾男',
'乾皋' => '乾皋',
'乾盛世' => '乾盛世',
@@ -13295,8 +13270,8 @@ $zh2Hans = array(
'乾祐' => '乾祐',
'乾神' => '乾神',
'乾穹' => '乾穹',
-'乾竇' => '乾窦',
'乾窦' => '乾窦',
+'乾竇' => '乾窦',
'乾竺' => '乾竺',
'乾笃' => '乾笃',
'乾篤' => '乾笃',
@@ -13307,14 +13282,14 @@ $zh2Hans = array(
'乾红' => '乾红',
'乾綱' => '乾纲',
'乾纲' => '乾纲',
-'乾纽' => '乾纽',
'乾紐' => '乾纽',
-'乾络' => '乾络',
+'乾纽' => '乾纽',
'乾絡' => '乾络',
+'乾络' => '乾络',
'乾統' => '乾统',
'乾统' => '乾统',
-'乾维' => '乾维',
'乾維' => '乾维',
+'乾维' => '乾维',
'乾罗' => '乾罗',
'乾羅' => '乾罗',
'乾花' => '乾花',
@@ -13325,18 +13300,18 @@ $zh2Hans = array(
'乾西' => '乾西',
'乾覆' => '乾覆',
'乾象' => '乾象',
-'乾象歷' => '乾象历',
'乾象历' => '乾象历',
+'乾象歷' => '乾象历',
'乾貞' => '乾贞',
'乾贞' => '乾贞',
-'乾贵士' => '乾贵士',
'乾貴士' => '乾贵士',
+'乾贵士' => '乾贵士',
'乾貺' => '乾贶',
'乾贶' => '乾贶',
'乾車' => '乾车',
'乾车' => '乾车',
-'乾轴' => '乾轴',
'乾軸' => '乾轴',
+'乾轴' => '乾轴',
'乾通' => '乾通',
'乾造' => '乾造',
'乾道' => '乾道',
@@ -13355,25 +13330,27 @@ $zh2Hans = array(
'乾風' => '乾风',
'乾风' => '乾风',
'乾首' => '乾首',
-'乾马' => '乾马',
'乾馬' => '乾马',
+'乾马' => '乾马',
'乾鵠' => '乾鹄',
'乾鹄' => '乾鹄',
'乾鵲' => '乾鹊',
'乾鹊' => '乾鹊',
-'乾龙' => '乾龙',
'乾龍' => '乾龙',
+'乾龙' => '乾龙',
'乾,健也' => '乾,健也',
'乾,天也' => '乾,天也',
'五箇山' => '五箇山',
+'什么' => '什么',
'仇讎' => '仇雠',
'以微知著' => '以微知著',
-'以莛叩鍾' => '以莛叩钟',
'仰屋著書' => '仰屋著书',
'彷彿' => '仿佛',
'夥計' => '伙计',
'佛頭著糞' => '佛头著粪',
'偵蒐' => '侦搜',
+'倖一郎' => '倖一郎',
+'倖田' => '倖田',
'候覆' => '候复',
'藉助' => '借助',
'藉口' => '借口',
@@ -13384,19 +13361,18 @@ $zh2Hans = array(
'藉由' => '借由',
'藉端' => '借端',
'藉詞' => '借词',
+'傒倖' => '傒倖',
'先名後姓' => '先名后姓',
+'兒寬' => '兒宽',
'六么' => '六幺',
'蘭質薰心' => '兰质薰心',
'內聯陞' => '内联升',
'憑藉' => '凭借',
-'分鍾' => '分钟',
'初昇' => '初升',
'利欲薰心' => '利欲薰心',
-'刻鍾' => '刻钟',
'剋了' => '剋了',
'剋架' => '剋架',
'剖釐' => '剖厘',
-'千鍾' => '千钟',
'陞為' => '升为',
'陞了' => '升了',
'昇仙' => '升仙',
@@ -13412,7 +13388,6 @@ $zh2Hans = array(
'昇降' => '升降',
'卓著' => '卓著',
'博和託' => '博和讬',
-'卷舌' => '卷舌',
'歷陞' => '历升',
'釐改' => '厘改',
'釐整' => '厘整',
@@ -13421,14 +13396,11 @@ $zh2Hans = array(
'釐清' => '厘清',
'釐訂' => '厘订',
'釐革' => '厘革',
-'原子鍾' => '原子钟',
'原著' => '原著',
'又陞' => '又升',
'反反覆覆' => '反反复复',
'反覆' => '反复',
-'古鍾' => '古钟',
'可穿著' => '可穿著',
-'台鍾' => '台钟',
'吃衣著飯' => '吃衣著饭',
'合著' => '合著',
'同陞和' => '同升和',
@@ -13439,41 +13411,40 @@ $zh2Hans = array(
'回覆' => '回复',
'土著' => '土著',
'坤乾' => '坤乾',
-'塔鍾' => '塔钟',
'墨瀋' => '墨渖',
-'壁鍾' => '壁钟',
'覆查' => '复查',
'覆核' => '复核',
'覆检' => '复检',
'復甦' => '复苏',
-'多鍾' => '多钟',
+'多么' => '多么',
'大麴' => '大曲',
-'大鍾' => '大钟',
-'天道為乾' => '天道为乾',
'天道为乾' => '天道为乾',
+'天道為乾' => '天道为乾',
'奧區' => '奧区',
'如瀋' => '如渖',
'姓么' => '姓幺',
'子餘' => '子馀',
'字乾生' => '字乾生',
-'孫乾' => '孙乾',
'孙乾' => '孙乾',
-'宋鍾國' => '宋钟国',
+'孫乾' => '孙乾',
'宏碁' => '宏碁',
'官陞' => '官升',
'將軍抽俥' => '将军抽俥',
'將軍抽車' => '将军抽車',
'爾冬陞' => '尔冬升',
'尼乾陀' => '尼乾陀',
+'侷促' => '局促',
'跼促' => '局促',
+'侷限' => '局限',
'跼限' => '局限',
-'山崩鍾應' => '山崩钟应',
-'崔秀鍾' => '崔秀钟',
+'山崎闇齋' => '山崎闇斋',
+'岳託' => '岳讬',
'巨著' => '巨著',
'乾乾淨淨' => '干干净净',
'乾乾脆脆' => '干干脆脆',
'乾泉水' => '干泉水',
'年陞' => '年升',
+'么九' => '幺九',
'么二三' => '幺二三',
'么元' => '幺元',
'么鳳' => '幺凤',
@@ -13482,15 +13453,18 @@ $zh2Hans = array(
'么廝' => '幺厮',
'幺厮' => '幺厮',
'么叔' => '幺叔',
+'么女' => '幺女',
'么媽' => '幺妈',
'么妹' => '幺妹',
'么姓' => '幺姓',
'么姨' => '幺姨',
'么娘' => '幺娘',
-'幺孃' => '幺娘',
'么孃' => '幺娘',
+'幺孃' => '幺娘',
+'么子' => '幺子',
'么小' => '幺小',
'么弟' => '幺弟',
+'么正' => '幺正',
'么氏' => '幺氏',
'么爸' => '幺爸',
'么爹' => '幺爹',
@@ -13498,22 +13472,20 @@ $zh2Hans = array(
'么舅' => '幺舅',
'么蛾子' => '幺蛾子',
'么謙' => '幺谦',
-'么麽' => '幺麽',
'么麼' => '幺麽',
+'么麽' => '幺麽',
'么麽小丑' => '幺麽小丑',
'慶餘' => '庆馀',
-'座鍾' => '座钟',
'康乾' => '康乾',
-'張法乾' => '张法乾',
'张法乾' => '张法乾',
-'張鍾英' => '张钟英',
+'張法乾' => '张法乾',
'彰明較著' => '彰明较著',
'待覆' => '待复',
'後姓' => '後姓',
'慫慂' => '怂恿',
+'怎么' => '怎么',
'恩威並著' => '恩威并著',
'噁心' => '恶心',
-'懸鍾' => '悬钟',
'情蒐' => '情搜',
'情鍾' => '情钟',
'惏悷' => '惏悷',
@@ -13526,6 +13498,7 @@ $zh2Hans = array(
'扞格' => '扞格',
'執著' => '执著',
'批覆' => '批复',
+'承乾' => '承乾',
'拉鍊' => '拉链',
'拙著' => '拙著',
'拚命' => '拚命',
@@ -13533,9 +13506,7 @@ $zh2Hans = array(
'拚死' => '拚死',
'拾瀋' => '拾渖',
'拿破崙' => '拿破仑',
-'掛鍾' => '挂钟',
'挨剋' => '挨剋',
-'掩耳盜鍾' => '掩耳盗钟',
'提昇' => '提升',
'蒐錄' => '搜录',
'蒐索' => '搜索',
@@ -13544,17 +13515,15 @@ $zh2Hans = array(
'蒐證' => '搜证',
'蒐購' => '搜购',
'蒐輯' => '搜辑',
-'蒐采' => '搜采',
'蒐採' => '搜采',
+'蒐采' => '搜采',
'蒐集' => '搜集',
'搥打' => '搥打',
'搥胸頓足' => '搥胸顿足',
-'擺鍾' => '摆钟',
-'撞鍾' => '撞钟',
'撰著' => '撰著',
'效果顯著' => '效果显著',
-'敲鍾' => '敲钟',
'文徵明' => '文徵明',
+'觔斗' => '斤斗',
'新著' => '新著',
'於世成' => '於世成',
'於之瑩' => '於之莹',
@@ -13572,10 +13541,10 @@ $zh2Hans = array(
'於志賀' => '於志贺',
'於志贺' => '於志贺',
'於戲' => '於戏',
-'於梨華' => '於梨华',
'於梨华' => '於梨华',
+'於梨華' => '於梨华',
'於氏' => '於氏',
-'於潜县' => '於潜县',
+'於潜' => '於潜',
'於潛縣' => '於潜县',
'於祥玉' => '於祥玉',
'於菟' => '於菟',
@@ -13583,7 +13552,6 @@ $zh2Hans = array(
'於除鞬' => '於除鞬',
'旋乾轉坤' => '旋乾转坤',
'旋乾转坤' => '旋乾转坤',
-'時鍾' => '时钟',
'曠若發矇' => '旷若发矇',
'崑崙' => '昆仑',
'崑劇' => '昆剧',
@@ -13593,10 +13561,10 @@ $zh2Hans = array(
'崑蘇' => '昆苏',
'崑調' => '昆调',
'易·乾' => '易·乾',
-'易经·乾' => '易经·乾',
'易經·乾' => '易经·乾',
-'易经乾' => '易经乾',
+'易经·乾' => '易经·乾',
'易經乾' => '易经乾',
+'易经乾' => '易经乾',
'昭著' => '昭著',
'顯著' => '显著',
'顯著地' => '显著地',
@@ -13606,17 +13574,17 @@ $zh2Hans = array(
'顯著效果' => '显著效果',
'顯著特點' => '显著特点',
'晉陞' => '晋升',
-'晚鍾' => '晚钟',
-'晨鍾' => '晨钟',
'暗闇' => '暗闇',
'麴黴' => '曲霉',
-'曾運乾' => '曾运乾',
'曾运乾' => '曾运乾',
+'曾運乾' => '曾运乾',
'月陞' => '月升',
'朝乾夕惕' => '朝乾夕惕',
-'朝鍾暮鼓' => '朝钟暮鼓',
'朱有燉' => '朱有燉',
'朱淛' => '朱淛',
+'硃砂' => '朱砂',
+'硃紅' => '朱红',
+'硃色' => '朱色',
'朴於宇同' => '朴於宇同',
'李乾德' => '李乾德',
'李乾順' => '李乾顺',
@@ -13624,18 +13592,14 @@ $zh2Hans = array(
'李澤鉅' => '李泽钜',
'李祕' => '李祕',
'李譔' => '李譔',
-'李鍾原' => '李钟原',
-'林鍾' => '林钟',
-'柳诒徵' => '柳诒徵',
'柳詒徵' => '柳诒徵',
+'柳诒徵' => '柳诒徵',
'校讎' => '校雠',
'楈枒' => '楈枒',
'樊於期' => '樊於期',
-'橡椀' => '橡椀',
-'此鍾' => '此钟',
'殘瀋' => '残渖',
-'慇懃' => '殷勤',
'慇勤' => '殷勤',
+'慇懃' => '殷勤',
'比較顯著' => '比较显著',
'毫釐' => '毫厘',
'氆氌' => '氆氌',
@@ -13647,9 +13611,7 @@ $zh2Hans = array(
'沈默' => '沉默',
'氾濫' => '泛滥',
'洗鍊' => '洗练',
-'洪鍾' => '洪钟',
'瀋液' => '渖液',
-'點鍾' => '点钟',
'薰習' => '熏习',
'薰心' => '熏心',
'薰沐' => '熏沐',
@@ -13660,36 +13622,34 @@ $zh2Hans = array(
'王道乾' => '王道乾',
'王餘魚' => '王馀鱼',
'甚夥' => '甚夥',
-'生物鍾' => '生物钟',
-'電鍾' => '电钟',
-'男為乾' => '男为乾',
'男为乾' => '男为乾',
-'男爲乾' => '男为乾',
-'男性爲乾' => '男性为乾',
-'男性為乾' => '男性为乾',
+'男為乾' => '男为乾',
'男性为乾' => '男性为乾',
+'男性為乾' => '男性为乾',
'療效顯著' => '疗效显著',
'白瀋' => '白渖',
'皁保' => '皁保',
'目劄' => '目劄',
'直昇' => '直升',
'睹微知著' => '睹微知著',
-'瞭臺' => '瞭台',
'瞭台' => '瞭台',
+'瞭臺' => '瞭台',
'瞭望' => '瞭望',
'矇眬' => '矇眬',
'矇矓' => '矇眬',
'石碁' => '石碁',
'石碁鎮' => '石碁镇',
-'石英鍾' => '石英钟',
-'石鍾乳' => '石钟乳',
+'碩託' => '硕讬',
'鹼菜' => '硷菜',
-'碁聖' => '碁圣',
'碁圣' => '碁圣',
+'碁聖' => '碁圣',
'碁所' => '碁所',
'祕宜' => '祕宜',
-'秒鍾' => '秒钟',
+'穀旦' => '穀旦',
'穀梁' => '穀梁',
+'穀水' => '穀水',
+'穀阳' => '穀阳',
+'穀陽' => '穀阳',
'穿著者' => '穿着者',
'竹昇' => '竹升',
'答覆' => '答复',
@@ -13697,10 +13657,11 @@ $zh2Hans = array(
'米瀋' => '米渖',
'餬口' => '糊口',
'繙㠾' => '繙㠾',
+'遶境' => '绕境',
'線國安' => '缐国安',
'線姓' => '缐姓',
'編著' => '编著',
-'編鍾' => '编钟',
+'老么' => '老幺',
'肉乾乾' => '肉干干',
'肘手鍊足' => '肘手链足',
'甦醒' => '苏醒',
@@ -13723,14 +13684,19 @@ $zh2Hans = array(
'著者' => '著者',
'著身' => '著身',
'著述' => '著述',
-'覆蓋' => '覆蓋',
+'蔡孝乾' => '蔡孝乾',
+'蔡絛' => '蔡絛',
+'行餘' => '行馀',
+'覆蓋' => '覆盖',
'見微知著' => '见微知著',
'見著' => '见著',
'視微知著' => '视微知著',
'言幾析理' => '言幾析理',
'諲譔' => '諲譔',
-'警鍾' => '警钟',
'譩譆' => '譩譆',
+'託庸' => '讬庸',
+'託恩多' => '讬恩多',
+'託麻' => '讬麻',
'論著' => '论著',
'譯著' => '译著',
'謝肇淛' => '谢肇淛',
@@ -13739,12 +13705,11 @@ $zh2Hans = array(
'較著' => '较著',
'近角聪信' => '近角聪信',
'这么' => '这么',
-'進化鍾' => '进化钟',
'造麴' => '造曲',
'遺著' => '遗著',
+'那么' => '那么',
'那麽' => '那麽',
'郭子乾' => '郭子乾',
-'郭行餘' => '郭行馀',
'酒麴' => '酒曲',
'醉瀋' => '醉渖',
'醯壶' => '醯壶',
@@ -13753,48 +13718,17 @@ $zh2Hans = array(
'醯醬' => '醯酱',
'醯醋' => '醯醋',
'醯醢' => '醯醢',
-'醯鸡' => '醯鸡',
'醯雞' => '醯鸡',
+'醯鸡' => '醯鸡',
'重覆' => '重复',
-'金尚鍾' => '金尚钟',
-'金民鍾' => '金民钟',
-'金鍾' => '金钟',
'金鍊' => '金链',
-'鍾麗緹' => '钟丽缇',
-'鍾乳石' => '钟乳石',
-'鍾儀奏楚' => '钟仪奏楚',
-'鍾關' => '钟关',
-'鍾聲' => '钟声',
-'鍾頭' => '钟头',
-'鍾山' => '钟山',
-'鍾差' => '钟差',
-'鍾座' => '钟座',
'鍾情' => '钟情',
'鍾意' => '钟意',
-'鍾慧冰' => '钟慧冰',
-'鍾擺' => '钟摆',
-'鍾架' => '钟架',
-'鍾楚紅' => '钟楚红',
-'鍾樓' => '钟楼',
-'鍾漢良' => '钟汉良',
-'鍾汶' => '钟汶',
-'鍾淑慧' => '钟淑慧',
'鍾靈' => '钟灵',
-'鍾點' => '钟点',
'鍾愛' => '钟爱',
-'鍾琴' => '钟琴',
-'鍾相' => '钟相',
-'鍾祥' => '钟祥',
-'鍾離' => '钟离',
-'鍾表' => '钟表',
-'鍾鎮濤' => '钟镇涛',
-'鍾面' => '钟面',
-'鍾馗' => '钟馗',
-'鍾鳴漏盡' => '钟鸣漏尽',
-'鍾鳴鼎食' => '钟鸣鼎食',
-'鍾鼓' => '钟鼓',
'鐵鍊' => '铁链',
'鉸鍊' => '铰链',
+'銀硃' => '银朱',
'銀鍊' => '银链',
'鍊子' => '链子',
'鍊條' => '链条',
@@ -13802,11 +13736,10 @@ $zh2Hans = array(
'鍊鎖' => '链锁',
'鍊錘' => '链锤',
'鎖鍊' => '锁链',
+'闇公' => '闇公',
'閻懷禮' => '闫怀礼',
-'鬧鍾' => '闹钟',
-'陽為乾' => '阳为乾',
'阳为乾' => '阳为乾',
-'陽爲乾' => '阳为乾',
+'陽為乾' => '阳为乾',
'阿部正瞭' => '阿部正瞭',
'陆徵祥' => '陆徵祥',
'陸徵祥' => '陆徵祥',
@@ -13816,8 +13749,8 @@ $zh2Hans = array(
'陳元扞' => '陈元扞',
'陈公乾生' => '陈公乾生',
'陳公乾生' => '陈公乾生',
-'陳遇乾' => '陈遇乾',
'陈遇乾' => '陈遇乾',
+'陳遇乾' => '陈遇乾',
'陳堵' => '陳堵',
'陳禕' => '陳禕',
'雍乾' => '雍乾',
@@ -13825,28 +13758,25 @@ $zh2Hans = array(
'讎定' => '雠定',
'讎校' => '雠校',
'讎問' => '雠问',
-'音聲如鍾' => '音声如钟',
'項鍊' => '项链',
'飛昇' => '飞升',
'飭令' => '飭令',
-'餘年無多' => '馀年无多',
+'飽託' => '饱讬',
'餘慶' => '馀庆',
'餘瀋' => '馀渖',
-'馬德鍾' => '马德钟',
+'馬鞌' => '马鞍',
'高昇' => '高升',
'高陞' => '高升',
'鬱姓' => '鬱姓',
'鬱氏' => '鬱氏',
'魏徵' => '魏徵',
'魚乾乾' => '鱼干干',
-'鳴鍾' => '鸣钟',
'麽氏' => '麽氏',
-'麽麽' => '麽麽',
'麼麼' => '麽麽',
+'麽麽' => '麽麽',
'黃麴毒素' => '黄曲毒素',
-'黄润乾' => '黄润乾',
'黃潤乾' => '黄润乾',
-'黃鍾' => '黄钟',
+'黄润乾' => '黄润乾',
'龍鍾' => '龙钟',
',陞' => ',升',
);
@@ -13870,8 +13800,8 @@ $zh2TW = array(
'丙肝' => 'C肝',
'IP地址' => 'IP位址',
'乔戈里峰' => 'K2',
-'·威爾士' => '·威爾士',
'·威尔士' => '·威爾士',
+'·威爾士' => '·威爾士',
'一杆' => '一桿',
'七杆' => '七桿',
'三杆' => '三桿',
@@ -13885,6 +13815,7 @@ $zh2TW = array(
'以太网' => '乙太網',
'九杆' => '九桿',
'了結他' => '了結他',
+'二手烟' => '二手菸',
'二手煙' => '二手菸',
'二杆' => '二桿',
'二极管' => '二極體',
@@ -13895,22 +13826,20 @@ $zh2TW = array(
'阿斯旺' => '亞斯文',
'人工智能' => '人工智慧',
'人机交互' => '人機互動',
-'石勒蘇益格' => '什勒斯維希',
'石勒苏益格' => '什勒斯維希',
+'石勒蘇益格' => '什勒斯維希',
'界面' => '介面',
'伊利诺伊州' => '伊利諾州',
-'伊斯坦布爾' => '伊斯坦堡',
'伊斯坦布尔' => '伊斯坦堡',
+'伊斯坦布爾' => '伊斯坦堡',
'伊斯兰堡' => '伊斯蘭瑪巴德',
'伊斯蘭堡' => '伊斯蘭瑪巴德',
'埃博拉' => '伊波拉',
'伊丽莎白' => '伊莉莎白',
-'掌上壓' => '伏地挺身',
'俯卧撑' => '伏地挺身',
+'掌上壓' => '伏地挺身',
'伯明翰' => '伯明罕',
'服务器' => '伺服器',
-'字节' => '位元組',
-'字節' => '位元組',
'佛罗伦萨' => '佛羅倫斯',
'操作系统' => '作業系統',
'系数' => '係數',
@@ -13918,8 +13847,8 @@ $zh2TW = array(
'傅里叶' => '傅立葉',
'光盘' => '光碟',
'光驱' => '光碟機',
-'克羅地亞' => '克羅埃西亞',
'克罗地亚' => '克羅埃西亞',
+'克羅地亞' => '克羅埃西亞',
'克里斯托弗' => '克里斯多福',
'万维网' => '全球資訊網',
'八杆' => '八桿',
@@ -13927,6 +13856,9 @@ $zh2TW = array(
'六杆' => '六桿',
'凯瑟琳' => '凱薩琳',
'嘉芙蓮' => '凱薩琳',
+'划着独木舟' => '划著獨木舟',
+'划着竹筏' => '划著竹筏',
+'划着船' => '划著船',
'打印' => '列印',
'列支敦士登' => '列支敦斯登',
'前波美拉尼亚' => '前波莫瑞',
@@ -13938,22 +13870,24 @@ $zh2TW = array(
'北朝鲜' => '北韓',
'局域网' => '區域網',
'十杆' => '十桿',
-'特立尼達和多巴哥' => '千里達托貝哥',
'特立尼达和托巴哥' => '千里達托貝哥',
+'特立尼達和多巴哥' => '千里達托貝哥',
'南朝鲜' => '南韓',
'卡斯特罗' => '卡斯楚',
'卡塔尔' => '卡達',
'卡塔爾' => '卡達',
+'铆足' => '卯足',
'打印机' => '印表機',
'打印機' => '印表機',
-'厄立特里亞' => '厄利垂亞',
-'厄立特里亚' => '厄利垂亞',
'厄利垂亚' => '厄利垂亞',
-'厄瓜多爾' => '厄瓜多',
+'厄立特里亚' => '厄利垂亞',
+'厄立特里亞' => '厄利垂亞',
'厄瓜多' => '厄瓜多',
'厄瓜多尔' => '厄瓜多',
+'厄瓜多爾' => '厄瓜多',
'源代码' => '原始碼',
'圆珠笔' => '原子筆',
+'反烟' => '反菸',
'反煙' => '反菸',
'可卡因' => '古柯鹼',
'便携式' => '可攜式',
@@ -13963,7 +13897,7 @@ $zh2TW = array(
'叱咤叱' => '叱咤叱',
'叱咤咤' => '叱咤咤',
'叱咤樂壇' => '叱咤樂壇',
-'斯坦福' => '史丹福',
+'斯坦福大学' => '史丹福大學',
'斯皮尔伯格' => '史匹柏',
'斯特劳斯' => '史特勞斯',
'斯威士兰' => '史瓦濟蘭',
@@ -13975,17 +13909,17 @@ $zh2TW = array(
'乞力马扎罗' => '吉力馬札羅',
'吉布堤' => '吉布地',
'吉布提' => '吉布地',
-'吉尔吉斯斯坦' => '吉爾吉斯',
'基里巴斯' => '吉里巴斯',
-'圖瓦盧' => '吐瓦魯',
'图瓦卢' => '吐瓦魯',
+'圖瓦盧' => '吐瓦魯',
+'吸烟' => '吸菸',
'吸煙' => '吸菸',
+'吕宋烟' => '呂宋菸',
'呂宋煙' => '呂宋菸',
-'哈萨克斯坦' => '哈薩克',
'格丁根' => '哥廷根',
'哥特式' => '哥德式',
-'哥斯達黎加' => '哥斯大黎加',
'哥斯达黎加' => '哥斯大黎加',
+'哥斯達黎加' => '哥斯大黎加',
'卡拉奇' => '喀拉蚩',
'乔治·奥威尔' => '喬治·歐威爾',
'佐治亚' => '喬治亞',
@@ -13996,63 +13930,63 @@ $zh2TW = array(
'單鏡反光機' => '單眼相機',
'嘯咤' => '嘯吒',
'四杆' => '四桿',
-'土库曼斯坦' => '土庫曼',
-'圖盧茲' => '土魯斯',
'图卢兹' => '土魯斯',
-'IP' => '地址',
+'圖盧茲' => '土魯斯',
'戛纳' => '坎城',
'堪培拉' => '坎培拉',
-'坦桑尼亞' => '坦尚尼亞',
'坦桑尼亚' => '坦尚尼亞',
+'坦桑尼亞' => '坦尚尼亞',
'端口' => '埠',
'首席执行官' => '執行長',
-'塔吉克斯坦' => '塔吉克',
-'塞舌爾' => '塞席爾',
+'报道' => '報導',
'塞舌尔' => '塞席爾',
+'塞舌爾' => '塞席爾',
'萨拉热窝' => '塞拉耶佛',
'薩拉熱窩' => '塞拉耶佛',
+'塞尔维亚和黑山' => '塞爾維亞與蒙特內哥羅',
'塞爾維亞和黑山' => '塞爾維亞與蒙特內哥羅',
'塞爾維亞與蒙特內哥羅' => '塞爾維亞與蒙特內哥羅',
-'塞尔维亚和黑山' => '塞爾維亞與蒙特內哥羅',
'塞维利亚' => '塞維亞',
'西維爾' => '塞維亞',
'塞黑' => '塞蒙',
-'英联邦' => '大英國協',
'共和联邦' => '大英國協',
+'英联邦' => '大英國協',
'英聯邦' => '大英國協',
-'宇航员' => '太空人',
'太空飛行員' => '太空人',
-'航天飞机' => '太空梭',
+'宇航员' => '太空人',
'穿梭機' => '太空梭',
+'航天飞机' => '太空梭',
'宇航服' => '太空衣',
'航天器' => '太空飛行器',
-'尼日利亞' => '奈及利亞',
'尼日利亚' => '奈及利亞',
+'尼日利亞' => '奈及利亞',
'忌廉' => '奶油',
'荷里活' => '好萊塢',
'威廉姆斯' => '威廉士',
-'威斯特法倫' => '威斯伐倫',
'威斯特法伦' => '威斯伐倫',
+'威斯特法倫' => '威斯伐倫',
'威士顿康星' => '威斯康辛',
-'威爾士' => '威爾斯',
'威尔士' => '威爾斯',
+'威爾士' => '威爾斯',
'字库' => '字型檔',
'存盘' => '存檔',
-'门德尔松' => '孟德爾頌',
'孟德爾遜' => '孟德爾頌',
-'安哈爾特' => '安哈特',
+'门德尔松' => '孟德爾頌',
'安哈尔特' => '安哈特',
-'安提瓜和巴布達' => '安地卡及巴布達',
+'安哈爾特' => '安哈特',
'安提瓜和巴布达' => '安地卡及巴布達',
+'安提瓜和巴布達' => '安地卡及巴布達',
'洪都拉斯' => '宏都拉斯',
'密歇根' => '密西根',
'宽带' => '寬頻',
-'老撾人民民主共和國' => '寮人民民主共和國',
'老挝人民民主共和国' => '寮人民民主共和國',
+'老撾人民民主共和國' => '寮人民民主共和國',
'老挝' => '寮國',
'老撾' => '寮國',
'老挝语' => '寮語',
'老撾語' => '寮語',
+'波里活' => '寶萊塢',
+'对着干' => '對著幹',
'高峰时段' => '尖峰時段',
'高峰时间' => '尖峰時間',
'贊比亞' => '尚比亞',
@@ -14065,8 +13999,8 @@ $zh2TW = array(
'機床' => '工具機',
'珍寶客機' => '巨無霸客機',
'发达国家' => '已開發國家',
-'巴塞隆拿' => '巴塞隆納',
'巴塞罗那' => '巴塞隆納',
+'巴塞隆拿' => '巴塞隆納',
'巴布亚新几内亚' => '巴布亞紐幾內亞',
'巴布亞新畿內亞' => '巴布亞紐幾內亞',
'巴士拉' => '巴斯拉',
@@ -14074,12 +14008,13 @@ $zh2TW = array(
'佈' => '布',
'布基納法索' => '布吉納法索',
'布基纳法索' => '布吉納法索',
-'布殊' => '布希',
'布什' => '布希',
+'布殊' => '布希',
'勃兰登堡' => '布蘭登堡',
'勃蘭登堡' => '布蘭登堡',
'布里斯托尔' => '布里斯托',
'布隆方丹' => '布隆泉',
+'希拉莉' => '希拉蕊',
'希拉里' => '希拉蕊',
'希特拉' => '希特勒',
'巴尔米拉环礁' => '帕邁拉環礁',
@@ -14092,12 +14027,15 @@ $zh2TW = array(
'几内亚比绍' => '幾內亞比索',
'幾內亞比紹' => '幾內亞比索',
'比利牛斯' => '庇里牛斯',
+'库尔德人' => '庫德人',
+'库尔德族' => '庫德族',
'康涅狄格' => '康乃狄克',
'约翰斯顿岛' => '強斯頓環礁',
+'汇编' => '彙編',
'形而上学' => '形上學',
'形而上學' => '形上學',
-'得克薩斯' => '德克薩斯',
'得克萨斯' => '德克薩斯',
+'得克薩斯' => '德克薩斯',
'德累斯頓' => '德勒斯登',
'德累斯顿' => '德勒斯登',
'德里达' => '德希達',
@@ -14111,74 +14049,86 @@ $zh2TW = array(
'艾奧瓦' => '愛荷華',
'爱德华州' => '愛達荷州',
'应用程序' => '應用程式',
-'戈爾巴喬夫' => '戈巴契夫',
'戈尔巴乔夫' => '戈巴契夫',
+'戈爾巴喬夫' => '戈巴契夫',
+'戒烟' => '戒菸',
'戒煙' => '戒菸',
'戴克里先' => '戴克里先',
+'打印度' => '打印度',
+'抽烟' => '抽菸',
'抽煙' => '抽菸',
'拉普兰' => '拉布蘭',
+'拒烟' => '拒菸',
'拒煙' => '拒菸',
+'卷烟' => '捲菸',
'捲煙' => '捲菸',
'積架' => '捷豹',
'控件' => '控制項',
'推杆' => '推桿',
'第比利斯' => '提比里西',
-'揮杆' => '揮桿',
'挥杆' => '揮桿',
+'揮杆' => '揮桿',
'搜索引擎' => '搜尋引擎',
'摩根士丹利' => '摩根史坦利',
'台球' => '撞球',
-'攻打印' => '攻打印',
+'攻打' => '攻打',
'数字技术' => '數位技術',
'數碼技術' => '數位技術',
-'數碼相機' => '數位相機',
+'数字照相机' => '數位照相機',
+'数码照相机' => '數位照相機',
+'數碼照相機' => '數位照相機',
'数码相机' => '數位相機',
+'數碼相機' => '數位相機',
'数字信号' => '數位訊號',
'數碼訊號' => '數位訊號',
'数字电视' => '數位電視',
'數碼電視' => '數位電視',
-'调制解调器' => '數據機',
'調制解調器' => '數據機',
+'调制解调器' => '數據機',
'斯洛文尼亚' => '斯洛維尼亞',
'斯洛文尼亞' => '斯洛維尼亞',
'新罕布什尔' => '新罕布夏',
'施罗德' => '施洛德',
+'旱烟' => '旱菸',
'旱煙' => '旱菸',
'普利策' => '普利茲',
'芯片' => '晶片',
'智能卡' => '智慧卡',
-'智能手機' => '智慧型手機',
'智能手机' => '智慧型手機',
+'智能手機' => '智慧型手機',
'智能电话' => '智慧型電話',
'智能電話' => '智慧型電話',
-'知识产权' => '智慧財產權',
'知識產權' => '智慧財產權',
+'知识产权' => '智慧財產權',
'萌島' => '曼島',
'马恩岛' => '曼島',
'木杆' => '木桿',
'列奥纳多' => '李奧納多',
-'杜塞爾多夫' => '杜塞道夫',
'杜塞尔多夫' => '杜塞道夫',
+'杜塞爾多夫' => '杜塞道夫',
'迪拜' => '杜拜',
-'亚细安' => '東協',
'东盟' => '東協',
-'东南亚国家联盟' => '東南亞國協',
+'亚细安' => '東協',
+'東盟' => '東協',
+'东南亚国家联盟' => '東南亞國家協會',
+'東南亞國家聯盟' => '東南亞國家協會',
'柏林墙' => '柏林圍牆',
'柏林牆' => '柏林圍牆',
'乍得' => '查德',
'查韦斯' => '查維茲',
-'克林顿' => '柯林頓',
'克林頓' => '柯林頓',
-'撒切尔' => '柴契爾',
+'克林顿' => '柯林頓',
'戴卓爾' => '柴契爾',
-'格林纳达' => '格瑞那達',
+'撒切尔' => '柴契爾',
'格林納達' => '格瑞那達',
-'乒乓球' => '桌球',
+'格林纳达' => '格瑞那達',
+'台式电脑' => '桌上型電腦',
'乒乓' => '桌球',
+'乒乓球' => '桌球',
'杆弟' => '桿弟',
'杆身' => '桿身',
-'杆頭' => '桿頭',
'杆头' => '桿頭',
+'杆頭' => '桿頭',
'梅尔·吉布森' => '梅爾·吉勃遜',
'梵高' => '梵谷',
'桑巴舞' => '森巴舞',
@@ -14189,38 +14139,41 @@ $zh2TW = array(
'標準杆' => '標準桿',
'毛里求斯' => '模里西斯',
'毛里裘斯' => '模里西斯',
-'機械人' => '機器人',
'机器人' => '機器人',
+'機械人' => '機器人',
'概率' => '機率',
'電單車' => '機車',
'枱' => '檯',
'字段' => '欄位',
-'奧巴馬' => '歐巴馬',
'奥巴马' => '歐巴馬',
+'奧巴馬' => '歐巴馬',
'正在叱咤' => '正在叱咤',
'文莱' => '汶萊',
'沙律' => '沙拉',
-'沙特阿拉伯' => '沙烏地阿拉伯',
'沙地阿拉伯' => '沙烏地阿拉伯',
+'沙特阿拉伯' => '沙烏地阿拉伯',
'法属圭亚那' => '法屬蓋亞那',
'波斯尼亚' => '波士尼亞',
'波斯尼亞' => '波士尼亞',
-'波斯尼亞黑塞哥維那' => '波士尼亞赫塞哥維納',
'波斯尼亚和黑塞哥维那' => '波士尼亞赫塞哥維納',
-'博茨瓦纳' => '波札那',
+'波斯尼亞黑塞哥維那' => '波士尼亞赫塞哥維納',
'博茨瓦納' => '波札那',
+'博茨瓦纳' => '波札那',
'波黑' => '波赫',
+'洋烟' => '洋菸',
'洋煙' => '洋菸',
'帕特里克' => '派屈克',
'海洛英' => '海洛因',
-'侯赛因' => '海珊',
'侯賽因' => '海珊',
+'侯赛因' => '海珊',
'鼠标' => '滑鼠',
-'漢诺威' => '漢諾瓦',
'汉诺威' => '漢諾瓦',
-'乌兹别克斯坦' => '烏茲別克',
+'漢诺威' => '漢諾瓦',
+'烤烟' => '烤菸',
'烤煙' => '烤菸',
+'无烟日' => '無菸日',
'無煙日' => '無菸日',
+'无烟环境' => '無菸環境',
'無煙環境' => '無菸環境',
'烟熏' => '煙燻',
'首席运营官' => '營運長',
@@ -14233,11 +14186,13 @@ $zh2TW = array(
'铁托' => '狄托',
'塞拉利昂' => '獅子山',
'独联体' => '獨立國協',
+'獨聯體' => '獨立國協',
'独立国家联合体' => '獨立國家國協',
+'獨立國家聯合體' => '獨立國家國協',
'波利尼西亚' => '玻里尼西亞',
'波利尼西亞' => '玻里尼西亞',
-'本杰明' => '班傑明',
'本傑明' => '班傑明',
+'本杰明' => '班傑明',
'球杆' => '球桿',
'理查德' => '理察',
'卢塞恩' => '琉森',
@@ -14254,12 +14209,12 @@ $zh2TW = array(
'徵狀' => '症狀',
'勃朗宁' => '白朗寧',
'百慕大' => '百慕達',
-'盧旺達' => '盧安達',
'卢旺达' => '盧安達',
+'盧旺達' => '盧安達',
'睾' => '睪',
'知识产权局' => '知識產權局',
-'知識產權署' => '知識產權署',
'知識產權局' => '知識產權署',
+'知識產權署' => '知識產權署',
'知识产权署' => '知識產權署',
'硅' => '矽',
'硅藻' => '硅藻',
@@ -14268,17 +14223,19 @@ $zh2TW = array(
'盘片' => '碟片',
'磁盘' => '磁碟',
'磁道' => '磁軌',
+'禁烟' => '禁菸',
'禁煙' => '禁菸',
'福尔马林' => '福馬林',
'福爾馬林' => '福馬林',
+'私烟' => '私菸',
'私煙' => '私菸',
'程序员' => '程式設計師',
'编程语言' => '程式語言',
-'空氣質素' => '空氣品質',
'空气质量' => '空氣品質',
+'空氣質素' => '空氣品質',
'突尼斯' => '突尼西亞',
-'蹦极跳' => '笨豬跳',
'绑紧跳' => '笨豬跳',
+'蹦极跳' => '笨豬跳',
'短信' => '簡訊',
'纽黑文' => '紐哈芬',
'新奥尔良' => '紐奧良',
@@ -14287,23 +14244,26 @@ $zh2TW = array(
'新西兰' => '紐西蘭',
'新西蘭' => '紐西蘭',
'紙煙' => '紙菸',
-'索贊尼辛' => '索忍尼辛',
+'纸烟' => '紙菸',
'索尔仁尼琴' => '索忍尼辛',
-'所羅門群島' => '索羅門群島',
+'索贊尼辛' => '索忍尼辛',
'所罗门群岛' => '索羅門群島',
-'索马里' => '索馬利亞',
+'所羅門群島' => '索羅門群島',
'索馬里' => '索馬利亞',
-'索马里兰' => '索馬利蘭',
+'索马里' => '索馬利亞',
'索馬里蘭' => '索馬利蘭',
+'索马里兰' => '索馬利蘭',
'維爾京群島' => '維京群島',
'维尔京群岛' => '維京群島',
'弗吉尼亚' => '維吉尼亞',
'佛得角' => '維德角',
'维特根斯坦' => '維根斯坦',
+'網絡遊戲' => '網路遊戲',
+'网络游戏' => '網路遊戲',
+'互联网' => '網際網路',
'互联网络' => '網際網路',
-'因特网' => '網際網路',
'互聯網' => '網際網路',
-'互联网' => '網際網路',
+'因特网' => '網際網路',
'系着' => '繫著',
'卢瓦尔' => '羅亞爾',
'盧瓦爾' => '羅亞爾',
@@ -14314,11 +14274,11 @@ $zh2TW = array(
'昂山素季' => '翁山蘇姬',
'圣基茨和尼维斯' => '聖克里斯多福及尼維斯',
'聖吉斯納域斯' => '聖克里斯多福及尼維斯',
-'聖文森特和格林納丁斯' => '聖文森及格瑞那丁',
'圣文森特和格林纳丁斯' => '聖文森及格瑞那丁',
+'聖文森特和格林納丁斯' => '聖文森及格瑞那丁',
'圣赫勒拿' => '聖赫倫那',
-'聖盧西亞' => '聖露西亞',
'圣卢西亚' => '聖露西亞',
+'聖盧西亞' => '聖露西亞',
'圣马力诺' => '聖馬利諾',
'聖馬力諾' => '聖馬利諾',
'肯尼亚' => '肯亞',
@@ -14328,8 +14288,8 @@ $zh2TW = array(
'三藩市' => '舊金山',
'艾森豪威尔' => '艾森豪',
'埃菲尔' => '艾菲爾',
-'阿里埃勒·沙龙' => '艾里爾·夏隆',
'阿里埃勒·沙龍' => '艾里爾·夏隆',
+'阿里埃勒·沙龙' => '艾里爾·夏隆',
'帕塔亚' => '芭達亞',
'黎克特制' => '芮氏',
'里氏0' => '芮氏0',
@@ -14347,8 +14307,8 @@ $zh2TW = array(
'里氏震级' => '芮氏規模',
'当且仅当' => '若且唯若',
'味美思' => '苦艾酒',
-'毛里塔尼亞' => '茅利塔尼亞',
'毛里塔尼亚' => '茅利塔尼亞',
+'毛里塔尼亞' => '茅利塔尼亞',
'霍尔木兹' => '荷姆茲',
'霍爾木茲' => '荷姆茲',
'荷李活道' => '荷李活道',
@@ -14356,27 +14316,45 @@ $zh2TW = array(
'瓦文萨' => '華勒沙',
'華里沙' => '華勒沙',
'瓦格纳' => '華格納',
+'烟具' => '菸具',
'煙具' => '菸具',
+'烟品' => '菸品',
'煙品' => '菸品',
+'烟嘴' => '菸嘴',
'煙嘴' => '菸嘴',
+'烟卷' => '菸捲',
'煙捲' => '菸捲',
+'烟斗' => '菸斗',
'煙斗' => '菸斗',
+'烟民' => '菸民',
'煙民' => '菸民',
+'烟灰' => '菸灰',
'煙灰' => '菸灰',
+'烟瘾' => '菸癮',
'煙癮' => '菸癮',
+'烟丝' => '菸絲',
'煙絲' => '菸絲',
+'烟草' => '菸草',
'煙草' => '菸草',
+'烟叶' => '菸葉',
'煙葉' => '菸葉',
+'烟蒂' => '菸蒂',
'煙蒂' => '菸蒂',
+'烟袋' => '菸袋',
'煙袋' => '菸袋',
+'烟农' => '菸農',
'煙農' => '菸農',
+'烟酒' => '菸酒',
'煙酒' => '菸酒',
+'烟头' => '菸頭',
'煙頭' => '菸頭',
+'烟鬼' => '菸鬼',
'煙鬼' => '菸鬼',
+'烟碱' => '菸鹼',
'煙鹼' => '菸鹼',
'万历朝鲜战争' => '萬曆朝鮮戰爭',
-'瓦努阿圖' => '萬那杜',
'瓦努阿图' => '萬那杜',
+'瓦努阿圖' => '萬那杜',
'叶利钦' => '葉爾欽',
'葉利欽' => '葉爾欽',
'埃里温' => '葉里溫',
@@ -14384,24 +14362,27 @@ $zh2TW = array(
'也門' => '葉門',
'也门' => '葉門',
'着' => '著',
+'着眼于' => '著眼於',
'科摩罗' => '葛摩',
'科摩羅' => '葛摩',
-'黑山共和國' => '蒙特內哥羅共和國',
+'格林美獎' => '葛萊美獎',
+'格莱美奖' => '葛萊美獎',
'黑山共和国' => '蒙特內哥羅共和國',
-'蒙特利爾' => '蒙特婁',
+'黑山共和國' => '蒙特內哥羅共和國',
'滿地可' => '蒙特婁',
'蒙特利尔' => '蒙特婁',
+'蒙特利爾' => '蒙特婁',
'普密蓬' => '蒲美蓬',
'布隆迪' => '蒲隆地',
'圭亚那' => '蓋亞那',
'开曼群岛' => '蓋曼群島',
'開曼群島' => '蓋曼群島',
-'蕭士達高維契' => '蕭士塔高維奇',
'肖斯塔科维奇' => '蕭士塔高維奇',
+'蕭士達高維契' => '蕭士塔高維奇',
'肖邦' => '蕭邦',
'薛定谔' => '薛丁格',
-'扎伊爾' => '薩伊',
'扎伊尔' => '薩伊',
+'扎伊爾' => '薩伊',
'素檀' => '蘇丹',
'苏里南' => '蘇利南',
'浮罗交怡' => '蘭卡威',
@@ -14412,49 +14393,51 @@ $zh2TW = array(
'屏幕' => '螢幕',
'流動網絡' => '行動網路',
'移动网络' => '行動網路',
-'移动电话' => '行動電話',
'流動電話' => '行動電話',
+'移动电话' => '行動電話',
'冲着' => '衝著',
-'埃塞俄比亞' => '衣索比亞',
'埃塞俄比亚' => '衣索比亞',
+'埃塞俄比亞' => '衣索比亞',
'克隆人' => '複製人',
-'國際象棋' => '西洋棋',
'囯际象棋' => '西洋棋',
'国际象棋' => '西洋棋',
+'國際象棋' => '西洋棋',
'赫梯' => '西臺',
-'解像度' => '解析度',
'分辨率' => '解析度',
+'解像度' => '解析度',
'译码' => '解碼',
'出租车' => '計程車',
'约翰逊' => '詹森',
'诺曼底' => '諾曼第',
-'瑙鲁' => '諾魯',
'瑙魯' => '諾魯',
+'瑙鲁' => '諾魯',
'科特迪瓦' => '象牙海岸',
-'贝尔格莱德' => '貝爾格勒',
+'碧咸' => '貝克漢',
'貝爾格萊德' => '貝爾格勒',
+'贝尔格莱德' => '貝爾格勒',
'伯利兹' => '貝里斯',
'伯利茲' => '貝里斯',
'首席财务官' => '財務長',
'集装箱' => '貨櫃',
-'數據庫' => '資料庫',
'数据库' => '資料庫',
+'數據庫' => '資料庫',
+'信息时代' => '資訊時代',
'信息论' => '資訊理論',
+'乔布斯' => '賈伯斯',
'宾西法尼亚' => '賓夕法尼亞',
-'利比里亞' => '賴比瑞亞',
'利比里亚' => '賴比瑞亞',
+'利比里亞' => '賴比瑞亞',
'莱索托' => '賴索托',
'萊索托' => '賴索托',
'塞浦路斯' => '賽普勒斯',
-'碧咸' => '贝克漢',
'赫丘勒·波洛' => '赫丘勒·白羅',
'赫鲁晓夫' => '赫魯雪夫',
'切尔诺贝利' => '車諾比',
'软驱' => '軟碟機',
'軟件' => '軟體',
'软件' => '軟體',
-'津巴布韦' => '辛巴威',
'津巴布韋' => '辛巴威',
+'津巴布韦' => '辛巴威',
'径入' => '逕入',
'径到' => '逕到',
'径取' => '逕取',
@@ -14468,23 +14451,21 @@ $zh2TW = array(
'链接' => '連結',
'連結他' => '連結他',
'进制' => '進位',
-'算子' => '運算元',
'达·芬奇' => '達·文西',
'达芬奇' => '達文西',
'溫納圖萬' => '那杜',
'丘吉尔' => '邱吉爾',
'多普勒' => '都卜勒',
-'奥斯曼' => '鄂圖曼',
'酰' => '醯',
'里士满' => '里奇蒙',
-'金沙薩' => '金夏沙',
'金沙萨' => '金夏沙',
-'健力士世界纪录' => '金氏世界紀錄',
+'金沙薩' => '金夏沙',
'健力士世界紀錄' => '金氏世界紀錄',
+'健力士世界纪录' => '金氏世界紀錄',
'吉尼斯世界纪录' => '金氏世界紀錄',
'钚' => '鈽',
-'钩' => '鉤',
'鈎' => '鉤',
+'钩' => '鉤',
'锎' => '鉲',
'锫' => '鉳',
'镅' => '鋂',
@@ -14513,28 +14494,32 @@ $zh2TW = array(
'雅穆苏克雷' => '雅穆索戈',
'雅穆蘇克雷' => '雅穆索戈',
'悉尼' => '雪梨',
+'雪茄烟' => '雪茄菸',
'雪茄煙' => '雪茄菸',
'莱特湾' => '雷伊泰灣',
'萊特灣' => '雷伊泰灣',
'激光' => '雷射',
'雷诺阿' => '雷諾瓦',
+'电子烟' => '電子菸',
'電子煙' => '電子菸',
-'晶體管' => '電晶體',
'晶体管' => '電晶體',
+'晶體管' => '電晶體',
'电杆' => '電桿',
'电线杆' => '電線桿',
-'计算机程序' => '電腦程式',
'电脑程序' => '電腦程式',
+'计算机程序' => '電腦程式',
'荷尔斯泰因' => '霍爾斯坦',
'荷爾斯泰因' => '霍爾斯坦',
+'面包着' => '面包著',
'朝鲜战争' => '韓戰',
'声卡' => '音效卡',
'缺省' => '預設',
'导弹' => '飛彈',
'糊口' => '餬口',
+'香烟' => '香菸',
'香煙' => '香菸',
-'马里共和国' => '馬利共和國',
'馬里共和國' => '馬利共和國',
+'马里共和国' => '馬利共和國',
'马拉维' => '馬拉威',
'馬斯特里赫特' => '馬斯垂克',
'马斯特里赫特' => '馬斯垂克',
@@ -14548,25 +14533,27 @@ $zh2TW = array(
'咪高峰' => '麥克風',
'迈克尔' => '麥可',
'麦克尔' => '麥可',
-'邁凱輪' => '麥拿輪',
'迈凯轮' => '麥拿輪',
+'邁凱輪' => '麥拿輪',
'马萨诸塞' => '麻薩諸塞',
'戴安娜' => '黛安娜',
'狄安娜' => '黛安娜',
+'点烟' => '點菸',
'點煙' => '點菸',
'霉素' => '黴素',
);
$zh2HK = array(
'IP地址' => 'IP位址',
-'·威爾士' => '·威爾士',
'·威尔士' => '·威爾士',
+'·威爾士' => '·威爾士',
'一地里' => '一地裏',
'一年里' => '一年裏',
'三十六著' => '三十六着',
'三極體' => '三極管',
'旧金山' => '三藩市',
'舊金山' => '三藩市',
+'上台面' => '上枱面',
'下著' => '下着',
'下著作' => '下著作',
'下著名' => '下著名',
@@ -14590,6 +14577,7 @@ $zh2HK = array(
'乘著作' => '乘著作',
'乘著名' => '乘著名',
'乘著書' => '乘著書',
+'乘著称' => '乘著稱',
'乘著稱' => '乘著稱',
'乘著者' => '乘著者',
'乘著述' => '乘著述',
@@ -14607,6 +14595,7 @@ $zh2HK = array(
'亮著作' => '亮著作',
'亮著名' => '亮著名',
'亮著書' => '亮著書',
+'亮著称' => '亮著稱',
'亮著稱' => '亮著稱',
'亮著者' => '亮著者',
'亮著述' => '亮著述',
@@ -14629,9 +14618,9 @@ $zh2HK = array(
'代表著者' => '代表著者',
'代表著述' => '代表著述',
'代表著錄' => '代表著錄',
-'伊斯坦堡' => '伊斯坦布爾',
'伊斯蘭瑪巴德' => '伊斯蘭堡',
'埃博拉' => '伊波拉',
+'伏著' => '伏着',
'貝里斯' => '伯利茲',
'伯明罕' => '伯明翰',
'伴著' => '伴着',
@@ -14656,8 +14645,8 @@ $zh2HK = array(
'布满' => '佈滿',
'布滿' => '佈滿',
'布置' => '佈置',
-'布设' => '佈設',
'布設' => '佈設',
+'布设' => '佈設',
'布警' => '佈警',
'布道' => '佈道',
'布防' => '佈防',
@@ -14665,12 +14654,12 @@ $zh2HK = array(
'布陣' => '佈陣',
'布雷、' => '佈雷、',
'布雷。' => '佈雷。',
-'布雷封锁' => '佈雷封鎖',
'布雷封鎖' => '佈雷封鎖',
+'布雷封锁' => '佈雷封鎖',
'布雷的' => '佈雷的',
'布雷艇' => '佈雷艇',
-'布雷艦' => '佈雷艦',
'布雷舰' => '佈雷艦',
+'布雷艦' => '佈雷艦',
'布雷速度' => '佈雷速度',
'布雷,' => '佈雷,',
'布雷;' => '佈雷;',
@@ -14682,6 +14671,7 @@ $zh2HK = array(
'低著作' => '低著作',
'低著名' => '低著名',
'低著書' => '低著書',
+'低著称' => '低著稱',
'低著稱' => '低著稱',
'低著者' => '低著者',
'低著述' => '低著述',
@@ -14737,8 +14727,8 @@ $zh2HK = array(
'占上風' => '佔上風',
'占上风' => '佔上風',
'占下' => '佔下',
-'占下风' => '佔下風',
'占下風' => '佔下風',
+'占下风' => '佔下風',
'占不占' => '佔不佔',
'占不足' => '佔不足',
'占世界' => '佔世界',
@@ -14759,10 +14749,10 @@ $zh2HK = array(
'占個' => '佔個',
'占个位' => '佔個位',
'占個位' => '佔個位',
-'占億' => '佔億',
'占亿' => '佔億',
-'占優' => '佔優',
+'占億' => '佔億',
'占优' => '佔優',
+'占優' => '佔優',
'占先' => '佔先',
'占光' => '佔光',
'占全' => '佔全',
@@ -14789,8 +14779,8 @@ $zh2HK = array(
'占國' => '佔國',
'占在' => '佔在',
'占地' => '佔地',
-'占場' => '佔場',
'占场' => '佔場',
+'占場' => '佔場',
'占压' => '佔壓',
'占壓' => '佔壓',
'占多' => '佔多',
@@ -14811,8 +14801,8 @@ $zh2HK = array(
'占德' => '佔德',
'占所有' => '佔所有',
'占掉' => '佔掉',
-'占據' => '佔據',
'占据' => '佔據',
+'占據' => '佔據',
'占整' => '佔整',
'占新' => '佔新',
'占有' => '佔有',
@@ -14825,45 +14815,46 @@ $zh2HK = array(
'占满' => '佔滿',
'占滿' => '佔滿',
'占澳' => '佔澳',
-'占為' => '佔為',
'占为' => '佔為',
+'占為' => '佔為',
'占率' => '佔率',
'占用' => '佔用',
-'占畢' => '佔畢',
'占毕' => '佔畢',
+'占畢' => '佔畢',
'占百' => '佔百',
-'占盡' => '佔盡',
'占尽' => '佔盡',
+'占盡' => '佔盡',
'占着' => '佔着',
'占著' => '佔着',
-'占网' => '佔網',
'占網' => '佔網',
+'占网' => '佔網',
'占線' => '佔線',
'占线' => '佔線',
-'占總' => '佔總',
'占总' => '佔總',
+'占總' => '佔總',
'占缺' => '佔缺',
-'占美' => '佔美',
+'占美国' => '佔美國',
+'占美國' => '佔美國',
'占耕' => '佔耕',
'占至多' => '佔至多',
'占至少' => '佔至少',
'占臺' => '佔臺',
'占英' => '佔英',
-'占萬' => '佔萬',
'占万' => '佔萬',
+'占萬' => '佔萬',
'占著名' => '佔著名',
'占著者' => '佔著者',
'占葡' => '佔葡',
-'占蘇' => '佔蘇',
'占苏' => '佔蘇',
+'占蘇' => '佔蘇',
'占西' => '佔西',
'占資' => '佔資',
'占资' => '佔資',
'占起' => '佔起',
'占超过' => '佔超過',
'占超過' => '佔超過',
-'占過' => '佔過',
'占过' => '佔過',
+'占過' => '佔過',
'占道' => '佔道',
'占零' => '佔零',
'占領' => '佔領',
@@ -14900,10 +14891,12 @@ $zh2HK = array(
'信著作' => '信著作',
'信著名' => '信著名',
'信著書' => '信著書',
+'信著称' => '信著稱',
'信著稱' => '信著稱',
'信著者' => '信著者',
'信著述' => '信著述',
'信著錄' => '信著錄',
+'个月里' => '個月裏',
'个里' => '個裏',
'倒楣' => '倒霉',
'候著' => '候着',
@@ -14931,8 +14924,8 @@ $zh2HK = array(
'做著者' => '做著者',
'做著述' => '做著述',
'做著錄' => '做著錄',
-'金氏世界紀錄' => '健力士世界紀錄',
'吉尼斯世界纪录' => '健力士世界紀錄',
+'金氏世界紀錄' => '健力士世界紀錄',
'側著' => '側着',
'側著作' => '側著作',
'側著名' => '側著名',
@@ -14970,6 +14963,7 @@ $zh2HK = array(
'光著作' => '光著作',
'光著名' => '光著名',
'光著書' => '光著書',
+'光著称' => '光著稱',
'光著稱' => '光著稱',
'光著者' => '光著者',
'光著述' => '光著述',
@@ -14977,14 +14971,6 @@ $zh2HK = array(
'柯林頓' => '克林頓',
'克羅埃西亞' => '克羅地亞',
'公布' => '公佈',
-'冀著' => '冀着',
-'冀著作' => '冀著作',
-'冀著名' => '冀著名',
-'冀著書' => '冀著書',
-'冀著稱' => '冀著稱',
-'冀著者' => '冀著者',
-'冀著述' => '冀著述',
-'冀著錄' => '冀著錄',
'冒著' => '冒着',
'冒著作' => '冒著作',
'冒著名' => '冒著名',
@@ -14997,7 +14983,11 @@ $zh2HK = array(
'恺撒' => '凱撒',
'函数里' => '函數裏',
'分布' => '分佈',
+'分布于' => '分佈於',
+'分佈著' => '分佈着',
+'分布著' => '分佈着',
'分占' => '分佔',
+'分钟里' => '分鐘裏',
'錢尼' => '切尼',
'切尔诺贝利' => '切爾諾貝爾',
'列支敦斯登' => '列支敦士登',
@@ -15017,6 +15007,7 @@ $zh2HK = array(
'刻著作' => '刻著作',
'刻著名' => '刻著名',
'刻著書' => '刻著書',
+'刻著称' => '刻著稱',
'刻著稱' => '刻著稱',
'刻著者' => '刻著者',
'刻著述' => '刻著述',
@@ -15025,8 +15016,8 @@ $zh2HK = array(
'剪彩' => '剪綵',
'割占' => '割佔',
'劃著' => '劃着',
-'擊劍' => '劍擊',
'击剑' => '劍擊',
+'擊劍' => '劍擊',
'加薩走廊' => '加沙地帶',
'迦納' => '加納',
'加彭' => '加蓬',
@@ -15034,18 +15025,11 @@ $zh2HK = array(
'努力著作' => '努力著作',
'努力著名' => '努力著名',
'努力著書' => '努力著書',
+'努力著称' => '努力著稱',
'努力著稱' => '努力著稱',
'努力著者' => '努力著者',
'努力著述' => '努力著述',
'努力著錄' => '努力著錄',
-'努著' => '努着',
-'努著作' => '努著作',
-'努著名' => '努著名',
-'努著書' => '努著書',
-'努著稱' => '努著稱',
-'努著者' => '努著者',
-'努著述' => '努著述',
-'努著錄' => '努著錄',
'布蘭登堡' => '勃蘭登堡',
'動著' => '動着',
'動著作' => '動著作',
@@ -15060,8 +15044,8 @@ $zh2HK = array(
'南朝鲜' => '南韓',
'波札那' => '博茨瓦納',
'占卜' => '占卜',
-'占國橋' => '占國橋',
'占国桥' => '占國橋',
+'占國橋' => '占國橋',
'占有五不' => '占有五不',
'占著作' => '占著作',
'占著稱' => '占著稱',
@@ -15081,20 +15065,12 @@ $zh2HK = array(
'印著錄' => '印著錄',
'瓜地馬拉' => '危地馬拉',
'厄瓜多' => '厄瓜多爾',
-'厄瓜多爾' => '厄瓜多爾',
'厄瓜多尔' => '厄瓜多爾',
+'厄瓜多爾' => '厄瓜多爾',
'厄利垂亚' => '厄立特里亞',
'厄利垂亞' => '厄立特里亞',
'源代码' => '原始碼',
'去山里' => '去山裏',
-'去著' => '去着',
-'去著作' => '去著作',
-'去著名' => '去著名',
-'去著書' => '去著書',
-'去著稱' => '去著稱',
-'去著者' => '去著者',
-'去著述' => '去著述',
-'去著錄' => '去著錄',
'参数里' => '參數裏',
'受著' => '受着',
'受著作' => '受著作',
@@ -15117,8 +15093,9 @@ $zh2HK = array(
'叫著錄' => '叫著錄',
'古柯鹼' => '可卡因',
'叱吒' => '叱咤',
-'斯皮尔伯格' => '史匹堡',
+'斯坦福大学' => '史丹福大學',
'史匹柏' => '史匹堡',
+'斯皮尔伯格' => '史匹堡',
'史蒂芬·史匹柏' => '史提芬·史匹堡',
'斯蒂芬·斯皮尔伯格' => '史提芬·史匹堡',
'吃不著' => '吃不着',
@@ -15127,7 +15104,6 @@ $zh2HK = array(
'吃里扒外' => '吃裏扒外',
'吃里爬外' => '吃裏爬外',
'吉布地' => '吉布堤',
-'吉尔吉斯斯坦' => '吉爾吉斯',
'吊著' => '吊着',
'向著' => '向着',
'向著作' => '向著作',
@@ -15161,13 +15137,14 @@ $zh2HK = array(
'味著作' => '味著作',
'味著名' => '味著名',
'味著書' => '味著書',
+'味著称' => '味著稱',
'味著稱' => '味著稱',
'味著者' => '味著者',
'味著述' => '味著述',
'味著錄' => '味著錄',
'咖哩' => '咖喱',
-'麦克风' => '咪高峰',
'麥克風' => '咪高峰',
+'麦克风' => '咪高峰',
'哥特式' => '哥德式',
'哥斯大黎加' => '哥斯達黎加',
'哪里' => '哪裏',
@@ -15195,14 +15172,15 @@ $zh2HK = array(
'喝著者' => '喝著者',
'喝著述' => '喝著述',
'喝著錄' => '喝著錄',
+'賈伯斯' => '喬布斯',
'乔治·奥威尔' => '喬治·歐威爾',
-'單眼相機' => '單鏡反光機',
'单反相机' => '單鏡反光機',
+'單眼相機' => '單鏡反光機',
'嗅不著' => '嗅不着',
'嗅得著' => '嗅得着',
'嗅著' => '嗅着',
-'凱薩琳' => '嘉芙蓮',
'凯瑟琳' => '嘉芙蓮',
+'凱薩琳' => '嘉芙蓮',
'嘯吒' => '嘯咤',
'嘴里' => '嘴裏',
'嚷著' => '嚷着',
@@ -15233,6 +15211,7 @@ $zh2HK = array(
'困著者' => '困著者',
'困著述' => '困著述',
'困著錄' => '困著錄',
+'固著' => '固着',
'圈占' => '圈佔',
'圈里' => '圈裏',
'西洋棋' => '國際象棋',
@@ -15251,18 +15230,9 @@ $zh2HK = array(
'图里,' => '圖裏,',
'土里' => '土裏',
'在山里' => '在山裏',
-'在著' => '在着',
-'在著作' => '在著作',
-'在著名' => '在著名',
-'在著書' => '在著書',
-'在著稱' => '在著稱',
-'在著者' => '在著者',
-'在著述' => '在著述',
-'在著錄' => '在著錄',
'蓋亞那' => '圭亞那',
'地占' => '地佔',
'地图里' => '地圖裏',
-'IP' => '地址',
'堪培拉' => '坎培拉',
'坐台' => '坐枱',
'坐著' => '坐着',
@@ -15278,15 +15248,18 @@ $zh2HK = array(
'衣索匹亞' => '埃塞俄比亚',
'衣索比亞' => '埃塞俄比亞',
'葉里溫' => '埃里溫',
+'城市里' => '城市裏',
'城里' => '城裏',
'域里' => '域裏',
'吉里巴斯' => '基里巴斯',
+'堅貞著' => '堅貞着',
'场里' => '場裏',
'塗著' => '塗着',
'塞普勒斯' => '塞浦路斯',
'賽普勒斯' => '塞浦路斯',
'塞爾維亞與蒙特內哥羅' => '塞爾維亞和黑山',
'塞席爾' => '塞舌爾',
+'境里' => '境裏',
'壓著' => '壓着',
'壓著作' => '壓著作',
'壓著名' => '壓著名',
@@ -15320,27 +15293,21 @@ $zh2HK = array(
'夾著者' => '夾著者',
'夾著述' => '夾著述',
'夾著錄' => '夾著錄',
-'奧占' => '奧佔',
'奥占' => '奧佔',
+'奧占' => '奧佔',
'歐巴馬' => '奧巴馬',
'妆台' => '妝枱',
'威斯伐倫' => '威斯特法倫',
-'威爾士' => '威爾斯',
'威尔士' => '威爾斯',
+'威爾士' => '威爾斯',
'子里' => '子裏',
'字里行间' => '字裏行間',
+'存在著' => '存在着',
'存著' => '存着',
+'存著作' => '存著作',
'存著名' => '存著名',
'孟德爾頌' => '孟德爾遜',
'门德尔松' => '孟德爾遜',
-'孤著' => '孤着',
-'孤著作' => '孤著作',
-'孤著名' => '孤著名',
-'孤著書' => '孤著書',
-'孤著稱' => '孤著稱',
-'孤著者' => '孤著者',
-'孤著述' => '孤著述',
-'孤著錄' => '孤著錄',
'學著' => '學着',
'學著作' => '學著作',
'學著名' => '學著名',
@@ -15354,6 +15321,7 @@ $zh2HK = array(
'守著作' => '守著作',
'守著名' => '守著名',
'守著書' => '守著書',
+'守著称' => '守著稱',
'守著稱' => '守著稱',
'守著者' => '守著者',
'守著述' => '守著述',
@@ -15364,6 +15332,7 @@ $zh2HK = array(
'定著作' => '定著作',
'定著名' => '定著名',
'定著書' => '定著書',
+'定著称' => '定著稱',
'定著稱' => '定著稱',
'定著者' => '定著者',
'定著述' => '定著述',
@@ -15386,10 +15355,10 @@ $zh2HK = array(
'寫著錄' => '寫著錄',
'宝里宝气' => '寶裏寶氣',
'封面里' => '封面裏',
-'將占' => '將佔',
'将占' => '將佔',
-'將占卜' => '將占卜',
+'將占' => '將佔',
'将占卜' => '將占卜',
+'將占卜' => '將占卜',
'专辑里' => '專輯裏',
'尋著' => '尋着',
'尋著作' => '尋著作',
@@ -15407,6 +15376,7 @@ $zh2HK = array(
'對著者' => '對著者',
'對著述' => '對著述',
'對著錄' => '對著錄',
+'小时里' => '小時裏',
'少占' => '少佔',
'就里' => '就裏',
'尼克松' => '尼克遜',
@@ -15435,13 +15405,14 @@ $zh2HK = array(
'巴士拉' => '巴斯拉',
'巷里' => '巷裏',
'市占' => '市佔',
-'市里' => '市裏',
+'市里的' => '市裏的',
'布吉納法索' => '布基納法索',
'布什' => '布殊',
'布里斯托尔' => '布里斯托',
'蒲隆地' => '布隆迪',
+'希冀著' => '希冀着',
'席哈克' => '希拉克',
-'希拉蕊' => '希拉里',
+'希拉蕊' => '希拉莉',
'希特勒' => '希特拉',
'帛琉' => '帕勞',
'巴尔米拉环礁' => '帕邁拉環礁',
@@ -15472,20 +15443,14 @@ $zh2HK = array(
'幹著名' => '幹著名',
'幹著稱' => '幹著稱',
'幾內亞比索' => '幾內亞比紹',
+'庫德人' => '库爾德人',
+'庫德族' => '库爾德族',
'店里' => '店裏',
'坎城' => '康城',
'戛纳' => '康城',
-'康著' => '康着',
-'康著作' => '康著作',
-'康著名' => '康著名',
-'康著書' => '康著書',
-'康著稱' => '康著稱',
-'康著者' => '康著者',
-'康著述' => '康著述',
-'康著錄' => '康著錄',
'庙里' => '廟裏',
-'强占' => '強佔',
'強占' => '強佔',
+'强占' => '強佔',
'约翰斯顿岛' => '強斯頓環礁',
'弹子台' => '彈子枱',
'蹦床' => '彈床',
@@ -15521,8 +15486,8 @@ $zh2HK = array(
'循著者' => '循著者',
'循著述' => '循著述',
'循著錄' => '循著錄',
-'徵占' => '徵佔',
'征占' => '徵佔',
+'徵占' => '徵佔',
'德占' => '德佔',
'得克萨斯' => '德克薩斯',
'德勒斯登' => '德累斯頓',
@@ -15531,6 +15496,7 @@ $zh2HK = array(
'心著作' => '心著作',
'心著名' => '心著名',
'心著書' => '心著書',
+'心著称' => '心著稱',
'心著稱' => '心著稱',
'心著者' => '心著者',
'心著述' => '心著述',
@@ -15545,13 +15511,6 @@ $zh2HK = array(
'忍著者' => '忍著者',
'忍著述' => '忍著述',
'忍著錄' => '忍著錄',
-'志著作' => '志著作',
-'志著名' => '志著名',
-'志著書' => '志著書',
-'志著稱' => '志著稱',
-'志著者' => '志著者',
-'志著述' => '志著述',
-'志著錄' => '志著錄',
'忙著' => '忙着',
'忙著作' => '忙著作',
'忙著名' => '忙著名',
@@ -15561,6 +15520,7 @@ $zh2HK = array(
'忙著述' => '忙著述',
'忙著錄' => '忙著錄',
'忙里' => '忙裏',
+'忠貞著' => '忠貞着',
'急著' => '急着',
'急著作' => '急著作',
'急著名' => '急著名',
@@ -15569,14 +15529,6 @@ $zh2HK = array(
'急著者' => '急著者',
'急著述' => '急著述',
'急著錄' => '急著錄',
-'性著' => '性着',
-'性著作' => '性著作',
-'性著名' => '性著名',
-'性著書' => '性著書',
-'性著稱' => '性著稱',
-'性著者' => '性著者',
-'性著述' => '性著述',
-'性著錄' => '性著錄',
'怪里怪气' => '怪裏怪氣',
'悠著' => '悠着',
'悠著作' => '悠著作',
@@ -15592,12 +15544,13 @@ $zh2HK = array(
'想著作' => '想著作',
'想著名' => '想著名',
'想著書' => '想著書',
+'想著称' => '想著稱',
'想著稱' => '想著稱',
'想著者' => '想著者',
'想著述' => '想著述',
'想著錄' => '想著錄',
-'義占' => '意佔',
'意占' => '意佔',
+'義占' => '意佔',
'義大利' => '意大利',
'艾滋' => '愛滋',
'愛著' => '愛着',
@@ -15693,6 +15646,7 @@ $zh2HK = array(
'扛著錄' => '扛著錄',
'找不著' => '找不着',
'找得著' => '找得着',
+'承宣布政' => '承宣布政',
'抓著' => '抓着',
'抓著作' => '抓著作',
'抓著名' => '抓著名',
@@ -15786,8 +15740,8 @@ $zh2HK = array(
'捆著者' => '捆著者',
'捆著述' => '捆著述',
'捆著錄' => '捆著錄',
-'俯卧撑' => '掌上壓',
'伏地挺身' => '掌上壓',
+'俯卧撑' => '掌上壓',
'掖著' => '掖着',
'掖著作' => '掖著作',
'掖著名' => '掖著名',
@@ -15893,14 +15847,18 @@ $zh2HK = array(
'敞著述' => '敞著述',
'敞著錄' => '敞著錄',
'散布' => '散佈',
+'散佈著' => '散佈着',
+'散布著' => '散佈着',
+'数字照相机' => '数碼照相機',
+'數位照相機' => '数碼照相機',
'數著' => '數着',
'数字技术' => '數碼技術',
'數位技術' => '數碼技術',
'數位相機' => '數碼相機',
-'數碼訊號' => '數碼訊號',
'数字信号' => '數碼訊號',
-'數位電視' => '數碼電視',
+'數碼訊號' => '數碼訊號',
'数字电视' => '數碼電視',
+'數位電視' => '數碼電視',
'數著作' => '數著作',
'數著名' => '數著名',
'數著稱' => '數著稱',
@@ -15933,8 +15891,8 @@ $zh2HK = array(
'昂著者' => '昂著者',
'昂著述' => '昂著述',
'昂著錄' => '昂著錄',
-'星羅棋布' => '星羅棋佈',
'星罗棋布' => '星羅棋佈',
+'星羅棋布' => '星羅棋佈',
'映著' => '映着',
'映著作' => '映著作',
'映著名' => '映著名',
@@ -15950,8 +15908,8 @@ $zh2HK = array(
'晃著者' => '晃著者',
'晃著述' => '晃著述',
'晃著錄' => '晃著錄',
-'芯片' => '晶片',
'晶元' => '晶片',
+'芯片' => '晶片',
'智慧型' => '智能',
'智慧卡' => '智能卡',
'智慧手機' => '智能手機',
@@ -15966,11 +15924,12 @@ $zh2HK = array(
'暗著述' => '暗著述',
'暗著錄' => '暗著錄',
'暗里' => '暗裏',
-'會占' => '會佔',
'会占' => '會佔',
-'會占卜' => '會占卜',
+'會占' => '會佔',
'会占卜' => '會占卜',
+'會占卜' => '會占卜',
'会里' => '會裏',
+'月裡来' => '月裏來',
'有著' => '有着',
'有著作' => '有著作',
'有著名' => '有著名',
@@ -16011,6 +15970,7 @@ $zh2HK = array(
'村里' => '村裏',
'杜塞道夫' => '杜塞爾多夫',
'迪拜' => '杜拜',
+'東南亞國家協會' => '東南亞國家聯盟',
'亚细安' => '東盟',
'東協' => '東盟',
'板著臉' => '板着臉',
@@ -16026,15 +15986,20 @@ $zh2HK = array(
'台历' => '枱曆',
'台灯' => '枱燈',
'台面上' => '枱面上',
+'台面化' => '枱面化',
'柏林墙' => '柏林圍牆',
'奧黛莉·朵杜' => '柯德莉·塔圖',
'奥黛丽·赫本' => '柯德莉·夏萍',
'奧黛麗·赫本' => '柯德莉·夏萍',
'哥廷根' => '格丁根',
'格瑞那達' => '格林納達',
+'格莱美奖' => '格林美獎',
+'葛萊美獎' => '格林美獎',
'格鲁吉亚' => '格魯吉亞',
-'撞球' => '桌球',
+'框里' => '框裏',
+'台式电脑' => '桌上型電腦',
'台球' => '桌球',
+'撞球' => '桌球',
'梅鐸' => '梅鐸',
'默多克' => '梅鐸',
'梳著' => '梳着',
@@ -16063,8 +16028,8 @@ $zh2HK = array(
'標誌著' => '標誌着',
'树林里' => '樹林裏',
'工具機' => '機床',
-'機器人' => '機械人',
'机器人' => '機械人',
+'機器人' => '機械人',
'柜台' => '櫃枱',
'历史里' => '歷史裏',
'死里求生' => '死裏求生',
@@ -16109,8 +16074,8 @@ $zh2HK = array(
'沖著。' => '沖著。',
'沖著《' => '沖著《',
'沖著,' => '沖著,',
-'沙烏地阿拉伯' => '沙特阿拉伯',
'沙地阿拉伯' => '沙特阿拉伯',
+'沙烏地阿拉伯' => '沙特阿拉伯',
'沙里淘金' => '沙裏淘金',
'河里' => '河裏',
'沿著' => '沿着',
@@ -16126,6 +16091,8 @@ $zh2HK = array(
'玻里尼西亞' => '波利尼西亞',
'波士尼亞' => '波斯尼亞',
'波士尼亞赫塞哥維納' => '波斯尼亞黑塞哥維那',
+'宝莱坞' => '波里活',
+'寶萊塢' => '波里活',
'幫浦' => '泵',
'洞里' => '洞裏',
'辛巴威' => '津巴布韋',
@@ -16140,8 +16107,8 @@ $zh2HK = array(
'活著錄' => '活著錄',
'移动网络' => '流動網絡',
'行動網路' => '流動網絡',
-'行動電話' => '流動電話',
'移动电话' => '流動電話',
+'行動電話' => '流動電話',
'流著' => '流着',
'流著作' => '流著作',
'流著名' => '流著名',
@@ -16162,16 +16129,8 @@ $zh2HK = array(
'浮著錄' => '浮著錄',
'海上布雷' => '海上佈雷',
'海洛因' => '海洛英',
-'海灣布雷' => '海灣佈雷',
'海湾布雷' => '海灣佈雷',
-'涵著' => '涵着',
-'涵著作' => '涵著作',
-'涵著名' => '涵著名',
-'涵著書' => '涵著書',
-'涵著稱' => '涵著稱',
-'涵著者' => '涵著者',
-'涵著述' => '涵著述',
-'涵著錄' => '涵著錄',
+'海灣布雷' => '海灣佈雷',
'涼著' => '涼着',
'涼著作' => '涼著作',
'涼著名' => '涼著名',
@@ -16298,17 +16257,12 @@ $zh2HK = array(
'猜著者' => '猜著者',
'猜著述' => '猜著述',
'猜著錄' => '猜著錄',
+'猶豫著' => '猶豫着',
'狱里' => '獄裏',
-'獨占' => '獨佔',
'独占' => '獨佔',
-'獨著' => '獨着',
-'獨著作' => '獨著作',
-'獨著名' => '獨著名',
-'獨著書' => '獨著書',
-'獨著稱' => '獨著稱',
-'獨著者' => '獨著者',
-'獨著述' => '獨著述',
-'獨著錄' => '獨著錄',
+'獨占' => '獨佔',
+'獨立國家國協' => '獨立國家聯合體',
+'獨立國協' => '獨聯體',
'獲著' => '獲着',
'獲著作' => '獲著作',
'獲著名' => '獲著名',
@@ -16317,6 +16271,7 @@ $zh2HK = array(
'獲著者' => '獲著者',
'獲著述' => '獲著述',
'獲著錄' => '獲著錄',
+'班固著' => '班固著',
'班里' => '班裏',
'球台' => '球枱',
'卢塞恩' => '琉森',
@@ -16365,16 +16320,16 @@ $zh2HK = array(
'過著作' => '當著作',
'當著名' => '當著名',
'過著名' => '當著名',
-'過著書' => '當著書',
'當著書' => '當著書',
+'過著書' => '當著書',
'當著稱' => '當著稱',
'過著稱' => '當著稱',
'當著者' => '當著者',
'過著者' => '當著者',
-'過著述' => '當著述',
'當著述' => '當著述',
-'過著錄' => '當著錄',
+'過著述' => '當著述',
'當著錄' => '當著錄',
+'過著錄' => '當著錄',
'几内亚' => '畿內亞',
'幾內亞' => '畿內亞',
'迭代' => '疊代',
@@ -16387,8 +16342,8 @@ $zh2HK = array(
'疑著述' => '疑著述',
'疑著錄' => '疑著錄',
'狂牛症' => '瘋牛症',
-'發布' => '發佈',
'发布' => '發佈',
+'發布' => '發佈',
'發著' => '發着',
'發著《' => '發著《',
'發著作' => '發著作',
@@ -16430,14 +16385,6 @@ $zh2HK = array(
'盯著者' => '盯著者',
'盯著述' => '盯著述',
'盯著錄' => '盯著錄',
-'盾著' => '盾着',
-'盾著作' => '盾著作',
-'盾著名' => '盾著名',
-'盾著書' => '盾著書',
-'盾著稱' => '盾著稱',
-'盾著者' => '盾著者',
-'盾著述' => '盾著述',
-'盾著錄' => '盾著錄',
'看不著' => '看不着',
'看得著' => '看得着',
'看法里' => '看法裏',
@@ -16515,6 +16462,7 @@ $zh2HK = array(
'瞪著者' => '瞪著者',
'瞪著述' => '瞪著述',
'瞪著錄' => '瞪著錄',
+'矛盾著' => '矛盾着',
'智慧財產權' => '知識產權',
'智財權' => '知識產權',
'短信' => '短訊',
@@ -16522,10 +16470,11 @@ $zh2HK = array(
'什勒斯維希' => '石勒蘇益格',
'硅' => '矽',
'硅藻' => '硅藻',
-'硬體' => '硬件',
'硬件' => '硬件',
+'硬體' => '硬件',
+'碗里' => '碗裏',
+'貝克漢' => '碧咸',
'贝克汉姆' => '碧咸',
-'贝克漢' => '碧咸',
'社里' => '社裏',
'福馬林' => '福爾馬林',
'福著' => '福着',
@@ -16538,18 +16487,18 @@ $zh2HK = array(
'福著錄' => '福著錄',
'秀发布' => '秀發佈',
'私下里' => '私下裏',
-'隱私' => '私隱',
'隐私' => '私隱',
+'隱私' => '私隱',
'葛摩' => '科摩羅',
'程序员' => '程式設計師',
'捷豹' => '積架',
-'穩占' => '穩佔',
'稳占' => '穩佔',
+'穩占' => '穩佔',
'穫著' => '穫着',
'空中布雷' => '空中佈雷',
'空投布雷' => '空投佈雷',
-'空氣品質' => '空氣質素',
'空气质量' => '空氣質素',
+'空氣品質' => '空氣質素',
'空著' => '空着',
'空著作' => '空著作',
'空著名' => '空著名',
@@ -16558,8 +16507,8 @@ $zh2HK = array(
'空著者' => '空著者',
'空著述' => '空著述',
'空著錄' => '空著錄',
-'航天飞机' => '穿梭機',
'太空梭' => '穿梭機',
+'航天飞机' => '穿梭機',
'穿著' => '穿着',
'穿著作' => '穿著作',
'穿著名' => '穿著名',
@@ -16569,6 +16518,15 @@ $zh2HK = array(
'穿著述' => '穿著述',
'穿著錄' => '穿著錄',
'窝里' => '窩裏',
+'立著' => '立着',
+'立著《' => '立著《',
+'立著作' => '立著作',
+'立著名' => '立著名',
+'立著有' => '立著有',
+'立著称' => '立著稱',
+'立著稱' => '立著稱',
+'立著者' => '立著者',
+'立著(' => '立著(',
'站著' => '站着',
'站著作' => '站著作',
'站著名' => '站著名',
@@ -16599,9 +16557,10 @@ $zh2HK = array(
'箱里' => '箱裏',
'节目里' => '節目裏',
'簽著' => '簽着',
+'篮板球' => '籃板球',
'籃板球' => '籃板球',
-'麦克尔' => '米高',
'迈克尔' => '米高',
+'麦克尔' => '米高',
'迈克尔·欧文' => '米高·奧雲',
'糊里糊涂' => '糊裏糊塗',
'系列里' => '系列裏',
@@ -16610,8 +16569,8 @@ $zh2HK = array(
'約占' => '約佔',
'约占' => '約佔',
'紐賓士域' => '紐賓士域',
-'索忍尼辛' => '索贊尼辛',
'索尔仁尼琴' => '索贊尼辛',
+'索忍尼辛' => '索贊尼辛',
'索馬利亞' => '索馬里',
'索馬利里' => '索馬里',
'紮著' => '紮着',
@@ -16624,8 +16583,8 @@ $zh2HK = array(
'紮著錄' => '紮著錄',
'组里' => '組裏',
'吉他' => '結他',
-'结彩' => '結綵',
'結彩' => '結綵',
+'结彩' => '結綵',
'綁著' => '綁着',
'綁著作' => '綁著作',
'綁著名' => '綁著名',
@@ -16634,6 +16593,7 @@ $zh2HK = array(
'綁著者' => '綁著者',
'綁著述' => '綁著述',
'綁著錄' => '綁著錄',
+'网站里' => '網站裏',
'網路' => '網絡',
'网里' => '網裏',
'彩带' => '綵帶',
@@ -16654,6 +16614,7 @@ $zh2HK = array(
'緝凶' => '緝兇',
'县里' => '縣裏',
'缝里' => '縫裏',
+'縱著' => '縱着',
'总数里' => '總數裏',
'尖峰時段' => '繁忙時段',
'尖峰時間' => '繁忙時間',
@@ -16667,8 +16628,8 @@ $zh2HK = array(
'繞著者' => '繞著者',
'繞著述' => '繞著述',
'繞著錄' => '繞著錄',
-'繫著' => '繫着',
'系着' => '繫着',
+'繫著' => '繫着',
'纏著' => '纏着',
'纏著作' => '纏著作',
'纏著名' => '纏著名',
@@ -16699,6 +16660,7 @@ $zh2HK = array(
'美著作' => '美著作',
'美著名' => '美著名',
'美著書' => '美著書',
+'美著称' => '美著稱',
'美著稱' => '美著稱',
'美著者' => '美著者',
'美著述' => '美著述',
@@ -16777,8 +16739,8 @@ $zh2HK = array(
'與著述' => '與著述',
'與著錄' => '與著錄',
'舒马赫' => '舒麥加',
-'爱荷华' => '艾奧瓦',
'愛荷華' => '艾奧瓦',
+'爱荷华' => '艾奧瓦',
'埃菲尔' => '艾菲爾',
'帕塔亚' => '芭達亞',
'花盆里' => '花盆裏',
@@ -16794,25 +16756,25 @@ $zh2HK = array(
'苦著錄' => '苦著錄',
'苦里' => '苦裏',
'英占' => '英佔',
-'大英國協' => '英聯邦',
'共和联邦' => '英聯邦',
+'大英國協' => '英聯邦',
'草丛里' => '草叢裏',
'霍爾斯坦' => '荷爾斯泰因',
-'好萊塢' => '荷里活',
'好莱坞' => '荷里活',
+'好萊塢' => '荷里活',
'庄里' => '莊裏',
'莫三比克' => '莫桑比克',
-'瓦倫西亞' => '華倫西亞',
'巴伦西亚' => '華倫西亞',
'巴倫西亞' => '華倫西亞',
+'瓦倫西亞' => '華倫西亞',
'瓦文萨' => '華里沙',
'華勒沙' => '華里沙',
'菲利普亲王' => '菲臘親王',
'菲利普親王' => '菲臘親王',
'賴索托' => '萊索托',
'马恩岛' => '萌島',
-'马自达' => '萬事得',
'馬自達' => '萬事得',
+'马自达' => '萬事得',
'万历朝鲜战争' => '萬曆朝鮮戰爭',
'落著' => '落着',
'落著作' => '落著作',
@@ -16825,8 +16787,8 @@ $zh2HK = array(
'葉爾欽' => '葉利欽',
'葡占' => '葡佔',
'葫芦里卖甚么药' => '葫蘆裏賣甚麼藥',
-'蒙特婁' => '蒙特利爾',
'滿地可' => '蒙特利爾',
+'蒙特婁' => '蒙特利爾',
'蒙著' => '蒙着',
'蒙著作' => '蒙著作',
'蒙著名' => '蒙著名',
@@ -16836,6 +16798,9 @@ $zh2HK = array(
'蒙著述' => '蒙著述',
'蒙著錄' => '蒙著錄',
'蓋著' => '蓋着',
+'蓋著作' => '蓋著作',
+'蓋著名' => '蓋著名',
+'蓋著稱' => '蓋著稱',
'肖斯塔科维奇' => '蕭士達高維契',
'蕭士塔高維奇' => '蕭士達高維契',
'肖邦' => '蕭邦',
@@ -16851,14 +16816,7 @@ $zh2HK = array(
'藏著者' => '藏著者',
'藏著述' => '藏著述',
'藏著錄' => '藏著錄',
-'藝著' => '藝着',
-'藝著作' => '藝著作',
-'藝著名' => '藝著名',
-'藝著書' => '藝著書',
-'藝著稱' => '藝著稱',
-'藝著者' => '藝著者',
-'藝著述' => '藝著述',
-'藝著錄' => '藝著錄',
+'蘊涵著' => '蘊涵着',
'蘸著' => '蘸着',
'蘸著作' => '蘸著作',
'蘸著名' => '蘸著名',
@@ -16870,6 +16828,7 @@ $zh2HK = array(
'蜜里调油' => '蜜裏調油',
'荧屏' => '螢屏',
'屏幕' => '螢幕',
+'行家里手' => '行家裏手',
'首席执行官' => '行政總裁',
'行著' => '行着',
'行著作' => '行著作',
@@ -16903,7 +16862,6 @@ $zh2HK = array(
'里带' => '裏帶',
'里弦' => '裏弦',
'里应外合' => '裏應外合',
-'里手' => '裏手',
'里海' => '裏海',
'里脊' => '裏脊',
'里衣' => '裏衣',
@@ -16912,7 +16870,6 @@ $zh2HK = array(
'里边' => '裏邊',
'里间' => '裏間',
'里面' => '裏面',
-'里面包' => '裏面包',
'里头' => '裏頭',
'裝著' => '裝着',
'裝著作' => '裝著作',
@@ -16933,11 +16890,12 @@ $zh2HK = array(
'裹著錄' => '裹著錄',
'衬里' => '襯裏',
'西占' => '西佔',
-'塞维利亚' => '西維爾',
'塞維亞' => '西維爾',
+'塞维利亚' => '西維爾',
'要占' => '要佔',
'要占卜' => '要占卜',
'覆著' => '覆着',
+'覆蓋著' => '覆蓋着',
'見著' => '見着',
'見著作' => '見著作',
'見著名' => '見著名',
@@ -16946,9 +16904,12 @@ $zh2HK = array(
'見著者' => '見著者',
'見著述' => '見著述',
'見著錄' => '見著錄',
+'視著' => '視着',
+'視著名' => '視著名',
'角落里' => '角落裏',
'分辨率' => '解像度',
'解析度' => '解像度',
+'言里' => '言裏',
'計畫' => '計劃',
'記著' => '記着',
'記著作' => '記著作',
@@ -17003,28 +16964,14 @@ $zh2HK = array(
'豎著錄' => '豎著錄',
'象徵著名' => '象徵著名',
'象徵著' => '象著着',
-'豫著' => '豫着',
-'豫著作' => '豫著作',
-'豫著名' => '豫著名',
-'豫著書' => '豫著書',
-'豫著稱' => '豫著稱',
-'豫著者' => '豫著者',
-'豫著述' => '豫著述',
-'豫著錄' => '豫著錄',
'貝爾格勒' => '貝爾格萊德',
'布莱尔' => '貝理雅',
-'貞著' => '貞着',
-'貞著作' => '貞著作',
-'貞著名' => '貞著名',
-'貞著書' => '貞著書',
-'貞著稱' => '貞著稱',
-'貞著者' => '貞著者',
-'貞著述' => '貞著述',
-'貞著錄' => '貞著錄',
'負著' => '負着',
+'貢寮' => '貢寮',
'買凶' => '買兇',
'費占' => '費佔',
'费占' => '費佔',
+'信息时代' => '資訊時代',
'赌台' => '賭枱',
'尚比亞' => '贊比亞',
'西臺人' => '赫梯人',
@@ -17218,11 +17165,14 @@ $zh2HK = array(
'遇著作' => '遇著作',
'遇著名' => '遇著名',
'遇著書' => '遇著書',
+'遇著称' => '遇著稱',
'遇著稱' => '遇著稱',
'遇著者' => '遇著者',
'遇著述' => '遇著述',
'遇著錄' => '遇著錄',
'遍布' => '遍佈',
+'遍佈著' => '遍佈着',
+'遍布著' => '遍佈着',
'過著' => '過着',
'达·芬奇' => '達·文西',
'达芬奇' => '達文西',
@@ -17234,19 +17184,11 @@ $zh2HK = array(
'達著者' => '達著者',
'達著述' => '達著述',
'達著錄' => '達著錄',
-'遠著' => '遠着',
-'遠著作' => '遠著作',
-'遠著名' => '遠著名',
-'遠著書' => '遠著書',
-'遠著稱' => '遠著稱',
-'遠著者' => '遠著者',
-'遠著述' => '遠著述',
-'遠著錄' => '遠著錄',
-'還占' => '還佔',
'还占' => '還佔',
+'還占' => '還佔',
'邋里邋遢' => '邋裏邋遢',
'那里' => '那裏',
-'奥斯曼' => '鄂圖曼',
+'都市里' => '都市裏',
'配合著' => '配合着',
'配合著名' => '配合著名',
'配图里' => '配圖裏',
@@ -17267,14 +17209,14 @@ $zh2HK = array(
'醜著者' => '醜著者',
'醜著述' => '醜著述',
'醜著錄' => '醜著錄',
-'醯壺' => '醯壺',
'醯壶' => '醯壺',
+'醯壺' => '醯壺',
'醯醋' => '醯醋',
'醯醢' => '醯醢',
'醯酱' => '醯醬',
'醯醬' => '醯醬',
-'醯鸡' => '醯雞',
'醯雞' => '醯雞',
+'醯鸡' => '醯雞',
'釀著' => '釀着',
'釀著作' => '釀著作',
'釀著名' => '釀著名',
@@ -17387,14 +17329,15 @@ $zh2HK = array(
'隨著者' => '隨著者',
'隨著述' => '隨著述',
'隨著錄' => '隨著錄',
-'隱占' => '隱佔',
'隐占' => '隱佔',
+'隱占' => '隱佔',
'雅爾達' => '雅爾塔',
'雅著' => '雅着',
'雅穆索戈' => '雅穆蘇克雷',
'雅著作' => '雅著作',
'雅著名' => '雅著名',
'雅著書' => '雅著書',
+'雅著称' => '雅著稱',
'雅著稱' => '雅著稱',
'雅著者' => '雅著者',
'雅著述' => '雅著述',
@@ -17413,10 +17356,12 @@ $zh2HK = array(
'冰淇淋' => '雪糕',
'冰激凌' => '雪糕',
'雪里' => '雪裏',
-'萊特灣' => '雷伊泰灣',
+'云里雾里' => '雲裏霧裏',
'莱特湾' => '雷伊泰灣',
-'晶體管' => '電晶體',
+'萊特灣' => '雷伊泰灣',
'晶体管' => '電晶體',
+'晶體管' => '電晶體',
+'电梯里' => '電梯裏',
'电脑程序' => '電腦程式',
'计算机程序' => '電腦程式',
'霄裡' => '霄裡',
@@ -17427,12 +17372,13 @@ $zh2HK = array(
'靠著' => '靠着',
'靠著作' => '靠著作',
'靠著名' => '靠著名',
-'靠著稱' => '靠著稱',
'靠著称' => '靠著稱',
+'靠著稱' => '靠著稱',
'靠著者' => '靠著者',
'靠著述' => '靠著述',
-'靠著錄' => '靠著錄',
'靠著录' => '靠著錄',
+'靠著錄' => '靠著錄',
+'面包著' => '面包着',
'鞋里' => '鞋裏',
'鞭辟入里' => '鞭辟入裏',
'朝鲜战争' => '韓戰',
@@ -17460,8 +17406,8 @@ $zh2HK = array(
'順著者' => '順著者',
'順著述' => '順著述',
'順著錄' => '順著錄',
-'颁布' => '頒佈',
'頒布' => '頒佈',
+'颁布' => '頒佈',
'領著' => '領着',
'領著作' => '領著作',
'領著名' => '領著名',
@@ -17485,8 +17431,8 @@ $zh2HK = array(
'餐台' => '餐枱',
'馆里' => '館裏',
'糊口' => '餬口',
-'马里兰' => '馬利蘭',
'馬里蘭' => '馬利蘭',
+'马里兰' => '馬利蘭',
'马拉特·萨芬' => '馬拉特·沙芬',
'馬斯垂克' => '馬斯特里赫特',
'馬爾地夫' => '馬爾代夫',
@@ -17521,18 +17467,11 @@ $zh2HK = array(
'高著作' => '高著作',
'高著名' => '高著名',
'高著書' => '高著書',
+'高著称' => '高著稱',
'高著稱' => '高著稱',
'高著者' => '高著者',
'高著述' => '高著述',
'高著錄' => '高著錄',
-'髭著' => '髭着',
-'髭著作' => '髭著作',
-'髭著名' => '髭著名',
-'髭著書' => '髭著書',
-'髭著稱' => '髭著稱',
-'髭著者' => '髭著者',
-'髭著述' => '髭著述',
-'髭著錄' => '髭著錄',
'斗着' => '鬥着',
'鬥著' => '鬥着',
'鬥著作' => '鬥著作',
@@ -17545,8 +17484,8 @@ $zh2HK = array(
'鬧著' => '鬧着',
'牛軋' => '鳥結',
'牛轧' => '鳥結',
-'鸠占' => '鳩佔',
'鳩占' => '鳩佔',
+'鸠占' => '鳩佔',
'麗著' => '麗着',
'麗著作' => '麗著作',
'麗著名' => '麗著名',
@@ -17566,21 +17505,21 @@ $zh2HK = array(
'里氏3' => '黎克特制3',
'芮氏4' => '黎克特制4',
'里氏4' => '黎克特制4',
-'里氏5' => '黎克特制5',
'芮氏5' => '黎克特制5',
-'里氏6' => '黎克特制6',
+'里氏5' => '黎克特制5',
'芮氏6' => '黎克特制6',
-'里氏7' => '黎克特制7',
+'里氏6' => '黎克特制6',
'芮氏7' => '黎克特制7',
-'里氏8' => '黎克特制8',
+'里氏7' => '黎克特制7',
'芮氏8' => '黎克特制8',
+'里氏8' => '黎克特制8',
'芮氏9' => '黎克特制9',
'里氏9' => '黎克特制9',
'芮氏地震規模' => '黎克特制地震震級',
'里氏地震规模' => '黎克特制地震震級',
-'里氏震级' => '黎克特制震級',
'芮氏規模' => '黎克特制震級',
'里氏规模' => '黎克特制震級',
+'里氏震级' => '黎克特制震級',
'黏著' => '黏着',
'黏著作' => '黏著作',
'黏著名' => '黏著名',
@@ -17614,11 +17553,11 @@ $zh2CN = array(
'下著' => '下着',
'下著作' => '下著作',
'下著名' => '下著名',
-'下著錄' => '下著录',
'下著录' => '下著录',
+'下著錄' => '下著录',
'下著有' => '下著有',
-'下著稱' => '下著称',
'下著称' => '下著称',
+'下著稱' => '下著称',
'下著者' => '下著者',
'下著述' => '下著述',
'不著' => '不着',
@@ -17646,8 +17585,10 @@ $zh2CN = array(
'邱吉爾' => '丘吉尔',
'C型肝炎' => '丙型肝炎',
'C肝' => '丙肝',
-'東協' => '东盟',
+'東南亞國家協會' => '东南亚国家联盟',
'亚细安' => '东盟',
+'東協' => '东盟',
+'仲介' => '中介',
'臨著' => '临着',
'臨著書' => '临著书',
'臨著作' => '临著作',
@@ -17674,7 +17615,6 @@ $zh2CN = array(
'麗著者' => '丽著者',
'麗著述' => '丽著述',
'麼著' => '么着',
-'烏茲別克' => '乌兹别克斯坦',
'樂著' => '乐着',
'樂著書' => '乐著书',
'樂著作' => '乐著作',
@@ -17683,12 +17623,14 @@ $zh2CN = array(
'樂著稱' => '乐著称',
'樂著者' => '乐著者',
'樂著述' => '乐著述',
+'賈伯斯' => '乔布斯',
'喬治·歐威爾' => '乔治·奥威尔',
'乘著' => '乘着',
'乘著書' => '乘著书',
'乘著作' => '乘著作',
'乘著名' => '乘著名',
'乘著錄' => '乘著录',
+'乘著称' => '乘著称',
'乘著稱' => '乘著称',
'乘著者' => '乘著者',
'乘著述' => '乘著述',
@@ -17709,17 +17651,17 @@ $zh2CN = array(
'二極體' => '二极管',
'二進位制' => '二进位制',
'二進位' => '二进制',
-'網際網路' => '互联网',
'網際網絡' => '互联网',
+'網際網路' => '互联网',
'亞歷山卓' => '亚历山大',
'雅穆索戈' => '亚穆苏克罗',
-'互動式' => '交互式',
'交帳' => '交账',
'亮著' => '亮着',
'亮著書' => '亮著书',
'亮著作' => '亮著作',
'亮著名' => '亮著名',
'亮著錄' => '亮著录',
+'亮著称' => '亮著称',
'亮著稱' => '亮著称',
'亮著者' => '亮著者',
'亮著述' => '亮著述',
@@ -17749,6 +17691,7 @@ $zh2CN = array(
'伊利諾伊' => '伊利诺伊',
'伊斯蘭瑪巴德' => '伊斯兰堡',
'伊斯坦堡' => '伊斯坦布尔',
+'伏著' => '伏着',
'優先順序' => '优先级',
'傳著' => '传着',
'傳著書' => '传著书',
@@ -17769,12 +17712,12 @@ $zh2CN = array(
'伴著者' => '伴著者',
'伴著述' => '伴著述',
'點陣圖' => '位图',
-'IP' => '位址',
'低著' => '低着',
'低著書' => '低著书',
'低著作' => '低著作',
'低著名' => '低著名',
'低著錄' => '低著录',
+'低著称' => '低著称',
'低著稱' => '低著称',
'低著者' => '低著者',
'低著述' => '低著述',
@@ -17783,6 +17726,7 @@ $zh2CN = array(
'住著作' => '住著作',
'住著名' => '住著名',
'住著錄' => '住著录',
+'住著称' => '住著称',
'住著稱' => '住著称',
'住著者' => '住著者',
'住著述' => '住著述',
@@ -17805,20 +17749,23 @@ $zh2CN = array(
'保障著作' => '保障著作',
'保障著名' => '保障著名',
'保障著錄' => '保障著录',
+'保障著称' => '保障著称',
'保障著稱' => '保障著称',
'保障著者' => '保障著者',
'保障著述' => '保障著述',
+'資訊時代' => '信息时代',
'資訊理論' => '信息论',
'信著' => '信着',
'信著書' => '信著书',
'信著作' => '信著作',
'信著名' => '信著名',
'信著錄' => '信著录',
+'信著称' => '信著称',
'信著稱' => '信著称',
'信著者' => '信著者',
'信著述' => '信著述',
-'掌上壓' => '俯卧撑',
'伏地挺身' => '俯卧撑',
+'掌上壓' => '俯卧撑',
'倒帳' => '倒账',
'候著' => '候着',
'候著書' => '候著书',
@@ -17828,8 +17775,8 @@ $zh2CN = array(
'候著稱' => '候著称',
'候著者' => '候著者',
'候著述' => '候著述',
-'藉著' => '借着',
'借著' => '借着',
+'藉著' => '借着',
'借著書' => '借著书',
'借著作' => '借著作',
'借著名' => '借著名',
@@ -17861,6 +17808,7 @@ $zh2CN = array(
'光著作' => '光著作',
'光著名' => '光著名',
'光著錄' => '光著录',
+'光著称' => '光著称',
'光著稱' => '光著称',
'光著者' => '光著者',
'光著述' => '光著述',
@@ -17895,15 +17843,6 @@ $zh2CN = array(
'關著者' => '关著者',
'關著述' => '关著述',
'關帳' => '关账',
-'氧份' => '养分',
-'冀著' => '冀着',
-'冀著書' => '冀著书',
-'冀著作' => '冀著作',
-'冀著名' => '冀著名',
-'冀著錄' => '冀著录',
-'冀著稱' => '冀著称',
-'冀著者' => '冀著者',
-'冀著述' => '冀著述',
'記憶體' => '内存',
'甘比亞' => '冈比亚',
'冒著' => '冒着',
@@ -17926,6 +17865,7 @@ $zh2CN = array(
'衝著' => '冲着',
'沖著。' => '冲著。',
'沖著《' => '冲著《',
+'沖著(' => '冲著(',
'沖著,' => '冲著,',
'沖帳' => '冲账',
'涼著' => '凉着',
@@ -17943,8 +17883,10 @@ $zh2CN = array(
'嘉芙蓮' => '凯瑟琳',
'份內' => '分内',
'份外' => '分外',
-'解析度' => '分辨率',
+'分佈著' => '分布着',
+'分布著' => '分布着',
'解像度' => '分辨率',
+'解析度' => '分辨率',
'份量' => '分量',
'車諾比' => '切尔诺贝利',
'劃著' => '划着',
@@ -17969,6 +17911,7 @@ $zh2CN = array(
'刻著作' => '刻著作',
'刻著名' => '刻著名',
'刻著錄' => '刻著录',
+'刻著称' => '刻著称',
'刻著稱' => '刻著称',
'刻著者' => '刻著者',
'刻著述' => '刻著述',
@@ -17997,17 +17940,10 @@ $zh2CN = array(
'努力著作' => '努力著作',
'努力著名' => '努力著名',
'努力著錄' => '努力著录',
+'努力著称' => '努力著称',
'努力著稱' => '努力著称',
'努力著者' => '努力著者',
'努力著述' => '努力著述',
-'努著' => '努着',
-'努著書' => '努著书',
-'努著作' => '努著作',
-'努著名' => '努著名',
-'努著錄' => '努著录',
-'努著稱' => '努著称',
-'努著者' => '努著者',
-'努著述' => '努著述',
'蘿拉' => '劳拉',
'布蘭登堡' => '勃兰登堡',
'白朗寧' => '勃朗宁',
@@ -18016,8 +17952,8 @@ $zh2CN = array(
'十進位制' => '十进位制',
'十進位' => '十进制',
'公升' => '升',
-'單鏡反光機' => '单反相机',
'單眼相機' => '单反相机',
+'單鏡反光機' => '单反相机',
'波札那' => '博茨瓦纳',
'占著' => '占着',
'占著作' => '占著作',
@@ -18038,12 +17974,12 @@ $zh2CN = array(
'印著者' => '印著者',
'印著述' => '印著述',
'瓜地馬拉' => '危地马拉',
+'厄瓜多' => '厄瓜多尔',
'厄瓜多尔' => '厄瓜多尔',
'厄瓜多爾' => '厄瓜多尔',
-'厄瓜多' => '厄瓜多尔',
-'厄立特里亞' => '厄立特里亚',
'厄利垂亚' => '厄立特里亚',
'厄利垂亞' => '厄立特里亚',
+'厄立特里亞' => '厄立特里亚',
'壓著' => '压着',
'壓著書' => '压著书',
'壓著作' => '压著作',
@@ -18052,14 +17988,6 @@ $zh2CN = array(
'壓著稱' => '压著称',
'壓著者' => '压著者',
'壓著述' => '压著述',
-'去著' => '去着',
-'去著書' => '去著书',
-'去著作' => '去著作',
-'去著名' => '去著名',
-'去著錄' => '去著录',
-'去著稱' => '去著称',
-'去著者' => '去著者',
-'去著述' => '去著述',
'發著' => '发着',
'發著《' => '发著《',
'發著作' => '发著作',
@@ -18083,6 +18011,8 @@ $zh2CN = array(
'變著稱' => '变著称',
'變著者' => '变著者',
'變著述' => '变著述',
+'隻字片語' => '只字片语',
+'隻言片語' => '只言片语',
'唯讀' => '只读',
'叫著' => '叫着',
'叫著書' => '叫著书',
@@ -18092,6 +18022,7 @@ $zh2CN = array(
'叫著稱' => '叫著称',
'叫著者' => '叫著者',
'叫著述' => '叫著述',
+'桌上型電腦' => '台式电脑',
'撞球' => '台球',
'台帳' => '台账',
'叱吒' => '叱咤',
@@ -18141,12 +18072,12 @@ $zh2CN = array(
'味著作' => '味著作',
'味著名' => '味著名',
'味著錄' => '味著录',
+'味著称' => '味著称',
'味著稱' => '味著称',
'味著者' => '味著者',
'味著述' => '味著述',
'咖哩' => '咖喱',
'諮' => '咨',
-'哈薩克' => '哈萨克斯坦',
'響著' => '响着',
'響著書' => '响著书',
'響著作' => '响著作',
@@ -18223,23 +18154,15 @@ $zh2CN = array(
'圍著者' => '围著者',
'圍著述' => '围著述',
'韌體' => '固件',
+'固著' => '固着',
'土魯斯' => '图卢兹',
'吐瓦魯' => '图瓦卢',
'原子筆' => '圆珠笔',
-'土庫曼' => '土库曼斯坦',
'聖露西亞' => '圣卢西亚',
-'聖吉斯納域斯' => '圣基茨和尼维斯',
'聖克里斯多福及尼維斯' => '圣基茨和尼维斯',
+'聖吉斯納域斯' => '圣基茨和尼维斯',
'聖文森及格瑞那丁' => '圣文森特和格林纳丁斯',
'聖馬利諾' => '圣马力诺',
-'在著' => '在着',
-'在著書' => '在著书',
-'在著作' => '在著作',
-'在著名' => '在著名',
-'在著錄' => '在著录',
-'在著稱' => '在著称',
-'在著者' => '在著者',
-'在著述' => '在著述',
'蓋亞那' => '圭亚那',
'坐著' => '坐着',
'坐著書' => '坐著书',
@@ -18249,6 +18172,7 @@ $zh2CN = array(
'坐著稱' => '坐著称',
'坐著者' => '坐著者',
'坐著述' => '坐著述',
+'堅貞著' => '坚贞着',
'坦尚尼亞' => '坦桑尼亚',
'伊波拉' => '埃博拉',
'衣索匹亞' => '埃塞俄比亚',
@@ -18259,14 +18183,12 @@ $zh2CN = array(
'吉里巴斯' => '基里巴斯',
'堂姊' => '堂姐',
'坎培拉' => '堪培拉',
-'塔吉克' => '塔吉克斯坦',
-'塔吉克斯坦' => '塔吉克斯坦',
'塞爾維亞與蒙特內哥羅' => '塞尔维亚和黑山',
'塞拉利昂' => '塞拉利昂',
'塞普勒斯' => '塞浦路斯',
'賽普勒斯' => '塞浦路斯',
-'西維爾' => '塞维利亚',
'塞維亞' => '塞维利亚',
+'西維爾' => '塞维利亚',
'塞席爾' => '塞舌尔',
'音效卡' => '声卡',
'備著' => '备着',
@@ -18305,16 +18227,10 @@ $zh2CN = array(
'字型檔' => '字库',
'欄位' => '字段',
'位元組' => '字节',
+'存在著' => '存在着',
'存著' => '存着',
+'存著作' => '存著作',
'存著名' => '存著名',
-'孤著' => '孤着',
-'孤著書' => '孤著书',
-'孤著作' => '孤著作',
-'孤著名' => '孤著名',
-'孤著錄' => '孤著录',
-'孤著稱' => '孤著称',
-'孤著者' => '孤著者',
-'孤著述' => '孤著述',
'學姊' => '学姐',
'學著' => '学着',
'學著書' => '学著书',
@@ -18331,6 +18247,7 @@ $zh2CN = array(
'守著作' => '守著作',
'守著名' => '守著名',
'守著錄' => '守著录',
+'守著称' => '守著称',
'守著稱' => '守著称',
'守著者' => '守著者',
'守著述' => '守著述',
@@ -18342,12 +18259,14 @@ $zh2CN = array(
'定著作' => '定著作',
'定著名' => '定著名',
'定著錄' => '定著录',
+'定著称' => '定著称',
'定著稱' => '定著称',
'定著者' => '定著者',
'定著述' => '定著述',
+'波里活' => '宝莱坞',
'寬頻' => '宽带',
-'密西根' => '密歇根',
'密执安' => '密歇根',
+'密西根' => '密歇根',
'對著' => '对着',
'對著書' => '对著书',
'對著作' => '对著作',
@@ -18379,10 +18298,10 @@ $zh2CN = array(
'展著稱' => '展著称',
'展著者' => '展著者',
'展著述' => '展著述',
-'華倫西亞' => '巴伦西亚',
'瓦倫西亞' => '巴伦西亚',
-'巴塞隆納' => '巴塞罗那',
+'華倫西亞' => '巴伦西亚',
'巴塞隆拿' => '巴塞罗那',
+'巴塞隆納' => '巴塞罗那',
'巴斯拉' => '巴士拉',
'帕邁拉環礁' => '巴尔米拉环礁',
'巴貝多' => '巴巴多斯',
@@ -18391,7 +18310,10 @@ $zh2CN = array(
'布吉納法索' => '布基纳法索',
'布隆泉' => '布隆方丹',
'蒲隆地' => '布隆迪',
+'希冀著' => '希冀着',
'席哈克' => '希拉克',
+'希拉莉' => '希拉里',
+'希拉蕊' => '希拉里',
'希特拉' => '希特勒',
'帛琉' => '帕劳',
'派屈克' => '帕特里克',
@@ -18417,6 +18339,8 @@ $zh2CN = array(
'幹著名' => '幹著名',
'幹著稱' => '幹著称',
'庇護著' => '庇护着',
+'庫德人' => '库尔德人',
+'庫德族' => '库尔德族',
'應用程式' => '应用程序',
'應著' => '应着',
'應著書' => '应著书',
@@ -18426,14 +18350,6 @@ $zh2CN = array(
'應著稱' => '应著称',
'應著者' => '应著者',
'應著述' => '应著述',
-'康著' => '康着',
-'康著書' => '康著书',
-'康著作' => '康著作',
-'康著名' => '康著名',
-'康著錄' => '康著录',
-'康著稱' => '康著称',
-'康著者' => '康著者',
-'康著述' => '康著述',
'建帳' => '建账',
'克卜勒' => '开普勒',
'蓋曼群島' => '开曼群岛',
@@ -18502,6 +18418,7 @@ $zh2CN = array(
'心著作' => '心著作',
'心著名' => '心著名',
'心著錄' => '心著录',
+'心著称' => '心著称',
'心著稱' => '心著称',
'心著者' => '心著者',
'心著述' => '心著述',
@@ -18513,14 +18430,6 @@ $zh2CN = array(
'忍著稱' => '忍著称',
'忍著者' => '忍著者',
'忍著述' => '忍著述',
-'志著' => '志着',
-'志著書' => '志著书',
-'志著作' => '志著作',
-'志著名' => '志著名',
-'志著錄' => '志著录',
-'志著稱' => '志著称',
-'志著者' => '志著者',
-'志著述' => '志著述',
'忙著' => '忙着',
'忙著書' => '忙著书',
'忙著作' => '忙著作',
@@ -18529,6 +18438,7 @@ $zh2CN = array(
'忙著稱' => '忙著称',
'忙著者' => '忙著者',
'忙著述' => '忙著述',
+'忠貞著' => '忠贞着',
'懷著' => '怀着',
'懷著書' => '怀著书',
'懷著作' => '怀著作',
@@ -18545,14 +18455,6 @@ $zh2CN = array(
'急著稱' => '急著称',
'急著者' => '急著者',
'急著述' => '急著述',
-'性著' => '性着',
-'性著書' => '性著书',
-'性著作' => '性著作',
-'性著名' => '性著名',
-'性著錄' => '性著录',
-'性著稱' => '性著称',
-'性著者' => '性著者',
-'性著述' => '性著述',
'匯流排' => '总线',
'總帳' => '总账',
'戀著' => '恋着',
@@ -18585,6 +18487,7 @@ $zh2CN = array(
'想著作' => '想著作',
'想著名' => '想著名',
'想著錄' => '想著录',
+'想著称' => '想著称',
'想著稱' => '想著称',
'想著者' => '想著者',
'想著述' => '想著述',
@@ -18663,8 +18566,8 @@ $zh2CN = array(
'披著稱' => '披著称',
'披著者' => '披著者',
'披著述' => '披著述',
-'擡著' => '抬着',
'抬著' => '抬着',
+'擡著' => '抬着',
'抬著作' => '抬著作',
'抬著名' => '抬著名',
'抬著錄' => '抬著录',
@@ -18847,14 +18750,17 @@ $zh2CN = array(
'敞著稱' => '敞著称',
'敞著者' => '敞著者',
'敞著述' => '敞著述',
-'數碼訊號' => '数字信号',
+'散佈著' => '散布着',
+'散布著' => '散布着',
'數位訊號' => '数字信号',
+'數碼訊號' => '数字信号',
'數位技術' => '数字技术',
'數碼技術' => '数字技术',
'數位電視' => '数字电视',
'數碼電視' => '数字电视',
'資料庫' => '数据库',
'數著' => '数着',
+'數位照相機' => '数码照相机',
'數位相機' => '数码相机',
'數著作' => '数著作',
'數著名' => '数著名',
@@ -18879,6 +18785,7 @@ $zh2CN = array(
'斥著稱' => '斥著称',
'斥著者' => '斥著者',
'斥著述' => '斥著述',
+'史丹福大學' => '斯坦福大学',
'史達林' => '斯大林',
'史瓦濟蘭' => '斯威士兰',
'斯洛維尼亞' => '斯洛文尼亚',
@@ -19006,8 +18913,11 @@ $zh2CN = array(
'柏林圍牆' => '柏林墙',
'查帳' => '查账',
'查維茲' => '查韦斯',
+'標志著' => '标志着',
'標誌著' => '标志着',
'格瑞那達' => '格林纳达',
+'格林美獎' => '格莱美奖',
+'葛萊美獎' => '格莱美奖',
'森巴舞' => '桑巴舞',
'梅赫西迪' => '梅赛德斯',
'夢著' => '梦着',
@@ -19032,10 +18942,11 @@ $zh2CN = array(
'庇里牛斯' => '比利牛斯',
'畢卡索' => '毕加索',
'茅利塔尼亞' => '毛里塔尼亚',
-'毛里裘斯' => '毛里求斯',
'模里西斯' => '毛里求斯',
+'毛里裘斯' => '毛里求斯',
'公厘' => '毫米',
'公釐' => '毫米',
+'氧份' => '氧分',
'胺基酸' => '氨基酸',
'水份' => '水分',
'水氣' => '水汽',
@@ -19057,8 +18968,8 @@ $zh2CN = array(
'沉著稱' => '沉著称',
'沉著者' => '沉著者',
'沉著述' => '沉著述',
-'沙烏地阿拉伯' => '沙特阿拉伯',
'沙地阿拉伯' => '沙特阿拉伯',
+'沙烏地阿拉伯' => '沙特阿拉伯',
'沿著' => '沿着',
'沿著書' => '沿著书',
'沿著作' => '沿著作',
@@ -19112,15 +19023,8 @@ $zh2CN = array(
'潤著稱' => '润著称',
'潤著者' => '润著者',
'潤著述' => '润著述',
-'涵著' => '涵着',
-'涵著書' => '涵著书',
-'涵著作' => '涵著作',
-'涵著名' => '涵著名',
-'涵著錄' => '涵著录',
-'涵著稱' => '涵著称',
-'涵著者' => '涵著者',
-'涵著述' => '涵著述',
'混帳' => '混账',
+'清澈' => '清澈',
'清帳' => '清账',
'渴著' => '渴着',
'渴著書' => '渴著书',
@@ -19211,14 +19115,9 @@ $zh2CN = array(
'千里達及托巴哥' => '特立尼达和多巴哥',
'千里達托貝哥' => '特立尼达和托巴哥',
'狗隻' => '犬只',
-'獨著' => '独着',
-'獨著書' => '独著书',
-'獨著作' => '独著作',
-'獨著名' => '独著名',
-'獨著錄' => '独著录',
-'獨著稱' => '独著称',
-'獨著者' => '独著者',
-'獨著述' => '独著述',
+'猶豫著' => '犹豫着',
+'獨立國家國協' => '独立国家联合体',
+'獨立國協' => '独联体',
'猜著' => '猜着',
'猜著書' => '猜着书',
'猜著作' => '猜著作',
@@ -19228,8 +19127,9 @@ $zh2CN = array(
'猜著者' => '猜著者',
'猜著述' => '猜著述',
'玩著' => '玩着',
-'萬那杜' => '瓦努阿图',
+'班固著' => '班固著',
'溫納圖' => '瓦努阿图',
+'萬那杜' => '瓦努阿图',
'華勒沙' => '瓦文萨',
'華里沙' => '瓦文萨',
'甜著' => '甜着',
@@ -19287,6 +19187,10 @@ $zh2CN = array(
'皺著者' => '皱著者',
'皺著述' => '皱著述',
'鹽份' => '盐分',
+'蓋著' => '盖着',
+'蓋著作' => '盖著作',
+'蓋著名' => '盖著名',
+'蓋著稱' => '盖著称',
'盛著' => '盛着',
'盛著書' => '盛著书',
'盛著作' => '盛著作',
@@ -19303,14 +19207,6 @@ $zh2CN = array(
'盯著稱' => '盯著称',
'盯著者' => '盯著者',
'盯著述' => '盯著述',
-'盾著' => '盾着',
-'盾著書' => '盾著书',
-'盾著作' => '盾著作',
-'盾著名' => '盾著名',
-'盾著錄' => '盾著录',
-'盾著稱' => '盾著称',
-'盾著者' => '盾著者',
-'盾著述' => '盾著述',
'看著' => '看着',
'看著書' => '看着书',
'看著作' => '看著作',
@@ -19323,8 +19219,8 @@ $zh2CN = array(
'著絲' => '着丝',
'著麼' => '着么',
'著人' => '着人',
-'著甚麽' => '着什么',
'著什麼' => '着什么',
+'著甚麽' => '着什么',
'著他' => '着他',
'著令' => '着令',
'著位' => '着位',
@@ -19453,8 +19349,9 @@ $zh2CN = array(
'瞪著稱' => '瞪著称',
'瞪著者' => '瞪著者',
'瞪著述' => '瞪著述',
-'智財權' => '知识产权',
+'矛盾著' => '矛盾着',
'智慧財產權' => '知识产权',
+'智財權' => '知识产权',
'知識份子' => '知识分子',
'什勒斯維希' => '石勒苏益格',
'矽塵' => '矽尘',
@@ -19482,15 +19379,15 @@ $zh2CN = array(
'葛摩' => '科摩罗',
'象牙海岸' => '科特迪瓦',
'積極份子' => '积极分子',
-'行動電話' => '移动电话',
'流動電話' => '移动电话',
-'行動網路' => '移动网络',
+'行動電話' => '移动电话',
'流動網絡' => '移动网络',
+'行動網路' => '移动网络',
'程式設計師' => '程序员',
'程式控制' => '程控',
'空中巴士' => '空中客车',
-'空氣質素' => '空气质量',
'空氣品質' => '空气质量',
+'空氣質素' => '空气质量',
'空著' => '空着',
'空著書' => '空著书',
'空著作' => '空著作',
@@ -19508,6 +19405,15 @@ $zh2CN = array(
'穿著者' => '穿著者',
'穿著述' => '穿著述',
'突尼西亞' => '突尼斯',
+'立著' => '立着',
+'立著《' => '立著《',
+'立著作' => '立著作',
+'立著名' => '立著名',
+'立著有' => '立著有',
+'立著称' => '立著称',
+'立著稱' => '立著称',
+'立著者' => '立著者',
+'立著(' => '立著(',
'豎著' => '竖着',
'豎著書' => '竖著书',
'豎著作' => '竖著作',
@@ -19553,13 +19459,14 @@ $zh2CN = array(
'糖份' => '糖分',
'動畫影集' => '系列动画片',
'繫著' => '系着',
-'索贊尼辛' => '索尔仁尼琴',
'索忍尼辛' => '索尔仁尼琴',
+'索贊尼辛' => '索尔仁尼琴',
'蘇辛尼津' => '索尔仁尼琴',
'索馬利亞' => '索马里',
'索馬利蘭' => '索马里兰',
'正體中文' => '繁体中文',
'強斯頓環礁' => '约翰斯顿岛',
+'縱著' => '纵着',
'組份' => '组分',
'經常帳' => '经常账',
'經濟帳' => '经济账',
@@ -19607,6 +19514,7 @@ $zh2CN = array(
'美著作' => '美著作',
'美著名' => '美著名',
'美著錄' => '美著录',
+'美著称' => '美著称',
'美著稱' => '美著称',
'美著者' => '美著者',
'美著述' => '美著述',
@@ -19653,17 +19561,9 @@ $zh2CN = array(
'舒麥加' => '舒马赫',
'太空梭' => '航天飞机',
'穿梭機' => '航天飞机',
-'藝著' => '艺着',
-'藝著書' => '艺著书',
-'藝著作' => '艺著作',
-'藝著名' => '艺著名',
-'藝著錄' => '艺著录',
-'藝著稱' => '艺著称',
-'藝著者' => '艺著者',
-'藝著述' => '艺著述',
'愛滋' => '艾滋',
-'晶片' => '芯片',
'晶元' => '芯片',
+'晶片' => '芯片',
'蘇利南' => '苏里南',
'苦著' => '苦着',
'苦著書' => '苦著书',
@@ -19675,8 +19575,8 @@ $zh2CN = array(
'苦著述' => '苦著述',
'英吋' => '英寸',
'英呎' => '英尺',
-'大英國協' => '英联邦',
'共和联邦' => '英联邦',
+'大英國協' => '英联邦',
'士多啤梨' => '草莓',
'螢光棒' => '荧光棒',
'螢屏' => '荧屏',
@@ -19684,8 +19584,8 @@ $zh2CN = array(
'莫三比克' => '莫桑比克',
'雷伊泰灣' => '莱特湾',
'賴索托' => '莱索托',
-'穫著' => '获着',
'獲著' => '获着',
+'穫著' => '获着',
'獲著書' => '获著书',
'獲著作' => '获著作',
'獲著名' => '获著名',
@@ -19712,8 +19612,8 @@ $zh2CN = array(
'蒙著稱' => '蒙著称',
'蒙著者' => '蒙著者',
'蒙著述' => '蒙著述',
-'蓋著' => '蓋着',
'藍芽' => '蓝牙',
+'蘊涵著' => '蕴涵着',
'薛丁格' => '薛定谔',
'藏著' => '藏着',
'藏著書' => '藏著书',
@@ -19744,6 +19644,7 @@ $zh2CN = array(
'衣著作' => '衣著作',
'衣著名' => '衣著名',
'衣著錄' => '衣著录',
+'衣著称' => '衣著称',
'衣著稱' => '衣著称',
'衣著者' => '衣著者',
'衣著述' => '衣著述',
@@ -19765,6 +19666,7 @@ $zh2CN = array(
'裹著者' => '裹著者',
'裹著述' => '裹著述',
'要帳' => '要账',
+'覆蓋著' => '覆盖着',
'覆著' => '覆着',
'見著' => '见着',
'見著書' => '见著书',
@@ -19774,6 +19676,9 @@ $zh2CN = array(
'見著稱' => '见著称',
'見著者' => '见著者',
'見著述' => '见著述',
+'規畫' => '规划',
+'視著' => '视着',
+'視著名' => '视著名',
'占士邦' => '詹姆斯·邦德',
'警戒著' => '警戒着',
'計畫' => '计划',
@@ -19788,7 +19693,6 @@ $zh2CN = array(
'記著者' => '记著者',
'記著述' => '记著述',
'記帳' => '记账',
-'辭彙' => '词汇',
'片語' => '词组',
'試著' => '试着',
'試著書' => '试著书',
@@ -19815,25 +19719,10 @@ $zh2CN = array(
'數據機' => '调制解调器',
'象徵著' => '象征着',
'象徵著名' => '象征著名',
-'豫著' => '豫着',
-'豫著書' => '豫著书',
-'豫著作' => '豫著作',
-'豫著名' => '豫著名',
-'豫著錄' => '豫著录',
-'豫著稱' => '豫著称',
-'豫著者' => '豫著者',
-'豫著述' => '豫著述',
'碧咸' => '贝克汉姆',
'貝爾格勒' => '贝尔格莱德',
-'貞著' => '贞着',
-'貞著書' => '贞著书',
-'貞著作' => '贞著作',
-'貞著名' => '贞著名',
-'貞著錄' => '贞著录',
-'貞著稱' => '贞著称',
-'貞著者' => '贞著者',
-'貞著述' => '贞著述',
'負著' => '负着',
+'貢寮' => '贡寮',
'帳上' => '账上',
'帳冊' => '账册',
'帳務' => '账务',
@@ -20003,14 +19892,6 @@ $zh2CN = array(
'還帳' => '还账',
'演化論' => '进化论',
'進帳' => '进账',
-'遠著' => '远着',
-'遠著書' => '远著书',
-'遠著作' => '远著作',
-'遠著名' => '远著名',
-'遠著錄' => '远著录',
-'遠著稱' => '远著称',
-'遠著者' => '远著者',
-'遠著述' => '远著述',
'連著' => '连着',
'連結他' => '连结他',
'連著書' => '连著书',
@@ -20052,9 +19933,12 @@ $zh2CN = array(
'遇著作' => '遇著作',
'遇著名' => '遇著名',
'遇著錄' => '遇著录',
+'遇著称' => '遇著称',
'遇著稱' => '遇著称',
'遇著者' => '遇著者',
'遇著述' => '遇著述',
+'遍佈著' => '遍布着',
+'遍布著' => '遍布着',
'部份' => '部分',
'配合著' => '配合着',
'配合著名' => '配合著名',
@@ -20091,6 +19975,7 @@ $zh2CN = array(
'鈽' => '钚',
'鍅' => '钫',
'狄托' => '铁托',
+'卯足' => '铆足',
'鋪著' => '铺着',
'鋪著書' => '铺著书',
'鋪著作' => '铺著作',
@@ -20099,6 +19984,7 @@ $zh2CN = array(
'鋪著稱' => '铺著称',
'鋪著者' => '铺著者',
'鋪著述' => '铺著述',
+'鏈結' => '链接',
'銷帳' => '销账',
'鉲' => '锎',
'鎝' => '锝',
@@ -20106,8 +19992,8 @@ $zh2CN = array(
'鑀' => '锿',
'鋂' => '镅',
'錼' => '镎',
-'孟德爾頌' => '门德尔松',
'孟德爾遜' => '门德尔松',
+'孟德爾頌' => '门德尔松',
'快閃記憶體' => '闪存',
'閉著' => '闭着',
'閉著書' => '闭著书',
@@ -20117,8 +20003,8 @@ $zh2CN = array(
'閉著稱' => '闭著称',
'閉著者' => '闭著者',
'閉著述' => '闭著述',
-'閒著' => '闲着',
'閑著' => '闲着',
+'閒著' => '闲着',
'閑著書' => '闲著书',
'閑著作' => '闲著作',
'閑著名' => '闲著名',
@@ -20181,10 +20067,10 @@ $zh2CN = array(
'雅著作' => '雅著作',
'雅著名' => '雅著名',
'雅著錄' => '雅著录',
+'雅著称' => '雅著称',
'雅著稱' => '雅著称',
'雅著者' => '雅著者',
'雅著述' => '雅著述',
-'山葉' => '雅马哈',
'雷諾瓦' => '雷诺阿',
'荷姆茲' => '霍尔木兹',
'非份' => '非分',
@@ -20221,8 +20107,8 @@ $zh2CN = array(
'領著稱' => '领著称',
'領著者' => '领著者',
'領著述' => '领著述',
-'飄著' => '飘着',
'飃著' => '飘着',
+'飄著' => '飘着',
'飄著書' => '飘著书',
'飄著作' => '飘著作',
'飄著名' => '飘著名',
@@ -20288,17 +20174,12 @@ $zh2CN = array(
'高著作' => '高著作',
'高著名' => '高著名',
'高著錄' => '高著录',
+'高著称' => '高著称',
'高著稱' => '高著称',
'高著者' => '高著者',
'高著述' => '高著述',
-'髭著' => '髭着',
-'髭著書' => '髭著书',
-'髭著作' => '髭著作',
-'髭著名' => '髭著名',
-'髭著錄' => '髭著录',
-'髭著稱' => '髭著称',
-'髭著者' => '髭著者',
-'髭著述' => '髭著述',
+'魚雷' => '鱼雷',
+'鱼雷' => '鱼雷',
'咪高峰' => '麦克风',
'黏著' => '黏着',
'黏著書' => '黏著书',
diff --git a/includes/actions/Action.php b/includes/actions/Action.php
index bb6a4d5d..43f03c3a 100644
--- a/includes/actions/Action.php
+++ b/includes/actions/Action.php
@@ -407,4 +407,14 @@ abstract class Action {
* @throws ErrorPageError
*/
abstract public function show();
+
+ /**
+ * Call wfTransactionalTimeLimit() if this request was POSTed
+ * @since 1.26
+ */
+ protected function useTransactionalTimeLimit() {
+ if ( $this->getRequest()->wasPosted() ) {
+ wfTransactionalTimeLimit();
+ }
+ }
}
diff --git a/includes/actions/DeleteAction.php b/includes/actions/DeleteAction.php
index be21a6f1..841a94df 100644
--- a/includes/actions/DeleteAction.php
+++ b/includes/actions/DeleteAction.php
@@ -41,6 +41,8 @@ class DeleteAction extends FormlessAction {
}
public function show() {
+ $this->useTransactionalTimeLimit();
+
$out = $this->getOutput();
if ( $this->getContext()->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
$out->addModuleStyles( array(
diff --git a/includes/actions/EditAction.php b/includes/actions/EditAction.php
index 6c8440ac..eb53f19a 100644
--- a/includes/actions/EditAction.php
+++ b/includes/actions/EditAction.php
@@ -41,6 +41,8 @@ class EditAction extends FormlessAction {
}
public function show() {
+ $this->useTransactionalTimeLimit();
+
if ( $this->getContext()->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
$out = $this->getOutput();
$out->addModuleStyles( array(
diff --git a/includes/actions/HistoryAction.php b/includes/actions/HistoryAction.php
index dcd77415..a81adf99 100644
--- a/includes/actions/HistoryAction.php
+++ b/includes/actions/HistoryAction.php
@@ -368,6 +368,9 @@ class HistoryPager extends ReverseChronologicalPager {
*/
protected $parentLens;
+ /** @var bool Whether to show the tag editing UI */
+ protected $showTagEditUI;
+
/**
* @param HistoryAction $historyPage
* @param string $year
@@ -381,6 +384,7 @@ class HistoryPager extends ReverseChronologicalPager {
$this->tagFilter = $tagFilter;
$this->getDateCond( $year, $month );
$this->conds = $conds;
+ $this->showTagEditUI = ChangeTags::showTagEditingUI( $this->getUser() );
}
// For hook compatibility...
@@ -432,8 +436,13 @@ class HistoryPager extends ReverseChronologicalPager {
$latest = ( $this->counter == 1 && $this->mIsFirst );
$firstInList = $this->counter == 1;
$this->counter++;
- $s = $this->historyLine( $this->lastRow, $row,
- $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList );
+
+ $notifTimestamp = $this->getConfig()->get( 'ShowUpdatedMarker' )
+ ? $this->getTitle()->getNotificationTimestamp( $this->getUser() )
+ : false;
+
+ $s = $this->historyLine(
+ $this->lastRow, $row, $notifTimestamp, $latest, $firstInList );
} else {
$s = '';
}
@@ -443,6 +452,10 @@ class HistoryPager extends ReverseChronologicalPager {
}
function doBatchLookups() {
+ if ( !Hooks::run( 'PageHistoryPager::doBatchLookups', array( $this, $this->mResult ) ) ) {
+ return;
+ }
+
# Do a link batch query
$this->mResult->seek( 0 );
$batch = new LinkBatch();
@@ -495,7 +508,7 @@ class HistoryPager extends ReverseChronologicalPager {
if ( $user->isAllowed( 'deleterevision' ) ) {
$actionButtons .= $this->getRevisionButton( 'revisiondelete', 'showhideselectedversions' );
}
- if ( ChangeTags::showTagEditingUI( $user ) ) {
+ if ( $this->showTagEditUI ) {
$actionButtons .= $this->getRevisionButton( 'editchangetags', 'history-edit-tags' );
}
if ( $actionButtons ) {
@@ -542,8 +555,13 @@ class HistoryPager extends ReverseChronologicalPager {
$next = $this->mPastTheEndRow;
}
$this->counter++;
- $s = $this->historyLine( $this->lastRow, $next,
- $this->getTitle()->getNotificationTimestamp( $this->getUser() ), $latest, $firstInList );
+
+ $notifTimestamp = $this->getConfig()->get( 'ShowUpdatedMarker' )
+ ? $this->getTitle()->getNotificationTimestamp( $this->getUser() )
+ : false;
+
+ $s = $this->historyLine(
+ $this->lastRow, $next, $notifTimestamp, $latest, $firstInList );
} else {
$s = '';
}
@@ -617,14 +635,13 @@ class HistoryPager extends ReverseChronologicalPager {
$del = '';
$user = $this->getUser();
$canRevDelete = $user->isAllowed( 'deleterevision' );
- $showTagEditUI = ChangeTags::showTagEditingUI( $user );
// Show checkboxes for each revision, to allow for revision deletion and
// change tags
- if ( $canRevDelete || $showTagEditUI ) {
+ if ( $canRevDelete || $this->showTagEditUI ) {
$this->preventClickjacking();
// If revision was hidden from sysops and we don't need the checkbox
// for anything else, disable it
- if ( !$showTagEditUI && !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
+ if ( !$this->showTagEditUI && !$rev->userCan( Revision::DELETED_RESTRICTED, $user ) ) {
$del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) );
// Otherwise, enable the checkbox...
} else {
diff --git a/includes/actions/InfoAction.php b/includes/actions/InfoAction.php
index b5a73910..f3670a86 100644
--- a/includes/actions/InfoAction.php
+++ b/includes/actions/InfoAction.php
@@ -62,14 +62,18 @@ class InfoAction extends FormlessAction {
*
* @since 1.22
* @param Title $title Title to clear cache for
+ * @param int|null $revid Revision id to clear
*/
- public static function invalidateCache( Title $title ) {
- global $wgMemc;
+ public static function invalidateCache( Title $title, $revid = null ) {
+ $cache = ObjectCache::getMainWANInstance();
- $revision = Revision::newFromTitle( $title, 0, Revision::READ_LATEST );
- if ( $revision !== null ) {
- $key = wfMemcKey( 'infoaction', sha1( $title->getPrefixedText() ), $revision->getId() );
- $wgMemc->delete( $key );
+ if ( !$revid ) {
+ $revision = Revision::newFromTitle( $title, 0, Revision::READ_LATEST );
+ $revid = $revision ? $revision->getId() : null;
+ }
+ if ( $revid !== null ) {
+ $key = wfMemcKey( 'infoaction', sha1( $title->getPrefixedText() ), $revid );
+ $cache->delete( $key );
}
}
@@ -193,7 +197,7 @@ class InfoAction extends FormlessAction {
* @return array
*/
protected function pageInfo() {
- global $wgContLang, $wgMemc;
+ global $wgContLang;
$user = $this->getUser();
$lang = $this->getLanguage();
@@ -201,16 +205,17 @@ class InfoAction extends FormlessAction {
$id = $title->getArticleID();
$config = $this->context->getConfig();
+ $cache = ObjectCache::getMainWANInstance();
$memcKey = wfMemcKey( 'infoaction',
sha1( $title->getPrefixedText() ), $this->page->getLatest() );
- $pageCounts = $wgMemc->get( $memcKey );
+ $pageCounts = $cache->get( $memcKey );
$version = isset( $pageCounts['cacheversion'] ) ? $pageCounts['cacheversion'] : false;
if ( $pageCounts === false || $version !== self::CACHE_VERSION ) {
// Get page information that would be too "expensive" to retrieve by normal means
$pageCounts = $this->pageCounts( $title );
$pageCounts['cacheversion'] = self::CACHE_VERSION;
- $wgMemc->set( $memcKey, $pageCounts );
+ $cache->set( $memcKey, $pageCounts );
}
// Get page properties
@@ -233,7 +238,7 @@ class InfoAction extends FormlessAction {
// Display title
$displayTitle = $title->getPrefixedText();
- if ( !empty( $pageProperties['displaytitle'] ) ) {
+ if ( isset( $pageProperties['displaytitle'] ) ) {
$displayTitle = $pageProperties['displaytitle'];
}
@@ -258,7 +263,7 @@ class InfoAction extends FormlessAction {
// Default sort key
$sortKey = $title->getCategorySortkey();
- if ( !empty( $pageProperties['defaultsort'] ) ) {
+ if ( isset( $pageProperties['defaultsort'] ) ) {
$sortKey = $pageProperties['defaultsort'];
}
@@ -324,8 +329,27 @@ class InfoAction extends FormlessAction {
) {
// Number of page watchers
$pageInfo['header-basic'][] = array(
- $this->msg( 'pageinfo-watchers' ), $lang->formatNum( $pageCounts['watchers'] )
+ $this->msg( 'pageinfo-watchers' ),
+ $lang->formatNum( $pageCounts['watchers'] )
);
+ if (
+ $config->get( 'ShowUpdatedMarker' ) &&
+ isset( $pageCounts['visitingWatchers'] )
+ ) {
+ $minToDisclose = $config->get( 'UnwatchedPageSecret' );
+ if ( $pageCounts['visitingWatchers'] > $minToDisclose ||
+ $user->isAllowed( 'unwatchedpages' ) ) {
+ $pageInfo['header-basic'][] = array(
+ $this->msg( 'pageinfo-visiting-watchers' ),
+ $lang->formatNum( $pageCounts['visitingWatchers'] )
+ );
+ } else {
+ $pageInfo['header-basic'][] = array(
+ $this->msg( 'pageinfo-visiting-watchers' ),
+ $this->msg( 'pageinfo-few-visiting-watchers' )
+ );
+ }
+ }
} elseif ( $unwatchedPageThreshold !== false ) {
$pageInfo['header-basic'][] = array(
$this->msg( 'pageinfo-watchers' ),
@@ -373,18 +397,30 @@ class InfoAction extends FormlessAction {
if ( $title->inNamespace( NS_CATEGORY ) ) {
$category = Category::newFromTitle( $title );
+
+ // $allCount is the total number of cat members,
+ // not the count of how many members are normal pages.
+ $allCount = (int)$category->getPageCount();
+ $subcatCount = (int)$category->getSubcatCount();
+ $fileCount = (int)$category->getFileCount();
+ $pagesCount = $allCount - $subcatCount - $fileCount;
+
$pageInfo['category-info'] = array(
array(
+ $this->msg( 'pageinfo-category-total' ),
+ $lang->formatNum( $allCount )
+ ),
+ array(
$this->msg( 'pageinfo-category-pages' ),
- $lang->formatNum( $category->getPageCount() )
+ $lang->formatNum( $pagesCount )
),
array(
$this->msg( 'pageinfo-category-subcats' ),
- $lang->formatNum( $category->getSubcatCount() )
+ $lang->formatNum( $subcatCount )
),
array(
$this->msg( 'pageinfo-category-files' ),
- $lang->formatNum( $category->getFileCount() )
+ $lang->formatNum( $fileCount )
)
);
}
@@ -434,6 +470,10 @@ class InfoAction extends FormlessAction {
$message = $message->escaped();
}
}
+ $expiry = $title->getRestrictionExpiry( $restrictionType );
+ $formattedexpiry = $this->msg( 'parentheses',
+ $this->getLanguage()->formatExpiry( $expiry ) )->escaped();
+ $message .= $this->msg( 'word-separator' )->escaped() . $formattedexpiry;
// Messages: restriction-edit, restriction-move, restriction-create,
// restriction-upload
@@ -639,11 +679,11 @@ class InfoAction extends FormlessAction {
$id = $title->getArticleID();
$config = $this->context->getConfig();
- $dbr = wfGetDB( DB_SLAVE );
+ $dbrWatchlist = wfGetDB( DB_SLAVE, 'watchlist' );
$result = array();
// Number of page watchers
- $watchers = (int)$dbr->selectField(
+ $watchers = (int)$dbrWatchlist->selectField(
'watchlist',
'COUNT(*)',
array(
@@ -654,6 +694,27 @@ class InfoAction extends FormlessAction {
);
$result['watchers'] = $watchers;
+ if ( $config->get( 'ShowUpdatedMarker' ) ) {
+ // Threshold: last visited about 26 weeks before latest edit
+ $updated = wfTimestamp( TS_UNIX, $this->page->getTimestamp() );
+ $age = $config->get( 'WatchersMaxAge' );
+ $threshold = $dbrWatchlist->timestamp( $updated - $age );
+ // Number of page watchers who also visited a "recent" edit
+ $visitingWatchers = (int)$dbrWatchlist->selectField(
+ 'watchlist',
+ 'COUNT(*)',
+ array(
+ 'wl_namespace' => $title->getNamespace(),
+ 'wl_title' => $title->getDBkey(),
+ 'wl_notificationtimestamp >= ' . $dbrWatchlist->addQuotes( $threshold ) .
+ ' OR wl_notificationtimestamp IS NULL'
+ ),
+ __METHOD__
+ );
+ $result['visitingWatchers'] = $visitingWatchers;
+ }
+
+ $dbr = wfGetDB( DB_SLAVE );
// Total number of edits
$edits = (int)$dbr->selectField(
'revision',
diff --git a/includes/actions/RawAction.php b/includes/actions/RawAction.php
index 727bed20..b71b0e9e 100644
--- a/includes/actions/RawAction.php
+++ b/includes/actions/RawAction.php
@@ -34,10 +34,10 @@
*/
class RawAction extends FormlessAction {
/**
- * @var bool Does the request include a gen=css|javascript parameter
- * @deprecated This used to be a string for "css" or "javascript" but
- * it is no longer used. Setting this parameter results in empty content
- * being served
+ * Whether the request includes a 'gen' parameter
+ * @var bool
+ * @deprecated since 1.17 This used to be a string for "css" or "javascript" but
+ * it is no longer used. Setting this parameter results in an empty response.
*/
private $gen = false;
@@ -56,6 +56,7 @@ class RawAction extends FormlessAction {
function onView() {
$this->getOutput()->disable();
$request = $this->getRequest();
+ $response = $request->response();
$config = $this->context->getConfig();
if ( !$request->checkUrlExtension() ) {
@@ -66,42 +67,35 @@ class RawAction extends FormlessAction {
return; // Client cache fresh and headers sent, nothing more to do.
}
- # special case for 'generated' raw things: user css/js
- # This is deprecated and will only return empty content
$gen = $request->getVal( 'gen' );
- $smaxage = $request->getIntOrNull( 'smaxage' );
-
if ( $gen == 'css' || $gen == 'js' ) {
$this->gen = true;
- if ( $smaxage === null ) {
- $smaxage = $config->get( 'SquidMaxage' );
- }
}
$contentType = $this->getContentType();
- # Force caching for CSS and JS raw content, default: 5 minutes.
- # Note: If using a canonical url for userpage css/js, we send an HTCP purge.
+ $maxage = $request->getInt( 'maxage', $config->get( 'SquidMaxage' ) );
+ $smaxage = $request->getIntOrNull( 'smaxage' );
if ( $smaxage === null ) {
- if ( $contentType == 'text/css' || $contentType == 'text/javascript' ) {
+ if ( $this->gen ) {
+ $smaxage = $config->get( 'SquidMaxage' );
+ } elseif ( $contentType == 'text/css' || $contentType == 'text/javascript' ) {
+ // CSS/JS raw content has its own squid max age configuration.
+ // Note: Title::getSquidURLs() includes action=raw for css/js pages,
+ // so if using the canonical url, this will get HTCP purges.
$smaxage = intval( $config->get( 'ForcedRawSMaxage' ) );
} else {
+ // No squid cache for anything else
$smaxage = 0;
}
}
- $maxage = $request->getInt( 'maxage', $config->get( 'SquidMaxage' ) );
-
- $response = $request->response();
-
$response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' );
- # Output may contain user-specific data;
- # vary generated content for open sessions on private wikis
+ // Output may contain user-specific data;
+ // vary generated content for open sessions on private wikis
$privateCache = !User::isEveryoneAllowed( 'read' ) && ( $smaxage == 0 || session_id() != '' );
- // Bug 53032 - make this private if user is logged in,
- // so we don't accidentally cache cookies
- $privateCache = $privateCache ?: $this->getUser()->isLoggedIn();
- # allow the client to cache this for 24 hours
+ // Don't accidentally cache cookies if user is logged in (T55032)
+ $privateCache = $privateCache || $this->getUser()->isLoggedIn();
$mode = $privateCache ? 'private' : 'public';
$response->header(
'Cache-Control: ' . $mode . ', s-maxage=' . $smaxage . ', max-age=' . $maxage
@@ -109,12 +103,12 @@ class RawAction extends FormlessAction {
$text = $this->getRawText();
+ // Don't return a 404 response for CSS or JavaScript;
+ // 404s aren't generally cached and it would create
+ // extra hits when user CSS/JS are on and the user doesn't
+ // have the pages.
if ( $text === false && $contentType == 'text/x-wiki' ) {
- # Don't return a 404 response for CSS or JavaScript;
- # 404s aren't generally cached and it would create
- # extra hits when user CSS/JS are on and the user doesn't
- # have the pages.
- $response->header( 'HTTP/1.x 404 Not Found' );
+ $response->statusHeader( 404 );
}
if ( !Hooks::run( 'RawPageViewBeforeOutput', array( &$this, &$text ) ) ) {
diff --git a/includes/actions/RevertAction.php b/includes/actions/RevertAction.php
index d0258784..c7f33463 100644
--- a/includes/actions/RevertAction.php
+++ b/includes/actions/RevertAction.php
@@ -107,6 +107,8 @@ class RevertAction extends FormAction {
}
public function onSubmit( $data ) {
+ $this->useTransactionalTimeLimit();
+
$source = $this->page->getFile()->getArchiveVirtualUrl(
$this->getRequest()->getText( 'oldimage' )
);
diff --git a/includes/actions/RollbackAction.php b/includes/actions/RollbackAction.php
index 76d70d70..93669cf4 100644
--- a/includes/actions/RollbackAction.php
+++ b/includes/actions/RollbackAction.php
@@ -36,6 +36,9 @@ class RollbackAction extends FormlessAction {
}
public function onView() {
+ // TODO: use $this->useTransactionalTimeLimit(); when POST only
+ wfTransactionalTimeLimit();
+
$details = null;
$request = $this->getRequest();
diff --git a/includes/actions/UnprotectAction.php b/includes/actions/UnprotectAction.php
index bc28c8ed..559cfaf7 100644
--- a/includes/actions/UnprotectAction.php
+++ b/includes/actions/UnprotectAction.php
@@ -37,7 +37,6 @@ class UnprotectAction extends ProtectAction {
}
public function show() {
-
$this->page->unprotect();
}
}
diff --git a/includes/actions/WatchAction.php b/includes/actions/WatchAction.php
index 96473409..8b6e329d 100644
--- a/includes/actions/WatchAction.php
+++ b/includes/actions/WatchAction.php
@@ -64,7 +64,7 @@ class WatchAction extends FormAction {
$this->checkCanExecute( $user );
// Must have valid token for this action/title
- $salt = array( $this->getName(), $this->getTitle()->getDBkey() );
+ $salt = array( $this->getName(), $this->getTitle()->getPrefixedDBkey() );
if ( $user->matchEditToken( $this->getRequest()->getVal( 'token' ), $salt ) ) {
$this->onSubmit( array() );
diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php
index 6c33da57..d53797bc 100644
--- a/includes/api/ApiBase.php
+++ b/includes/api/ApiBase.php
@@ -85,6 +85,15 @@ abstract class ApiBase extends ContextSource {
// $msg for ApiBase::makeMessage(). Any value not having a mapping will use
// apihelp-{$path}-paramvalue-{$param}-{$value} is used.
const PARAM_HELP_MSG_PER_VALUE = 14;
+ /// @since 1.26
+ // When PARAM_TYPE is 'submodule', map parameter values to submodule paths.
+ // Default is to use all modules in $this->getModuleManager() in the group
+ // matching the parameter name.
+ const PARAM_SUBMODULE_MAP = 15;
+ /// @since 1.26
+ // When PARAM_TYPE is 'submodule', used to indicate the 'g' prefix added by
+ // ApiQueryGeneratorBase (and similar if anything else ever does that).
+ const PARAM_SUBMODULE_PARAM_PREFIX = 16;
const LIMIT_BIG1 = 500; // Fast query, std user limit
const LIMIT_BIG2 = 5000; // Fast query, bot/sysop limit
@@ -98,12 +107,17 @@ abstract class ApiBase extends ContextSource {
*/
const GET_VALUES_FOR_HELP = 1;
+ /** @var array Maps extension paths to info arrays */
+ private static $extensionInfo = null;
+
/** @var ApiMain */
private $mMainModule;
/** @var string */
private $mModuleName, $mModulePrefix;
private $mSlaveDB = null;
private $mParamCache = array();
+ /** @var array|null|bool */
+ private $mModuleSource = false;
/**
* @param ApiMain $mainModule
@@ -331,6 +345,22 @@ abstract class ApiBase extends ContextSource {
return null;
}
+ /**
+ * Returns data for HTTP conditional request mechanisms.
+ *
+ * @since 1.26
+ * @param string $condition Condition being queried:
+ * - last-modified: Return a timestamp representing the maximum of the
+ * last-modified dates for all resources involved in the request. See
+ * RFC 7232 § 2.2 for semantics.
+ * - etag: Return an entity-tag representing the state of all resources involved
+ * in the request. Quotes must be included. See RFC 7232 § 2.3 for semantics.
+ * @return string|boolean|null As described above, or null if no value is available.
+ */
+ public function getConditionalRequestData( $condition ) {
+ return null;
+ }
+
/**@}*/
/************************************************************************//**
@@ -833,7 +863,11 @@ abstract class ApiBase extends ContextSource {
$type = MWNamespace::getValidNamespaces();
}
if ( isset( $value ) && $type == 'submodule' ) {
- $type = $this->getModuleManager()->getNames( $paramName );
+ if ( isset( $paramSettings[self::PARAM_SUBMODULE_MAP] ) ) {
+ $type = array_keys( $paramSettings[self::PARAM_SUBMODULE_MAP] );
+ } else {
+ $type = $this->getModuleManager()->getNames( $paramName );
+ }
}
}
@@ -854,6 +888,8 @@ abstract class ApiBase extends ContextSource {
case 'NULL': // nothing to do
break;
case 'string':
+ case 'text':
+ case 'password':
if ( $required && $value === '' ) {
$this->dieUsageMsg( array( 'missingparam', $paramName ) );
}
@@ -1036,7 +1072,6 @@ abstract class ApiBase extends ContextSource {
*/
protected function validateLimit( $paramName, &$value, $min, $max, $botMax = null, $enforceLimits = false ) {
if ( !is_null( $min ) && $value < $min ) {
-
$msg = $this->encodeParamName( $paramName ) . " may not be less than $min (set to $value)";
$this->warnOrDie( $msg, $enforceLimits );
$value = $min;
@@ -1073,6 +1108,24 @@ abstract class ApiBase extends ContextSource {
* @return string Validated and normalized parameter
*/
protected function validateTimestamp( $value, $encParamName ) {
+ // Confusing synonyms for the current time accepted by wfTimestamp()
+ // (wfTimestamp() also accepts various non-strings and the string of 14
+ // ASCII NUL bytes, but those can't get here)
+ if ( !$value ) {
+ $this->logFeatureUsage( 'unclear-"now"-timestamp' );
+ $this->setWarning(
+ "Passing '$value' for timestamp parameter $encParamName has been deprecated." .
+ ' If for some reason you need to explicitly specify the current time without' .
+ ' calculating it client-side, use "now".'
+ );
+ return wfTimestamp( TS_MW );
+ }
+
+ // Explicit synonym for the current time
+ if ( $value === 'now' ) {
+ return wfTimestamp( TS_MW );
+ }
+
$unixTimestamp = wfTimestamp( TS_UNIX, $value );
if ( $unixTimestamp === false ) {
$this->dieUsage(
@@ -2203,6 +2256,93 @@ abstract class ApiBase extends ContextSource {
}
/**
+ * Returns information about the source of this module, if known
+ *
+ * Returned array is an array with the following keys:
+ * - path: Install path
+ * - name: Extension name, or "MediaWiki" for core
+ * - namemsg: (optional) i18n message key for a display name
+ * - license-name: (optional) Name of license
+ *
+ * @return array|null
+ */
+ protected function getModuleSourceInfo() {
+ global $IP;
+
+ if ( $this->mModuleSource !== false ) {
+ return $this->mModuleSource;
+ }
+
+ // First, try to find where the module comes from...
+ $rClass = new ReflectionClass( $this );
+ $path = $rClass->getFileName();
+ if ( !$path ) {
+ // No path known?
+ $this->mModuleSource = null;
+ return null;
+ }
+ $path = realpath( $path ) ?: $path;
+
+ // Build map of extension directories to extension info
+ if ( self::$extensionInfo === null ) {
+ self::$extensionInfo = array(
+ realpath( __DIR__ ) ?: __DIR__ => array(
+ 'path' => $IP,
+ 'name' => 'MediaWiki',
+ 'license-name' => 'GPL-2.0+',
+ ),
+ realpath( "$IP/extensions" ) ?: "$IP/extensions" => null,
+ );
+ $keep = array(
+ 'path' => null,
+ 'name' => null,
+ 'namemsg' => null,
+ 'license-name' => null,
+ );
+ foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $group ) {
+ foreach ( $group as $ext ) {
+ if ( !isset( $ext['path'] ) || !isset( $ext['name'] ) ) {
+ // This shouldn't happen, but does anyway.
+ continue;
+ }
+
+ $extpath = $ext['path'];
+ if ( !is_dir( $extpath ) ) {
+ $extpath = dirname( $extpath );
+ }
+ self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
+ array_intersect_key( $ext, $keep );
+ }
+ }
+ foreach ( ExtensionRegistry::getInstance()->getAllThings() as $ext ) {
+ $extpath = $ext['path'];
+ if ( !is_dir( $extpath ) ) {
+ $extpath = dirname( $extpath );
+ }
+ self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
+ array_intersect_key( $ext, $keep );
+ }
+ }
+
+ // Now traverse parent directories until we find a match or run out of
+ // parents.
+ do {
+ if ( array_key_exists( $path, self::$extensionInfo ) ) {
+ // Found it!
+ $this->mModuleSource = self::$extensionInfo[$path];
+ return $this->mModuleSource;
+ }
+
+ $oldpath = $path;
+ $path = dirname( $path );
+ } while ( $path !== $oldpath );
+
+ // No idea what extension this might be.
+ $this->mModuleSource = null;
+ return null;
+ }
+
+ /**
* Called from ApiHelp before the pieces are joined together and returned.
*
* This exists mainly for ApiMain to add the Permissions and Credits
@@ -2210,8 +2350,10 @@ abstract class ApiBase extends ContextSource {
*
* @param string[] &$help Array of help data
* @param array $options Options passed to ApiHelp::getHelp
+ * @param array &$tocData If a TOC is being generated, this array has keys
+ * as anchors in the page and values as for Linker::generateTOC().
*/
- public function modifyHelp( array &$help, array $options ) {
+ public function modifyHelp( array &$help, array $options, array &$tocData ) {
}
/**@}*/
@@ -2355,7 +2497,7 @@ abstract class ApiBase extends ContextSource {
* Returns the description string for this module
*
* Ignored if an i18n message exists for
- * "apihelp-{$this->getModulePathString()}-description".
+ * "apihelp-{$this->getModulePath()}-description".
*
* @deprecated since 1.25
* @return Message|string|array
@@ -2369,7 +2511,7 @@ abstract class ApiBase extends ContextSource {
*
* For each parameter, ignored if an i18n message exists for the parameter.
* By default that message is
- * "apihelp-{$this->getModulePathString()}-param-{$param}", but it may be
+ * "apihelp-{$this->getModulePath()}-param-{$param}", but it may be
* overridden using ApiBase::PARAM_HELP_MSG in the data returned by
* self::getFinalParams().
*
@@ -2519,7 +2661,6 @@ abstract class ApiBase extends ContextSource {
wfDeprecated( __METHOD__, '1.25' );
$params = $this->getFinalParams( ApiBase::GET_VALUES_FOR_HELP );
if ( $params ) {
-
$paramsDescription = $this->getFinalParamDescription();
$msg = '';
$paramPrefix = "\n" . str_repeat( ' ', 24 );
@@ -2578,7 +2719,11 @@ abstract class ApiBase extends ContextSource {
}
if ( $type === 'submodule' ) {
- $type = $this->getModuleManager()->getNames( $paramName );
+ if ( isset( $paramSettings[self::PARAM_SUBMODULE_MAP] ) ) {
+ $type = array_keys( $paramSettings[self::PARAM_SUBMODULE_MAP] );
+ } else {
+ $type = $this->getModuleManager()->getNames( $paramName );
+ }
sort( $type );
}
if ( is_array( $type ) ) {
@@ -2741,6 +2886,16 @@ abstract class ApiBase extends ContextSource {
return $this->getResult()->getData();
}
+ /**
+ * Call wfTransactionalTimeLimit() if this request was POSTed
+ * @since 1.26
+ */
+ protected function useTransactionalTimeLimit() {
+ if ( $this->getRequest()->wasPosted() ) {
+ wfTransactionalTimeLimit();
+ }
+ }
+
/**@}*/
}
diff --git a/includes/api/ApiBlock.php b/includes/api/ApiBlock.php
index 4d39ce1b..6adfc1a0 100644
--- a/includes/api/ApiBlock.php
+++ b/includes/api/ApiBlock.php
@@ -39,6 +39,8 @@ class ApiBlock extends ApiBase {
* of success. If it fails, the result will specify the nature of the error.
*/
public function execute() {
+ global $wgContLang;
+
$user = $this->getUser();
$params = $this->extractRequestParams();
@@ -50,7 +52,13 @@ class ApiBlock extends ApiBase {
if ( $user->isBlocked() ) {
$status = SpecialBlock::checkUnblockSelf( $params['user'], $user );
if ( $status !== true ) {
- $this->dieUsageMsg( array( $status ) );
+ $msg = $this->parseMsg( $status );
+ $this->dieUsage(
+ $msg['info'],
+ $msg['code'],
+ 0,
+ array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) )
+ );
}
}
@@ -100,11 +108,9 @@ class ApiBlock extends ApiBase {
$res['user'] = $params['user'];
$res['userID'] = $target instanceof User ? $target->getId() : 0;
- $block = Block::newFromTarget( $target );
+ $block = Block::newFromTarget( $target, null, true );
if ( $block instanceof Block ) {
- $res['expiry'] = $block->mExpiry == $this->getDB()->getInfinity()
- ? 'infinite'
- : wfTimestamp( TS_ISO_8601, $block->mExpiry );
+ $res['expiry'] = $wgContLang->formatExpiry( $block->mExpiry, TS_ISO_8601, 'infinite' );
$res['id'] = $block->getId();
} else {
# should be unreachable
diff --git a/includes/api/ApiCreateAccount.php b/includes/api/ApiCreateAccount.php
index 455540b4..5443faca 100644
--- a/includes/api/ApiCreateAccount.php
+++ b/includes/api/ApiCreateAccount.php
@@ -21,6 +21,7 @@
*
* @file
*/
+use MediaWiki\Logger\LoggerFactory;
/**
* Unit to authenticate account registration attempts to the current wiki.
@@ -48,7 +49,12 @@ class ApiCreateAccount extends ApiBase {
);
}
if ( $this->getUser()->isBlockedFromCreateAccount() ) {
- $this->dieUsage( 'You cannot create a new account because you are blocked', 'blocked' );
+ $this->dieUsage(
+ 'You cannot create a new account because you are blocked',
+ 'blocked',
+ 0,
+ array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $this->getUser()->getBlock() ) )
+ );
}
$params = $this->extractRequestParams();
@@ -90,6 +96,10 @@ class ApiCreateAccount extends ApiBase {
$loginForm->load();
$status = $loginForm->addNewaccountInternal();
+ LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt via API', array(
+ 'event' => 'accountcreation',
+ 'status' => $status,
+ ) );
$result = array();
if ( $status->isGood() ) {
// Success!
@@ -186,7 +196,9 @@ class ApiCreateAccount extends ApiBase {
ApiBase::PARAM_TYPE => 'user',
ApiBase::PARAM_REQUIRED => true
),
- 'password' => null,
+ 'password' => array(
+ ApiBase::PARAM_TYPE => 'password',
+ ),
'domain' => null,
'token' => null,
'email' => array(
diff --git a/includes/api/ApiDelete.php b/includes/api/ApiDelete.php
index d8b57182..bdf02bf1 100644
--- a/includes/api/ApiDelete.php
+++ b/includes/api/ApiDelete.php
@@ -39,6 +39,8 @@ class ApiDelete extends ApiBase {
* result object.
*/
public function execute() {
+ $this->useTransactionalTimeLimit();
+
$params = $this->extractRequestParams();
$pageObj = $this->getTitleOrPageId( $params, 'fromdbmaster' );
@@ -131,7 +133,7 @@ class ApiDelete extends ApiBase {
$error = '';
// Luckily, Article.php provides a reusable delete function that does the hard work for us
- return $page->doDeleteArticleReal( $reason, false, 0, true, $error );
+ return $page->doDeleteArticleReal( $reason, false, 0, true, $error, $user );
}
/**
diff --git a/includes/api/ApiEditPage.php b/includes/api/ApiEditPage.php
index 54a83915..2f1c01ce 100644
--- a/includes/api/ApiEditPage.php
+++ b/includes/api/ApiEditPage.php
@@ -35,6 +35,8 @@
*/
class ApiEditPage extends ApiBase {
public function execute() {
+ $this->useTransactionalTimeLimit();
+
$user = $this->getUser();
$params = $this->extractRequestParams();
@@ -96,8 +98,14 @@ class ApiEditPage extends ApiBase {
$contentHandler = ContentHandler::getForModelID( $params['contentmodel'] );
}
- // @todo Ask handler whether direct editing is supported at all! make
- // allowFlatEdit() method or some such
+ $name = $titleObj->getPrefixedDBkey();
+ $model = $contentHandler->getModelID();
+ if ( $contentHandler->supportsDirectApiEditing() === false ) {
+ $this->dieUsage(
+ "Direct editing via API is not supported for content model $model used by $name",
+ 'no-direct-editing'
+ );
+ }
if ( !isset( $params['contentformat'] ) || $params['contentformat'] == '' ) {
$params['contentformat'] = $contentHandler->getDefaultFormat();
@@ -106,8 +114,6 @@ class ApiEditPage extends ApiBase {
$contentFormat = $params['contentformat'];
if ( !$contentHandler->isSupportedFormat( $contentFormat ) ) {
- $name = $titleObj->getPrefixedDBkey();
- $model = $contentHandler->getModelID();
$this->dieUsage( "The requested format $contentFormat is not supported for content model " .
" $model used by $name", 'badformat' );
@@ -126,7 +132,30 @@ class ApiEditPage extends ApiBase {
$errors = array_merge( $errors, $titleObj->getUserPermissionsErrors( 'create', $user ) );
}
if ( count( $errors ) ) {
- $this->dieUsageMsg( $errors[0] );
+ if ( is_array( $errors[0] ) ) {
+ switch ( $errors[0][0] ) {
+ case 'blockedtext':
+ $this->dieUsage(
+ 'You have been blocked from editing',
+ 'blocked',
+ 0,
+ array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) )
+ );
+ break;
+ case 'autoblockedtext':
+ $this->dieUsage(
+ 'Your IP address has been blocked automatically, because it was used by a blocked user',
+ 'autoblocked',
+ 0,
+ array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) )
+ );
+ break;
+ default:
+ $this->dieUsageMsg( $errors[0] );
+ }
+ } else {
+ $this->dieUsageMsg( $errors[0] );
+ }
}
$toMD5 = $params['text'];
@@ -242,7 +271,7 @@ class ApiEditPage extends ApiBase {
$titleObj->getNextRevisionID( $undoafterRev->getID() ) == $params['undo']
) {
$params['summary'] = wfMessage( 'undo-summary' )
- ->params ( $params['undo'], $undoRev->getUserText() )->inContentLanguage()->text();
+ ->params( $params['undo'], $undoRev->getUserText() )->inContentLanguage()->text();
}
}
@@ -277,16 +306,16 @@ class ApiEditPage extends ApiBase {
$requestArray['wpUndidRevision'] = $params['undo'];
}
- // Watch out for basetimestamp == ''
- // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict
- if ( !is_null( $params['basetimestamp'] ) && $params['basetimestamp'] != '' ) {
- $requestArray['wpEdittime'] = wfTimestamp( TS_MW, $params['basetimestamp'] );
+ // Watch out for basetimestamp == '' or '0'
+ // It gets treated as NOW, almost certainly causing an edit conflict
+ if ( $params['basetimestamp'] !== null && (bool)$this->getMain()->getVal( 'basetimestamp' ) ) {
+ $requestArray['wpEdittime'] = $params['basetimestamp'];
} else {
$requestArray['wpEdittime'] = $pageObj->getTimestamp();
}
- if ( !is_null( $params['starttimestamp'] ) && $params['starttimestamp'] != '' ) {
- $requestArray['wpStarttime'] = wfTimestamp( TS_MW, $params['starttimestamp'] );
+ if ( $params['starttimestamp'] !== null ) {
+ $requestArray['wpStarttime'] = $params['starttimestamp'];
} else {
$requestArray['wpStarttime'] = wfTimestampNow(); // Fake wpStartime
}
@@ -362,9 +391,7 @@ class ApiEditPage extends ApiBase {
$ep = new EditPage( $articleObject );
- // allow editing of non-textual content.
- $ep->allowNonTextContent = true;
-
+ $ep->setApiEditOverride( true );
$ep->setContextTitle( $titleObj );
$ep->importFormData( $req );
$content = $ep->textbox1;
@@ -448,7 +475,12 @@ class ApiEditPage extends ApiBase {
$this->dieUsageMsg( array( 'spamdetected', $result['spam'] ) );
case EditPage::AS_BLOCKED_PAGE_FOR_USER:
- $this->dieUsageMsg( 'blockedtext' );
+ $this->dieUsage(
+ 'You have been blocked from editing',
+ 'blocked',
+ 0,
+ array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) )
+ );
case EditPage::AS_MAX_ARTICLE_SIZE_EXCEEDED:
case EditPage::AS_CONTENT_TOO_BIG:
@@ -495,7 +527,7 @@ class ApiEditPage extends ApiBase {
$r['result'] = 'Success';
$r['pageid'] = intval( $titleObj->getArticleID() );
$r['title'] = $titleObj->getPrefixedText();
- $r['contentmodel'] = $titleObj->getContentModel();
+ $r['contentmodel'] = $articleObject->getContentModel();
$newRevId = $articleObject->getLatest();
if ( $newRevId == $oldRevId ) {
$r['nochange'] = true;
@@ -541,7 +573,9 @@ class ApiEditPage extends ApiBase {
'sectiontitle' => array(
ApiBase::PARAM_TYPE => 'string',
),
- 'text' => null,
+ 'text' => array(
+ ApiBase::PARAM_TYPE => 'text',
+ ),
'summary' => null,
'tags' => array(
ApiBase::PARAM_TYPE => ChangeTags::listExplicitlyDefinedTags(),
@@ -550,8 +584,12 @@ class ApiEditPage extends ApiBase {
'minor' => false,
'notminor' => false,
'bot' => false,
- 'basetimestamp' => null,
- 'starttimestamp' => null,
+ 'basetimestamp' => array(
+ ApiBase::PARAM_TYPE => 'timestamp',
+ ),
+ 'starttimestamp' => array(
+ ApiBase::PARAM_TYPE => 'timestamp',
+ ),
'recreate' => false,
'createonly' => false,
'nocreate' => false,
@@ -573,8 +611,12 @@ class ApiEditPage extends ApiBase {
),
),
'md5' => null,
- 'prependtext' => null,
- 'appendtext' => null,
+ 'prependtext' => array(
+ ApiBase::PARAM_TYPE => 'text',
+ ),
+ 'appendtext' => array(
+ ApiBase::PARAM_TYPE => 'text',
+ ),
'undo' => array(
ApiBase::PARAM_TYPE => 'integer'
),
diff --git a/includes/api/ApiEmailUser.php b/includes/api/ApiEmailUser.php
index 15eb475e..efb9769b 100644
--- a/includes/api/ApiEmailUser.php
+++ b/includes/api/ApiEmailUser.php
@@ -95,7 +95,7 @@ class ApiEmailUser extends ApiBase {
),
'subject' => null,
'text' => array(
- ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_TYPE => 'text',
ApiBase::PARAM_REQUIRED => true
),
'ccme' => false,
diff --git a/includes/api/ApiExpandTemplates.php b/includes/api/ApiExpandTemplates.php
index 6d064eb2..6112534c 100644
--- a/includes/api/ApiExpandTemplates.php
+++ b/includes/api/ApiExpandTemplates.php
@@ -111,8 +111,9 @@ class ApiExpandTemplates extends ApiBase {
// the old way
ApiResult::setContentValue( $retval, 'wikitext', $wikitext );
} else {
+ $p_output = $wgParser->getOutput();
if ( isset( $prop['categories'] ) ) {
- $categories = $wgParser->getOutput()->getCategories();
+ $categories = $p_output->getCategories();
if ( $categories ) {
$categories_result = array();
foreach ( $categories as $category => $sortkey ) {
@@ -126,7 +127,7 @@ class ApiExpandTemplates extends ApiBase {
}
}
if ( isset( $prop['properties'] ) ) {
- $properties = $wgParser->getOutput()->getProperties();
+ $properties = $p_output->getProperties();
if ( $properties ) {
ApiResult::setArrayType( $properties, 'BCkvp', 'name' );
ApiResult::setIndexedTagName( $properties, 'property' );
@@ -142,6 +143,27 @@ class ApiExpandTemplates extends ApiBase {
if ( isset( $prop['wikitext'] ) ) {
$retval['wikitext'] = $wikitext;
}
+ if ( isset( $prop['modules'] ) ) {
+ $retval['modules'] = array_values( array_unique( $p_output->getModules() ) );
+ $retval['modulescripts'] = array_values( array_unique( $p_output->getModuleScripts() ) );
+ $retval['modulestyles'] = array_values( array_unique( $p_output->getModuleStyles() ) );
+ }
+ if ( isset( $prop['jsconfigvars'] ) ) {
+ $retval['jsconfigvars'] =
+ ApiResult::addMetadataToResultVars( $p_output->getJsConfigVars() );
+ }
+ if ( isset( $prop['encodedjsconfigvars'] ) ) {
+ $retval['encodedjsconfigvars'] = FormatJson::encode(
+ $p_output->getJsConfigVars(), false, FormatJson::ALL_OK
+ );
+ $retval[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
+ }
+ if ( isset( $prop['modules'] ) &&
+ !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
+ $this->setWarning( "Property 'modules' was set but not 'jsconfigvars' " .
+ "or 'encodedjsconfigvars'. Configuration variables are necessary " .
+ "for proper module usage." );
+ }
}
}
ApiResult::setSubelementsList( $retval, array( 'wikitext', 'parsetree' ) );
@@ -154,7 +176,7 @@ class ApiExpandTemplates extends ApiBase {
ApiBase::PARAM_DFLT => 'API',
),
'text' => array(
- ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_TYPE => 'text',
ApiBase::PARAM_REQUIRED => true,
),
'revid' => array(
@@ -167,9 +189,13 @@ class ApiExpandTemplates extends ApiBase {
'properties',
'volatile',
'ttl',
+ 'modules',
+ 'jsconfigvars',
+ 'encodedjsconfigvars',
'parsetree',
),
ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'includecomments' => false,
'generatexml' => array(
diff --git a/includes/api/ApiFeedRecentChanges.php b/includes/api/ApiFeedRecentChanges.php
index d452bbd6..d24112c7 100644
--- a/includes/api/ApiFeedRecentChanges.php
+++ b/includes/api/ApiFeedRecentChanges.php
@@ -66,9 +66,17 @@ class ApiFeedRecentChanges extends ApiBase {
$formatter = $this->getFeedObject( $feedFormat, $specialClass );
- // Everything is passed implicitly via $wgRequest… :(
- // The row-getting functionality should maybe be factored out of ChangesListSpecialPage too…
+ // Parameters are passed via the request in the context… :(
+ $context = new DerivativeContext( $this );
+ $context->setRequest( new DerivativeRequest(
+ $this->getRequest(),
+ $this->params,
+ $this->getRequest()->wasPosted()
+ ) );
+
+ // The row-getting functionality should be factored out of ChangesListSpecialPage too…
$rc = new $specialClass();
+ $rc->setContext( $context );
$rows = $rc->getRows();
$feedItems = $rows ? ChangesFeed::buildItems( $rows ) : array();
diff --git a/includes/api/ApiFeedWatchlist.php b/includes/api/ApiFeedWatchlist.php
index d1beef8a..0ddb3c38 100644
--- a/includes/api/ApiFeedWatchlist.php
+++ b/includes/api/ApiFeedWatchlist.php
@@ -126,7 +126,8 @@ class ApiFeedWatchlist extends ApiBase {
$msg = wfMessage( 'watchlist' )->inContentLanguage()->text();
- $feedTitle = $this->getConfig()->get( 'Sitename' ) . ' - ' . $msg . ' [' . $this->getConfig()->get( 'LanguageCode' ) . ']';
+ $feedTitle = $this->getConfig()->get( 'Sitename' ) . ' - ' . $msg .
+ ' [' . $this->getConfig()->get( 'LanguageCode' ) . ']';
$feedUrl = SpecialPage::getTitleFor( 'Watchlist' )->getFullURL();
$feed = new $feedClasses[$params['feedformat']] (
@@ -168,6 +169,11 @@ class ApiFeedWatchlist extends ApiBase {
* @return FeedItem
*/
private function createFeedItem( $info ) {
+ if ( !isset( $info['title'] ) ) {
+ // Probably a revdeled log entry, skip it.
+ return null;
+ }
+
$titleStr = $info['title'];
$title = Title::newFromText( $titleStr );
$curidParam = array();
@@ -204,9 +210,14 @@ class ApiFeedWatchlist extends ApiBase {
}
$timestamp = $info['timestamp'];
- $user = $info['user'];
- $completeText = "$comment ($user)";
+ if ( isset( $info['user'] ) ) {
+ $user = $info['user'];
+ $completeText = "$comment ($user)";
+ } else {
+ $user = '';
+ $completeText = (string)$comment;
+ }
return new FeedItem( $titleStr, $completeText, $titleUrl, $timestamp, $user );
}
diff --git a/includes/api/ApiFileRevert.php b/includes/api/ApiFileRevert.php
index 5517ee08..a49397dc 100644
--- a/includes/api/ApiFileRevert.php
+++ b/includes/api/ApiFileRevert.php
@@ -38,6 +38,8 @@ class ApiFileRevert extends ApiBase {
protected $params;
public function execute() {
+ $this->useTransactionalTimeLimit();
+
$this->params = $this->extractRequestParams();
// Extract the file and archiveName from the request parameters
$this->validateParameters();
diff --git a/includes/api/ApiFormatBase.php b/includes/api/ApiFormatBase.php
index d078dc45..e522d709 100644
--- a/includes/api/ApiFormatBase.php
+++ b/includes/api/ApiFormatBase.php
@@ -173,6 +173,7 @@ abstract class ApiFormatBase extends ApiBase {
$mime = $this->getMimeType();
if ( $this->getIsHtml() && $mime !== null ) {
$format = $this->getFormat();
+ $lcformat = strtolower( $format );
$result = $this->getBuffer();
$context = new DerivativeContext( $this->getMain() );
@@ -181,12 +182,17 @@ abstract class ApiFormatBase extends ApiBase {
$out = new OutputPage( $context );
$context->setOutput( $out );
- $out->addModules( 'mediawiki.apipretty' );
+ $out->addModuleStyles( 'mediawiki.apipretty' );
$out->setPageTitle( $context->msg( 'api-format-title' ) );
- $header = $context->msg( 'api-format-prettyprint-header' )
- ->params( $format, strtolower( $format ) )
- ->parseAsBlock();
+ // When the format without suffix 'fm' is defined, there is a non-html version
+ if ( $this->getMain()->getModuleManager()->isDefined( $lcformat, 'format' ) ) {
+ $msg = $context->msg( 'api-format-prettyprint-header' )->params( $format, $lcformat );
+ } else {
+ $msg = $context->msg( 'api-format-prettyprint-header-only-html' )->params( $format );
+ }
+
+ $header = $msg->parseAsBlock();
$out->addHTML(
Html::rawElement( 'div', array( 'class' => 'api-pretty-header' ),
ApiHelp::fixHelpLinks( $header )
@@ -240,7 +246,7 @@ abstract class ApiFormatBase extends ApiBase {
}
/**
- * To avoid code duplication with the deprecation of dbg, dump, txt, wddx,
+ * To avoid code duplication with the deprecation of dbg, txt
* and yaml, this method is added to do the necessary work. It should be
* removed when those deprecated formats are removed.
*/
@@ -306,7 +312,7 @@ abstract class ApiFormatBase extends ApiBase {
// Escape everything first for full coverage
$text = htmlspecialchars( $text );
- if ( $this->mFormat === 'XML' || $this->mFormat === 'WDDX' ) {
+ if ( $this->mFormat === 'XML' ) {
// encode all comments or tags as safe blue strings
$text = str_replace( '&lt;', '<span style="color:blue;">&lt;', $text );
$text = str_replace( '&gt;', '&gt;</span>', $text );
@@ -381,10 +387,11 @@ abstract class ApiFormatBase extends ApiBase {
* are required to ignore it or filter it out.
*
* @deprecated since 1.25
- * @return bool
+ * @return bool Always true
*/
public function getNeedsRawData() {
- return false;
+ wfDeprecated( __METHOD__, '1.25' );
+ return true;
}
/**@}*/
diff --git a/includes/api/ApiFormatFeedWrapper.php b/includes/api/ApiFormatFeedWrapper.php
index 00747eef..d2bfd48d 100644
--- a/includes/api/ApiFormatFeedWrapper.php
+++ b/includes/api/ApiFormatFeedWrapper.php
@@ -60,15 +60,6 @@ class ApiFormatFeedWrapper extends ApiFormatBase {
}
/**
- * Optimization - no need to sanitize data that will not be needed
- *
- * @return bool
- */
- public function getNeedsRawData() {
- return true;
- }
-
- /**
* ChannelFeed doesn't give us a method to print errors in a friendly
* manner, so just punt errors to the default printer.
* @return bool
diff --git a/includes/api/ApiFormatJson.php b/includes/api/ApiFormatJson.php
index 43877b78..be1b12c3 100644
--- a/includes/api/ApiFormatJson.php
+++ b/includes/api/ApiFormatJson.php
@@ -35,6 +35,15 @@ class ApiFormatJson extends ApiFormatBase {
public function __construct( ApiMain $main, $format ) {
parent::__construct( $main, $format );
$this->isRaw = ( $format === 'rawfm' );
+
+ if ( $this->getMain()->getCheck( 'callback' ) ) {
+ # T94015: jQuery appends a useless '_' parameter in jsonp mode.
+ # Mark the parameter as used in that case to avoid a warning that's
+ # outside the control of the end user.
+ # (and do it here because ApiMain::reportUnusedParams() gets called
+ # before our ::execute())
+ $this->getMain()->getCheck( '_' );
+ }
}
public function getMimeType() {
@@ -50,13 +59,6 @@ class ApiFormatJson extends ApiFormatBase {
/**
* @deprecated since 1.25
*/
- public function getNeedsRawData() {
- return $this->isRaw;
- }
-
- /**
- * @deprecated since 1.25
- */
public function getWantsHelp() {
wfDeprecated( __METHOD__, '1.25' );
// Help is always ugly in JSON
diff --git a/includes/api/ApiFormatPhp.php b/includes/api/ApiFormatPhp.php
index d88dd40b..6420a5b5 100644
--- a/includes/api/ApiFormatPhp.php
+++ b/includes/api/ApiFormatPhp.php
@@ -68,7 +68,8 @@ class ApiFormatPhp extends ApiFormatBase {
preg_match( '/\<\s*cross-domain-policy\s*\>/i', $text )
) {
$this->dieUsage(
- 'This response cannot be represented using format=php. See https://bugzilla.wikimedia.org/show_bug.cgi?id=66776',
+ 'This response cannot be represented using format=php. ' .
+ 'See https://bugzilla.wikimedia.org/show_bug.cgi?id=66776',
'internalerror'
);
}
diff --git a/includes/api/ApiFormatRaw.php b/includes/api/ApiFormatRaw.php
index 7bb2453d..9dbd4a55 100644
--- a/includes/api/ApiFormatRaw.php
+++ b/includes/api/ApiFormatRaw.php
@@ -31,14 +31,20 @@
class ApiFormatRaw extends ApiFormatBase {
private $errorFallback;
+ private $mFailWithHTTPError = false;
+
/**
* @param ApiMain $main
- * @param ApiFormatBase $errorFallback Object to fall back on for errors
+ * @param ApiFormatBase |null $errorFallback Object to fall back on for errors
*/
- public function __construct( ApiMain $main, ApiFormatBase $errorFallback ) {
+ public function __construct( ApiMain $main, ApiFormatBase $errorFallback = null ) {
parent::__construct( $main, 'raw' );
- $this->errorFallback = $errorFallback;
+ if ( $errorFallback === null ) {
+ $this->errorFallback = $main->createPrinterByName( $main->getParameter( 'format' ) );
+ } else {
+ $this->errorFallback = $errorFallback;
+ }
}
public function getMimeType() {
@@ -59,6 +65,9 @@ class ApiFormatRaw extends ApiFormatBase {
$data = $this->getResult()->getResultData();
if ( isset( $data['error'] ) ) {
$this->errorFallback->initPrinter( $unused );
+ if ( $this->mFailWithHTTPError ) {
+ $this->getMain()->getRequest()->response()->statusHeader( 400 );
+ }
} else {
parent::initPrinter( $unused );
}
@@ -85,4 +94,17 @@ class ApiFormatRaw extends ApiFormatBase {
}
$this->printText( $data['text'] );
}
+
+ /**
+ * Output HTTP error code 400 when if an error is encountered
+ *
+ * The purpose is for output formats where the user-agent will
+ * not be able to interpret the validity of the content in any
+ * other way. For example subtitle files read by browser video players.
+ *
+ * @param bool $fail
+ */
+ public function setFailWithHTTPError( $fail ) {
+ $this->mFailWithHTTPError = $fail;
+ }
}
diff --git a/includes/api/ApiFormatWddx.php b/includes/api/ApiFormatWddx.php
deleted file mode 100644
index c18353fe..00000000
--- a/includes/api/ApiFormatWddx.php
+++ /dev/null
@@ -1,162 +0,0 @@
-<?php
-/**
- *
- *
- * Created on Oct 22, 2006
- *
- * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * API WDDX output formatter
- * @deprecated since 1.24
- * @ingroup API
- */
-class ApiFormatWddx extends ApiFormatBase {
-
- public function getMimeType() {
- return 'text/xml';
- }
-
- public function execute() {
- $this->markDeprecated();
-
- $data = $this->getResult()->getResultData( null, array(
- 'BC' => array(),
- 'Types' => array( 'AssocAsObject' => true ),
- 'Strip' => 'all',
- ) );
-
- if ( !$this->getIsHtml() && !static::useSlowPrinter() ) {
- $txt = wddx_serialize_value( $data );
- $txt = str_replace(
- '<struct><var name=\'php_class_name\'><string>stdClass</string></var>',
- '<struct>',
- $txt
- );
- $this->printText( $txt );
- } else {
- // Don't do newlines and indentation if we weren't asked
- // for pretty output
- $nl = ( $this->getIsHtml() ? "\n" : '' );
- $indstr = ( $this->getIsHtml() ? ' ' : '' );
- $this->printText( "<?xml version=\"1.0\"?>$nl" );
- $this->printText( "<wddxPacket version=\"1.0\">$nl" );
- $this->printText( "$indstr<header />$nl" );
- $this->printText( "$indstr<data>$nl" );
- $this->slowWddxPrinter( $data, 4 );
- $this->printText( "$indstr</data>$nl" );
- $this->printText( "</wddxPacket>$nl" );
- }
- }
-
- public static function useSlowPrinter() {
- if ( !function_exists( 'wddx_serialize_value' ) ) {
- return true;
- }
-
- // Some versions of PHP have a broken wddx_serialize_value, see
- // PHP bug 45314. Test encoding an affected character (U+00A0)
- // to avoid this.
- $expected =
- "<wddxPacket version='1.0'><header/><data><string>\xc2\xa0</string></data></wddxPacket>";
- if ( wddx_serialize_value( "\xc2\xa0" ) !== $expected ) {
- return true;
- }
-
- // Some versions of HHVM don't correctly encode ampersands.
- $expected =
- "<wddxPacket version='1.0'><header/><data><string>&amp;</string></data></wddxPacket>";
- if ( wddx_serialize_value( '&' ) !== $expected ) {
- return true;
- }
-
- // Some versions of HHVM don't correctly encode empty arrays as subvalues.
- $expected =
- "<wddxPacket version='1.0'><header/><data><array length='1'><array length='0'></array></array></data></wddxPacket>";
- if ( wddx_serialize_value( array( array() ) ) !== $expected ) {
- return true;
- }
-
- // Some versions of HHVM don't correctly encode associative arrays with numeric keys.
- $expected =
- "<wddxPacket version='1.0'><header/><data><struct><var name='2'><number>1</number></var></struct></data></wddxPacket>";
- if ( wddx_serialize_value( array( 2 => 1 ) ) !== $expected ) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Recursively go through the object and output its data in WDDX format.
- * @param mixed $elemValue
- * @param int $indent
- */
- function slowWddxPrinter( $elemValue, $indent = 0 ) {
- $indstr = ( $this->getIsHtml() ? str_repeat( ' ', $indent ) : '' );
- $indstr2 = ( $this->getIsHtml() ? str_repeat( ' ', $indent + 2 ) : '' );
- $nl = ( $this->getIsHtml() ? "\n" : '' );
-
- if ( is_array( $elemValue ) ) {
- $cnt = count( $elemValue );
- if ( $cnt != 0 && array_keys( $elemValue ) !== range( 0, $cnt - 1 ) ) {
- $elemValue = (object)$elemValue;
- }
- }
-
- if ( is_array( $elemValue ) ) {
- // Regular array
- $this->printText( $indstr . Xml::element( 'array', array(
- 'length' => count( $elemValue ) ), null ) . $nl );
- foreach ( $elemValue as $subElemValue ) {
- $this->slowWddxPrinter( $subElemValue, $indent + 2 );
- }
- $this->printText( "$indstr</array>$nl" );
- } elseif ( is_object( $elemValue ) ) {
- // Associative array (<struct>)
- $this->printText( "$indstr<struct>$nl" );
- foreach ( $elemValue as $subElemName => $subElemValue ) {
- $this->printText( $indstr2 . Xml::element( 'var', array(
- 'name' => $subElemName
- ), null ) . $nl );
- $this->slowWddxPrinter( $subElemValue, $indent + 4 );
- $this->printText( "$indstr2</var>$nl" );
- }
- $this->printText( "$indstr</struct>$nl" );
- } elseif ( is_int( $elemValue ) || is_float( $elemValue ) ) {
- $this->printText( $indstr . Xml::element( 'number', null, $elemValue ) . $nl );
- } elseif ( is_string( $elemValue ) ) {
- $this->printText( $indstr . Xml::element( 'string', null, $elemValue, false ) . $nl );
- } elseif ( is_bool( $elemValue ) ) {
- $this->printText( $indstr . Xml::element( 'boolean',
- array( 'value' => $elemValue ? 'true' : 'false' ) ) . $nl
- );
- } elseif ( $elemValue === null ) {
- $this->printText( $indstr . Xml::element( 'null', array() ) . $nl );
- } else {
- ApiBase::dieDebug( __METHOD__, 'Unknown type ' . gettype( $elemValue ) );
- }
- }
-
- public function isDeprecated() {
- return true;
- }
-}
diff --git a/includes/api/ApiFormatXml.php b/includes/api/ApiFormatXml.php
index fa0bac34..e8ad387b 100644
--- a/includes/api/ApiFormatXml.php
+++ b/includes/api/ApiFormatXml.php
@@ -39,13 +39,6 @@ class ApiFormatXml extends ApiFormatBase {
return 'text/xml';
}
- /**
- * @deprecated since 1.25
- */
- public function getNeedsRawData() {
- return true;
- }
-
public function setRootElement( $rootElemName ) {
$this->mRootElemName = $rootElemName;
}
@@ -72,7 +65,7 @@ class ApiFormatXml extends ApiFormatBase {
'Custom' => function ( &$data, &$metadata ) {
if ( isset( $metadata[ApiResult::META_TYPE] ) ) {
// We want to use non-BC for BCassoc to force outputting of _idx.
- switch( $metadata[ApiResult::META_TYPE] ) {
+ switch ( $metadata[ApiResult::META_TYPE] ) {
case 'BCassoc':
$metadata[ApiResult::META_TYPE] = 'assoc';
break;
@@ -267,7 +260,7 @@ class ApiFormatXml extends ApiFormatBase {
return '_' . preg_replace_callback(
"/[^$nc]/uS",
function ( $m ) {
- return sprintf( '.%X.', utf8ToCodepoint( $m[0] ) );
+ return sprintf( '.%X.', UtfNormal\Utils::utf8ToCodepoint( $m[0] ) );
},
str_replace( '.', '.2E.', $name )
);
diff --git a/includes/api/ApiHelp.php b/includes/api/ApiHelp.php
index 53e8c343..f6d124f0 100644
--- a/includes/api/ApiHelp.php
+++ b/includes/api/ApiHelp.php
@@ -45,6 +45,7 @@ class ApiHelp extends ApiBase {
$context->setLanguage( $this->getMain()->getLanguage() );
$context->setTitle( SpecialPage::getTitleFor( 'ApiHelp' ) );
$out = new OutputPage( $context );
+ $out->setCopyrightUrl( 'https://www.mediawiki.org/wiki/Special:MyLanguage/Copyright' );
$context->setOutput( $out );
self::getHelp( $context, $modules, $params );
@@ -82,6 +83,7 @@ class ApiHelp extends ApiBase {
* - submodules: (bool) Include help for submodules of the current module
* - recursivesubmodules: (bool) Include help for submodules recursively
* - helptitle: (string) Title to link for additional modules' help. Should contain $1.
+ * - toc: (bool) Include a table of contents
*
* @param IContextSource $context
* @param ApiBase[]|ApiBase $modules
@@ -97,6 +99,9 @@ class ApiHelp extends ApiBase {
$out = $context->getOutput();
$out->addModules( 'mediawiki.apihelp' );
+ if ( !empty( $options['toc'] ) ) {
+ $out->addModules( 'mediawiki.toc' );
+ }
$out->setPageTitle( $context->msg( 'api-help-title' ) );
$cacheKey = null;
@@ -107,6 +112,7 @@ class ApiHelp extends ApiBase {
if ( $cacheHelpTimeout > 0 ) {
// Get help text from cache if present
$cacheKey = wfMemcKey( 'apihelp', $modules[0]->getModulePath(),
+ (int)!empty( $options['toc'] ),
str_replace( ' ', '_', SpecialVersion::getVersion( 'nodb' ) ) );
$cached = $wgMemc->get( $cacheKey );
if ( $cached ) {
@@ -133,7 +139,11 @@ class ApiHelp extends ApiBase {
}
$haveModules = array();
- $out->addHTML( self::getHelpInternal( $context, $modules, $options, $haveModules ) );
+ $html = self::getHelpInternal( $context, $modules, $options, $haveModules );
+ if ( !empty( $options['toc'] ) && $haveModules ) {
+ $out->addHTML( Linker::generateTOC( $haveModules, $context->getLanguage() ) );
+ }
+ $out->addHTML( $html );
$helptitle = isset( $options['helptitle'] ) ? $options['helptitle'] : null;
$html = self::fixHelpLinks( $out->getHTML(), $helptitle, $haveModules );
@@ -150,7 +160,7 @@ class ApiHelp extends ApiBase {
*
* @param string $html
* @param string|null $helptitle Title to link to rather than api.php, must contain '$1'
- * @param array $localModules Modules to link within the current page
+ * @param array $localModules Keys are modules to link within the current page, values are ignored
* @return string
*/
public static function fixHelpLinks( $html, $helptitle = null, $localModules = array() ) {
@@ -164,17 +174,17 @@ class ApiHelp extends ApiBase {
$old = $href;
$href = rawurldecode( $href );
} while ( $old !== $href );
- if ( preg_match( '!Special:ApiHelp/([^&/|]+)!', $href, $m ) ) {
+ if ( preg_match( '!Special:ApiHelp/([^&/|#]+)((?:#.*)?)!', $href, $m ) ) {
if ( isset( $localModules[$m[1]] ) ) {
- $href = '#' . $m[1];
+ $href = $m[2] === '' ? '#' . $m[1] : $m[2];
} elseif ( $helptitle !== null ) {
- $href = Title::newFromText( str_replace( '$1', $m[1], $helptitle ) )
+ $href = Title::newFromText( str_replace( '$1', $m[1], $helptitle ) . $m[2] )
->getFullUrl();
} else {
$href = wfAppendQuery( wfScript( 'api' ), array(
'action' => 'help',
'modules' => $m[1],
- ) );
+ ) ) . $m[2];
}
$node->setAttribute( 'href', $href );
$node->removeAttribute( 'title' );
@@ -212,11 +222,16 @@ class ApiHelp extends ApiBase {
) {
$out = '';
- $level = min( 6, empty( $options['headerlevel'] ) ? 2 : $options['headerlevel'] );
- $options['headerlevel'] = $level;
+ $level = empty( $options['headerlevel'] ) ? 2 : $options['headerlevel'];
+ if ( empty( $options['tocnumber'] ) ) {
+ $tocnumber = array( 2 => 0 );
+ } else {
+ $tocnumber = &$options['tocnumber'];
+ }
foreach ( $modules as $module ) {
- $haveModules[$module->getModulePath()] = true;
+ $tocnumber[$level]++;
+ $path = $module->getModulePath();
$module->setContext( $context );
$help = array(
'header' => '',
@@ -228,8 +243,13 @@ class ApiHelp extends ApiBase {
'submodules' => '',
);
- if ( empty( $options['noheader'] ) ) {
- $path = $module->getModulePath();
+ if ( empty( $options['noheader'] ) || !empty( $options['toc'] ) ) {
+ $anchor = $path;
+ $i = 1;
+ while ( isset( $haveModules[$anchor] ) ) {
+ $anchor = $path . '|' . ++$i;
+ }
+
if ( $module->isMain() ) {
$header = $context->msg( 'api-help-main-header' )->parse();
} else {
@@ -241,10 +261,22 @@ class ApiHelp extends ApiBase {
$context->msg( 'parentheses', $module->getModulePrefix() )->parse();
}
}
- $help['header'] .= Html::element( "h$level",
- array( 'id' => $path, 'class' => 'apihelp-header' ),
- $header
+ $haveModules[$anchor] = array(
+ 'toclevel' => count( $tocnumber ),
+ 'level' => $level,
+ 'anchor' => $anchor,
+ 'line' => $header,
+ 'number' => join( '.', $tocnumber ),
+ 'index' => false,
);
+ if ( empty( $options['noheader'] ) ) {
+ $help['header'] .= Html::element( 'h' . min( 6, $level ),
+ array( 'id' => $anchor, 'class' => 'apihelp-header' ),
+ $header
+ );
+ }
+ } else {
+ $haveModules[$path] = true;
}
$links = array();
@@ -277,25 +309,55 @@ class ApiHelp extends ApiBase {
);
}
- $flags = $module->getHelpFlags();
- if ( $flags ) {
- $help['flags'] .= Html::openElement( 'div',
- array( 'class' => 'apihelp-block apihelp-flags' ) );
- $msg = $context->msg( 'api-help-flags' );
- if ( !$msg->isDisabled() ) {
- $help['flags'] .= self::wrap(
- $msg->numParams( count( $flags ) ), 'apihelp-block-head', 'div'
- );
+ $help['flags'] .= Html::openElement( 'div',
+ array( 'class' => 'apihelp-block apihelp-flags' ) );
+ $msg = $context->msg( 'api-help-flags' );
+ if ( !$msg->isDisabled() ) {
+ $help['flags'] .= self::wrap(
+ $msg->numParams( count( $flags ) ), 'apihelp-block-head', 'div'
+ );
+ }
+ $help['flags'] .= Html::openElement( 'ul' );
+ foreach ( $module->getHelpFlags() as $flag ) {
+ $help['flags'] .= Html::rawElement( 'li', null,
+ self::wrap( $context->msg( "api-help-flag-$flag" ), "apihelp-flag-$flag" )
+ );
+ }
+ $sourceInfo = $module->getModuleSourceInfo();
+ if ( $sourceInfo ) {
+ if ( isset( $sourceInfo['namemsg'] ) ) {
+ $extname = $context->msg( $sourceInfo['namemsg'] )->text();
+ } else {
+ $extname = $sourceInfo['name'];
}
- $help['flags'] .= Html::openElement( 'ul' );
- foreach ( $flags as $flag ) {
- $help['flags'] .= Html::rawElement( 'li', null,
- self::wrap( $context->msg( "api-help-flag-$flag" ), "apihelp-flag-$flag" )
- );
+ $help['flags'] .= Html::rawElement( 'li', null,
+ self::wrap(
+ $context->msg( 'api-help-source', $extname, $sourceInfo['name'] ),
+ 'apihelp-source'
+ )
+ );
+
+ $link = SpecialPage::getTitleFor( 'Version', 'License/' . $sourceInfo['name'] );
+ if ( isset( $sourceInfo['license-name'] ) ) {
+ $msg = $context->msg( 'api-help-license', $link, $sourceInfo['license-name'] );
+ } elseif ( SpecialVersion::getExtLicenseFileName( dirname( $sourceInfo['path'] ) ) ) {
+ $msg = $context->msg( 'api-help-license-noname', $link );
+ } else {
+ $msg = $context->msg( 'api-help-license-unknown' );
}
- $help['flags'] .= Html::closeElement( 'ul' );
- $help['flags'] .= Html::closeElement( 'div' );
+ $help['flags'] .= Html::rawElement( 'li', null,
+ self::wrap( $msg, 'apihelp-license' )
+ );
+ } else {
+ $help['flags'] .= Html::rawElement( 'li', null,
+ self::wrap( $context->msg( 'api-help-source-unknown' ), 'apihelp-source' )
+ );
+ $help['flags'] .= Html::rawElement( 'li', null,
+ self::wrap( $context->msg( 'api-help-license-unknown' ), 'apihelp-license' )
+ );
}
+ $help['flags'] .= Html::closeElement( 'ul' );
+ $help['flags'] .= Html::closeElement( 'div' );
foreach ( $module->getFinalDescription() as $msg ) {
$msg->setContext( $context );
@@ -429,19 +491,30 @@ class ApiHelp extends ApiBase {
switch ( $type ) {
case 'submodule':
$groups[] = $name;
- $submodules = $module->getModuleManager()->getNames( $name );
+ if ( isset( $settings[ApiBase::PARAM_SUBMODULE_MAP] ) ) {
+ $map = $settings[ApiBase::PARAM_SUBMODULE_MAP];
+ ksort( $map );
+ $submodules = array();
+ foreach ( $map as $v => $m ) {
+ $submodules[] = "[[Special:ApiHelp/{$m}|{$v}]]";
+ }
+ } else {
+ $submodules = $module->getModuleManager()->getNames( $name );
+ sort( $submodules );
+ $prefix = $module->isMain()
+ ? '' : ( $module->getModulePath() . '+' );
+ $submodules = array_map( function ( $name ) use ( $prefix ) {
+ return "[[Special:ApiHelp/{$prefix}{$name}|{$name}]]";
+ }, $submodules );
+ }
$count = count( $submodules );
- sort( $submodules );
- $prefix = $module->isMain()
- ? '' : ( $module->getModulePath() . '+' );
- $submodules = array_map( function ( $name ) use ( $prefix ) {
- return "[[Special:ApiHelp/{$prefix}{$name}|{$name}]]";
- }, $submodules );
$info[] = $context->msg( 'api-help-param-list' )
->params( $multi ? 2 : 1 )
->params( $context->getLanguage()->commaList( $submodules ) )
->parse();
$hintPipeSeparated = false;
+ // No type message necessary, we have a list of values.
+ $type = null;
break;
case 'namespace':
@@ -452,6 +525,8 @@ class ApiHelp extends ApiBase {
->params( $context->getLanguage()->commaList( $namespaces ) )
->parse();
$hintPipeSeparated = false;
+ // No type message necessary, we have a list of values.
+ $type = null;
break;
case 'limit':
@@ -494,10 +569,29 @@ class ApiHelp extends ApiBase {
case 'upload':
$info[] = $context->msg( 'api-help-param-upload' )
->parse();
+ // No type message necessary, api-help-param-upload should handle it.
+ $type = null;
+ break;
+
+ case 'string':
+ case 'text':
+ // Displaying a type message here would be useless.
+ $type = null;
break;
}
}
+ // Add type. Messages for grep: api-help-param-type-limit
+ // api-help-param-type-integer api-help-param-type-boolean
+ // api-help-param-type-timestamp api-help-param-type-user
+ // api-help-param-type-password
+ if ( is_string( $type ) ) {
+ $msg = $context->msg( "api-help-param-type-$type" );
+ if ( !$msg->isDisabled() ) {
+ $info[] = $msg->params( $multi ? 2 : 1 )->parse();
+ }
+ }
+
if ( $multi ) {
$extra = array();
if ( $hintPipeSeparated ) {
@@ -590,6 +684,15 @@ class ApiHelp extends ApiBase {
$help['examples'] .= Html::closeElement( 'div' );
}
+ $subtocnumber = $tocnumber;
+ $subtocnumber[$level + 1] = 0;
+ $suboptions = array(
+ 'submodules' => $options['recursivesubmodules'],
+ 'headerlevel' => $level + 1,
+ 'tocnumber' => &$subtocnumber,
+ 'noheader' => false,
+ ) + $options;
+
if ( $options['submodules'] && $module->getModuleManager() ) {
$manager = $module->getModuleManager();
$submodules = array();
@@ -600,16 +703,13 @@ class ApiHelp extends ApiBase {
$submodules[] = $manager->getModule( $name );
}
}
- $help['submodules'] .= self::getHelpInternal( $context, $submodules, array(
- 'submodules' => $options['recursivesubmodules'],
- 'headerlevel' => $level + 1,
- 'noheader' => false,
- ) + $options, $haveModules );
+ $help['submodules'] .= self::getHelpInternal( $context, $submodules, $suboptions, $haveModules );
+ $numSubmodules = count( $submodules );
}
- $module->modifyHelp( $help, $options );
+ $module->modifyHelp( $help, $suboptions, $haveModules );
- Hooks::run( 'APIHelpModifyOutput', array( $module, &$help, $options ) );
+ Hooks::run( 'APIHelpModifyOutput', array( $module, &$help, $suboptions, &$haveModules ) );
$out .= join( "\n", $help );
}
diff --git a/includes/api/ApiImageRotate.php b/includes/api/ApiImageRotate.php
index 865d39fa..7a544ec0 100644
--- a/includes/api/ApiImageRotate.php
+++ b/includes/api/ApiImageRotate.php
@@ -49,6 +49,8 @@ class ApiImageRotate extends ApiBase {
}
public function execute() {
+ $this->useTransactionalTimeLimit();
+
$params = $this->extractRequestParams();
$rotation = $params['rotation'];
@@ -60,7 +62,7 @@ class ApiImageRotate extends ApiBase {
$result = array();
- self::addValues( $result, $pageSet->getInvalidTitles(), 'invalid', 'title' );
+ self::addValues( $result, $pageSet->getInvalidTitlesAndReasons(), 'invalid' );
self::addValues( $result, $pageSet->getSpecialTitles(), 'special', 'title' );
self::addValues( $result, $pageSet->getMissingPageIDs(), 'missing', 'pageid' );
self::addValues( $result, $pageSet->getMissingRevisionIDs(), 'missing', 'revid' );
diff --git a/includes/api/ApiImport.php b/includes/api/ApiImport.php
index 2e87d22d..735cc7fa 100644
--- a/includes/api/ApiImport.php
+++ b/includes/api/ApiImport.php
@@ -32,9 +32,13 @@
class ApiImport extends ApiBase {
public function execute() {
+ $this->useTransactionalTimeLimit();
+
$user = $this->getUser();
$params = $this->extractRequestParams();
+ $this->requireMaxOneParameter( $params, 'namespace', 'rootpage' );
+
$isUpload = false;
if ( isset( $params['interwikisource'] ) ) {
if ( !$user->isAllowed( 'import' ) ) {
@@ -63,8 +67,7 @@ class ApiImport extends ApiBase {
$importer = new WikiImporter( $source->value, $this->getConfig() );
if ( isset( $params['namespace'] ) ) {
$importer->setTargetNamespace( $params['namespace'] );
- }
- if ( isset( $params['rootpage'] ) ) {
+ } elseif ( isset( $params['rootpage'] ) ) {
$statusRootPage = $importer->setTargetRootPage( $params['rootpage'] );
if ( !$statusRootPage->isGood() ) {
$this->dieStatus( $statusRootPage );
diff --git a/includes/api/ApiLogin.php b/includes/api/ApiLogin.php
index 5480d940..c66e2156 100644
--- a/includes/api/ApiLogin.php
+++ b/includes/api/ApiLogin.php
@@ -24,6 +24,7 @@
*
* @file
*/
+use MediaWiki\Logger\LoggerFactory;
/**
* Unit to authenticate log-in attempts to the current wiki.
@@ -144,6 +145,10 @@ class ApiLogin extends ApiBase {
case LoginForm::CREATE_BLOCKED:
$result['result'] = 'CreateBlocked';
$result['details'] = 'Your IP address is blocked from account creation';
+ $block = $context->getUser()->getBlock();
+ if ( $block ) {
+ $result = array_merge( $result, ApiQueryUserInfo::getBlockInfo( $block ) );
+ }
break;
case LoginForm::THROTTLED:
@@ -154,6 +159,10 @@ class ApiLogin extends ApiBase {
case LoginForm::USER_BLOCKED:
$result['result'] = 'Blocked';
+ $block = User::newFromName( $params['name'] )->getBlock();
+ if ( $block ) {
+ $result = array_merge( $result, ApiQueryUserInfo::getBlockInfo( $block ) );
+ }
break;
case LoginForm::ABORTED:
@@ -166,6 +175,12 @@ class ApiLogin extends ApiBase {
}
$this->getResult()->addValue( null, 'login', $result );
+
+ LoggerFactory::getInstance( 'authmanager' )->info( 'Login attempt', array(
+ 'event' => 'login',
+ 'successful' => $authRes === LoginForm::SUCCESS,
+ 'status' => LoginForm::$statusCodes[$authRes],
+ ) );
}
public function mustBePosted() {
@@ -179,7 +194,9 @@ class ApiLogin extends ApiBase {
public function getAllowedParams() {
return array(
'name' => null,
- 'password' => null,
+ 'password' => array(
+ ApiBase::PARAM_TYPE => 'password',
+ ),
'domain' => null,
'token' => null,
);
diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php
index 3bf066cf..d943c86b 100644
--- a/includes/api/ApiMain.php
+++ b/includes/api/ApiMain.php
@@ -100,8 +100,6 @@ class ApiMain extends ApiBase {
'jsonfm' => 'ApiFormatJson',
'php' => 'ApiFormatPhp',
'phpfm' => 'ApiFormatPhp',
- 'wddx' => 'ApiFormatWddx',
- 'wddxfm' => 'ApiFormatWddx',
'xml' => 'ApiFormatXml',
'xmlfm' => 'ApiFormatXml',
'yaml' => 'ApiFormatYaml',
@@ -111,8 +109,6 @@ class ApiMain extends ApiBase {
'txtfm' => 'ApiFormatTxt',
'dbg' => 'ApiFormatDbg',
'dbgfm' => 'ApiFormatDbg',
- 'dump' => 'ApiFormatDump',
- 'dumpfm' => 'ApiFormatDump',
'none' => 'ApiFormatNone',
);
@@ -429,13 +425,16 @@ class ApiMain extends ApiBase {
// In case an error occurs during data output,
// clear the output buffer and print just the error information
+ $obLevel = ob_get_level();
ob_start();
$t = microtime( true );
try {
$this->executeAction();
+ $isError = false;
} catch ( Exception $e ) {
$this->handleException( $e );
+ $isError = true;
}
// Log the request whether or not there was an error
@@ -443,9 +442,13 @@ class ApiMain extends ApiBase {
// Send cache headers after any code which might generate an error, to
// avoid sending public cache headers for errors.
- $this->sendCacheHeaders();
+ $this->sendCacheHeaders( $isError );
- ob_end_flush();
+ // Executing the action might have already messed with the output
+ // buffers.
+ while ( ob_get_level() > $obLevel ) {
+ ob_end_flush();
+ }
}
/**
@@ -536,7 +539,7 @@ class ApiMain extends ApiBase {
// Log the request and reset cache headers
$main->logRequest( 0 );
- $main->sendCacheHeaders();
+ $main->sendCacheHeaders( true );
ob_end_flush();
}
@@ -577,8 +580,7 @@ class ApiMain extends ApiBase {
if ( !in_array( $originParam, $origins ) ) {
// origin parameter set but incorrect
// Send a 403 response
- $message = HttpStatus::getMessage( 403 );
- $response->header( "HTTP/1.1 403 $message", true, 403 );
+ $response->statusHeader( 403 );
$response->header( 'Cache-Control: no-cache' );
echo "'origin' parameter does not match Origin header\n";
@@ -706,7 +708,12 @@ class ApiMain extends ApiBase {
return "/^https?:\/\/$wildcard$/";
}
- protected function sendCacheHeaders() {
+ /**
+ * Send caching headers
+ * @param boolean $isError Whether an error response is being output
+ * @since 1.26 added $isError parameter
+ */
+ protected function sendCacheHeaders( $isError ) {
$response = $this->getRequest()->response();
$out = $this->getOutput();
@@ -716,6 +723,19 @@ class ApiMain extends ApiBase {
$out->addVaryHeader( 'X-Forwarded-Proto' );
}
+ if ( !$isError && $this->mModule &&
+ ( $this->getRequest()->getMethod() === 'GET' || $this->getRequest()->getMethod() === 'HEAD' )
+ ) {
+ $etag = $this->mModule->getConditionalRequestData( 'etag' );
+ if ( $etag !== null ) {
+ $response->header( "ETag: $etag" );
+ }
+ $lastMod = $this->mModule->getConditionalRequestData( 'last-modified' );
+ if ( $lastMod !== null ) {
+ $response->header( 'Last-Modified: ' . wfTimestamp( TS_RFC2822, $lastMod ) );
+ }
+ }
+
// The logic should be:
// $this->mCacheControl['max-age'] is set?
// Use it, the module knows better than our guess.
@@ -999,6 +1019,121 @@ class ApiMain extends ApiBase {
}
/**
+ * Check selected RFC 7232 precondition headers
+ *
+ * RFC 7232 envisions a particular model where you send your request to "a
+ * resource", and for write requests that you can read "the resource" by
+ * changing the method to GET. When the API receives a GET request, it
+ * works out even though "the resource" from RFC 7232's perspective might
+ * be many resources from MediaWiki's perspective. But it totally fails for
+ * a POST, since what HTTP sees as "the resource" is probably just
+ * "/api.php" with all the interesting bits in the body.
+ *
+ * Therefore, we only support RFC 7232 precondition headers for GET (and
+ * HEAD). That means we don't need to bother with If-Match and
+ * If-Unmodified-Since since they only apply to modification requests.
+ *
+ * And since we don't support Range, If-Range is ignored too.
+ *
+ * @since 1.26
+ * @param ApiBase $module Api module being used
+ * @return bool True on success, false should exit immediately
+ */
+ protected function checkConditionalRequestHeaders( $module ) {
+ if ( $this->mInternalMode ) {
+ // No headers to check in internal mode
+ return true;
+ }
+
+ if ( $this->getRequest()->getMethod() !== 'GET' && $this->getRequest()->getMethod() !== 'HEAD' ) {
+ // Don't check POSTs
+ return true;
+ }
+
+ $return304 = false;
+
+ $ifNoneMatch = array_diff(
+ $this->getRequest()->getHeader( 'If-None-Match', WebRequest::GETHEADER_LIST ) ?: array(),
+ array( '' )
+ );
+ if ( $ifNoneMatch ) {
+ if ( $ifNoneMatch === array( '*' ) ) {
+ // API responses always "exist"
+ $etag = '*';
+ } else {
+ $etag = $module->getConditionalRequestData( 'etag' );
+ }
+ }
+ if ( $ifNoneMatch && $etag !== null ) {
+ $test = substr( $etag, 0, 2 ) === 'W/' ? substr( $etag, 2 ) : $etag;
+ $match = array_map( function ( $s ) {
+ return substr( $s, 0, 2 ) === 'W/' ? substr( $s, 2 ) : $s;
+ }, $ifNoneMatch );
+ $return304 = in_array( $test, $match, true );
+ } else {
+ $value = trim( $this->getRequest()->getHeader( 'If-Modified-Since' ) );
+
+ // Some old browsers sends sizes after the date, like this:
+ // Wed, 20 Aug 2003 06:51:19 GMT; length=5202
+ // Ignore that.
+ $i = strpos( $value, ';' );
+ if ( $i !== false ) {
+ $value = trim( substr( $value, 0, $i ) );
+ }
+
+ if ( $value !== '' ) {
+ try {
+ $ts = new MWTimestamp( $value );
+ if (
+ // RFC 7231 IMF-fixdate
+ $ts->getTimestamp( TS_RFC2822 ) === $value ||
+ // RFC 850
+ $ts->format( 'l, d-M-y H:i:s' ) . ' GMT' === $value ||
+ // asctime (with and without space-padded day)
+ $ts->format( 'D M j H:i:s Y' ) === $value ||
+ $ts->format( 'D M j H:i:s Y' ) === $value
+ ) {
+ $lastMod = $module->getConditionalRequestData( 'last-modified' );
+ if ( $lastMod !== null ) {
+ // Mix in some MediaWiki modification times
+ $modifiedTimes = array(
+ 'page' => $lastMod,
+ 'user' => $this->getUser()->getTouched(),
+ 'epoch' => $this->getConfig()->get( 'CacheEpoch' ),
+ );
+ if ( $this->getConfig()->get( 'UseSquid' ) ) {
+ // T46570: the core page itself may not change, but resources might
+ $modifiedTimes['sepoch'] = wfTimestamp(
+ TS_MW, time() - $this->getConfig()->get( 'SquidMaxage' )
+ );
+ }
+ Hooks::run( 'OutputPageCheckLastModified', array( &$modifiedTimes ) );
+ $lastMod = max( $modifiedTimes );
+ $return304 = wfTimestamp( TS_MW, $lastMod ) <= $ts->getTimestamp( TS_MW );
+ }
+ }
+ } catch ( TimestampException $e ) {
+ // Invalid timestamp, ignore it
+ }
+ }
+ }
+
+ if ( $return304 ) {
+ $this->getRequest()->response()->statusHeader( 304 );
+
+ // Avoid outputting the compressed representation of a zero-length body
+ MediaWiki\suppressWarnings();
+ ini_set( 'zlib.output_compression', 0 );
+ MediaWiki\restoreWarnings();
+ wfClearOutputBuffers();
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* Check for sufficient permissions to execute
* @param ApiBase $module An Api module
*/
@@ -1068,10 +1203,6 @@ class ApiMain extends ApiBase {
// Create an appropriate printer
$this->mPrinter = $this->createPrinterByName( $params['format'] );
}
-
- if ( $this->mPrinter->getNeedsRawData() ) {
- $this->getResult()->setRawMode();
- }
}
/**
@@ -1088,6 +1219,10 @@ class ApiMain extends ApiBase {
return;
}
+ if ( !$this->checkConditionalRequestHeaders( $module ) ) {
+ return;
+ }
+
if ( !$this->mInternalMode ) {
$this->setupExternalResponse( $module, $params );
}
@@ -1307,7 +1442,7 @@ class ApiMain extends ApiBase {
);
}
- public function modifyHelp( array &$help, array $options ) {
+ public function modifyHelp( array &$help, array $options, array &$tocData ) {
// Wish PHP had an "array_insert_before". Instead, we have to manually
// reindex the array to get 'permissions' in the right place.
$oldHelp = $help;
@@ -1318,6 +1453,7 @@ class ApiMain extends ApiBase {
}
$help[$k] = $v;
}
+ $help['datatypes'] = '';
$help['credits'] = '';
// Fill 'permissions'
@@ -1350,13 +1486,48 @@ class ApiMain extends ApiBase {
$help['permissions'] .= Html::closeElement( 'dl' );
$help['permissions'] .= Html::closeElement( 'div' );
- // Fill 'credits', if applicable
+ // Fill 'datatypes' and 'credits', if applicable
if ( empty( $options['nolead'] ) ) {
- $help['credits'] .= Html::element( 'h' . min( 6, $options['headerlevel'] + 1 ),
- array( 'id' => '+credits', 'class' => 'apihelp-header' ),
- $this->msg( 'api-credits-header' )->parse()
+ $level = $options['headerlevel'];
+ $tocnumber = &$options['tocnumber'];
+
+ $header = $this->msg( 'api-help-datatypes-header' )->parse();
+ $help['datatypes'] .= Html::rawelement( 'h' . min( 6, $level ),
+ array( 'id' => 'main/datatypes', 'class' => 'apihelp-header' ),
+ Html::element( 'span', array( 'id' => Sanitizer::escapeId( 'main/datatypes' ) ) ) .
+ $header
+ );
+ $help['datatypes'] .= $this->msg( 'api-help-datatypes' )->parseAsBlock();
+ if ( !isset( $tocData['main/datatypes'] ) ) {
+ $tocnumber[$level]++;
+ $tocData['main/datatypes'] = array(
+ 'toclevel' => count( $tocnumber ),
+ 'level' => $level,
+ 'anchor' => 'main/datatypes',
+ 'line' => $header,
+ 'number' => join( '.', $tocnumber ),
+ 'index' => false,
+ );
+ }
+
+ $header = $this->msg( 'api-credits-header' )->parse();
+ $help['credits'] .= Html::rawelement( 'h' . min( 6, $level ),
+ array( 'id' => 'main/credits', 'class' => 'apihelp-header' ),
+ Html::element( 'span', array( 'id' => Sanitizer::escapeId( 'main/credits' ) ) ) .
+ $header
);
$help['credits'] .= $this->msg( 'api-credits' )->useDatabase( false )->parseAsBlock();
+ if ( !isset( $tocData['main/credits'] ) ) {
+ $tocnumber[$level]++;
+ $tocData['main/credits'] = array(
+ 'toclevel' => count( $tocnumber ),
+ 'level' => $level,
+ 'anchor' => 'main/credits',
+ 'line' => $header,
+ 'number' => join( '.', $tocnumber ),
+ 'index' => false,
+ );
+ }
}
}
diff --git a/includes/api/ApiMessage.php b/includes/api/ApiMessage.php
index 6717c390..db826a68 100644
--- a/includes/api/ApiMessage.php
+++ b/includes/api/ApiMessage.php
@@ -132,6 +132,21 @@ class ApiMessage extends Message implements IApiMessage {
public function setApiData( array $data ) {
$this->apiData = $data;
}
+
+ public function serialize() {
+ return serialize( array(
+ 'parent' => parent::serialize(),
+ 'apiCode' => $this->apiCode,
+ 'apiData' => $this->apiData,
+ ) );
+ }
+
+ public function unserialize( $serialized ) {
+ $data = unserialize( $serialized );
+ parent::unserialize( $data['parent'] );
+ $this->apiCode = $data['apiCode'];
+ $this->apiData = $data['apiData'];
+ }
}
/**
@@ -188,4 +203,19 @@ class ApiRawMessage extends RawMessage implements IApiMessage {
public function setApiData( array $data ) {
$this->apiData = $data;
}
+
+ public function serialize() {
+ return serialize( array(
+ 'parent' => parent::serialize(),
+ 'apiCode' => $this->apiCode,
+ 'apiData' => $this->apiData,
+ ) );
+ }
+
+ public function unserialize( $serialized ) {
+ $data = unserialize( $serialized );
+ parent::unserialize( $data['parent'] );
+ $this->apiCode = $data['apiCode'];
+ $this->apiData = $data['apiData'];
+ }
}
diff --git a/includes/api/ApiMove.php b/includes/api/ApiMove.php
index e42958bf..aca43784 100644
--- a/includes/api/ApiMove.php
+++ b/includes/api/ApiMove.php
@@ -31,6 +31,8 @@
class ApiMove extends ApiBase {
public function execute() {
+ $this->useTransactionalTimeLimit();
+
$user = $this->getUser();
$params = $this->extractRequestParams();
diff --git a/includes/api/ApiOptions.php b/includes/api/ApiOptions.php
index 8ef06299..a62bcb6d 100644
--- a/includes/api/ApiOptions.php
+++ b/includes/api/ApiOptions.php
@@ -52,6 +52,14 @@ class ApiOptions extends ApiBase {
$this->dieUsageMsg( array( 'missingparam', 'optionname' ) );
}
+ // Load the user from the master to reduce CAS errors on double post (T95839)
+ if ( wfGetLB()->getServerCount() > 1 ) {
+ $user = User::newFromId( $user->getId() );
+ if ( !$user->loadFromId( User::READ_LATEST ) ) {
+ $this->dieUsage( 'Anonymous users cannot change preferences', 'notloggedin' );
+ }
+ }
+
if ( $params['reset'] ) {
$user->resetOptions( $params['resetkinds'], $this->getContext() );
$changed = true;
@@ -75,11 +83,17 @@ class ApiOptions extends ApiBase {
$prefs = Preferences::getPreferences( $user, $this->getContext() );
$prefsKinds = $user->getOptionKinds( $this->getContext(), $changes );
+ $htmlForm = null;
foreach ( $changes as $key => $value ) {
switch ( $prefsKinds[$key] ) {
case 'registered':
// Regular option.
+ if ( $htmlForm === null ) {
+ // We need a dummy HTMLForm for the validate callback...
+ $htmlForm = new HTMLForm( array(), $this );
+ }
$field = HTMLForm::loadInputFromParameters( $key, $prefs[$key] );
+ $field->mParent = $htmlForm;
$validation = $field->validate( $value, $user->getOptions() );
break;
case 'registered-multiselect':
diff --git a/includes/api/ApiPageSet.php b/includes/api/ApiPageSet.php
index e6f218d6..1415b794 100644
--- a/includes/api/ApiPageSet.php
+++ b/includes/api/ApiPageSet.php
@@ -58,7 +58,7 @@ class ApiPageSet extends ApiBase {
private $mGoodTitles = array();
private $mMissingPages = array(); // [ns][dbkey] => fake page_id
private $mMissingTitles = array();
- private $mInvalidTitles = array();
+ private $mInvalidTitles = array(); // [fake_page_id] => array( 'title' => $title, 'invalidreason' => $reason )
private $mMissingPageIDs = array();
private $mRedirectTitles = array();
private $mSpecialTitles = array();
@@ -66,6 +66,7 @@ class ApiPageSet extends ApiBase {
private $mInterwikiTitles = array();
/** @var Title[] */
private $mPendingRedirectIDs = array();
+ private $mResolvedRedirectTitles = array();
private $mConvertedTitles = array();
private $mGoodRevIDs = array();
private $mLiveRevIDs = array();
@@ -396,9 +397,22 @@ class ApiPageSet extends ApiBase {
/**
* Titles that were deemed invalid by Title::newFromText()
* The array's index will be unique and negative for each item
+ * @deprecated since 1.26, use self::getInvalidTitlesAndReasons()
* @return string[] Array of strings (not Title objects)
*/
public function getInvalidTitles() {
+ wfDeprecated( __METHOD__, '1.26' );
+ return array_map( function ( $t ) {
+ return $t['title'];
+ }, $this->mInvalidTitles );
+ }
+
+ /**
+ * Titles that were deemed invalid by Title::newFromText()
+ * The array's index will be unique and negative for each item
+ * @return array[] Array of arrays with 'title' and 'invalidreason' properties
+ */
+ public function getInvalidTitlesAndReasons() {
return $this->mInvalidTitles;
}
@@ -421,7 +435,7 @@ class ApiPageSet extends ApiBase {
/**
* Get a list of redirect resolutions - maps a title to its redirect
- * target.
+ * target. Includes generator data for redirect source when available.
* @param ApiResult $result
* @return array Array of prefixed_title (string) => Title object
* @since 1.21
@@ -439,6 +453,15 @@ class ApiPageSet extends ApiBase {
if ( $titleTo->isExternal() ) {
$r['tointerwiki'] = $titleTo->getInterwiki();
}
+ if ( isset( $this->mResolvedRedirectTitles[$titleStrFrom] ) ) {
+ $titleFrom = $this->mResolvedRedirectTitles[$titleStrFrom];
+ $ns = $titleFrom->getNamespace();
+ $dbkey = $titleFrom->getDBkey();
+ if ( isset( $this->mGeneratorData[$ns][$dbkey] ) ) {
+ $r = array_merge( $this->mGeneratorData[$ns][$dbkey], $r );
+ }
+ }
+
$values[] = $r;
}
if ( !empty( $values ) && $result ) {
@@ -552,7 +575,7 @@ class ApiPageSet extends ApiBase {
*
* @param array $invalidChecks List of types of invalid titles to include.
* Recognized values are:
- * - invalidTitles: Titles from $this->getInvalidTitles()
+ * - invalidTitles: Titles and reasons from $this->getInvalidTitlesAndReasons()
* - special: Titles from $this->getSpecialTitles()
* - missingIds: ids from $this->getMissingPageIDs()
* - missingRevIds: ids from $this->getMissingRevisionIDs()
@@ -566,7 +589,7 @@ class ApiPageSet extends ApiBase {
) {
$result = array();
if ( in_array( "invalidTitles", $invalidChecks ) ) {
- self::addValues( $result, $this->getInvalidTitles(), 'invalid', 'title' );
+ self::addValues( $result, $this->getInvalidTitlesAndReasons(), 'invalid' );
}
if ( in_array( "special", $invalidChecks ) ) {
self::addValues( $result, $this->getSpecialTitles(), 'special', 'title' );
@@ -1017,6 +1040,7 @@ class ApiPageSet extends ApiBase {
$row->rd_fragment,
$row->rd_interwiki
);
+ $this->mResolvedRedirectTitles[$from] = $this->mPendingRedirectIDs[$rdfrom];
unset( $this->mPendingRedirectIDs[$rdfrom] );
if ( $to->isExternal() ) {
$this->mInterwikiTitles[$to->getPrefixedText()] = $to->getInterwiki();
@@ -1037,7 +1061,9 @@ class ApiPageSet extends ApiBase {
continue;
}
$lb->addObj( $rt );
- $this->mRedirectTitles[$title->getPrefixedText()] = $rt;
+ $from = $title->getPrefixedText();
+ $this->mResolvedRedirectTitles[$from] = $title;
+ $this->mRedirectTitles[$from] = $rt;
unset( $this->mPendingRedirectIDs[$id] );
}
}
@@ -1077,17 +1103,21 @@ class ApiPageSet extends ApiBase {
foreach ( $titles as $title ) {
if ( is_string( $title ) ) {
- $titleObj = Title::newFromText( $title, $this->mDefaultNamespace );
+ try {
+ $titleObj = Title::newFromTextThrow( $title, $this->mDefaultNamespace );
+ } catch ( MalformedTitleException $ex ) {
+ // Handle invalid titles gracefully
+ $this->mAllPages[0][$title] = $this->mFakePageId;
+ $this->mInvalidTitles[$this->mFakePageId] = array(
+ 'title' => $title,
+ 'invalidreason' => $ex->getMessage(),
+ );
+ $this->mFakePageId--;
+ continue; // There's nothing else we can do
+ }
} else {
$titleObj = $title;
}
- if ( !$titleObj ) {
- // Handle invalid titles gracefully
- $this->mAllPages[0][$title] = $this->mFakePageId;
- $this->mInvalidTitles[$this->mFakePageId] = $title;
- $this->mFakePageId--;
- continue; // There's nothing else we can do
- }
$unconvertedTitle = $titleObj->getPrefixedText();
$titleWasConverted = false;
if ( $titleObj->isExternal() ) {
@@ -1287,8 +1317,8 @@ class ApiPageSet extends ApiBase {
),
'generator' => array(
ApiBase::PARAM_TYPE => null,
- ApiBase::PARAM_VALUE_LINKS => array(),
ApiBase::PARAM_HELP_MSG => 'api-pageset-param-generator',
+ ApiBase::PARAM_SUBMODULE_PARAM_PREFIX => 'g',
),
'redirects' => array(
ApiBase::PARAM_DFLT => false,
@@ -1314,10 +1344,8 @@ class ApiPageSet extends ApiBase {
if ( !$this->mAllowGenerator ) {
unset( $result['generator'] );
} elseif ( $flags & ApiBase::GET_VALUES_FOR_HELP ) {
- foreach ( $this->getGenerators() as $g ) {
- $result['generator'][ApiBase::PARAM_TYPE][] = $g;
- $result['generator'][ApiBase::PARAM_VALUE_LINKS][$g] = "Special:ApiHelp/query+$g";
- }
+ $result['generator'][ApiBase::PARAM_TYPE] = 'submodule';
+ $result['generator'][ApiBase::PARAM_SUBMODULE_MAP] = $this->getGenerators();
}
return $result;
@@ -1338,13 +1366,14 @@ class ApiPageSet extends ApiBase {
$query = $this->getMain()->getModuleManager()->getModule( 'query' );
}
$gens = array();
+ $prefix = $query->getModulePath() . '+';
$mgr = $query->getModuleManager();
foreach ( $mgr->getNamesWithClasses() as $name => $class ) {
if ( is_subclass_of( $class, 'ApiQueryGeneratorBase' ) ) {
- $gens[] = $name;
+ $gens[$name] = $prefix . $name;
}
}
- sort( $gens );
+ ksort( $gens );
self::$generators = $gens;
}
diff --git a/includes/api/ApiParamInfo.php b/includes/api/ApiParamInfo.php
index 4dcaf78e..2ab37ad1 100644
--- a/includes/api/ApiParamInfo.php
+++ b/includes/api/ApiParamInfo.php
@@ -195,6 +195,24 @@ class ApiParamInfo extends ApiBase {
}
$ret['prefix'] = $module->getModulePrefix();
+ $sourceInfo = $module->getModuleSourceInfo();
+ if ( $sourceInfo ) {
+ $ret['source'] = $sourceInfo['name'];
+ if ( isset( $sourceInfo['namemsg'] ) ) {
+ $ret['sourcename'] = $this->context->msg( $sourceInfo['namemsg'] )->text();
+ } else {
+ $ret['sourcename'] = $ret['source'];
+ }
+
+ $link = SpecialPage::getTitleFor( 'Version', 'License/' . $sourceInfo['name'] )->getFullUrl();
+ if ( isset( $sourceInfo['license-name'] ) ) {
+ $ret['licensetag'] = $sourceInfo['license-name'];
+ $ret['licenselink'] = (string)$link;
+ } elseif ( SpecialVersion::getExtLicenseFileName( dirname( $sourceInfo['path'] ) ) ) {
+ $ret['licenselink'] = (string)$link;
+ }
+ }
+
$this->formatHelpMessages( $ret, 'description', $module->getFinalDescription() );
foreach ( $module->getHelpFlags() as $flag ) {
@@ -273,14 +291,20 @@ class ApiParamInfo extends ApiBase {
if ( isset( $settings[ApiBase::PARAM_DFLT] ) ) {
switch ( $settings[ApiBase::PARAM_TYPE] ) {
case 'boolean':
- $item['default'] = ( $settings[ApiBase::PARAM_DFLT] ? 'true' : 'false' );
+ $item['default'] = (bool)$settings[ApiBase::PARAM_DFLT];
break;
case 'string':
+ case 'text':
+ case 'password':
$item['default'] = strval( $settings[ApiBase::PARAM_DFLT] );
break;
case 'integer':
+ case 'limit':
$item['default'] = intval( $settings[ApiBase::PARAM_DFLT] );
break;
+ case 'timestamp':
+ $item['default'] = wfTimestamp( TS_ISO_8601, $settings[ApiBase::PARAM_DFLT] );
+ break;
default:
$item['default'] = $settings[ApiBase::PARAM_DFLT];
break;
@@ -302,9 +326,23 @@ class ApiParamInfo extends ApiBase {
if ( isset( $settings[ApiBase::PARAM_TYPE] ) ) {
if ( $settings[ApiBase::PARAM_TYPE] === 'submodule' ) {
- $item['type'] = $module->getModuleManager()->getNames( $name );
- sort( $item['type'] );
- $item['submodules'] = true;
+ if ( isset( $settings[ApiBase::PARAM_SUBMODULE_MAP] ) ) {
+ ksort( $settings[ApiBase::PARAM_SUBMODULE_MAP] );
+ $item['type'] = array_keys( $settings[ApiBase::PARAM_SUBMODULE_MAP] );
+ $item['submodules'] = $settings[ApiBase::PARAM_SUBMODULE_MAP];
+ } else {
+ $item['type'] = $module->getModuleManager()->getNames( $name );
+ sort( $item['type'] );
+ $prefix = $module->isMain()
+ ? '' : ( $module->getModulePath() . '+' );
+ $item['submodules'] = array();
+ foreach ( $item['type'] as $v ) {
+ $item['submodules'][$v] = $prefix . $v;
+ }
+ }
+ if ( isset( $settings[ApiBase::PARAM_SUBMODULE_PARAM_PREFIX] ) ) {
+ $item['submoduleparamprefix'] = $settings[ApiBase::PARAM_SUBMODULE_PARAM_PREFIX];
+ }
} else {
$item['type'] = $settings[ApiBase::PARAM_TYPE];
}
@@ -323,6 +361,9 @@ class ApiParamInfo extends ApiBase {
if ( isset( $settings[ApiBase::PARAM_MIN] ) ) {
$item['min'] = $settings[ApiBase::PARAM_MIN];
}
+ if ( !empty( $settings[ApiBase::PARAM_RANGE_ENFORCE] ) ) {
+ $item['enforcerange'] = true;
+ }
if ( !empty( $settings[ApiBase::PARAM_HELP_MSG_INFO] ) ) {
$item['info'] = array();
diff --git a/includes/api/ApiParse.php b/includes/api/ApiParse.php
index 1b5e2658..cce85723 100644
--- a/includes/api/ApiParse.php
+++ b/includes/api/ApiParse.php
@@ -71,7 +71,9 @@ class ApiParse extends ApiBase {
if ( isset( $params['section'] ) ) {
$this->section = $params['section'];
if ( !preg_match( '/^((T-)?\d+|new)$/', $this->section ) ) {
- $this->dieUsage( "The section parameter must be a valid section id or 'new'", "invalidsection" );
+ $this->dieUsage(
+ "The section parameter must be a valid section id or 'new'", "invalidsection"
+ );
}
} else {
$this->section = false;
@@ -89,7 +91,10 @@ class ApiParse extends ApiBase {
if ( !is_null( $oldid ) || !is_null( $pageid ) || !is_null( $page ) ) {
if ( $this->section === 'new' ) {
- $this->dieUsage( 'section=new cannot be combined with oldid, pageid or page parameters. Please use text', 'params' );
+ $this->dieUsage(
+ 'section=new cannot be combined with oldid, pageid or page parameters. ' .
+ 'Please use text', 'params'
+ );
}
if ( !is_null( $oldid ) ) {
// Don't use the parser cache
@@ -107,7 +112,10 @@ class ApiParse extends ApiBase {
$popts = $this->makeParserOptions( $pageObj, $params );
// If for some reason the "oldid" is actually the current revision, it may be cached
- if ( $rev->isCurrent() ) {
+ // Deliberately comparing $pageObj->getLatest() with $rev->getId(), rather than
+ // checking $rev->isCurrent(), because $pageObj is what actually ends up being used,
+ // and if its ->getLatest() is outdated, $rev->isCurrent() won't tell us that.
+ if ( $rev->getId() == $pageObj->getLatest() ) {
// May get from/save to parser cache
$p_result = $this->getParsedContent( $pageObj, $popts,
$pageid, isset( $prop['wikitext'] ) );
@@ -161,9 +169,24 @@ class ApiParse extends ApiBase {
$popts = $this->makeParserOptions( $pageObj, $params );
- // Potentially cached
- $p_result = $this->getParsedContent( $pageObj, $popts, $pageid,
- isset( $prop['wikitext'] ) );
+ // Don't pollute the parser cache when setting options that aren't
+ // in ParserOptions::optionsHash()
+ /// @todo: This should be handled closer to the actual cache instead of here, see T110269
+ $suppressCache =
+ $params['disablepp'] ||
+ $params['disablelimitreport'] ||
+ $params['preview'] ||
+ $params['sectionpreview'] ||
+ $params['disabletidy'];
+
+ if ( $suppressCache ) {
+ $this->content = $this->getContent( $pageObj, $pageid );
+ $p_result = $this->content->getParserOutput( $titleObj, null, $popts );
+ } else {
+ // Potentially cached
+ $p_result = $this->getParsedContent( $pageObj, $popts, $pageid,
+ isset( $prop['wikitext'] ) );
+ }
}
} else { // Not $oldid, $pageid, $page. Hence based on $text
$titleObj = Title::newFromText( $title );
@@ -252,6 +275,7 @@ class ApiParse extends ApiBase {
$result_array = array();
$result_array['title'] = $titleObj->getPrefixedText();
+ $result_array['pageid'] = $pageid ? $pageid : $pageObj->getId();
if ( !is_null( $oldid ) ) {
$result_array['revid'] = intval( $oldid );
@@ -347,7 +371,28 @@ class ApiParse extends ApiBase {
$result_array['modules'] = array_values( array_unique( $p_result->getModules() ) );
$result_array['modulescripts'] = array_values( array_unique( $p_result->getModuleScripts() ) );
$result_array['modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
- $result_array['modulemessages'] = array_values( array_unique( $p_result->getModuleMessages() ) );
+ // To be removed in 1.27
+ $result_array['modulemessages'] = array();
+ $this->setWarning( 'modulemessages is deprecated since MediaWiki 1.26' );
+ }
+
+ if ( isset( $prop['jsconfigvars'] ) ) {
+ $result_array['jsconfigvars'] =
+ ApiResult::addMetadataToResultVars( $p_result->getJsConfigVars() );
+ }
+
+ if ( isset( $prop['encodedjsconfigvars'] ) ) {
+ $result_array['encodedjsconfigvars'] = FormatJson::encode(
+ $p_result->getJsConfigVars(), false, FormatJson::ALL_OK
+ );
+ $result_array[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars';
+ }
+
+ if ( isset( $prop['modules'] ) &&
+ !isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
+ $this->setWarning( "Property 'modules' was set but not 'jsconfigvars' " .
+ "or 'encodedjsconfigvars'. Configuration variables are necessary " .
+ "for proper module usage." );
}
if ( isset( $prop['indicators'] ) ) {
@@ -381,9 +426,12 @@ class ApiParse extends ApiBase {
$result_array[ApiResult::META_BC_SUBELEMENTS][] = 'limitreporthtml';
}
- if ( $params['generatexml'] ) {
+ if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
+ if ( !isset( $prop['parsetree'] ) ) {
+ $this->logFeatureUsage( 'action=parse&generatexml' );
+ }
if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
- $this->dieUsage( "generatexml is only supported for wikitext content", "notwikitext" );
+ $this->dieUsage( "parsetree is only supported for wikitext content", "notwikitext" );
}
$wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
@@ -431,10 +479,13 @@ class ApiParse extends ApiBase {
protected function makeParserOptions( WikiPage $pageObj, array $params ) {
$popts = $pageObj->makeParserOptions( $this->getContext() );
- $popts->enableLimitReport( !$params['disablepp'] );
+ $popts->enableLimitReport( !$params['disablepp'] && !$params['disablelimitreport'] );
$popts->setIsPreview( $params['preview'] || $params['sectionpreview'] );
$popts->setIsSectionPreview( $params['sectionpreview'] );
$popts->setEditSection( !$params['disableeditsection'] );
+ if ( $params['disabletidy'] ) {
+ $popts->setTidy( false );
+ }
return $popts;
}
@@ -447,14 +498,9 @@ class ApiParse extends ApiBase {
* @return ParserOutput
*/
private function getParsedContent( WikiPage $page, $popts, $pageId = null, $getWikitext = false ) {
- $this->content = $page->getContent( Revision::RAW ); //XXX: really raw?
+ $this->content = $this->getContent( $page, $pageId );
if ( $this->section !== false && $this->content !== null ) {
- $this->content = $this->getSectionContent(
- $this->content,
- !is_null( $pageId ) ? 'page id ' . $pageId : $page->getTitle()->getPrefixedText()
- );
-
// Not cached (save or load)
return $this->content->getParserOutput( $page->getTitle(), null, $popts );
}
@@ -473,6 +519,27 @@ class ApiParse extends ApiBase {
}
/**
+ * Get the content for the given page and the requested section.
+ *
+ * @param WikiPage $page
+ * @param int $pageId
+ * @return Content
+ */
+ private function getContent( WikiPage $page, $pageId = null ) {
+ $content = $page->getContent( Revision::RAW ); //XXX: really raw?
+
+ if ( $this->section !== false && $content !== null ) {
+ $content = $this->getSectionContent(
+ $content,
+ !is_null( $pageId ) ? 'page id ' . $pageId : $page->getTitle()->getPrefixedText()
+ );
+ }
+ return $content;
+ }
+
+ /**
+ * Extract the requested section from the given Content
+ *
* @param Content $content
* @param string $what Identifies the content in error messages, e.g. page title.
* @return Content|bool
@@ -504,12 +571,13 @@ class ApiParse extends ApiBase {
$sectionTitle = !is_null( $params['sectiontitle'] ) ? $params['sectiontitle'] : '';
if ( $this->section === 'new' && ( $sectionTitle === '' || $summary === '' ) ) {
- if( $sectionTitle !== '' ) {
+ if ( $sectionTitle !== '' ) {
$summary = $params['sectiontitle'];
}
if ( $summary !== '' ) {
- $summary = wfMessage( 'newsectionsummary' )->rawParams( $wgParser->stripSectionName( $summary ) )
- ->inContentLanguage()->text();
+ $summary = wfMessage( 'newsectionsummary' )
+ ->rawParams( $wgParser->stripSectionName( $summary ) )
+ ->inContentLanguage()->text();
}
}
return Linker::formatComment( $summary, $title, $this->section === 'new' );
@@ -676,7 +744,9 @@ class ApiParse extends ApiBase {
public function getAllowedParams() {
return array(
'title' => null,
- 'text' => null,
+ 'text' => array(
+ ApiBase::PARAM_TYPE => 'text',
+ ),
'summary' => null,
'page' => null,
'pageid' => array(
@@ -705,13 +775,19 @@ class ApiParse extends ApiBase {
'headitems',
'headhtml',
'modules',
+ 'jsconfigvars',
+ 'encodedjsconfigvars',
'indicators',
'iwlinks',
'wikitext',
'properties',
'limitreportdata',
'limitreporthtml',
- )
+ 'parsetree',
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(
+ 'parsetree' => array( 'apihelp-parse-paramvalue-prop-parsetree', CONTENT_MODEL_WIKITEXT ),
+ ),
),
'pst' => false,
'onlypst' => false,
@@ -720,13 +796,19 @@ class ApiParse extends ApiBase {
'sectiontitle' => array(
ApiBase::PARAM_TYPE => 'string',
),
- 'disablepp' => false,
+ 'disablepp' => array(
+ ApiBase::PARAM_DFLT => false,
+ ApiBase::PARAM_DEPRECATED => true,
+ ),
+ 'disablelimitreport' => false,
'disableeditsection' => false,
+ 'disabletidy' => false,
'generatexml' => array(
ApiBase::PARAM_DFLT => false,
ApiBase::PARAM_HELP_MSG => array(
'apihelp-parse-param-generatexml', CONTENT_MODEL_WIKITEXT
),
+ ApiBase::PARAM_DEPRECATED => true,
),
'preview' => false,
'sectionpreview' => false,
diff --git a/includes/api/ApiProtect.php b/includes/api/ApiProtect.php
index ad028375..c07aaca4 100644
--- a/includes/api/ApiProtect.php
+++ b/includes/api/ApiProtect.php
@@ -29,6 +29,8 @@
*/
class ApiProtect extends ApiBase {
public function execute() {
+ global $wgContLang;
+
$params = $this->extractRequestParams();
$pageObj = $this->getTitleOrPageId( $params, 'fromdbmaster' );
@@ -78,7 +80,7 @@ class ApiProtect extends ApiBase {
}
if ( wfIsInfinity( $expiry[$i] ) ) {
- $expiryarray[$p[0]] = $db->getInfinity();
+ $expiryarray[$p[0]] = 'infinity';
} else {
$exp = strtotime( $expiry[$i] );
if ( $exp < 0 || !$exp ) {
@@ -93,10 +95,7 @@ class ApiProtect extends ApiBase {
}
$resultProtections[] = array(
$p[0] => $protections[$p[0]],
- 'expiry' => ( $expiryarray[$p[0]] == $db->getInfinity()
- ? 'infinite'
- : wfTimestamp( TS_ISO_8601, $expiryarray[$p[0]] )
- )
+ 'expiry' => $wgContLang->formatExpiry( $expiryarray[$p[0]], TS_ISO_8601, 'infinite' ),
);
}
diff --git a/includes/api/ApiQuery.php b/includes/api/ApiQuery.php
index bfe32052..5378e925 100644
--- a/includes/api/ApiQuery.php
+++ b/includes/api/ApiQuery.php
@@ -292,7 +292,7 @@ class ApiQuery extends ApiBase {
// Write the continuation data into the result
$this->setContinuationManager( null );
- if ( $this->mParams['continue'] === null ) {
+ if ( $this->mParams['rawcontinue'] ) {
$data = $continuationManager->getRawContinuation();
if ( $data ) {
$this->getResult()->addValue( null, 'query-continue', $data,
@@ -302,15 +302,14 @@ class ApiQuery extends ApiBase {
$continuationManager->setContinuationIntoResult( $this->getResult() );
}
+ /// @todo: Remove this after a suitable period of time. When REL1_26 is cut, if not before.
if ( $this->mParams['continue'] === null && !$this->mParams['rawcontinue'] &&
- $this->getResult()->getResultData( 'query-continue' ) !== null
+ $this->getResult()->getResultData( 'continue' ) !== null
) {
- $this->logFeatureUsage( 'action=query&!rawcontinue&!continue' );
$this->setWarning(
- 'Formatting of continuation data will be changing soon. ' .
- 'To continue using the current formatting, use the \'rawcontinue\' parameter. ' .
- 'To begin using the new format, pass an empty string for \'continue\' ' .
- 'in the initial query.'
+ 'Formatting of continuation data has changed. ' .
+ 'To receive raw query-continue data, use the \'rawcontinue\' parameter. ' .
+ 'To silence this warning, pass an empty string for \'continue\' in the initial query.'
);
}
}
@@ -407,8 +406,8 @@ class ApiQuery extends ApiBase {
$pages[$fakeId] = $vals;
}
// Report any invalid titles
- foreach ( $pageSet->getInvalidTitles() as $fakeId => $title ) {
- $pages[$fakeId] = array( 'title' => $title, 'invalid' => true );
+ foreach ( $pageSet->getInvalidTitlesAndReasons() as $fakeId => $data ) {
+ $pages[$fakeId] = $data + array( 'invalid' => true );
}
// Report any missing page ids
foreach ( $pageSet->getMissingPageIDs() as $pageid ) {
@@ -485,7 +484,7 @@ class ApiQuery extends ApiBase {
public function setGeneratorContinue( $module, $paramName, $paramValue ) {
wfDeprecated( __METHOD__, '1.24' );
$this->getContinuationManager()->addGeneratorContinueParam( $module, $paramName, $paramValue );
- return $this->getParameter( 'continue' ) !== null;
+ return !$this->getParameter( 'rawcontinue' );
}
/**
@@ -549,7 +548,9 @@ class ApiQuery extends ApiBase {
'export' => false,
'exportnowrap' => false,
'iwurl' => false,
- 'continue' => null,
+ 'continue' => array(
+ ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
+ ),
'rawcontinue' => false,
);
if ( $flags ) {
diff --git a/includes/api/ApiQueryAllCategories.php b/includes/api/ApiQueryAllCategories.php
index cc0b71af..0711c902 100644
--- a/includes/api/ApiQueryAllCategories.php
+++ b/includes/api/ApiQueryAllCategories.php
@@ -186,7 +186,8 @@ class ApiQueryAllCategories extends ApiQueryGeneratorBase {
'prop' => array(
ApiBase::PARAM_TYPE => array( 'size', 'hidden' ),
ApiBase::PARAM_DFLT => '',
- ApiBase::PARAM_ISMULTI => true
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
);
}
diff --git a/includes/api/ApiQueryAllDeletedRevisions.php b/includes/api/ApiQueryAllDeletedRevisions.php
index 4e4d2af7..172ee999 100644
--- a/includes/api/ApiQueryAllDeletedRevisions.php
+++ b/includes/api/ApiQueryAllDeletedRevisions.php
@@ -55,7 +55,6 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
$result = $this->getResult();
$pageSet = $this->getPageSet();
- $titles = $pageSet->getTitles();
// This module operates in two modes:
// 'user': List deleted revs by a certain user
@@ -83,6 +82,21 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
}
}
+ // If we're generating titles only, we can use DISTINCT for a better
+ // query. But we can't do that in 'user' mode (wrong index), and we can
+ // only do it when sorting ASC (because MySQL apparently can't use an
+ // index backwards for grouping even though it can for ORDER BY, WTF?)
+ $dir = $params['dir'];
+ $optimizeGenerateTitles = false;
+ if ( $mode === 'all' && $params['generatetitles'] && $resultPageSet !== null ) {
+ if ( $dir === 'newer' ) {
+ $optimizeGenerateTitles = true;
+ } else {
+ $p = $this->getModulePrefix();
+ $this->setWarning( "For better performance when generating titles, set {$p}dir=newer" );
+ }
+ }
+
$this->addTables( 'archive' );
if ( $resultPageSet === null ) {
$this->parseParameters( $params );
@@ -90,7 +104,12 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
$this->addFields( array( 'ar_title', 'ar_namespace' ) );
} else {
$this->limit = $this->getParameter( 'limit' ) ?: 10;
- $this->addFields( array( 'ar_title', 'ar_namespace', 'ar_timestamp', 'ar_rev_id', 'ar_id' ) );
+ $this->addFields( array( 'ar_title', 'ar_namespace' ) );
+ if ( $optimizeGenerateTitles ) {
+ $this->addOption( 'DISTINCT' );
+ } else {
+ $this->addFields( array( 'ar_timestamp', 'ar_rev_id', 'ar_id' ) );
+ }
}
if ( $this->fld_tags ) {
@@ -130,7 +149,6 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
}
}
- $dir = $params['dir'];
$miser_ns = null;
if ( $mode == 'all' ) {
@@ -229,7 +247,14 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
if ( !is_null( $params['continue'] ) ) {
$cont = explode( '|', $params['continue'] );
$op = ( $dir == 'newer' ? '>' : '<' );
- if ( $mode == 'all' ) {
+ if ( $optimizeGenerateTitles ) {
+ $this->dieContinueUsageIf( count( $cont ) != 2 );
+ $ns = intval( $cont[0] );
+ $this->dieContinueUsageIf( strval( $ns ) !== $cont[0] );
+ $title = $db->addQuotes( $cont[1] );
+ $this->addWhere( "ar_namespace $op $ns OR " .
+ "(ar_namespace = $ns AND ar_title $op= $title)" );
+ } elseif ( $mode == 'all' ) {
$this->dieContinueUsageIf( count( $cont ) != 4 );
$ns = intval( $cont[0] );
$this->dieContinueUsageIf( strval( $ns ) !== $cont[0] );
@@ -259,7 +284,13 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
$sort = ( $dir == 'newer' ? '' : ' DESC' );
$orderby = array();
- if ( $mode == 'all' ) {
+ if ( $optimizeGenerateTitles ) {
+ // Targeting index name_title_timestamp
+ if ( $params['namespace'] === null || count( array_unique( $params['namespace'] ) ) > 1 ) {
+ $orderby[] = "ar_namespace $sort";
+ }
+ $orderby[] = "ar_title $sort";
+ } elseif ( $mode == 'all' ) {
// Targeting index name_title_timestamp
if ( $params['namespace'] === null || count( array_unique( $params['namespace'] ) ) > 1 ) {
$orderby[] = "ar_namespace $sort";
@@ -283,7 +314,9 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
foreach ( $res as $row ) {
if ( ++$count > $this->limit ) {
// We've had enough
- if ( $mode == 'all' ) {
+ if ( $optimizeGenerateTitles ) {
+ $this->setContinueEnumParameter( 'continue', "$row->ar_namespace|$row->ar_title" );
+ } elseif ( $mode == 'all' ) {
$this->setContinueEnumParameter( 'continue',
"$row->ar_namespace|$row->ar_title|$row->ar_timestamp|$row->ar_id"
);
diff --git a/includes/api/ApiQueryAllLinks.php b/includes/api/ApiQueryAllLinks.php
index fadecfb4..347da896 100644
--- a/includes/api/ApiQueryAllLinks.php
+++ b/includes/api/ApiQueryAllLinks.php
@@ -255,6 +255,7 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
ApiBase::PARAM_TYPE => array_merge(
array( 'ids', 'title' ), array_keys( $this->props )
),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'namespace' => array(
ApiBase::PARAM_DFLT => $this->dfltNamespace,
diff --git a/includes/api/ApiQueryAllMessages.php b/includes/api/ApiQueryAllMessages.php
index 44af83d0..152711f8 100644
--- a/includes/api/ApiQueryAllMessages.php
+++ b/includes/api/ApiQueryAllMessages.php
@@ -136,7 +136,11 @@ class ApiQueryAllMessages extends ApiQueryBase {
}
if ( !$skip ) {
- $a = array( 'name' => $message );
+ $a = array(
+ 'name' => $message,
+ 'normalizedname' => MessageCache::normalizeKey( $message ),
+ );
+
$args = array();
if ( isset( $params['args'] ) && count( $params['args'] ) != 0 ) {
$args = $params['args'];
@@ -245,6 +249,6 @@ class ApiQueryAllMessages extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Meta#allmessages_.2F_am';
+ return 'https://www.mediawiki.org/wiki/API:Allmessages';
}
}
diff --git a/includes/api/ApiQueryAllPages.php b/includes/api/ApiQueryAllPages.php
index 0149ad2f..e441991a 100644
--- a/includes/api/ApiQueryAllPages.php
+++ b/includes/api/ApiQueryAllPages.php
@@ -175,10 +175,14 @@ class ApiQueryAllPages extends ApiQueryGeneratorBase {
// 1999 rules works fine, but that breaks other DBs. Sigh.
/// @todo Once we drop support for 1992-rule DBs, we can simplify this.
$dbType = $db->getType();
- if ( $dbType === 'mysql' || $dbType === 'sqlite' ||
- $dbType === 'postgres' && $db->getServerVersion() >= 9.1
- ) {
- // 1999 rules, or screw-the-rules
+ if ( $dbType === 'mysql' || $dbType === 'sqlite' ) {
+ // Ignore the rules, or 1999 rules if you count unique keys
+ // over non-NULL columns as satisfying the requirement for
+ // "functional dependency" and don't require including
+ // constant-in-WHERE columns in the GROUP BY.
+ $this->addOption( 'GROUP BY', array( 'page_title' ) );
+ } elseif ( $dbType === 'postgres' && $db->getServerVersion() >= 9.1 ) {
+ // 1999 rules only counting primary keys
$this->addOption( 'GROUP BY', array( 'page_title', 'page_id' ) );
} else {
// 1992 rules
diff --git a/includes/api/ApiQueryAllUsers.php b/includes/api/ApiQueryAllUsers.php
index 0cea84f8..eb3e5537 100644
--- a/includes/api/ApiQueryAllUsers.php
+++ b/includes/api/ApiQueryAllUsers.php
@@ -41,7 +41,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
* @return string
*/
private function getCanonicalUserName( $name ) {
- return str_replace( '_', ' ', $name );
+ return strtr( $name, '_', ' ' );
}
public function execute() {
@@ -235,14 +235,14 @@ class ApiQueryAllUsers extends ApiQueryBase {
}
$data = array(
- 'userid' => $row->user_id,
+ 'userid' => (int)$row->user_id,
'name' => $row->user_name,
);
if ( $fld_blockinfo && !is_null( $row->ipb_by_text ) ) {
- $data['blockid'] = $row->ipb_id;
+ $data['blockid'] = (int)$row->ipb_id;
$data['blockedby'] = $row->ipb_by_text;
- $data['blockedbyid'] = $row->ipb_by;
+ $data['blockedbyid'] = (int)$row->ipb_by;
$data['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $row->ipb_timestamp );
$data['blockreason'] = $row->ipb_reason;
$data['blockexpiry'] = $row->ipb_expiry;
@@ -340,7 +340,8 @@ class ApiQueryAllUsers extends ApiQueryBase {
'rights',
'editcount',
'registration'
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'limit' => array(
ApiBase::PARAM_DFLT => 10,
diff --git a/includes/api/ApiQueryBacklinksprop.php b/includes/api/ApiQueryBacklinksprop.php
index 8e271e7b..a50d58b2 100644
--- a/includes/api/ApiQueryBacklinksprop.php
+++ b/includes/api/ApiQueryBacklinksprop.php
@@ -277,7 +277,7 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
$vals = array();
if ( $fld_pageid ) {
- $vals['pageid'] = $row->page_id;
+ $vals['pageid'] = (int)$row->page_id;
}
if ( $fld_title ) {
ApiQueryBase::addTitleInfo( $vals,
@@ -335,6 +335,7 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
),
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_DFLT => 'pageid|title',
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'namespace' => array(
ApiBase::PARAM_ISMULTI => true,
@@ -405,8 +406,7 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
}
public function getHelpUrls() {
- $name = $this->getModuleName();
- $prefix = $this->getModulePrefix();
- return "https://www.mediawiki.org/wiki/API:Properties#{$name}_.2F_{$prefix}";
+ $name = ucfirst( $this->getModuleName() );
+ return "https://www.mediawiki.org/wiki/API:{$name}";
}
}
diff --git a/includes/api/ApiQueryBase.php b/includes/api/ApiQueryBase.php
index a15754ce..c66e21b7 100644
--- a/includes/api/ApiQueryBase.php
+++ b/includes/api/ApiQueryBase.php
@@ -123,6 +123,7 @@ abstract class ApiQueryBase extends ApiBase {
*/
public function selectNamedDB( $name, $db, $groups ) {
$this->mDb = $this->getQuery()->getNamedDB( $name, $db, $groups );
+ return $this->mDb;
}
/**
@@ -503,7 +504,7 @@ abstract class ApiQueryBase extends ApiBase {
* capitalization settings.
*
* @param string $titlePart Title part
- * @param int $defaultNamespace Namespace of the title
+ * @param int $namespace Namespace of the title
* @return string DBkey (no namespace prefix)
*/
public function titlePartToKey( $titlePart, $namespace = NS_MAIN ) {
@@ -525,6 +526,24 @@ abstract class ApiQueryBase extends ApiBase {
}
/**
+ * Convert an input title or title prefix into a namespace constant and dbkey.
+ *
+ * @since 1.26
+ * @param string $titlePart Title part
+ * @param int $defaultNamespace Default namespace if none is given
+ * @return array (int, string) Namespace number and DBkey
+ */
+ public function prefixedTitlePartToKey( $titlePart, $defaultNamespace = NS_MAIN ) {
+ $t = Title::newFromText( $titlePart . 'x', $defaultNamespace );
+ if ( !$t || $t->hasFragment() || $t->isExternal() ) {
+ // Invalid title (e.g. bad chars) or contained a '#'.
+ $this->dieUsageMsg( array( 'invalidtitle', $titlePart ) );
+ }
+
+ return array( $t->getNamespace(), substr( $t->getDbKey(), 0, -1 ) );
+ }
+
+ /**
* Gets the personalised direction parameter description
*
* @param string $p ModulePrefix
diff --git a/includes/api/ApiQueryBlocks.php b/includes/api/ApiQueryBlocks.php
index 4a7023b7..d004020d 100644
--- a/includes/api/ApiQueryBlocks.php
+++ b/includes/api/ApiQueryBlocks.php
@@ -191,19 +191,19 @@ class ApiQueryBlocks extends ApiQueryBase {
ApiResult::META_TYPE => 'assoc',
);
if ( $fld_id ) {
- $block['id'] = $row->ipb_id;
+ $block['id'] = (int)$row->ipb_id;
}
if ( $fld_user && !$row->ipb_auto ) {
$block['user'] = $row->ipb_address;
}
if ( $fld_userid && !$row->ipb_auto ) {
- $block['userid'] = $row->ipb_user;
+ $block['userid'] = (int)$row->ipb_user;
}
if ( $fld_by ) {
$block['by'] = $row->ipb_by_text;
}
if ( $fld_byid ) {
- $block['byid'] = $row->ipb_by;
+ $block['byid'] = (int)$row->ipb_by;
}
if ( $fld_timestamp ) {
$block['timestamp'] = wfTimestamp( TS_ISO_8601, $row->ipb_timestamp );
@@ -303,7 +303,8 @@ class ApiQueryBlocks extends ApiQueryBase {
'range',
'flags'
),
- ApiBase::PARAM_ISMULTI => true
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'show' => array(
ApiBase::PARAM_TYPE => array(
diff --git a/includes/api/ApiQueryCategories.php b/includes/api/ApiQueryCategories.php
index 35fa56ef..9e82fe7e 100644
--- a/includes/api/ApiQueryCategories.php
+++ b/includes/api/ApiQueryCategories.php
@@ -184,7 +184,8 @@ class ApiQueryCategories extends ApiQueryGeneratorBase {
'sortkey',
'timestamp',
'hidden',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'show' => array(
ApiBase::PARAM_ISMULTI => true,
@@ -226,6 +227,6 @@ class ApiQueryCategories extends ApiQueryGeneratorBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#categories_.2F_cl';
+ return 'https://www.mediawiki.org/wiki/API:Categories';
}
}
diff --git a/includes/api/ApiQueryCategoryInfo.php b/includes/api/ApiQueryCategoryInfo.php
index 9f6c6044..9266442e 100644
--- a/includes/api/ApiQueryCategoryInfo.php
+++ b/includes/api/ApiQueryCategoryInfo.php
@@ -115,6 +115,6 @@ class ApiQueryCategoryInfo extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#categoryinfo_.2F_ci';
+ return 'https://www.mediawiki.org/wiki/API:Categoryinfo';
}
}
diff --git a/includes/api/ApiQueryCategoryMembers.php b/includes/api/ApiQueryCategoryMembers.php
index ec0c1d14..6dcfe0eb 100644
--- a/includes/api/ApiQueryCategoryMembers.php
+++ b/includes/api/ApiQueryCategoryMembers.php
@@ -158,7 +158,9 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
}
$startsortkey = pack( 'H*', $params['starthexsortkey'] );
} else {
- $this->logFeatureUsage( 'list=categorymembers&cmstartsortkey' );
+ if ( $params['startsortkey'] !== null ) {
+ $this->logFeatureUsage( 'list=categorymembers&cmstartsortkey' );
+ }
$startsortkey = $params['startsortkey'];
}
if ( $params['endsortkeyprefix'] !== null ) {
@@ -169,7 +171,9 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
}
$endsortkey = pack( 'H*', $params['endhexsortkey'] );
} else {
- $this->logFeatureUsage( 'list=categorymembers&cmendsortkey' );
+ if ( $params['endsortkey'] !== null ) {
+ $this->logFeatureUsage( 'list=categorymembers&cmendsortkey' );
+ }
$endsortkey = $params['endsortkey'];
}
@@ -310,7 +314,8 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
'sortkeyprefix',
'type',
'timestamp',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'namespace' => array(
ApiBase::PARAM_ISMULTI => true,
diff --git a/includes/api/ApiQueryContributors.php b/includes/api/ApiQueryContributors.php
index 7e76db25..524bffd4 100644
--- a/includes/api/ApiQueryContributors.php
+++ b/includes/api/ApiQueryContributors.php
@@ -89,7 +89,7 @@ class ApiQueryContributors extends ApiQueryBase {
$res = $this->select( __METHOD__ );
foreach ( $res as $row ) {
$fit = $result->addValue( array( 'query', 'pages', $row->page ),
- 'anoncontributors', $row->anons
+ 'anoncontributors', (int)$row->anons
);
if ( !$fit ) {
// This not fitting isn't reasonable, so it probably means that
@@ -189,7 +189,7 @@ class ApiQueryContributors extends ApiQueryBase {
}
$fit = $this->addPageSubItem( $row->page,
- array( 'userid' => $row->user, 'name' => $row->username ),
+ array( 'userid' => (int)$row->user, 'name' => $row->username ),
'user'
);
if ( !$fit ) {
@@ -250,6 +250,6 @@ class ApiQueryContributors extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#contributors_.2F_pc';
+ return 'https://www.mediawiki.org/wiki/API:Contributors';
}
}
diff --git a/includes/api/ApiQueryDeletedRevisions.php b/includes/api/ApiQueryDeletedRevisions.php
index 26ae2668..bf48b194 100644
--- a/includes/api/ApiQueryDeletedRevisions.php
+++ b/includes/api/ApiQueryDeletedRevisions.php
@@ -234,8 +234,10 @@ class ApiQueryDeletedRevisions extends ApiQueryRevisionsBase {
}
}
if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) {
- ApiBase::dieDebug( "Found row in archive (ar_id={$row->ar_id}) that didn't " .
- "get processed by ApiPageSet" );
+ ApiBase::dieDebug(
+ __METHOD__,
+ "Found row in archive (ar_id={$row->ar_id}) that didn't get processed by ApiPageSet"
+ );
}
$fit = $this->addPageSubItem(
@@ -299,6 +301,6 @@ class ApiQueryDeletedRevisions extends ApiQueryRevisionsBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#deletedrevisions_.2F_drv';
+ return 'https://www.mediawiki.org/wiki/API:Deletedrevisions';
}
}
diff --git a/includes/api/ApiQueryDeletedrevs.php b/includes/api/ApiQueryDeletedrevs.php
index 72a331f1..76f594e2 100644
--- a/includes/api/ApiQueryDeletedrevs.php
+++ b/includes/api/ApiQueryDeletedrevs.php
@@ -328,7 +328,7 @@ class ApiQueryDeletedrevs extends ApiQueryBase {
$rev['user'] = $row->ar_user_text;
}
if ( $fld_userid ) {
- $rev['userid'] = $row->ar_user;
+ $rev['userid'] = (int)$row->ar_user;
}
}
}
diff --git a/includes/api/ApiQueryDuplicateFiles.php b/includes/api/ApiQueryDuplicateFiles.php
index 4d0bcfed..3282c717 100644
--- a/includes/api/ApiQueryDuplicateFiles.php
+++ b/includes/api/ApiQueryDuplicateFiles.php
@@ -189,6 +189,6 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#duplicatefiles_.2F_df';
+ return 'https://www.mediawiki.org/wiki/API:Duplicatefiles';
}
}
diff --git a/includes/api/ApiQueryExtLinksUsage.php b/includes/api/ApiQueryExtLinksUsage.php
index 3f65a19e..38eba12c 100644
--- a/includes/api/ApiQueryExtLinksUsage.php
+++ b/includes/api/ApiQueryExtLinksUsage.php
@@ -155,7 +155,8 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
'ids',
'title',
'url'
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'offset' => array(
ApiBase::PARAM_TYPE => 'integer',
diff --git a/includes/api/ApiQueryExternalLinks.php b/includes/api/ApiQueryExternalLinks.php
index ec3d9d27..725ac88b 100644
--- a/includes/api/ApiQueryExternalLinks.php
+++ b/includes/api/ApiQueryExternalLinks.php
@@ -134,6 +134,6 @@ class ApiQueryExternalLinks extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#extlinks_.2F_el';
+ return 'https://www.mediawiki.org/wiki/API:Extlinks';
}
}
diff --git a/includes/api/ApiQueryFileRepoInfo.php b/includes/api/ApiQueryFileRepoInfo.php
index 9ad7e27e..12b9893d 100644
--- a/includes/api/ApiQueryFileRepoInfo.php
+++ b/includes/api/ApiQueryFileRepoInfo.php
@@ -41,18 +41,26 @@ class ApiQueryFileRepoInfo extends ApiQueryBase {
}
public function execute() {
+ $conf = $this->getConfig();
+
$params = $this->extractRequestParams();
$props = array_flip( $params['prop'] );
$repos = array();
$repoGroup = $this->getInitialisedRepoGroup();
+ $foreignTargets = $conf->get( 'ForeignUploadTargets' );
+
+ $repoGroup->forEachForeignRepo( function ( $repo ) use ( &$repos, $props, $foreignTargets ) {
+ $repoProps = $repo->getInfo();
+ $repoProps['canUpload'] = in_array( $repoProps['name'], $foreignTargets );
- $repoGroup->forEachForeignRepo( function ( $repo ) use ( &$repos, $props ) {
- $repos[] = array_intersect_key( $repo->getInfo(), $props );
+ $repos[] = array_intersect_key( $repoProps, $props );
} );
- $repos[] = array_intersect_key( $repoGroup->getLocalRepo()->getInfo(), $props );
+ $localInfo = $repoGroup->getLocalRepo()->getInfo();
+ $localInfo['canUpload'] = $conf->get( 'EnableUploads' );
+ $repos[] = array_intersect_key( $localInfo, $props );
$result = $this->getResult();
ApiResult::setIndexedTagName( $repos, 'repo' );
@@ -85,10 +93,14 @@ class ApiQueryFileRepoInfo extends ApiQueryBase {
$props = array_merge( $props, array_keys( $repo->getInfo() ) );
} );
- return array_values( array_unique( array_merge(
+ $propValues = array_values( array_unique( array_merge(
$props,
array_keys( $repoGroup->getLocalRepo()->getInfo() )
) ) );
+
+ $propValues[] = 'canUpload';
+
+ return $propValues;
}
protected function getExamplesMessages() {
@@ -97,4 +109,8 @@ class ApiQueryFileRepoInfo extends ApiQueryBase {
=> 'apihelp-query+filerepoinfo-example-simple',
);
}
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Filerepoinfo';
+ }
}
diff --git a/includes/api/ApiQueryFilearchive.php b/includes/api/ApiQueryFilearchive.php
index 4d357a7f..8156edb9 100644
--- a/includes/api/ApiQueryFilearchive.php
+++ b/includes/api/ApiQueryFilearchive.php
@@ -162,7 +162,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
}
$file = array();
- $file['id'] = $row->fa_id;
+ $file['id'] = (int)$row->fa_id;
$file['name'] = $row->fa_name;
$title = Title::makeTitle( NS_FILE, $row->fa_name );
self::addTitleInfo( $file, $title );
@@ -179,7 +179,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
if ( $fld_user &&
Revision::userCanBitfield( $row->fa_deleted, File::DELETED_USER, $user )
) {
- $file['userid'] = $row->fa_user;
+ $file['userid'] = (int)$row->fa_user;
$file['user'] = $row->fa_user_text;
}
if ( $fld_sha1 ) {
@@ -274,6 +274,7 @@ class ApiQueryFilearchive extends ApiQueryBase {
'bitdepth',
'archivename',
),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'limit' => array(
ApiBase::PARAM_DFLT => 10,
diff --git a/includes/api/ApiQueryIWBacklinks.php b/includes/api/ApiQueryIWBacklinks.php
index 618387d2..2fe4bd91 100644
--- a/includes/api/ApiQueryIWBacklinks.php
+++ b/includes/api/ApiQueryIWBacklinks.php
@@ -186,6 +186,7 @@ class ApiQueryIWBacklinks extends ApiQueryGeneratorBase {
'iwprefix',
'iwtitle',
),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'dir' => array(
ApiBase::PARAM_DFLT => 'ascending',
diff --git a/includes/api/ApiQueryIWLinks.php b/includes/api/ApiQueryIWLinks.php
index aca3f700..82619cc4 100644
--- a/includes/api/ApiQueryIWLinks.php
+++ b/includes/api/ApiQueryIWLinks.php
@@ -151,7 +151,8 @@ class ApiQueryIWLinks extends ApiQueryBase {
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_TYPE => array(
'url',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'prefix' => null,
'title' => null,
diff --git a/includes/api/ApiQueryImageInfo.php b/includes/api/ApiQueryImageInfo.php
index 095e5dda..ba36c67f 100644
--- a/includes/api/ApiQueryImageInfo.php
+++ b/includes/api/ApiQueryImageInfo.php
@@ -523,9 +523,9 @@ class ApiQueryImageInfo extends ApiQueryBase {
}
if ( $meta ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$metadata = unserialize( $file->getMetadata() );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $metadata && $version !== 'latest' ) {
$metadata = $file->convertMetadataVersion( $metadata, $version );
}
@@ -798,6 +798,6 @@ class ApiQueryImageInfo extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#imageinfo_.2F_ii';
+ return 'https://www.mediawiki.org/wiki/API:Imageinfo';
}
}
diff --git a/includes/api/ApiQueryImages.php b/includes/api/ApiQueryImages.php
index 029d945d..1b39d282 100644
--- a/includes/api/ApiQueryImages.php
+++ b/includes/api/ApiQueryImages.php
@@ -172,6 +172,6 @@ class ApiQueryImages extends ApiQueryGeneratorBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#images_.2F_im';
+ return 'https://www.mediawiki.org/wiki/API:Images';
}
}
diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php
index 66178d4f..b05c75c3 100644
--- a/includes/api/ApiQueryInfo.php
+++ b/includes/api/ApiQueryInfo.php
@@ -37,7 +37,7 @@ class ApiQueryInfo extends ApiQueryBase {
$fld_notificationtimestamp = false,
$fld_preload = false, $fld_displaytitle = false;
- private $params, $titles, $missing, $everything, $pageCounter;
+ private $params, $titles, $missing, $everything;
private $pageRestrictions, $pageIsRedir, $pageIsNew, $pageTouched,
$pageLatest, $pageLength;
@@ -799,6 +799,7 @@ class ApiQueryInfo extends ApiQueryBase {
}
public function getCacheMode( $params ) {
+ // Other props depend on something about the current user
$publicProps = array(
'protection',
'talkid',
@@ -807,13 +808,15 @@ class ApiQueryInfo extends ApiQueryBase {
'preload',
'displaytitle',
);
- if ( !is_null( $params['prop'] ) ) {
- foreach ( $params['prop'] as $prop ) {
- if ( !in_array( $prop, $publicProps ) ) {
- return 'private';
- }
- }
+ if ( array_diff( (array)$params['prop'], $publicProps ) ) {
+ return 'private';
}
+
+ // testactions also depends on the current user
+ if ( $params['testactions'] ) {
+ return 'private';
+ }
+
if ( !is_null( $params['token'] ) ) {
return 'private';
}
@@ -868,6 +871,6 @@ class ApiQueryInfo extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#info_.2F_in';
+ return 'https://www.mediawiki.org/wiki/API:Info';
}
}
diff --git a/includes/api/ApiQueryLangBacklinks.php b/includes/api/ApiQueryLangBacklinks.php
index 7be18b2f..9f77b84a 100644
--- a/includes/api/ApiQueryLangBacklinks.php
+++ b/includes/api/ApiQueryLangBacklinks.php
@@ -185,6 +185,7 @@ class ApiQueryLangBacklinks extends ApiQueryGeneratorBase {
'lllang',
'lltitle',
),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'dir' => array(
ApiBase::PARAM_DFLT => 'ascending',
diff --git a/includes/api/ApiQueryLangLinks.php b/includes/api/ApiQueryLangLinks.php
index 5919ee97..25e534e1 100644
--- a/includes/api/ApiQueryLangLinks.php
+++ b/includes/api/ApiQueryLangLinks.php
@@ -146,7 +146,8 @@ class ApiQueryLangLinks extends ApiQueryBase {
'url',
'langname',
'autonym',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'lang' => null,
'title' => null,
@@ -183,6 +184,6 @@ class ApiQueryLangLinks extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#langlinks_.2F_ll';
+ return 'https://www.mediawiki.org/wiki/API:Langlinks';
}
}
diff --git a/includes/api/ApiQueryLinks.php b/includes/api/ApiQueryLinks.php
index 3bd37144..d7b85c93 100644
--- a/includes/api/ApiQueryLinks.php
+++ b/includes/api/ApiQueryLinks.php
@@ -42,13 +42,13 @@ class ApiQueryLinks extends ApiQueryGeneratorBase {
$this->table = 'pagelinks';
$this->prefix = 'pl';
$this->titlesParam = 'titles';
- $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Properties#links_.2F_pl';
+ $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Links';
break;
case self::TEMPLATES:
$this->table = 'templatelinks';
$this->prefix = 'tl';
$this->titlesParam = 'templates';
- $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Properties#templates_.2F_tl';
+ $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Templates';
break;
default:
ApiBase::dieDebug( __METHOD__, 'Unknown module name' );
diff --git a/includes/api/ApiQueryLogEvents.php b/includes/api/ApiQueryLogEvents.php
index 7b2381f4..d87ad1e3 100644
--- a/includes/api/ApiQueryLogEvents.php
+++ b/includes/api/ApiQueryLogEvents.php
@@ -401,7 +401,8 @@ class ApiQueryLogEvents extends ApiQueryBase {
'parsedcomment',
'details',
'tags'
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'type' => array(
ApiBase::PARAM_TYPE => $config->get( 'LogTypes' )
diff --git a/includes/api/ApiQueryPageProps.php b/includes/api/ApiQueryPageProps.php
index dd19bf23..1f992f8f 100644
--- a/includes/api/ApiQueryPageProps.php
+++ b/includes/api/ApiQueryPageProps.php
@@ -137,12 +137,12 @@ class ApiQueryPageProps extends ApiQueryBase {
protected function getExamplesMessages() {
return array(
- 'action=query&prop=pageprops&titles=Category:Foo'
+ 'action=query&prop=pageprops&titles=Main%20Page|MediaWiki'
=> 'apihelp-query+pageprops-example-simple',
);
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#pageprops_.2F_pp';
+ return 'https://www.mediawiki.org/wiki/API:Pageprops';
}
}
diff --git a/includes/api/ApiQueryPagesWithProp.php b/includes/api/ApiQueryPagesWithProp.php
index 7bcaf247..ad641a46 100644
--- a/includes/api/ApiQueryPagesWithProp.php
+++ b/includes/api/ApiQueryPagesWithProp.php
@@ -140,7 +140,8 @@ class ApiQueryPagesWithProp extends ApiQueryGeneratorBase {
'ids',
'title',
'value',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'continue' => array(
ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
diff --git a/includes/api/ApiQueryProtectedTitles.php b/includes/api/ApiQueryProtectedTitles.php
index fb65e5e2..5ef2f70b 100644
--- a/includes/api/ApiQueryProtectedTitles.php
+++ b/includes/api/ApiQueryProtectedTitles.php
@@ -123,7 +123,7 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
}
if ( isset( $prop['userid'] ) || /*B/C*/isset( $prop['user'] ) ) {
- $vals['userid'] = $row->pt_user;
+ $vals['userid'] = (int)$row->pt_user;
}
if ( isset( $prop['comment'] ) ) {
@@ -216,7 +216,8 @@ class ApiQueryProtectedTitles extends ApiQueryGeneratorBase {
'parsedcomment',
'expiry',
'level'
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'continue' => array(
ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
diff --git a/includes/api/ApiQueryRandom.php b/includes/api/ApiQueryRandom.php
index a2c28443..8e7031c0 100644
--- a/includes/api/ApiQueryRandom.php
+++ b/includes/api/ApiQueryRandom.php
@@ -31,8 +31,6 @@
* @ingroup API
*/
class ApiQueryRandom extends ApiQueryGeneratorBase {
- private $pageIDs;
-
public function __construct( ApiQuery $query, $moduleName ) {
parent::__construct( $query, $moduleName, 'rn' );
}
@@ -46,102 +44,131 @@ class ApiQueryRandom extends ApiQueryGeneratorBase {
}
/**
- * @param string $randstr
- * @param int $limit
- * @param int $namespace
- * @param ApiPageSet $resultPageSet
- * @param bool $redirect
- * @return void
+ * Actually perform the query and add pages to the result.
+ * @param ApiPageSet|null $resultPageSet
+ * @param int $limit Number of pages to fetch
+ * @param string|null $start Starting page_random
+ * @param int|null $startId Starting page_id
+ * @param string|null $end Ending page_random
+ * @return array (int, string|null) Number of pages left to query and continuation string
*/
- protected function prepareQuery( $randstr, $limit, $namespace, &$resultPageSet, $redirect ) {
+ protected function runQuery( $resultPageSet, $limit, $start, $startId, $end ) {
+ $params = $this->extractRequestParams();
+
$this->resetQueryParams();
$this->addTables( 'page' );
- $this->addOption( 'LIMIT', $limit );
- $this->addWhereFld( 'page_namespace', $namespace );
- $this->addWhereRange( 'page_random', 'newer', $randstr, null );
- $this->addWhereFld( 'page_is_redirect', $redirect );
+ $this->addFields( array( 'page_id', 'page_random' ) );
if ( is_null( $resultPageSet ) ) {
- $this->addFields( array( 'page_id', 'page_title', 'page_namespace' ) );
+ $this->addFields( array( 'page_title', 'page_namespace' ) );
} else {
$this->addFields( $resultPageSet->getPageTableFields() );
}
- }
+ $this->addWhereFld( 'page_namespace', $params['namespace'] );
+ if ( $params['redirect'] || $params['filterredir'] === 'redirects' ) {
+ $this->addWhereFld( 'page_is_redirect', 1 );
+ } elseif ( $params['filterredir'] === 'nonredirects' ) {
+ $this->addWhereFld( 'page_is_redirect', 0 );
+ } elseif ( is_null( $resultPageSet ) ) {
+ $this->addFields( array( 'page_is_redirect' ) );
+ }
+ $this->addOption( 'LIMIT', $limit + 1 );
+
+ if ( $start !== null ) {
+ $start = $this->getDB()->addQuotes( $start );
+ if ( $startId !== null ) {
+ $startId = (int)$startId;
+ $this->addWhere( "page_random = $start AND page_id >= $startId OR page_random > $start" );
+ } else {
+ $this->addWhere( "page_random >= $start" );
+ }
+ }
+ if ( $end !== null ) {
+ $this->addWhere( 'page_random < ' . $this->getDB()->addQuotes( $end ) );
+ }
+ $this->addOption( 'ORDER BY', array( 'page_random', 'page_id' ) );
+
+ $result = $this->getResult();
+ $path = array( 'query', $this->getModuleName() );
- /**
- * @param ApiPageSet $resultPageSet
- * @return int
- */
- protected function runQuery( $resultPageSet = null ) {
$res = $this->select( __METHOD__ );
$count = 0;
foreach ( $res as $row ) {
- $count++;
+ if ( $count++ >= $limit ) {
+ return array( 0, "{$row->page_random}|{$row->page_id}" );
+ }
if ( is_null( $resultPageSet ) ) {
- // Prevent duplicates
- if ( !in_array( $row->page_id, $this->pageIDs ) ) {
- $fit = $this->getResult()->addValue(
- array( 'query', $this->getModuleName() ),
- null, $this->extractRowInfo( $row ) );
- if ( !$fit ) {
- // We can't really query-continue a random list.
- // Return an insanely high value so
- // $count < $limit is false
- return 1E9;
- }
- $this->pageIDs[] = $row->page_id;
+ $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+ $page = array(
+ 'id' => (int)$row->page_id,
+ );
+ ApiQueryBase::addTitleInfo( $page, $title );
+ if ( isset( $row->page_is_redirect ) ) {
+ $page['redirect'] = (bool)$row->page_is_redirect;
+ }
+ $fit = $result->addValue( $path, null, $page );
+ if ( !$fit ) {
+ return array( 0, "{$row->page_random}|{$row->page_id}" );
}
} else {
$resultPageSet->processDbRow( $row );
}
}
- return $count;
+ return array( $limit - $count, null );
}
/**
- * @param ApiPageSet $resultPageSet
- * @return void
+ * @param ApiPageSet|null $resultPageSet
*/
public function run( $resultPageSet = null ) {
$params = $this->extractRequestParams();
- $result = $this->getResult();
- $this->pageIDs = array();
-
- $this->prepareQuery(
- wfRandom(),
- $params['limit'],
- $params['namespace'],
- $resultPageSet,
- $params['redirect']
- );
- $count = $this->runQuery( $resultPageSet );
- if ( $count < $params['limit'] ) {
- /* We got too few pages, we probably picked a high value
- * for page_random. We'll just take the lowest ones, see
- * also the comment in Title::getRandomTitle()
- */
- $this->prepareQuery(
- 0,
- $params['limit'] - $count,
- $params['namespace'],
- $resultPageSet,
- $params['redirect']
- );
- $this->runQuery( $resultPageSet );
+
+ // Since 'filterredir" will always be set in $params, we have to dig
+ // into the WebRequest to see if it was actually passed.
+ $request = $this->getMain()->getRequest();
+ if ( $request->getCheck( $this->encodeParamName( 'filterredir' ) ) ) {
+ $this->requireMaxOneParameter( $params, 'filterredir', 'redirect' );
}
- if ( is_null( $resultPageSet ) ) {
- $result->addIndexedTagName( array( 'query', $this->getModuleName() ), 'page' );
+ if ( $params['redirect'] ) {
+ $this->logFeatureUsage( "list=random&rnredirect=" );
+ }
+
+ if ( isset( $params['continue'] ) ) {
+ $cont = explode( '|', $params['continue'] );
+ $this->dieContinueUsageIf( count( $cont ) != 4 );
+ $rand = $cont[0];
+ $start = $cont[1];
+ $startId = (int)$cont[2];
+ $end = $cont[3] ? $rand : null;
+ $this->dieContinueUsageIf( !preg_match( '/^0\.\d+$/', $rand ) );
+ $this->dieContinueUsageIf( !preg_match( '/^0\.\d+$/', $start ) );
+ $this->dieContinueUsageIf( $cont[2] !== (string)$startId );
+ $this->dieContinueUsageIf( $cont[3] !== '0' && $cont[3] !== '1' );
+ } else {
+ $rand = wfRandom();
+ $start = $rand;
+ $startId = null;
+ $end = null;
}
- }
- private function extractRowInfo( $row ) {
- $title = Title::makeTitle( $row->page_namespace, $row->page_title );
- $vals = array();
- $vals['id'] = intval( $row->page_id );
- ApiQueryBase::addTitleInfo( $vals, $title );
+ list( $left, $continue ) = $this->runQuery( $resultPageSet, $params['limit'], $start, $startId, $end );
+ if ( $end === null && $continue === null ) {
+ // Wrap around. We do this even if $left === 0 for continuation
+ // (saving a DB query in this rare case probably isn't worth the
+ // added code complexity it would require).
+ $end = $rand;
+ list( $left, $continue ) = $this->runQuery( $resultPageSet, $left, null, null, $end );
+ }
+
+ if ( $continue !== null ) {
+ $endFlag = $end === null ? 0 : 1;
+ $this->setContinueEnumParameter( 'continue', "$rand|$continue|$endFlag" );
+ }
- return $vals;
+ if ( is_null( $resultPageSet ) ) {
+ $this->getResult()->addIndexedTagName( array( 'query', $this->getModuleName() ), 'page' );
+ }
}
public function getCacheMode( $params ) {
@@ -154,14 +181,24 @@ class ApiQueryRandom extends ApiQueryGeneratorBase {
ApiBase::PARAM_TYPE => 'namespace',
ApiBase::PARAM_ISMULTI => true
),
+ 'filterredir' => array(
+ ApiBase::PARAM_TYPE => array( 'all', 'redirects', 'nonredirects' ),
+ ApiBase::PARAM_DFLT => 'nonredirects', // for BC
+ ),
+ 'redirect' => array(
+ ApiBase::PARAM_DEPRECATED => true,
+ ApiBase::PARAM_DFLT => false,
+ ),
'limit' => array(
ApiBase::PARAM_TYPE => 'limit',
ApiBase::PARAM_DFLT => 1,
ApiBase::PARAM_MIN => 1,
- ApiBase::PARAM_MAX => 10,
- ApiBase::PARAM_MAX2 => 20
+ ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
+ ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
+ ),
+ 'continue' => array(
+ ApiBase::PARAM_HELP_MSG => 'api-help-param-continue'
),
- 'redirect' => false,
);
}
diff --git a/includes/api/ApiQueryRecentChanges.php b/includes/api/ApiQueryRecentChanges.php
index f6a64785..f5790629 100644
--- a/includes/api/ApiQueryRecentChanges.php
+++ b/includes/api/ApiQueryRecentChanges.php
@@ -458,7 +458,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
}
if ( $this->fld_userid ) {
- $vals['userid'] = $row->rc_user;
+ $vals['userid'] = (int)$row->rc_user;
}
if ( !$row->rc_user ) {
@@ -636,7 +636,8 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
'loginfo',
'tags',
'sha1',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'token' => array(
ApiBase::PARAM_DEPRECATED => true,
diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php
index 552ca3b4..0282fc59 100644
--- a/includes/api/ApiQueryRevisions.php
+++ b/includes/api/ApiQueryRevisions.php
@@ -91,10 +91,10 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
// Enum mode can only be used when exactly one page is provided.
// Enumerating revisions on multiple pages make it extremely
// difficult to manage continuations and require additional SQL indexes
- $enumRevMode = ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ||
- !is_null( $params['limit'] ) || !is_null( $params['startid'] ) ||
- !is_null( $params['endid'] ) || $params['dir'] === 'newer' ||
- !is_null( $params['start'] ) || !is_null( $params['end'] ) );
+ $enumRevMode = ( $params['user'] !== null || $params['excludeuser'] !== null ||
+ $params['limit'] !== null || $params['startid'] !== null ||
+ $params['endid'] !== null || $params['dir'] === 'newer' ||
+ $params['start'] !== null || $params['end'] !== null );
$pageSet = $this->getPageSet();
$pageCount = $pageSet->getGoodTitleCount();
@@ -149,7 +149,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
}
} else {
$this->limit = $this->getParameter( 'limit' ) ?: 10;
- $this->addFields( array( 'rev_id', 'rev_page' ) );
+ $this->addFields( array( 'rev_id', 'rev_timestamp', 'rev_page' ) );
}
if ( $this->fld_tags ) {
@@ -160,7 +160,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
$this->addFields( 'ts_tags' );
}
- if ( !is_null( $params['tag'] ) ) {
+ if ( $params['tag'] !== null ) {
$this->addTables( 'change_tag' );
$this->addJoinConds(
array( 'change_tag' => array( 'INNER JOIN', array( 'rev_id=ct_rev_id' ) ) )
@@ -196,58 +196,63 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
}
if ( $enumRevMode ) {
+ // Indexes targeted:
+ // page_timestamp if we don't have rvuser
+ // page_user_timestamp if we have a logged-in rvuser
+ // page_timestamp or usertext_timestamp if we have an IP rvuser
+
// This is mostly to prevent parameter errors (and optimize SQL?)
- if ( !is_null( $params['startid'] ) && !is_null( $params['start'] ) ) {
+ if ( $params['startid'] !== null && $params['start'] !== null ) {
$this->dieUsage( 'start and startid cannot be used together', 'badparams' );
}
- if ( !is_null( $params['endid'] ) && !is_null( $params['end'] ) ) {
+ if ( $params['endid'] !== null && $params['end'] !== null ) {
$this->dieUsage( 'end and endid cannot be used together', 'badparams' );
}
- if ( !is_null( $params['user'] ) && !is_null( $params['excludeuser'] ) ) {
+ if ( $params['user'] !== null && $params['excludeuser'] !== null ) {
$this->dieUsage( 'user and excludeuser cannot be used together', 'badparams' );
}
- // Continuing effectively uses startid. But we can't use rvstartid
- // directly, because there is no way to tell the client to ''not''
- // send rvstart if it sent it in the original query. So instead we
- // send the continuation startid as rvcontinue, and ignore both
- // rvstart and rvstartid when that is supplied.
- if ( !is_null( $params['continue'] ) ) {
- $params['startid'] = $params['continue'];
- $params['start'] = null;
+ if ( $params['continue'] !== null ) {
+ $cont = explode( '|', $params['continue'] );
+ $this->dieContinueUsageIf( count( $cont ) != 2 );
+ $op = ( $params['dir'] === 'newer' ? '>' : '<' );
+ $continueTimestamp = $db->addQuotes( $db->timestamp( $cont[0] ) );
+ $continueId = (int)$cont[1];
+ $this->dieContinueUsageIf( $continueId != $cont[1] );
+ $this->addWhere( "rev_timestamp $op $continueTimestamp OR " .
+ "(rev_timestamp = $continueTimestamp AND " .
+ "rev_id $op= $continueId)"
+ );
}
- // This code makes an assumption that sorting by rev_id and rev_timestamp produces
- // the same result. This way users may request revisions starting at a given time,
- // but to page through results use the rev_id returned after each page.
- // Switching to rev_id removes the potential problem of having more than
- // one row with the same timestamp for the same page.
- // The order needs to be the same as start parameter to avoid SQL filesort.
- if ( is_null( $params['startid'] ) && is_null( $params['endid'] ) ) {
- $this->addTimestampWhereRange( 'rev_timestamp', $params['dir'],
- $params['start'], $params['end'] );
- } else {
- $this->addWhereRange( 'rev_id', $params['dir'],
- $params['startid'], $params['endid'] );
- // One of start and end can be set
- // If neither is set, this does nothing
- $this->addTimestampWhereRange( 'rev_timestamp', $params['dir'],
- $params['start'], $params['end'], false );
- }
+ $this->addTimestampWhereRange( 'rev_timestamp', $params['dir'],
+ $params['start'], $params['end'] );
+ $this->addWhereRange( 'rev_id', $params['dir'],
+ $params['startid'], $params['endid'] );
// There is only one ID, use it
$ids = array_keys( $pageSet->getGoodTitles() );
$this->addWhereFld( 'rev_page', reset( $ids ) );
- if ( !is_null( $params['user'] ) ) {
- $this->addWhereFld( 'rev_user_text', $params['user'] );
- } elseif ( !is_null( $params['excludeuser'] ) ) {
- $this->addWhere( 'rev_user_text != ' .
- $db->addQuotes( $params['excludeuser'] ) );
+ if ( $params['user'] !== null ) {
+ $user = User::newFromName( $params['user'] );
+ if ( $user && $user->getId() > 0 ) {
+ $this->addWhereFld( 'rev_user', $user->getId() );
+ } else {
+ $this->addWhereFld( 'rev_user_text', $params['user'] );
+ }
+ } elseif ( $params['excludeuser'] !== null ) {
+ $user = User::newFromName( $params['excludeuser'] );
+ if ( $user && $user->getId() > 0 ) {
+ $this->addWhere( 'rev_user != ' . $user->getId() );
+ } else {
+ $this->addWhere( 'rev_user_text != ' .
+ $db->addQuotes( $params['excludeuser'] ) );
+ }
}
- if ( !is_null( $params['user'] ) || !is_null( $params['excludeuser'] ) ) {
+ if ( $params['user'] !== null || $params['excludeuser'] !== null ) {
// Paranoia: avoid brute force searches (bug 17342)
if ( !$this->getUser()->isAllowed( 'deletedhistory' ) ) {
$bitmask = Revision::DELETED_USER;
@@ -261,16 +266,20 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
}
}
} elseif ( $revCount > 0 ) {
+ // Always targets the PRIMARY index
+
$revs = $pageSet->getLiveRevisionIDs();
// Get all revision IDs
$this->addWhereFld( 'rev_id', array_keys( $revs ) );
- if ( !is_null( $params['continue'] ) ) {
+ if ( $params['continue'] !== null ) {
$this->addWhere( 'rev_id >= ' . intval( $params['continue'] ) );
}
$this->addOption( 'ORDER BY', 'rev_id' );
} elseif ( $pageCount > 0 ) {
+ // Always targets the rev_page_id index
+
$titles = $pageSet->getGoodTitles();
// When working in multi-page non-enumeration mode,
@@ -282,7 +291,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
// Every time someone relies on equality propagation, god kills a kitten :)
$this->addWhereFld( 'rev_page', array_keys( $titles ) );
- if ( !is_null( $params['continue'] ) ) {
+ if ( $params['continue'] !== null ) {
$cont = explode( '|', $params['continue'] );
$this->dieContinueUsageIf( count( $cont ) != 2 );
$pageid = intval( $cont[0] );
@@ -312,7 +321,8 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
// We've reached the one extra which shows that there are
// additional pages to be had. Stop here...
if ( $enumRevMode ) {
- $this->setContinueEnumParameter( 'continue', intval( $row->rev_id ) );
+ $this->setContinueEnumParameter( 'continue',
+ $row->rev_timestamp . '|' . intval( $row->rev_id ) );
} elseif ( $revCount > 0 ) {
$this->setContinueEnumParameter( 'continue', intval( $row->rev_id ) );
} else {
@@ -344,7 +354,8 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
$fit = $this->addPageSubItem( $row->rev_page, $rev, 'rev' );
if ( !$fit ) {
if ( $enumRevMode ) {
- $this->setContinueEnumParameter( 'continue', intval( $row->rev_id ) );
+ $this->setContinueEnumParameter( 'continue',
+ $row->rev_timestamp . '|' . intval( $row->rev_id ) );
} elseif ( $revCount > 0 ) {
$this->setContinueEnumParameter( 'continue', intval( $row->rev_id ) );
} else {
@@ -443,6 +454,6 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Properties#revisions_.2F_rv';
+ return 'https://www.mediawiki.org/wiki/API:Revisions';
}
}
diff --git a/includes/api/ApiQueryRevisionsBase.php b/includes/api/ApiQueryRevisionsBase.php
index 64f6120a..d57dc3cc 100644
--- a/includes/api/ApiQueryRevisionsBase.php
+++ b/includes/api/ApiQueryRevisionsBase.php
@@ -37,7 +37,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
protected $fld_ids = false, $fld_flags = false, $fld_timestamp = false,
$fld_size = false, $fld_sha1 = false, $fld_comment = false,
$fld_parsedcomment = false, $fld_user = false, $fld_userid = false,
- $fld_content = false, $fld_tags = false, $fld_contentmodel = false;
+ $fld_content = false, $fld_tags = false, $fld_contentmodel = false, $fld_parsetree = false;
public function execute() {
$this->run();
@@ -104,6 +104,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
$this->fld_userid = isset( $prop['userid'] );
$this->fld_user = isset( $prop['user'] );
$this->fld_tags = isset( $prop['tags'] );
+ $this->fld_parsetree = isset( $prop['parsetree'] );
if ( !empty( $params['contentformat'] ) ) {
$this->contentFormat = $params['contentformat'];
@@ -112,7 +113,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
$this->limit = $params['limit'];
$this->fetchContent = $this->fld_content || !is_null( $this->diffto )
- || !is_null( $this->difftotext );
+ || !is_null( $this->difftotext ) || $this->fld_parsetree;
$smallLimit = false;
if ( $this->fetchContent ) {
@@ -273,10 +274,11 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
$vals['textmissing'] = true;
}
}
- if ( $this->fld_content && $content ) {
- $text = null;
-
- if ( $this->generateXML ) {
+ if ( $this->fld_parsetree || ( $this->fld_content && $this->generateXML ) ) {
+ if ( !$this->fld_parsetree ) {
+ $this->logFeatureUsage( 'action=query&prop=revisions+base&generatexml' );
+ }
+ if ( $content ) {
if ( $content->getModel() === CONTENT_MODEL_WIKITEXT ) {
$t = $content->getNativeData(); # note: don't set $text
@@ -299,6 +301,10 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
" uses content model " . $content->getModel() );
}
}
+ }
+
+ if ( $this->fld_content && $content ) {
+ $text = null;
if ( $this->expandTemplates && !$this->parseContent ) {
#XXX: implement template expansion for all content types in ContentHandler?
@@ -431,9 +437,26 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
'comment',
'parsedcomment',
'content',
- 'tags'
+ 'tags',
+ 'parsetree',
),
ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-prop',
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(
+ 'ids' => 'apihelp-query+revisions+base-paramvalue-prop-ids',
+ 'flags' => 'apihelp-query+revisions+base-paramvalue-prop-flags',
+ 'timestamp' => 'apihelp-query+revisions+base-paramvalue-prop-timestamp',
+ 'user' => 'apihelp-query+revisions+base-paramvalue-prop-user',
+ 'userid' => 'apihelp-query+revisions+base-paramvalue-prop-userid',
+ 'size' => 'apihelp-query+revisions+base-paramvalue-prop-size',
+ 'sha1' => 'apihelp-query+revisions+base-paramvalue-prop-sha1',
+ 'contentmodel' => 'apihelp-query+revisions+base-paramvalue-prop-contentmodel',
+ 'comment' => 'apihelp-query+revisions+base-paramvalue-prop-comment',
+ 'parsedcomment' => 'apihelp-query+revisions+base-paramvalue-prop-parsedcomment',
+ 'content' => 'apihelp-query+revisions+base-paramvalue-prop-content',
+ 'tags' => 'apihelp-query+revisions+base-paramvalue-prop-tags',
+ 'parsetree' => array( 'apihelp-query+revisions+base-paramvalue-prop-parsetree',
+ CONTENT_MODEL_WIKITEXT ),
+ ),
),
'limit' => array(
ApiBase::PARAM_TYPE => 'limit',
@@ -448,6 +471,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
),
'generatexml' => array(
ApiBase::PARAM_DFLT => false,
+ ApiBase::PARAM_DEPRECATED => true,
ApiBase::PARAM_HELP_MSG => 'apihelp-query+revisions+base-param-generatexml',
),
'parse' => array(
diff --git a/includes/api/ApiQuerySearch.php b/includes/api/ApiQuerySearch.php
index e29ef8d2..b866f43e 100644
--- a/includes/api/ApiQuerySearch.php
+++ b/includes/api/ApiQuerySearch.php
@@ -82,6 +82,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
SearchEngine::create( $params['backend'] ) : SearchEngine::create();
$search->setLimitOffset( $limit + 1, $params['offset'] );
$search->setNamespaces( $params['namespace'] );
+ $search->setFeatureData( 'rewrite', (bool)$params['enablerewrites'] );
$query = $search->transformSearchTerm( $query );
$query = $search->replacePrefixes( $query );
@@ -92,7 +93,9 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
} elseif ( $what == 'title' ) {
$matches = $search->searchTitle( $query );
} elseif ( $what == 'nearmatch' ) {
- $matches = SearchEngine::getNearMatchResultSet( $query );
+ // near matches must receive the user input as provided, otherwise
+ // the near matches within namespaces are lost.
+ $matches = SearchEngine::getNearMatchResultSet( $params['search'] );
} else {
// We default to title searches; this is a terrible legacy
// of the way we initially set up the MySQL fulltext-based
@@ -129,6 +132,14 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
if ( isset( $searchInfo['suggestion'] ) && $matches->hasSuggestion() ) {
$apiResult->addValue( array( 'query', 'searchinfo' ),
'suggestion', $matches->getSuggestionQuery() );
+ $apiResult->addValue( array( 'query', 'searchinfo' ),
+ 'suggestionsnippet', $matches->getSuggestionSnippet() );
+ }
+ if ( isset( $searchInfo['rewrittenquery'] ) && $matches->hasRewrittenQuery() ) {
+ $apiResult->addValue( array( 'query', 'searchinfo' ),
+ 'rewrittenquery', $matches->getQueryAfterRewrite() );
+ $apiResult->addValue( array( 'query', 'searchinfo' ),
+ 'rewrittenquerysnippet', $matches->getQueryAfterRewriteSnippet() );
}
}
@@ -172,6 +183,9 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
if ( isset( $prop['titlesnippet'] ) ) {
$vals['titlesnippet'] = $result->getTitleSnippet();
}
+ if ( isset( $prop['categorysnippet'] ) ) {
+ $vals['categorysnippet'] = $result->getCategorySnippet();
+ }
if ( !is_null( $result->getRedirectTitle() ) ) {
if ( isset( $prop['redirecttitle'] ) ) {
$vals['redirecttitle'] = $result->getRedirectTitle()->getPrefixedText();
@@ -188,6 +202,9 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
$vals['sectionsnippet'] = $result->getSectionSnippet();
}
}
+ if ( isset( $prop['isfilematch'] ) ) {
+ $vals['isfilematch'] = $result->isFileMatch();
+ }
// Add item to results and see whether it fits
$fit = $apiResult->addValue( array( 'query', $this->getModuleName() ),
@@ -228,7 +245,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
// Add item to results and see whether it fits
$fit = $apiResult->addValue(
- array( 'query', 'interwiki' . $this->getModuleName(), $result->getInterwikiPrefix() ),
+ array( 'query', 'interwiki' . $this->getModuleName(), $result->getInterwikiPrefix() ),
null,
$vals
);
@@ -293,10 +310,11 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
)
),
'info' => array(
- ApiBase::PARAM_DFLT => 'totalhits|suggestion',
+ ApiBase::PARAM_DFLT => 'totalhits|suggestion|rewrittenquery',
ApiBase::PARAM_TYPE => array(
'totalhits',
'suggestion',
+ 'rewrittenquery',
),
ApiBase::PARAM_ISMULTI => true,
),
@@ -306,16 +324,19 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
'size',
'wordcount',
'timestamp',
- 'score',
'snippet',
'titlesnippet',
'redirecttitle',
'redirectsnippet',
'sectiontitle',
'sectionsnippet',
- 'hasrelated',
+ 'isfilematch',
+ 'categorysnippet',
+ 'score', // deprecated
+ 'hasrelated', // deprecated
),
ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'offset' => array(
ApiBase::PARAM_DFLT => 0,
@@ -329,6 +350,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_SML2
),
'interwiki' => false,
+ 'enablerewrites' => false,
);
$alternatives = SearchEngine::getSearchTypes();
diff --git a/includes/api/ApiQuerySiteinfo.php b/includes/api/ApiQuerySiteinfo.php
index b7b10846..12651558 100644
--- a/includes/api/ApiQuerySiteinfo.php
+++ b/includes/api/ApiQuerySiteinfo.php
@@ -176,6 +176,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
$data['linktrail'] = $linktrail ?: '';
$data['legaltitlechars'] = Title::legalChars();
+ $data['invalidusernamechars'] = $config->get( 'InvalidUsernameCharacters' );
global $IP;
$git = SpecialVersion::getGitHeadSha1( $IP );
@@ -297,6 +298,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
}
}
+ ApiResult::setArrayType( $data, 'assoc' );
ApiResult::setIndexedTagName( $data, 'ns' );
return $this->getResult()->addValue( 'query', $property, $data );
@@ -511,6 +513,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
$groups = array_intersect( $rights[$group], $allGroups );
if ( $groups ) {
$arr[$type] = $groups;
+ ApiResult::setArrayType( $arr[$type], 'BCarray' );
ApiResult::setIndexedTagName( $arr[$type], 'group' );
}
}
@@ -682,6 +685,11 @@ class ApiQuerySiteinfo extends ApiQueryBase {
'semiprotectedlevels' => $config->get( 'SemiprotectedRestrictionLevels' ),
);
+ ApiResult::setArrayType( $data['types'], 'BCarray' );
+ ApiResult::setArrayType( $data['levels'], 'BCarray' );
+ ApiResult::setArrayType( $data['cascadinglevels'], 'BCarray' );
+ ApiResult::setArrayType( $data['semiprotectedlevels'], 'BCarray' );
+
ApiResult::setIndexedTagName( $data['types'], 'type' );
ApiResult::setIndexedTagName( $data['levels'], 'level' );
ApiResult::setIndexedTagName( $data['cascadinglevels'], 'level' );
@@ -741,6 +749,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
global $wgParser;
$wgParser->firstCallInit();
$tags = array_map( array( $this, 'formatParserTags' ), $wgParser->getTags() );
+ ApiResult::setArrayType( $tags, 'BCarray' );
ApiResult::setIndexedTagName( $tags, 't' );
return $this->getResult()->addValue( 'query', $property, $tags );
@@ -750,6 +759,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
global $wgParser;
$wgParser->firstCallInit();
$hooks = $wgParser->getFunctionHooks();
+ ApiResult::setArrayType( $hooks, 'BCarray' );
ApiResult::setIndexedTagName( $hooks, 'h' );
return $this->getResult()->addValue( 'query', $property, $hooks );
@@ -757,6 +767,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
public function appendVariables( $property ) {
$variables = MagicWord::getVariableIDs();
+ ApiResult::setArrayType( $variables, 'BCarray' );
ApiResult::setIndexedTagName( $variables, 'v' );
return $this->getResult()->addValue( 'query', $property, $variables );
@@ -765,6 +776,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
public function appendProtocols( $property ) {
// Make a copy of the global so we don't try to set the _element key of it - bug 45130
$protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
+ ApiResult::setArrayType( $protocols, 'BCarray' );
ApiResult::setIndexedTagName( $protocols, 'p' );
return $this->getResult()->addValue( 'query', $property, $protocols );
@@ -792,6 +804,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $subscribers ),
);
+ ApiResult::setArrayType( $arr['subscribers'], 'BCarray' );
ApiResult::setIndexedTagName( $arr['subscribers'], 's' );
$data[] = $arr;
}
@@ -842,7 +855,8 @@ class ApiQuerySiteinfo extends ApiQueryBase {
'variables',
'protocols',
'defaultoptions',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'filteriw' => array(
ApiBase::PARAM_TYPE => array(
@@ -868,6 +882,6 @@ class ApiQuerySiteinfo extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Meta#siteinfo_.2F_si';
+ return 'https://www.mediawiki.org/wiki/API:Siteinfo';
}
}
diff --git a/includes/api/ApiQueryStashImageInfo.php b/includes/api/ApiQueryStashImageInfo.php
index 11268426..3de72bfe 100644
--- a/includes/api/ApiQueryStashImageInfo.php
+++ b/includes/api/ApiQueryStashImageInfo.php
@@ -122,4 +122,8 @@ class ApiQueryStashImageInfo extends ApiQueryImageInfo {
=> 'apihelp-query+stashimageinfo-example-params',
);
}
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Stashimageinfo';
+ }
}
diff --git a/includes/api/ApiQueryTags.php b/includes/api/ApiQueryTags.php
index 45f73b20..284bb821 100644
--- a/includes/api/ApiQueryTags.php
+++ b/includes/api/ApiQueryTags.php
@@ -163,7 +163,8 @@ class ApiQueryTags extends ApiQueryBase {
'source',
'active',
),
- ApiBase::PARAM_ISMULTI => true
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
)
);
}
diff --git a/includes/api/ApiQueryTokens.php b/includes/api/ApiQueryTokens.php
index 65a08a3b..f8876646 100644
--- a/includes/api/ApiQueryTokens.php
+++ b/includes/api/ApiQueryTokens.php
@@ -93,4 +93,8 @@ class ApiQueryTokens extends ApiQueryBase {
public function getCacheMode( $params ) {
return 'private';
}
+
+ public function getHelpUrls() {
+ return 'https://www.mediawiki.org/wiki/API:Tokens';
+ }
}
diff --git a/includes/api/ApiQueryUserContributions.php b/includes/api/ApiQueryUserContributions.php
index e5ec67d0..e3030944 100644
--- a/includes/api/ApiQueryUserContributions.php
+++ b/includes/api/ApiQueryUserContributions.php
@@ -340,7 +340,7 @@ class ApiQueryContributions extends ApiQueryBase {
}
// Any rows where we can't view the user were filtered out in the query.
- $vals['userid'] = $row->rev_user;
+ $vals['userid'] = (int)$row->rev_user;
$vals['user'] = $row->rev_user_text;
if ( $row->rev_deleted & Revision::DELETED_USER ) {
$vals['userhidden'] = true;
@@ -491,7 +491,8 @@ class ApiQueryContributions extends ApiQueryBase {
'flags',
'patrolled',
'tags'
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'show' => array(
ApiBase::PARAM_ISMULTI => true,
diff --git a/includes/api/ApiQueryUserInfo.php b/includes/api/ApiQueryUserInfo.php
index 4a7d1e0f..251c42bc 100644
--- a/includes/api/ApiQueryUserInfo.php
+++ b/includes/api/ApiQueryUserInfo.php
@@ -51,9 +51,33 @@ class ApiQueryUserInfo extends ApiQueryBase {
$result->addValue( 'query', $this->getModuleName(), $r );
}
+ /**
+ * Get basic info about a given block
+ * @param Block $block
+ * @return array Array containing several keys:
+ * - blockid - ID of the block
+ * - blockedby - username of the blocker
+ * - blockedbyid - user ID of the blocker
+ * - blockreason - reason provided for the block
+ * - blockedtimestamp - timestamp for when the block was placed/modified
+ * - blockexpiry - expiry time of the block
+ */
+ public static function getBlockInfo( Block $block ) {
+ global $wgContLang;
+ $vals = array();
+ $vals['blockid'] = $block->getId();
+ $vals['blockedby'] = $block->getByName();
+ $vals['blockedbyid'] = $block->getBy();
+ $vals['blockreason'] = $block->mReason;
+ $vals['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $block->mTimestamp );
+ $vals['blockexpiry'] = $wgContLang->formatExpiry(
+ $block->getExpiry(), TS_ISO_8601, 'infinite'
+ );
+ return $vals;
+ }
+
protected function getCurrentUserInfo() {
$user = $this->getUser();
- $result = $this->getResult();
$vals = array();
$vals['id'] = intval( $user->getId() );
$vals['name'] = $user->getName();
@@ -62,18 +86,8 @@ class ApiQueryUserInfo extends ApiQueryBase {
$vals['anon'] = true;
}
- if ( isset( $this->prop['blockinfo'] ) ) {
- if ( $user->isBlocked() ) {
- $block = $user->getBlock();
- $vals['blockid'] = $block->getId();
- $vals['blockedby'] = $block->getByName();
- $vals['blockedbyid'] = $block->getBy();
- $vals['blockreason'] = $user->blockedFor();
- $vals['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $block->mTimestamp );
- $vals['blockexpiry'] = $block->getExpiry() === 'infinity'
- ? 'infinite'
- : wfTimestamp( TS_ISO_8601, $block->getExpiry() );
- }
+ if ( isset( $this->prop['blockinfo'] ) && $user->isBlocked() ) {
+ $vals = array_merge( $vals, self::getBlockInfo( $user->getBlock() ) );
}
if ( isset( $this->prop['hasmsg'] ) ) {
@@ -253,10 +267,12 @@ class ApiQueryUserInfo extends ApiQueryBase {
'registrationdate',
'unreadcount',
),
- ApiBase::PARAM_HELP_MSG => array(
- 'apihelp-query+userinfo-param-prop',
- self::WL_UNREAD_LIMIT - 1,
- self::WL_UNREAD_LIMIT . '+',
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(
+ 'unreadcount' => array(
+ 'apihelp-query+userinfo-paramvalue-prop-unreadcount',
+ self::WL_UNREAD_LIMIT - 1,
+ self::WL_UNREAD_LIMIT . '+',
+ ),
),
)
);
@@ -272,6 +288,6 @@ class ApiQueryUserInfo extends ApiQueryBase {
}
public function getHelpUrls() {
- return 'https://www.mediawiki.org/wiki/API:Meta#userinfo_.2F_ui';
+ return 'https://www.mediawiki.org/wiki/API:Userinfo';
}
}
diff --git a/includes/api/ApiQueryUsers.php b/includes/api/ApiQueryUsers.php
index f22c2134..1d0048ce 100644
--- a/includes/api/ApiQueryUsers.php
+++ b/includes/api/ApiQueryUsers.php
@@ -193,9 +193,9 @@ class ApiQueryUsers extends ApiQueryBase {
$data[$name]['hidden'] = true;
}
if ( isset( $this->prop['blockinfo'] ) && !is_null( $row->ipb_by_text ) ) {
- $data[$name]['blockid'] = $row->ipb_id;
+ $data[$name]['blockid'] = (int)$row->ipb_id;
$data[$name]['blockedby'] = $row->ipb_by_text;
- $data[$name]['blockedbyid'] = $row->ipb_by;
+ $data[$name]['blockedbyid'] = (int)$row->ipb_by;
$data[$name]['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $row->ipb_timestamp );
$data[$name]['blockreason'] = $row->ipb_reason;
$data[$name]['blockexpiry'] = $row->ipb_expiry;
@@ -305,7 +305,8 @@ class ApiQueryUsers extends ApiQueryBase {
'registration',
'emailable',
'gender',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'users' => array(
ApiBase::PARAM_ISMULTI => true
diff --git a/includes/api/ApiQueryWatchlist.php b/includes/api/ApiQueryWatchlist.php
index 9f7387c7..648d2596 100644
--- a/includes/api/ApiQueryWatchlist.php
+++ b/includes/api/ApiQueryWatchlist.php
@@ -332,9 +332,9 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
}
if ( Revision::userCanBitfield( $row->rc_deleted, Revision::DELETED_USER, $user ) ) {
if ( $this->fld_userid ) {
- $vals['userid'] = $row->rc_user;
+ $vals['userid'] = (int)$row->rc_user;
// for backwards compatibility
- $vals['user'] = $row->rc_user;
+ $vals['user'] = (int)$row->rc_user;
}
if ( $this->fld_user ) {
@@ -451,6 +451,7 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
'prop' => array(
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_DFLT => 'ids|title|flags',
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
ApiBase::PARAM_TYPE => array(
'ids',
'title',
diff --git a/includes/api/ApiQueryWatchlistRaw.php b/includes/api/ApiQueryWatchlistRaw.php
index 493c192a..fc7b80c5 100644
--- a/includes/api/ApiQueryWatchlistRaw.php
+++ b/includes/api/ApiQueryWatchlistRaw.php
@@ -83,6 +83,28 @@ class ApiQueryWatchlistRaw extends ApiQueryGeneratorBase {
);
}
+ if ( isset( $params['fromtitle'] ) ) {
+ list( $ns, $title ) = $this->prefixedTitlePartToKey( $params['fromtitle'] );
+ $title = $this->getDB()->addQuotes( $title );
+ $op = $params['dir'] == 'ascending' ? '>' : '<';
+ $this->addWhere(
+ "wl_namespace $op $ns OR " .
+ "(wl_namespace = $ns AND " .
+ "wl_title $op= $title)"
+ );
+ }
+
+ if ( isset( $params['totitle'] ) ) {
+ list( $ns, $title ) = $this->prefixedTitlePartToKey( $params['totitle'] );
+ $title = $this->getDB()->addQuotes( $title );
+ $op = $params['dir'] == 'ascending' ? '<' : '>'; // Reversed from above!
+ $this->addWhere(
+ "wl_namespace $op $ns OR " .
+ "(wl_namespace = $ns AND " .
+ "wl_title $op= $title)"
+ );
+ }
+
$sort = ( $params['dir'] == 'descending' ? ' DESC' : '' );
// Don't ORDER BY wl_namespace if it's constant in the WHERE clause
if ( count( $params['namespace'] ) == 1 ) {
@@ -149,7 +171,8 @@ class ApiQueryWatchlistRaw extends ApiQueryGeneratorBase {
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_TYPE => array(
'changed',
- )
+ ),
+ ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
),
'show' => array(
ApiBase::PARAM_ISMULTI => true,
@@ -172,6 +195,12 @@ class ApiQueryWatchlistRaw extends ApiQueryGeneratorBase {
),
ApiBase::PARAM_HELP_MSG => 'api-help-param-direction',
),
+ 'fromtitle' => array(
+ ApiBase::PARAM_TYPE => 'string'
+ ),
+ 'totitle' => array(
+ ApiBase::PARAM_TYPE => 'string'
+ ),
);
}
diff --git a/includes/api/ApiResult.php b/includes/api/ApiResult.php
index 7c573a8f..cd4165b6 100644
--- a/includes/api/ApiResult.php
+++ b/includes/api/ApiResult.php
@@ -108,13 +108,25 @@ class ApiResult implements ApiSerializable {
const META_TYPE = '_type';
/**
- * Key (rather than "name" or other default) for when META_TYPE is 'kvp' or
- * 'BCkvp'. Value is string.
+ * Key for the metadata item whose value specifies the name used for the
+ * kvp key in the alternative output format with META_TYPE 'kvp' or
+ * 'BCkvp', i.e. the "name" in <container><item name="key">value</item></container>.
+ * Value is string.
* @since 1.25
*/
const META_KVP_KEY_NAME = '_kvpkeyname';
/**
+ * Key for the metadata item that indicates that the KVP key should be
+ * added into an assoc value, i.e. {"key":{"val1":"a","val2":"b"}}
+ * transforms to {"name":"key","val1":"a","val2":"b"} rather than
+ * {"name":"key","value":{"val1":"a","val2":"b"}}.
+ * Value is boolean.
+ * @since 1.26
+ */
+ const META_KVP_MERGE = '_kvpmerge';
+
+ /**
* Key for the 'BC bools' metadata item. Value is string[].
* Note no setter is provided.
* @since 1.25
@@ -132,7 +144,7 @@ class ApiResult implements ApiSerializable {
private $errorFormatter;
// Deprecated fields
- private $isRawMode, $checkingSize, $mainForContinuation;
+ private $checkingSize, $mainForContinuation;
/**
* @param int|bool $maxSize Maximum result "size", or false for no limit
@@ -147,7 +159,6 @@ class ApiResult implements ApiSerializable {
}
$this->maxSize = $maxSize;
- $this->isRawMode = false;
$this->checkingSize = true;
$this->reset();
}
@@ -276,7 +287,7 @@ class ApiResult implements ApiSerializable {
* @param int $flags Zero or more OR-ed flags like OVERRIDE | ADD_ON_TOP.
*/
public static function setValue( array &$arr, $name, $value, $flags = 0 ) {
- if ( !( $flags & ApiResult::NO_VALIDATE ) ) {
+ if ( ( $flags & ApiResult::NO_VALIDATE ) !== ApiResult::NO_VALIDATE ) {
$value = self::validateValue( $value );
}
@@ -302,10 +313,14 @@ class ApiResult implements ApiSerializable {
$arr[$name] += $value;
} else {
$keys = join( ', ', array_keys( $conflicts ) );
- throw new RuntimeException( "Conflicting keys ($keys) when attempting to merge element $name" );
+ throw new RuntimeException(
+ "Conflicting keys ($keys) when attempting to merge element $name"
+ );
}
} else {
- throw new RuntimeException( "Attempting to add element $name=$value, existing value is {$arr[$name]}" );
+ throw new RuntimeException(
+ "Attempting to add element $name=$value, existing value is {$arr[$name]}"
+ );
}
}
@@ -386,6 +401,11 @@ class ApiResult implements ApiSerializable {
$arr = &$this->path( $path, ( $flags & ApiResult::ADD_ON_TOP ) ? 'prepend' : 'append' );
if ( $this->checkingSize && !( $flags & ApiResult::NO_SIZE_CHECK ) ) {
+ // self::valueSize needs the validated value. Then flag
+ // to not re-validate later.
+ $value = self::validateValue( $value );
+ $flags |= ApiResult::NO_VALIDATE;
+
$newsize = $this->size + self::valueSize( $value );
if ( $this->maxSize !== false && $newsize > $this->maxSize ) {
/// @todo Add i18n message when replacing calls to ->setWarning()
@@ -703,7 +723,9 @@ class ApiResult implements ApiSerializable {
* @param string $kvpKeyName See ApiResult::META_KVP_KEY_NAME
*/
public static function setArrayType( array &$arr, $type, $kvpKeyName = null ) {
- if ( !in_array( $type, array( 'default', 'array', 'assoc', 'kvp', 'BCarray', 'BCassoc', 'BCkvp' ), true ) ) {
+ if ( !in_array( $type, array(
+ 'default', 'array', 'assoc', 'kvp', 'BCarray', 'BCassoc', 'BCkvp'
+ ), true ) ) {
throw new InvalidArgumentException( 'Bad type' );
}
$arr[self::META_TYPE] = $type;
@@ -935,19 +957,43 @@ class ApiResult implements ApiSerializable {
: $transformTypes['ArmorKVP'];
$valKey = isset( $transforms['BC'] ) ? '*' : 'value';
$assocAsObject = !empty( $transformTypes['AssocAsObject'] );
+ $merge = !empty( $metadata[self::META_KVP_MERGE] );
$ret = array();
foreach ( $data as $k => $v ) {
- $item = array(
- $key => $k,
- $valKey => $v,
- );
- if ( $strip === 'none' ) {
- $item += array(
- self::META_PRESERVE_KEYS => array( $key ),
- self::META_CONTENT => $valKey,
- self::META_TYPE => 'assoc',
+ if ( $merge && ( is_array( $v ) || is_object( $v ) ) ) {
+ $vArr = (array)$v;
+ if ( isset( $vArr[self::META_TYPE] ) ) {
+ $mergeType = $vArr[self::META_TYPE];
+ } elseif ( is_object( $v ) ) {
+ $mergeType = 'assoc';
+ } else {
+ $keys = array_keys( $vArr );
+ sort( $keys, SORT_NUMERIC );
+ $mergeType = ( $keys === array_keys( $keys ) ) ? 'array' : 'assoc';
+ }
+ } else {
+ $mergeType = 'n/a';
+ }
+ if ( $mergeType === 'assoc' ) {
+ $item = $vArr + array(
+ $key => $k,
);
+ if ( $strip === 'none' ) {
+ self::setPreserveKeysList( $item, array( $key ) );
+ }
+ } else {
+ $item = array(
+ $key => $k,
+ $valKey => $v,
+ );
+ if ( $strip === 'none' ) {
+ $item += array(
+ self::META_PRESERVE_KEYS => array( $key ),
+ self::META_CONTENT => $valKey,
+ self::META_TYPE => 'assoc',
+ );
+ }
}
$ret[] = $assocAsObject ? (object)$item : $item;
}
@@ -1035,15 +1081,14 @@ class ApiResult implements ApiSerializable {
/**
* Get the 'real' size of a result item. This means the strlen() of the item,
* or the sum of the strlen()s of the elements if the item is an array.
- * @note Once the deprecated public self::size is removed, we can rename this back to a less awkward name.
- * @param mixed $value
+ * @note Once the deprecated public self::size is removed, we can rename
+ * this back to a less awkward name.
+ * @param mixed $value Validated value (see self::validateValue())
* @return int
*/
private static function valueSize( $value ) {
$s = 0;
- if ( is_array( $value ) ||
- is_object( $value ) && !is_callable( array( $value, '__toString' ) )
- ) {
+ if ( is_array( $value ) ) {
foreach ( $value as $k => $v ) {
if ( !self::isMetadataKey( $s ) ) {
$s += self::valueSize( $v );
@@ -1096,6 +1141,61 @@ class ApiResult implements ApiSerializable {
return $ret;
}
+ /**
+ * Add the correct metadata to an array of vars we want to export through
+ * the API.
+ *
+ * @param array $vars
+ * @param boolean $forceHash
+ * @return array
+ */
+ public static function addMetadataToResultVars( $vars, $forceHash = true ) {
+ // Process subarrays and determine if this is a JS [] or {}
+ $hash = $forceHash;
+ $maxKey = -1;
+ $bools = array();
+ foreach ( $vars as $k => $v ) {
+ if ( is_array( $v ) || is_object( $v ) ) {
+ $vars[$k] = ApiResult::addMetadataToResultVars( (array)$v, is_object( $v ) );
+ } elseif ( is_bool( $v ) ) {
+ // Better here to use real bools even in BC formats
+ $bools[] = $k;
+ }
+ if ( is_string( $k ) ) {
+ $hash = true;
+ } elseif ( $k > $maxKey ) {
+ $maxKey = $k;
+ }
+ }
+ if ( !$hash && $maxKey !== count( $vars ) - 1 ) {
+ $hash = true;
+ }
+
+ // Set metadata appropriately
+ if ( $hash ) {
+ // Get the list of keys we actually care about. Unfortunately, we can't support
+ // certain keys that conflict with ApiResult metadata.
+ $keys = array_diff( array_keys( $vars ), array(
+ ApiResult::META_TYPE, ApiResult::META_PRESERVE_KEYS, ApiResult::META_KVP_KEY_NAME,
+ ApiResult::META_INDEXED_TAG_NAME, ApiResult::META_BC_BOOLS
+ ) );
+
+ return array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => $keys,
+ ApiResult::META_BC_BOOLS => $bools,
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ ) + $vars;
+ } else {
+ return array(
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_BC_BOOLS => $bools,
+ ApiResult::META_INDEXED_TAG_NAME => 'value',
+ ) + $vars;
+ }
+ }
+
/**@}*/
/************************************************************************//**
@@ -1104,27 +1204,23 @@ class ApiResult implements ApiSerializable {
*/
/**
- * Call this function when special elements such as '_element'
- * are needed by the formatter, for example in XML printing.
+ * Formerly used to enable/disable "raw mode".
* @deprecated since 1.25, you shouldn't have been using it in the first place
* @since 1.23 $flag parameter added
* @param bool $flag Set the raw mode flag to this state
*/
public function setRawMode( $flag = true ) {
- // Can't wfDeprecated() here, since we need to set this flag from
- // ApiMain for BC with stuff using self::getIsRawMode as
- // "self::getIsXMLMode".
- $this->isRawMode = $flag;
+ wfDeprecated( __METHOD__, '1.25' );
}
/**
- * Returns true whether the formatter requested raw data.
+ * Returns true, the equivalent of "raw mode" is always enabled now
* @deprecated since 1.25, you shouldn't have been using it in the first place
* @return bool
*/
public function getIsRawMode() {
- /// @todo: After Wikibase stops calling this, warn
- return $this->isRawMode;
+ wfDeprecated( __METHOD__, '1.25' );
+ return true;
}
/**
@@ -1137,7 +1233,7 @@ class ApiResult implements ApiSerializable {
return $this->getResultData( null, array(
'BC' => array(),
'Types' => array(),
- 'Strip' => $this->isRawMode ? 'bc' : 'all',
+ 'Strip' => 'all',
) );
}
@@ -1176,7 +1272,7 @@ class ApiResult implements ApiSerializable {
*/
public static function setElement( &$arr, $name, $value, $flags = 0 ) {
wfDeprecated( __METHOD__, '1.25' );
- return self::setValue( $arr, $name, $value, $flags );
+ self::setValue( $arr, $name, $value, $flags );
}
/**
@@ -1390,7 +1486,7 @@ class ApiResult implements ApiSerializable {
*/
public static function size( $value ) {
wfDeprecated( __METHOD__, '1.25' );
- return self::valueSize( $value );
+ return self::valueSize( self::validateValue( $value ) );
}
/**
diff --git a/includes/api/ApiRevisionDelete.php b/includes/api/ApiRevisionDelete.php
index 28962316..7d89b690 100644
--- a/includes/api/ApiRevisionDelete.php
+++ b/includes/api/ApiRevisionDelete.php
@@ -32,6 +32,8 @@
class ApiRevisionDelete extends ApiBase {
public function execute() {
+ $this->useTransactionalTimeLimit();
+
$params = $this->extractRequestParams();
$user = $this->getUser();
@@ -137,10 +139,8 @@ class ApiRevisionDelete extends ApiBase {
if ( !$messages ) {
return array();
}
- $result = $this->getResult();
$ret = array();
foreach ( $messages as $m ) {
- $message = array();
if ( $m['message'] instanceof Message ) {
$msg = $m['message'];
$message = array( 'message' => $msg->getKey() );
diff --git a/includes/api/ApiRollback.php b/includes/api/ApiRollback.php
index 02e62a03..6a3346f4 100644
--- a/includes/api/ApiRollback.php
+++ b/includes/api/ApiRollback.php
@@ -40,6 +40,8 @@ class ApiRollback extends ApiBase {
private $mUser = null;
public function execute() {
+ $this->useTransactionalTimeLimit();
+
$user = $this->getUser();
$params = $this->extractRequestParams();
diff --git a/includes/api/ApiSetNotificationTimestamp.php b/includes/api/ApiSetNotificationTimestamp.php
index 86a3f6aa..fa6fabf6 100644
--- a/includes/api/ApiSetNotificationTimestamp.php
+++ b/includes/api/ApiSetNotificationTimestamp.php
@@ -112,9 +112,7 @@ class ApiSetNotificationTimestamp extends ApiBase {
: wfTimestamp( TS_ISO_8601, $timestamp );
} else {
// First, log the invalid titles
- foreach ( $pageSet->getInvalidTitles() as $title ) {
- $r = array();
- $r['title'] = $title;
+ foreach ( $pageSet->getInvalidTitlesAndReasons() as $r ) {
$r['invalid'] = true;
$result[] = $r;
}
diff --git a/includes/api/ApiStashEdit.php b/includes/api/ApiStashEdit.php
index d068e945..e87fc97a 100644
--- a/includes/api/ApiStashEdit.php
+++ b/includes/api/ApiStashEdit.php
@@ -20,7 +20,7 @@
*/
/**
- * Prepare and edit in shared cache so that it can be reused on edit
+ * Prepare an edit in shared cache so that it can be reused on edit
*
* This endpoint can be called via AJAX as the user focuses on the edit
* summary box. By the time of submission, the parse may have already
@@ -112,6 +112,7 @@ class ApiStashEdit extends ApiBase {
if ( $user->pingLimiter( 'stashedit' ) ) {
$status = 'ratelimited';
} elseif ( $wgMemc->lock( $key, 0, 30 ) ) {
+ /** @noinspection PhpUnusedLocalVariableInspection */
$unlocker = new ScopedCallback( function() use ( $key ) {
global $wgMemc;
$wgMemc->unlock( $key );
@@ -350,7 +351,7 @@ class ApiStashEdit extends ApiBase {
$content->getDefaultFormat(),
sha1( $content->serialize( $content->getDefaultFormat() ) ),
$user->getId() ?: md5( $user->getName() ), // account for user parser options
- $user->getId() ? $user->getTouched() : '-' // handle preference change races
+ $user->getId() ? $user->getDBTouched() : '-' // handle preference change races
) ) );
return wfMemcKey( 'prepared-edit', md5( $title->getPrefixedDBkey() ), $hash );
@@ -399,7 +400,7 @@ class ApiStashEdit extends ApiBase {
ApiBase::PARAM_TYPE => 'string'
),
'text' => array(
- ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_TYPE => 'text',
ApiBase::PARAM_REQUIRED => true
),
'contentmodel' => array(
diff --git a/includes/api/ApiUnblock.php b/includes/api/ApiUnblock.php
index 1af83ba3..f6c24b76 100644
--- a/includes/api/ApiUnblock.php
+++ b/includes/api/ApiUnblock.php
@@ -53,7 +53,13 @@ class ApiUnblock extends ApiBase {
if ( $user->isBlocked() ) {
$status = SpecialBlock::checkUnblockSelf( $params['user'], $user );
if ( $status !== true ) {
- $this->dieUsageMsg( $status );
+ $msg = $this->parseMsg( $status );
+ $this->dieUsage(
+ $msg['info'],
+ $msg['code'],
+ 0,
+ array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $user->getBlock() ) )
+ );
}
}
diff --git a/includes/api/ApiUndelete.php b/includes/api/ApiUndelete.php
index c23e9ff6..cd50ee65 100644
--- a/includes/api/ApiUndelete.php
+++ b/includes/api/ApiUndelete.php
@@ -30,6 +30,8 @@
class ApiUndelete extends ApiBase {
public function execute() {
+ $this->useTransactionalTimeLimit();
+
$params = $this->extractRequestParams();
if ( !$this->getUser()->isAllowed( 'undelete' ) ) {
@@ -37,7 +39,12 @@ class ApiUndelete extends ApiBase {
}
if ( $this->getUser()->isBlocked() ) {
- $this->dieUsageMsg( 'blockedtext' );
+ $this->dieUsage(
+ 'You have been blocked from editing',
+ 'blocked',
+ 0,
+ array( 'blockinfo' => ApiQueryUserInfo::getBlockInfo( $this->getUser()->getBlock() ) )
+ );
}
$titleObj = Title::newFromText( $params['title'] );
diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php
index 7661625c..65403ec4 100644
--- a/includes/api/ApiUpload.php
+++ b/includes/api/ApiUpload.php
@@ -313,6 +313,7 @@ class ApiUpload extends ApiBase {
$result['result'] = 'Continue';
$result['offset'] = $totalSoFar;
}
+
$result['filekey'] = $filekey;
return $result;
@@ -580,17 +581,28 @@ class ApiUpload extends ApiBase {
$this->dieUsage( $msg, 'filetype-banned', 0, $extradata );
break;
case UploadBase::VERIFICATION_ERROR:
+ $params = $verification['details'];
+ $key = array_shift( $params );
+ $msg = $this->msg( $key, $params )->inLanguage( 'en' )->useDatabase( false )->text();
ApiResult::setIndexedTagName( $verification['details'], 'detail' );
- $this->dieUsage( 'This file did not pass file verification', 'verification-error',
+ $this->dieUsage( "This file did not pass file verification: $msg", 'verification-error',
0, array( 'details' => $verification['details'] ) );
break;
case UploadBase::HOOK_ABORTED:
- $this->dieUsage( "The modification you tried to make was aborted by an extension hook",
- 'hookaborted', 0, array( 'error' => $verification['error'] ) );
+ if ( is_array( $verification['error'] ) ) {
+ $params = $verification['error'];
+ } elseif ( $verification['error'] !== '' ) {
+ $params = array( $verification['error'] );
+ } else {
+ $params = array( 'hookaborted' );
+ }
+ $key = array_shift( $params );
+ $msg = $this->msg( $key, $params )->inLanguage( 'en' )->useDatabase( false )->text();
+ $this->dieUsage( $msg, 'hookaborted', 0, array( 'details' => $verification['error'] ) );
break;
default:
$this->dieUsage( 'An unknown error occurred', 'unknown-error',
- 0, array( 'code' => $verification['status'] ) );
+ 0, array( 'details' => array( 'code' => $verification['status'] ) ) );
break;
}
}
@@ -788,7 +800,9 @@ class ApiUpload extends ApiBase {
'comment' => array(
ApiBase::PARAM_DFLT => ''
),
- 'text' => null,
+ 'text' => array(
+ ApiBase::PARAM_TYPE => 'text',
+ ),
'watch' => array(
ApiBase::PARAM_DFLT => false,
ApiBase::PARAM_DEPRECATED => true,
diff --git a/includes/api/i18n/ar.json b/includes/api/i18n/ar.json
index aa456f00..7bdf29ab 100644
--- a/includes/api/i18n/ar.json
+++ b/includes/api/i18n/ar.json
@@ -4,7 +4,8 @@
"Meno25",
"أحمد المحمودي",
"Khaled",
- "Fatz"
+ "Fatz",
+ "Hiba Alshawi"
]
},
"apihelp-main-param-format": "صيغة الخرج.",
@@ -24,5 +25,6 @@
"apihelp-edit-param-watch": "أضف الصفحة إلى لائحة مراقبة المستعمل الحالي",
"apihelp-emailuser-description": "مراسلة المستخدم",
"apihelp-patrol-example-rcid": "ابحث عن تغيير جديد",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "إضافة هوية المستخدم الذي قام بتحميل كل إصدار ملف.",
"apihelp-query+prefixsearch-param-offset": "عدد النتائج المراد تخطيها."
}
diff --git a/includes/api/i18n/ast.json b/includes/api/i18n/ast.json
new file mode 100644
index 00000000..9494a7cb
--- /dev/null
+++ b/includes/api/i18n/ast.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xuacu"
+ ]
+ },
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentación]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Llista d'alderique]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Anuncios de la API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Fallos y solicitúes]\n</div>\n<strong>Estau:</strong> Toles carauterístiques qu'apaecen nesta páxina tendríen de funcionar, pero la API inda ta en desendolcu activu, y puede camudar en cualquier momentu. Suscríbete a la [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ llista de corréu mediawiki-api-announce] p'avisos sobro anovamientos.\n\n<strong>Solicitúes incorreutes:</strong> Cuando s'unvíen solicitúes incorreutes a la API, unvíase una cabecera HTTP cola clave \"MediaWiki-API-Error\" y, darréu, tanto'l valor de la cabecera como'l códigu d'error devueltu pondránse al mesmu valor. Pa más información, consulta [[mw:API:Errors_and_warnings|API: Errores y avisos]].",
+ "apihelp-main-param-action": "Qué aición facer.",
+ "apihelp-main-param-format": "El formatu de la salida."
+}
diff --git a/includes/api/i18n/ba.json b/includes/api/i18n/ba.json
new file mode 100644
index 00000000..bda2291d
--- /dev/null
+++ b/includes/api/i18n/ba.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Рустам Нурыев"
+ ]
+ },
+ "apihelp-feedcontributions-param-toponly": "Һуңғы өлгө булған төҙәтеүҙәрҙе генә күрһәтергә",
+ "apihelp-feedcontributions-param-showsizediff": "Өлгәоәр араһыдағы күләм айырмаһын күрһәтергә",
+ "apihelp-feedrecentchanges-param-from": "Теге ваҡыттын булған үҙгәрештәрҙе күрһәтергә",
+ "apihelp-feedrecentchanges-param-target": "Был биттән һылтанған биттәрҙә һуңғы үҙгәртеүҙәрҙе күрһәтергә",
+ "apihelp-feedrecentchanges-example-simple": "Һуңғы үҙгәртеүҙәрҙе күрһәтергә.",
+ "apihelp-feedwatchlist-example-default": "Күҙәтеү каналын күрһәтергә"
+}
diff --git a/includes/api/i18n/bcl.json b/includes/api/i18n/bcl.json
new file mode 100644
index 00000000..420aded3
--- /dev/null
+++ b/includes/api/i18n/bcl.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Geopoet"
+ ]
+ },
+ "apihelp-expandtemplates-paramvalue-prop-categories": "Arinman na mga kategoriyang yaon sa pinapalaog na bakong representado sa laog kan wikitext na kinaluwasan.",
+ "apihelp-query+watchlistraw-param-fromtitle": "Titulo (may espasyong ngaran sa enotang panigmitan) sa pagpopoon kan gikanang pinagkuanan.",
+ "apihelp-query+watchlistraw-param-totitle": "Titulo (may espasyong ngaran sa enotang panigmitan) sa pagpapauntok kan gikanang pinaghalean."
+}
diff --git a/includes/api/i18n/be-tarask.json b/includes/api/i18n/be-tarask.json
index a09cb5ab..98485cff 100644
--- a/includes/api/i18n/be-tarask.json
+++ b/includes/api/i18n/be-tarask.json
@@ -8,8 +8,8 @@
"apihelp-main-param-action": "Дзеяньне для выкананьня.",
"apihelp-main-param-format": "Фармат вываду.",
"apihelp-main-param-maxlag": "Максымальная затрымка можа ўжывацца, калі MediaWiki ўсталяваная ў клястэр з рэплікаванай базай зьвестак. Дзеля захаваньня дзеяньняў, якія выклікаюць затрымку рэплікацыі, гэты парамэтар можа прымусіць кліента чакаць, пакуль затрымка рэплікацыі меншая за яго значэньне. У выпадку доўгай затрымкі, вяртаецца код памылкі <samp>maxlag</samp> з паведамленьнем кшталту <samp>Чаканьне $host: $lag сэкундаў затрымкі</samp>.<br />Глядзіце [[mw:Manual:Maxlag_parameter|Інструкцыя:Парамэтар maxlag]] дзеля дадатковай інфармацыі.",
- "apihelp-main-param-smaxage": "Выстаўце загаловак <code>s-maxage</code> на зададзеную колькасьць сэкундаў. Памылкі ніколі не кэшуюцца.",
- "apihelp-main-param-maxage": "Выстаўляе загаловак <code>max-age</code> на зададзеную колькасьць сэкундаў. Памылкі ніколі не кэшуюцца.",
+ "apihelp-main-param-smaxage": "Выстаўце HTTP-загаловак кантролю кэшу <code>s-maxage</code> на зададзеную колькасьць сэкундаў. Памылкі ніколі не кэшуюцца.",
+ "apihelp-main-param-maxage": "Выстаўляе HTTP-загаловак кантролю кэшу <code>max-age</code> на зададзеную колькасьць сэкундаў. Памылкі ніколі не кэшуюцца.",
"apihelp-main-param-assert": "Упэўніцеся, што ўдзельнік увайшоў у сыстэму, калі зададзена <kbd>user</kbd>, або мае правы робата, калі зададзена <kbd>bot</kbd>.",
"apihelp-main-param-requestid": "Любое значэньне, пададзенае тут, будзе ўключанае ў адказ. Можа быць выкарыстанае для адрозьненьня запытаў.",
"apihelp-main-param-servedby": "Уключае ў вынік назву сэрвэра, які апрацаваў запыт.",
diff --git a/includes/api/i18n/br.json b/includes/api/i18n/br.json
new file mode 100644
index 00000000..68102359
--- /dev/null
+++ b/includes/api/i18n/br.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Y-M D"
+ ]
+ },
+ "apihelp-block-description": "Stankañ un implijer",
+ "apihelp-block-param-reason": "Abeg evit stankañ.",
+ "apihelp-delete-description": "Diverkañ ur bajenn.",
+ "apihelp-edit-param-minor": "Kemmig dister.",
+ "apihelp-edit-example-edit": "Kemmañ ur bajenn.",
+ "apihelp-expandtemplates-param-title": "Titl ar bajenn."
+}
diff --git a/includes/api/i18n/bs.json b/includes/api/i18n/bs.json
index 420e6ac0..841bb2a4 100644
--- a/includes/api/i18n/bs.json
+++ b/includes/api/i18n/bs.json
@@ -1,14 +1,15 @@
{
"@metadata": {
"authors": [
- "Palapa"
+ "Palapa",
+ "Semso98"
]
},
"apihelp-main-param-action": "Koju akciju izvesti.",
"apihelp-main-param-format": "Format izlaza.",
"apihelp-block-description": "Blokiraj korisnika",
"apihelp-block-param-reason": "Razlog za blokadu",
- "apihelp-block-example-ip-simple": "Blokiraj IP 192.0.2.5 na tri dana sa razlogom \"Prvi napad\"",
+ "apihelp-block-example-ip-simple": "Blokiraj IP adresu <kbd>192.0.2.5</kbd> na tri dana sa razlogom <kbd>Prvi napad</kbd>.",
"apihelp-compare-param-fromtitle": "Prvi naslov za poređenje.",
"apihelp-delete-description": "Obriši stranicu.",
"apihelp-edit-param-text": "Sadržaj stranice.",
diff --git a/includes/api/i18n/ca.json b/includes/api/i18n/ca.json
index 7aa17307..4aacd1aa 100644
--- a/includes/api/i18n/ca.json
+++ b/includes/api/i18n/ca.json
@@ -3,7 +3,9 @@
"authors": [
"Toniher",
"Macofe",
- "Xavier Dengra"
+ "Xavier Dengra",
+ "F3RaN",
+ "Eduardo Martinez"
]
},
"apihelp-main-param-format": "El format de la sortida.",
@@ -39,5 +41,16 @@
"apihelp-feedrecentchanges-example-simple": "Mostra els canvis recents.",
"apihelp-help-example-recursive": "Tota l'ajuda en una sola pàgina.",
"apihelp-import-param-rootpage": "Importa com a subpàgina d'aquesta pàgina.",
- "apihelp-login-example-login": "Inicia sessió."
+ "apihelp-login-param-name": "Nom d'usuari.",
+ "apihelp-login-param-password": "Contrasenya.",
+ "apihelp-login-example-login": "Inicia sessió.",
+ "apihelp-protect-param-cascade": "Activa la protecció en cascada (és a dir, protegeix les plantilles i imatges utilitzades en aquesta pàgina). S'ignora si cap dels nivells de protecció suporta la protecció en cascada.",
+ "apihelp-query+pageswithprop-example-generator": "Obtenir informació addicional sobre les 10 primeres pàgines utilitzant <code>__NOTOC__</code>.",
+ "apihelp-query+watchlist-paramvalue-prop-title": "Afegeix el títol de la pàgina.",
+ "apihelp-query+watchlist-paramvalue-prop-user": "Afegeix l'usuari que ha fet l'edició.",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "Afegeix l'IDentificador de l'usuari que ha fet l'edició.",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "Afegeix comentari de l'edició.",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "Afegeix timestamp de l'edició.",
+ "apihelp-query+watchlist-paramvalue-prop-patrol": "Etiqueta les modificacions que són vigilades.",
+ "apihelp-query+watchlist-paramvalue-prop-loginfo": "Afegeix informació de registre, si s'escau."
}
diff --git a/includes/api/i18n/ce.json b/includes/api/i18n/ce.json
index 1d866ba6..5b057559 100644
--- a/includes/api/i18n/ce.json
+++ b/includes/api/i18n/ce.json
@@ -8,5 +8,6 @@
"apihelp-main-param-format": "Гойту формат.",
"apihelp-main-param-curtimestamp": "Хилламийн юкъатоха ханна йолу билгало",
"apihelp-createaccount-param-name": "Декъашхочун цӀе.",
- "apihelp-userrights-param-userid": "Декъашхочун ID."
+ "apihelp-userrights-param-userid": "Декъашхочун ID.",
+ "api-help-datatypes-header": "Хаамийн тайпанаш"
}
diff --git a/includes/api/i18n/ckb.json b/includes/api/i18n/ckb.json
new file mode 100644
index 00000000..025741cb
--- /dev/null
+++ b/includes/api/i18n/ckb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pirehelokan"
+ ]
+ },
+ "apihelp-parse-param-disabletoc": "پێرستی ناوەرۆک پیشان مەدە."
+}
diff --git a/includes/api/i18n/cs.json b/includes/api/i18n/cs.json
index 059eb82e..b544cc8b 100644
--- a/includes/api/i18n/cs.json
+++ b/includes/api/i18n/cs.json
@@ -5,20 +5,21 @@
"YjM",
"Juandev",
"Aktron",
- "Cvanca"
+ "Cvanca",
+ "Utar"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Dokumentace]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-mailová konference]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Oznámení k API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Chyby a požadavky]\n</div>\n<strong>Stav:</strong> Všechny funkce uvedené na této stránce by měly fungovat, ale API se stále aktivně vyvíjí a může se kdykoli změnit. Upozornění na změny získáte přihlášením se k [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ e-mailové konferenci mediawiki-api-announce].\n\n<strong>Chybné požadavky:</strong> Pokud jsou do API zaslány chybné požadavky, bude vrácena HTTP hlavička s klíčem „MediaWiki-API-Error“ a hodnota této hlavičky a chybový kód budou nastaveny na stejnou hodnotu. Více informací najdete [[mw:API:Errors_and_warnings|v dokumentaci]].",
"apihelp-main-param-action": "Jaká akce se má provést.",
"apihelp-main-param-format": "Formát výstupu.",
"apihelp-main-param-maxlag": "Maximální zpoždění lze použít, když je MediaWiki nainstalováno na cluster s replikovanou databází. Abyste se vyhnuli zhoršování už tak špatného replikačního zpoždění, můžete tímto parametrem nechat klienta čekat, dokud replikační zpoždění neklesne pod uvedenou hodnotu. V případě příliš vysokého zpoždění se vrátí chybový kód „<samp>maxlag</samp>“ s hlášením typu „<samp>Waiting for $host: $lag seconds lagged</samp>“.<br />Více informací najdete v [[mw:Manual:Maxlag_parameter|příručce]].",
- "apihelp-main-param-smaxage": "Nastaví hlavičku <code>s-maxage</code> na uvedený počet sekund. Chyby se nekešují nikdy.",
- "apihelp-main-param-maxage": "Nastaví hlavičku <code>max-age</code> na uvedený počet sekund. Chyby se nekešují nikdy.",
+ "apihelp-main-param-smaxage": "Nastaví HTTP hlavičku pro řízení kešování <code>s-maxage</code> na uvedený počet sekund. Chyby se nekešují nikdy.",
+ "apihelp-main-param-maxage": "Nastaví HTTP hlavičku pro řízení kešování <code>max-age</code> na uvedený počet sekund. Chyby se nekešují nikdy.",
"apihelp-main-param-assert": "Pokud je nastaveno na „<kbd>user</kbd>“, ověří, že je uživatel přihlášen, pokud je nastaveno na „<kbd>bot</kbd>“, ověří, že má oprávnění „bot“.",
"apihelp-main-param-requestid": "Libovolná zde uvedená hodnota bude zahrnuta v odpovědi. Lze použít pro rozlišení požadavků.",
"apihelp-main-param-servedby": "Zahrnout do odpovědi název hostitele, který požadavek obsloužil.",
"apihelp-main-param-curtimestamp": "Zahrnout do odpovědi aktuální časové razítko.",
- "apihelp-main-param-origin": "Pokud k API přistupujete pomocí mezidoménového AJAXového požadavku (CORS), nastavte tento parametr na doménu původu. Musí být součástí všech předběžných požadavků, takže musí být součástí URI požadavku (nikoli těla POSTu). Hodnota musí přesně odpovídat jednomu z původů v hlavičce Origin:, takže musí být nastavena na něco jako http://en.wikipedia.org nebo https://meta.wikimedia.org. Pokud parametr neodpovídá hlavičce Origin:, bude vrácena odpověď 403. Pokud parametr odpovídá hlavičce Origin: a tento původ je na bílé listině, bude nastavena hlavička Access-Control-Allow-Origin.",
+ "apihelp-main-param-origin": "Pokud k API přistupujete pomocí mezidoménového AJAXového požadavku (CORS), nastavte tento parametr na doménu původu. Musí být součástí všech předběžných požadavků, takže musí být součástí URI požadavku (nikoli těla POSTu). Hodnota musí přesně odpovídat jednomu z původů v hlavičce <code>Origin</code>, takže musí být nastavena na něco jako <kbd>https://en.wikipedia.org</kbd> nebo <kbd>https://meta.wikimedia.org</kbd>. Pokud parametr neodpovídá hlavičce <code>Origin</code>, bude vrácena odpověď 403. Pokud parametr odpovídá hlavičce <code>Origin</code> a tento původ je na bílé listině, bude nastavena hlavička <code>Access-Control-Allow-Origin</code>.",
"apihelp-main-param-uselang": "Jazyk, který se má použít pro překlad hlášení. Seznam kódů lze načíst z <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> se <kbd>siprop=languages</kbd>, nebo zadejte „<kbd>user</kbd>“ pro použití předvoleného jazyka aktuálního uživatele či „<kbd>content</kbd>“ pro použití jazyka obsahu této wiki.",
"apihelp-block-description": "Zablokovat uživatele.",
"apihelp-block-param-user": "Uživatelské jméno, IP adresa nebo rozsah IP adres, které chcete zablokovat.",
@@ -32,7 +33,9 @@
"apihelp-block-param-watchuser": "Sledovat stránku uživatele nebo IP adresy a jejich diskuzní stránky.",
"apihelp-block-example-ip-simple": "Na tři dny zablokovat IP adresu <kbd>192.0.2.5</kbd> s odůvodněním <kbd>First strike</kbd>.",
"apihelp-block-example-user-complex": "Trvale zablokovat uživatele <kbd>Vandal</kbd> s odůvodněním <kbd>Vandalism</kbd> a zabránit vytváření nových účtů a odesílání e-mailů.",
- "apihelp-compare-description": "Vrátí rozdíl dvou stránek.\n\nVe „from“ a „to“ musíte zadat číslo revize, název stránky nebo ID stránky.",
+ "apihelp-checktoken-param-type": "Typ testovaného tokenu.",
+ "apihelp-checktoken-param-token": "Token, který se má otestovat.",
+ "apihelp-compare-description": "Vrátí rozdíl dvou stránek.\n\nVe „from“ i „to“ musíte zadat číslo revize, název stránky nebo ID stránky.",
"apihelp-compare-param-fromtitle": "Název první stránky k porovnání.",
"apihelp-compare-param-fromid": "ID první stránky k porovnání.",
"apihelp-compare-param-fromrev": "Číslo revize první stránky k porovnání.",
@@ -55,9 +58,13 @@
"apihelp-delete-param-title": "Název stránky, která se má smazat. Není možné použít společně s <var>$1pageid</var>.",
"apihelp-delete-param-pageid": "ID stránky, která se má smazat. Není možné použít společně s <var>$1title</var>.",
"apihelp-delete-param-watch": "Přidat stránku na seznam sledovaných.",
+ "apihelp-delete-param-unwatch": "Odstranit stránku ze seznamu sledovaných.",
"apihelp-delete-example-simple": "Smazat stránku <kbd>Main Page</kbd>.",
+ "apihelp-delete-example-reason": "Smazat stránku <kbd>Main Page</kbd> s odůvodněním <kbd>Preparing for move</kbd>.",
"apihelp-disabled-description": "Tento modul byl deaktivován.",
"apihelp-edit-description": "Vytvářet a upravovat stránky.",
+ "apihelp-edit-param-title": "Název stránky, kterou chcete editovat. Nelze použít společně s <var>$1pageid</var>.",
+ "apihelp-edit-param-pageid": "ID stránky, která se má editovat. Není možné použít společně s <var>$1title</var>.",
"apihelp-edit-param-sectiontitle": "Název nové sekce.",
"apihelp-edit-param-text": "Obsah stránky.",
"apihelp-edit-param-minor": "Malá editace.",
@@ -71,14 +78,24 @@
"apihelp-edit-param-redirect": "Automaticky opravit přesměrování.",
"apihelp-edit-example-edit": "Upravit stránku.",
"apihelp-emailuser-description": "Poslat uživateli e-mail.",
+ "apihelp-emailuser-param-target": "Uživatel, kterému se má e-mail poslat.",
+ "apihelp-emailuser-param-subject": "Hlavička s předmětem.",
"apihelp-emailuser-param-text": "Tělo zprávy.",
"apihelp-emailuser-param-ccme": "Odeslat mi kopii této zprávy.",
+ "apihelp-emailuser-example-email": "Poslat e-mail uživateli <kbd>WikiSysop</kbd> s textem <kbd>Content</kbd>.",
+ "apihelp-expandtemplates-description": "Rozbalí všechny šablony ve wikitextu.",
+ "apihelp-expandtemplates-param-title": "Název stránky.",
"apihelp-expandtemplates-param-text": "Wikitext k převedení.",
+ "apihelp-expandtemplates-param-revid": "ID revize, pro <nowiki>{{REVISIONID}}</nowiki> a podobné proměnné.",
"apihelp-feedcontributions-description": "Vrátí kanál příspěvků uživatele.",
"apihelp-feedcontributions-param-feedformat": "Formát kanálu.",
"apihelp-feedcontributions-param-year": "Od roku (a dříve).",
"apihelp-feedcontributions-param-month": "Od měsíce (a dříve)",
+ "apihelp-feedcontributions-param-tagfilter": "Filtrovat příspěvky, které mají tyto značky.",
"apihelp-feedcontributions-param-deletedonly": "Zobrazit pouze smazané příspěvky.",
+ "apihelp-feedcontributions-param-toponly": "Zobrazit pouze ty editace, které jsou aktuální revize.",
+ "apihelp-feedcontributions-param-newonly": "Zobrazit pouze ty editace, které vytvořily stránku.",
+ "apihelp-feedcontributions-param-showsizediff": "Zobrazit rozdíl velikosti mezi revizemi.",
"apihelp-feedrecentchanges-param-namespace": "Jmenný prostor, na který mají být výsledky omezeny.",
"apihelp-feedrecentchanges-param-from": "Zobrazit změny od",
"apihelp-feedrecentchanges-param-hideminor": "Skrýt drobné změny.",
@@ -95,7 +112,7 @@
"apihelp-filerevert-param-filename": "Cílový název souboru, bez prefixu Soubor:",
"apihelp-filerevert-param-comment": "Vložit komentář.",
"apihelp-help-description": "Zobrazuje nápovědu k uvedeným modulům.",
- "apihelp-help-param-modules": "Moduly, pro které se má zobrazit nápověda (hodnoty parametrů action= a format= nebo „main“). Submoduly lze zadávat pomocí „+“.",
+ "apihelp-help-param-modules": "Moduly, pro které se má zobrazit nápověda (hodnoty parametrů <var>action</var> a <var>format</var> anebo <kbd>main</kbd>). Submoduly lze zadávat pomocí <kbd>+</kbd>.",
"apihelp-help-param-submodules": "Zahrnout nápovědu pro podmoduly uvedeného modulu.",
"apihelp-help-param-recursivesubmodules": "Zahrnout nápovědu pro podmoduly rekurzivně.",
"apihelp-help-param-helpformat": "Formát výstupu nápovědy.",
@@ -106,9 +123,11 @@
"apihelp-help-example-help": "Nápověda k samotnému modulu nápovědy",
"apihelp-help-example-query": "Nápověda pro dva podmoduly query",
"apihelp-imagerotate-description": "Otočit jeden nebo více obrázků.",
+ "apihelp-imagerotate-example-generator": "Otočit všechny obrázky v <kbd>Category:Flip</kbd> o <kbd>180</kbd> stupňů.",
"apihelp-import-param-summary": "Import shrnutí.",
"apihelp-import-param-xml": "Nahraný XML soubor.",
- "apihelp-import-param-rootpage": "Importovat jako podstránku k této stránce.",
+ "apihelp-import-param-namespace": "Importovat do tohoto jmenného prostoru. Nelze používat současně s parametrem <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Importovat jako podstránku k této stránce. Nelze používat současně s parametrem <var>$1namespace</var>.",
"apihelp-login-param-name": "Uživatelské jméno.",
"apihelp-login-param-password": "Heslo.",
"apihelp-login-param-domain": "Doména (volitelná)",
@@ -122,23 +141,35 @@
"apihelp-move-param-watch": "Přidat stránku a přesměrování do sledovaných stránek aktuálního uživatele.",
"apihelp-move-param-unwatch": "Odstranit stránku a přesměrování ze sledovaných stránek současného uživatele.",
"apihelp-move-param-ignorewarnings": "Ignorovat všechna varování.",
+ "apihelp-opensearch-description": "Vyhledávání na wiki pomocí protokolu OpenSearch.",
"apihelp-opensearch-param-search": "Hledaný řetězec.",
"apihelp-opensearch-param-limit": "Maximální počet vrácených výsledků",
"apihelp-opensearch-param-namespace": "Jmenné prostory pro vyhledávání.",
+ "apihelp-opensearch-param-suggest": "Pokud je <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> vypnuto, nedělat nic.",
"apihelp-opensearch-param-format": "Formát výstupu.",
"apihelp-opensearch-example-te": "Najít stránky začínající na „<kbd>Te</kbd>“.",
+ "apihelp-options-param-reset": "Vrátit nastavení na výchozí hodnoty.",
"apihelp-options-example-reset": "Vrátit všechna nastavení.",
+ "apihelp-parse-param-summary": "Shrnutí, které se má parsovat.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Přidává název parsovaného wikitextu.",
+ "apihelp-parse-param-preview": "Parsovat v režimu náhledu.",
"apihelp-parse-example-page": "Parsovat stránku.",
"apihelp-parse-example-text": "Parsovat wikitext.",
+ "apihelp-parse-example-summary": "Parsovat shrnutí.",
"apihelp-patrol-example-revid": "Prověřit revizi.",
"apihelp-protect-description": "Změnit úroveň zamčení stránky.",
"apihelp-protect-param-reason": "Důvod pro odemčení.",
"apihelp-protect-example-protect": "Zamknout stránku.",
+ "apihelp-query+allcategories-param-limit": "Kolik má být zobrazeno kategorií.",
"apihelp-query+alldeletedrevisions-description": "Seznam všech smazaných revizí od konkrétního uživatele nebo v konkrétním jmenném prostoru.",
+ "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "Není možné užít s <var>$3user</var>.",
"apihelp-query+alldeletedrevisions-example-user": "Seznam posledních 50 smazaných editací uživatele <kbd>Příklad<kbd>.",
"apihelp-query+alldeletedrevisions-example-ns-main": "Seznam prvních 50 smazaných revizí v hlavním jmenném prostoru.",
"apihelp-query+allfileusages-description": "Zobrazit seznam všech použití souboru, včetně neexistujících.",
"apihelp-query+allfileusages-example-unique": "Zobrazit seznam unikátních názvů souborů.",
+ "apihelp-query+allimages-param-minsize": "Omezit na obrázky, které mají alespoň tento počet bajtů.",
+ "apihelp-query+allimages-param-maxsize": "Omezit na obrázky, které mají maximálně tento počet bajtů.",
+ "apihelp-query+allimages-param-limit": "Kolik má být celkem zobrazeno obrázků.",
"apihelp-query+alllinks-example-generator": "Získat stránky obsahující odkazy.",
"apihelp-query+allpages-param-filterredir": "Které stránky uvést na seznam.",
"apihelp-query+allpages-param-minsize": "Omezit na stránky s určitým počtem bajtů.",
@@ -147,15 +178,44 @@
"apihelp-query+allredirects-description": "Seznam všech přesměrování pro jmenný prostor.",
"apihelp-query+allredirects-example-unique": "Seznam unikátních cílových stránek.",
"apihelp-query+allredirects-example-generator": "Získat stránky obsahující přesměrování.",
+ "apihelp-query+alltransclusions-param-limit": "Kolik položek zobrazit celkem.",
"apihelp-query+alltransclusions-example-unique": "Seznam unikátně vložených titulů.",
+ "apihelp-query+allusers-example-Y": "Zobrazit uživatele počínaje písmenem <kbd>Y</kbd>.",
+ "apihelp-query+backlinks-description": "Najít všechny stránky, které odkazují na danou stránku.",
"apihelp-query+backlinks-example-simple": "Zobrazit odkazy na <kbd>Hlavní stránka</kbd>",
+ "apihelp-query+blocks-example-simple": "Vypsat zablokování.",
+ "apihelp-query+blocks-example-users": "Seznam bloků uživatelů <kbd>Alice</kbd> a <kbd>Bob</kbd>.",
+ "apihelp-query+categories-description": "Zobrazit všechny kategorie, do kterých je stránka zařazena.",
+ "apihelp-query+categories-param-limit": "Kolik kategorií má být zobrazeno.",
"apihelp-query+categorymembers-description": "Seznam všech stránek v dané kategorii.",
+ "apihelp-query+categorymembers-param-limit": "Maximální počet stránek k zobrazení.",
+ "apihelp-query+categorymembers-example-simple": "Zobrazit prvních 10 stránek v <kbd>Category:Physics</kbd>",
+ "apihelp-query+categorymembers-example-generator": "Získat informace o prvních 10 stránkách v <kbd>Category:Physics</kbd>",
+ "apihelp-query+contributors-description": "Zobrazit seznam registrovaných a počet anonymních přispěvatelů stránky.",
+ "apihelp-query+contributors-param-limit": "Kolik přispěvatelů má být zobrazeno.",
+ "apihelp-query+contributors-example-simple": "Zobrazit přispěvatele stránky <kbd>Main Page</kbd>.",
"apihelp-query+deletedrevisions-param-limit": "Maximální počet revizí pro zobrazení v seznamu.",
+ "apihelp-query+deletedrevs-param-excludeuser": "Nezahrnovat revize od tohoto uživatele.",
+ "apihelp-query+deletedrevs-param-namespace": "Zahrnout pouze stránky z tohoto jmenného prostoru.",
+ "apihelp-query+deletedrevs-param-limit": "Maximální počet revizí k zobrazení.",
"apihelp-query+embeddedin-example-simple": "Zobrazit stránky, které obahují <kbd>Template:Stub</kbd>.",
"apihelp-query+filearchive-example-simple": "Zobrazit seznam všech smazaných souborů.",
"apihelp-query+filerepoinfo-example-simple": "Získat informace o souborových repozitářích.",
+ "apihelp-query+iwbacklinks-param-prefix": "Prefix pro interwiki",
+ "apihelp-query+iwlinks-param-limit": "Počet interwiki odkazů k zobrazení.",
+ "apihelp-query+iwlinks-param-prefix": "Zobrazit pouze interwiki odkazy s tímto prefixem.",
+ "apihelp-query+iwlinks-param-title": "Interwiki odkaz, který se má hledat. Musí se použít spolu s <var>$1prefix</var>.",
+ "apihelp-query+langbacklinks-param-lang": "Jazyk pro jazykový odkaz.",
+ "apihelp-query+langbacklinks-example-simple": "Zobrazit stránky odkazující na [[:fr:Test]]",
+ "apihelp-query+langbacklinks-example-generator": "Získat informace o stránkách odkazujících na [[:fr:Test]].",
+ "apihelp-query+langlinks-description": "Zobrazit všechny mezijazykové odkazy z daných stránek.",
+ "apihelp-query+langlinks-param-lang": "Zobrazit pouze jazykové odkazy s tímto kódem jazyka.",
"apihelp-query+linkshere-example-generator": "Získat informace o stránkách, které odkazují na [[Hlavní Stránka|Hlavní stránku]].",
+ "apihelp-query+recentchanges-param-excludeuser": "Nezobrazovat změny od tohoto uživatele.",
"apihelp-query+recentchanges-example-simple": "Seznam posledních změn.",
+ "apihelp-query+redirects-param-limit": "Počet přesměrování, který má být zobrazen.",
+ "apihelp-query+redirects-example-simple": "Zobrazit seznam přesměrování na stránku [[Main Page]].",
+ "apihelp-query+search-example-simple": "Hledat <kbd>meaning</kbd>",
"apihelp-query+tags-example-simple": "Získat seznam dostupných tagů.",
"apihelp-query+usercontribs-example-user": "Zobrazit příspěvky uživatele <kbd>Příklad</kbd>",
"apihelp-query+watchlistraw-description": "Získat všechny stránky, které jsou aktuálním uživatelem sledovány.",
@@ -164,30 +224,31 @@
"apihelp-watch-example-watch": "Sledovat stránku <kbd>Hlavní stránka</kbd>.",
"apihelp-watch-example-generator": "Zobrazit prvních několik stránek z hlavního jmenného prostoru.",
"apihelp-format-example-generic": "Výsledek dotazu vypsat ve formátu $1.",
- "apihelp-dbg-description": "Vypisuje data ve formátu funkce var_export() z PHP.",
- "apihelp-dbgfm-description": "Vypisuje data ve formátu funkce var_export() z PHP (v čitelné HTML podobě).",
- "apihelp-dump-description": "Vypisuje data ve formátu funkce var_dump() z PHP.",
- "apihelp-dumpfm-description": "Vypisuje data ve formátu funkce var_dump() z PHP (v čitelné HTML podobě).",
+ "apihelp-dbg-description": "Vypisuje data ve formátu funkce <code>var_export()</code> z PHP.",
+ "apihelp-dbgfm-description": "Vypisuje data ve formátu funkce <code>var_export()</code> z PHP (v čitelné HTML podobě).",
+ "apihelp-dump-description": "Vypisuje data ve formátu funkce <code>var_dump()</code> z PHP.",
+ "apihelp-dumpfm-description": "Vypisuje data ve formátu funkce <code>var_dump()</code> z PHP (v čitelné HTML podobě).",
"apihelp-json-description": "Vypisuje data ve formátu JSON.",
"apihelp-json-param-callback": "Pokud je uvedeno, obalí výstup do zadaného volání funkce. Z bezpečnostních důvodů budou omezena všechna data specifická pro uživatele.",
- "apihelp-json-param-utf8": "Pokud je uvedeno, bude většina ne-ASCII znaků (ale ne všechny) kódována v UTF-8 místo nahrazení hexadecimálními escape sekvencemi.",
+ "apihelp-json-param-utf8": "Pokud je uvedeno, bude většina ne-ASCII znaků (ale ne všechny) kódována v UTF-8 místo nahrazení hexadecimálními escape sekvencemi. Implicitní chování, pokud není <var>formatversion</var> nastaveno na <kbd>1</kbd>.",
"apihelp-jsonfm-description": "Vypisuje data ve formátu JSON (v čitelné HTML podobě).",
"apihelp-none-description": "Nevypisuje nic.",
"apihelp-php-description": "Vypisuje data v serializačním formátu PHP.",
"apihelp-phpfm-description": "Vypisuje data v serializačním formátu PHP (v čitelné HTML podobě).",
"apihelp-rawfm-description": "Vypisuje data s ladicími prvky ve formátu JSON (v čitelné HTML podobě).",
- "apihelp-txt-description": "Vypisuje data ve formátu funkce print_r() z PHP.",
- "apihelp-txtfm-description": "Vypisuje data ve formátu funkce print_r() z PHP (v čitelné HTML podobě).",
+ "apihelp-txt-description": "Vypisuje data ve formátu funkce <code>print_r()</code> z PHP.",
+ "apihelp-txtfm-description": "Vypisuje data ve formátu funkce <code>print_r()</code> z PHP (v čitelné HTML podobě).",
"apihelp-wddx-description": "Vypisuje data ve formátu WDDX.",
"apihelp-wddxfm-description": "Vypisuje data ve formátu WDDX (v čitelné HTML podobě).",
"apihelp-xml-description": "Vypisuje data ve formátu XML.",
- "apihelp-xml-param-xslt": "Pokud je uvedeno, přidá stylopis &lt;xslt&gt;. Měla by jím být wikistránka v jmenném prostoru MediaWiki, jejíž název končí na „.xsl“.",
+ "apihelp-xml-param-xslt": "Pokud je uvedeno, přidá uvedenou stránku jako stylopis XSL. Hodnotou musí být název stránky ve jmenném prostoru MediaWiki, jejíž název končí na <code>.xsl</code>.",
"apihelp-xml-param-includexmlnamespace": "Pokud je uvedeno, přidá jmenný prostor XML.",
"apihelp-xmlfm-description": "Vypisuje data ve formátu XML (v čitelné HTML podobě).",
"apihelp-yaml-description": "Vypisuje data ve formátu YAML.",
"apihelp-yamlfm-description": "Vypisuje data ve formátu YAML (v čitelné HTML podobě).",
"api-format-title": "Odpověď z MediaWiki API",
- "api-format-prettyprint-header": "Díváte se na HTML reprezentaci formátu $1. HTML se hodí pro ladění, ale pro aplikační použití je nevhodné.\n\nPro změnu výstupního formátu uveďte parametr format. Abyste viděli ne-HTML reprezentaci formátu $1, nastavte format=$2.\n\nVíce informací najdete v [https://www.mediawiki.org/wiki/Special:MyLanguage/API:Main_page úplné dokumentaci] nebo [[Special:ApiHelp/main|nápovědě k API]].",
+ "api-format-prettyprint-header": "Toto je HTML reprezentace formátu $1. HTML se hodí pro ladění, ale pro aplikační použití je nevhodné.\n\nPro změnu výstupního formátu uveďte parametr <var>format</var>. Abyste viděli ne-HTML reprezentaci formátu $1, nastavte <kbd>format=$2</kbd>.\n\nVíce informací najdete v [[mw:Special:MyLanguage/API:Main page|úplné dokumentaci]] nebo v [[Special:ApiHelp/main|nápovědě k API]].",
+ "api-format-prettyprint-header-only-html": "Toto je HTML reprezentace určená pro ladění, která není vhodná pro použití v aplikacích.\n\nVíce informací najdete v [[mw:API|úplné dokumentaci]] nebo [[Special:ApiHelp/main|dokumentaci API]].",
"api-help-title": "Nápověda k MediaWiki API",
"api-help-lead": "Toto je automaticky generovaná dokumentační stránka k MediaWiki API.\n\nDokumentace a příklady: https://www.mediawiki.org/wiki/API",
"api-help-main-header": "Hlavní modul",
@@ -197,10 +258,18 @@
"api-help-flag-writerights": "Tento modul vyžaduje oprávnění k zápisu.",
"api-help-flag-mustbeposted": "Tento modul přijímá pouze požadavky POST.",
"api-help-flag-generator": "Tento modul lze využívat jako generátor.",
+ "api-help-source": "Zdroj: $1",
+ "api-help-license": "Licence: [[$1|$2]]",
+ "api-help-license-noname": "Licence: [[$1|Vizte odkaz]]",
+ "api-help-license-unknown": "Licence: <span class=\"apihelp-unknown\">neznámá</span>",
"api-help-parameters": "{{PLURAL:$1|Parametr|Parametry}}:",
"api-help-param-deprecated": "Zastaralý.",
"api-help-param-required": "Tento parametr je povinný.",
- "api-help-param-list": "{{PLURAL:$1|1=Jedna hodnota|2=Hodnoty (oddělené „{{!}}“)}}: $2",
+ "api-help-datatypes-header": "Datové typy",
+ "api-help-datatypes": "Některé typy parametrů v API potřebují bližší vysvětlení:\n;boolean\n:Booleovské parametry fungují jako zaškrtávací políčka v HTML: pokud je parametr uveden, bez ohledu na hodnotu, je považován za pravdivý. Pro nepravdivou hodnotu parametr zcela vynechte.\n;časová značka\n:Časové značky lze uvádět v několika formátech. Doporučuje se datum a čas podle ISO 8601. Všechny časy jsou v UTC a obsažené časové pásmo je ignorováno.\n:* Datum a čas podle ISO 8601, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (interpunkce a <kbd>Z</kbd> jsou nepovinné)\n:* Datum a čas podle ISO 8601 s (ignorovaným) zlomkem sekundy, <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> (pomlčky, dvojtečky a <kbd>Z</kbd> jsou nepovinné)\n:* Formát MediaWiki, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Obecný číselný formát, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (nepovinné časové pásmo <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd> nebo <kbd>-<var>##</var></kbd> se ignoruje)\n:* Formát EXIF, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Formát podle RFC 2822 (časové pásmo lze vynechat), <kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Formát podle RFC 850 (časové pásmo lze vynechat), <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Formát podle céčkové funkce ctime, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* Sekundy od 1970-01-01T00:00:00Z jako celé číslo o 1–13 číslicích (s výjimkou <kbd>0</kbd>)\n:* Řetězec <kbd>now</kbd>",
+ "api-help-param-type-integer": "Typ: {{PLURAL:$1|1=celé číslo|2=seznam celých čísel}}",
+ "api-help-param-type-boolean": "Typ: boolean ([[Special:ApiHelp/main#main/datatypes|podrobnosti]])",
+ "api-help-param-list": "{{PLURAL:$1|1=Jedna hodnota|2=Hodnoty (oddělené <kbd>{{!}}</kbd>)}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Musí být prázdné|Může být prázdné nebo $2}}",
"api-help-param-limit": "Není dovoleno více než $1.",
"api-help-param-limit2": "Není dovoleno více než $1 ($2 pro boty).",
@@ -208,7 +277,7 @@
"api-help-param-integer-max": "{{PLURAL:$1|1=Hodnota nesmí|2=Hodnoty nesmějí}} být vyšší než $3.",
"api-help-param-integer-minmax": "{{PLURAL:$1|1=Hodnota|2=Hodnoty}} musí ležet mezi $2 a $3.",
"api-help-param-upload": "Musí se odeslat POST požadavkem jako načítaný soubor pomocí multipart/form-data.",
- "api-help-param-multi-separate": "Hodnoty oddělujte pomocí „|“.",
+ "api-help-param-multi-separate": "Hodnoty oddělujte pomocí <kbd>|</kbd>.",
"api-help-param-multi-max": "Maximální počet hodnot je {{PLURAL:$1|$1}} (pro boty {{PLURAL:$2|$2}}).",
"api-help-param-default": "Implicitní hodnota: $1",
"api-help-param-default-empty": "Implicitní hodnota: <span class=\"apihelp-empty\">(prázdné)</span>",
diff --git a/includes/api/i18n/de.json b/includes/api/i18n/de.json
index 96172040..98e1c105 100644
--- a/includes/api/i18n/de.json
+++ b/includes/api/i18n/de.json
@@ -9,15 +9,19 @@
"Giftpflanze",
"Macofe",
"Se4598",
- "Purodha"
+ "Purodha",
+ "Andreasburmeister",
+ "Anomie",
+ "Duder",
+ "Ljonka"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page/de|Dokumentation]]\n* [[mw:API:FAQ/de|Häufig gestellte Fragen]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailingliste]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-Ankündigungen]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Fehlerberichte und Anfragen]\n</div>\n<strong>Status:</strong> Alle auf dieser Seite gezeigten Funktionen sollten funktionieren, allerdings ist die API in aktiver Entwicklung und kann sich zu jeder Zeit ändern. Abonniere die [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ MediaWiki-API-Ankündigungs-Mailingliste], um über Aktualisierungen informiert zu werden.\n\n<strong>Fehlerhafte Anfragen:</strong> Wenn fehlerhafte Anfragen an die API gesendet werden, wird ein HTTP-Header mit dem Schlüssel „MediaWiki-API-Error“ gesendet. Der Wert des Headers und der Fehlercode werden auf den gleichen Wert gesetzt. Für weitere Informationen siehe [[mw:API:Errors_and_warnings|API: Fehler und Warnungen]].",
"apihelp-main-param-action": "Auszuführende Aktion.",
"apihelp-main-param-format": "Format der Ausgabe.",
"apihelp-main-param-maxlag": "maxlag kann verwendet werden, wenn MediaWiki auf einem datenbankreplizierten Cluster installiert ist. Um weitere Replikationsrückstände zu verhindern, lässt dieser Parameter den Client warten, bis der Replikationsrückstand kleiner als der angegebene Wert (in Sekunden) ist. Bei einem größerem Rückstand wird der Fehlercode <samp>maxlag</samp> zurückgegeben mit einer Nachricht wie <samp>Waiting for $host: $lag seconds lagged</samp>.<br />Siehe [[mw:Manual:Maxlag_parameter|Handbuch: Maxlag parameter]] für weitere Informationen.",
- "apihelp-main-param-smaxage": "Den <code>s-maxage</code>-Header auf diese Anzahl Sekunden festlegen. Fehler werden niemals gecacht.",
- "apihelp-main-param-maxage": "Den <code>max-age</code>-Header auf diese Anzahl Sekunden festlegen. Fehler werden niemals gecacht.",
+ "apihelp-main-param-smaxage": "Den <code>s-maxage</code>-HTTP-Cache-Control-Header auf diese Anzahl Sekunden festlegen. Fehler werden niemals gecacht.",
+ "apihelp-main-param-maxage": "Den <code>max-age</code>-HTTP-Cache-Control-Header auf diese Anzahl Sekunden festlegen. Fehler werden niemals gecacht.",
"apihelp-main-param-assert": "Sicherstellen, dass der Benutzer eingeloggt ist, wenn auf <kbd>user</kbd> gesetzt, oder Bot ist, wenn auf <kbd>bot</kbd> gesetzt.",
"apihelp-main-param-requestid": "Der angegebene Wert wird mit in die Antwort aufgenommen und kann zur Unterscheidung von Anfragen verwendet werden.",
"apihelp-main-param-servedby": "Namen des bearbeitenden Hosts mit zurückgeben.",
@@ -116,6 +120,8 @@
"apihelp-expandtemplates-param-title": "Titel der Seite.",
"apihelp-expandtemplates-param-text": "Zu konvertierender Wikitext.",
"apihelp-expandtemplates-param-revid": "Versionsnummer, die für die Anzeige von <nowiki>{{REVISIONID}}</nowiki> und ähnlichen Variablen verwendet wird.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "Der expandierte Wikitext.",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "Der XML-Parserbaum der Eingabe.",
"apihelp-expandtemplates-param-includecomments": "Ob HTML-Kommentare in der Ausgabe eingeschlossen werden sollen.",
"apihelp-expandtemplates-param-generatexml": "XML-Parserbaum erzeugen (ersetzt durch $1prop=parsetree).",
"apihelp-expandtemplates-example-simple": "Den Wikitext <kbd><nowiki>{{Project:Spielwiese}}</nowiki></kbd> expandieren.",
@@ -176,16 +182,16 @@
"apihelp-imagerotate-param-rotation": "Anzahl der Grad, um die das Bild im Uhrzeigersinn gedreht werden soll.",
"apihelp-imagerotate-example-simple": "<kbd>Datei:Beispiel.png</kbd> um <kbd>90</kbd> Grad drehen.",
"apihelp-imagerotate-example-generator": "Alle Bilder in der <kbd>Kategorie:Flip</kbd> um <kbd>180</kbd> Grad drehen.",
- "apihelp-import-description": "Importiert eine Seite von einem anderen Wiki oder einer XML-Datei.\n\nBitte beachte, dass der HTTP-POST-Vorgang als Dateiupload ausgeführt werden muss (z.B. durch multipart/form-data), um eine Datei über den <var>xml</var>-Parameter zu senden.",
+ "apihelp-import-description": "Importiert eine Seite aus einem anderen Wiki oder von einer XML-Datei.\n\nBitte beachte, dass der HTTP-POST-Vorgang als Dateiupload ausgeführt werden muss (z.B. durch multipart/form-data), um eine Datei über den <var>xml</var>-Parameter zu senden.",
"apihelp-import-param-summary": "Import-Zusammenfassung.",
"apihelp-import-param-xml": "Hochgeladene XML-Datei.",
"apihelp-import-param-interwikisource": "Für Interwiki-Importe: Wiki, von dem importiert werden soll.",
"apihelp-import-param-interwikipage": "Für Interwiki-Importe: zu importierende Seite.",
"apihelp-import-param-fullhistory": "Für Interwiki-Importe: importiere die komplette Versionsgeschichte, nicht nur die aktuelle Version.",
"apihelp-import-param-templates": "Für Interwiki-Importe: importiere auch alle eingebundenen Vorlagen.",
- "apihelp-import-param-namespace": "Für Interwiki-Importe: importiere in diesen Namensraum.",
- "apihelp-import-param-rootpage": "Als Unterseite dieser Seite importieren.",
- "apihelp-import-example-import": "Importiere [[meta:Help:Parserfunctions]] mit der kompletten Versionsgeschichte in den Namensraum 100.",
+ "apihelp-import-param-namespace": "In diesen Namensraum importieren. Kann nicht zusammen mit <var>$1rootpage</var> verwendet werden.",
+ "apihelp-import-param-rootpage": "Als Unterseite dieser Seite importieren. Kann nicht zusammen mit <var>$1namespace</var> verwendet werden.",
+ "apihelp-import-example-import": "Importiere [[meta:Help:ParserFunctions]] mit der kompletten Versionsgeschichte in den Namensraum 100.",
"apihelp-login-description": "Anmelden und Authentifizierungs-Cookies beziehen.\n\nFalls das Anmelden erfolgreich war, werden die benötigten Cookies im Header der HTTP-Antwort des Servers übermittelt. Bei fehlgeschlagenen Anmeldeversuchen können weitere Versuche gedrosselt werden, um automatische Passwortermittlungsattacken zu verhinden.",
"apihelp-login-param-name": "Benutzername.",
"apihelp-login-param-password": "Passwort.",
@@ -229,11 +235,20 @@
"apihelp-paraminfo-description": "Ruft Informationen über API-Module ab.",
"apihelp-paraminfo-param-helpformat": "Format der Hilfe-Zeichenfolgen.",
"apihelp-parse-param-summary": "Zu parsende Zusammenfassung.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Gibt die Sprachlinks im geparsten Wikitext zurück.",
+ "apihelp-parse-paramvalue-prop-categories": "Gibt die Kategorien im geparsten Wikitext zurück.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Gibt die HTML-Version der Kategorien zurück.",
+ "apihelp-parse-paramvalue-prop-links": "Gibt die internen Links im geparsten Wikitext zurück.",
+ "apihelp-parse-paramvalue-prop-templates": "Gibt die Vorlagen im geparsten Wikitext zurück.",
+ "apihelp-parse-paramvalue-prop-images": "Gibt die Bilder im geparsten Wikitext zurück.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Gibt die externen Links im geparsten Wikitext zurück.",
+ "apihelp-parse-paramvalue-prop-revid": "Ergänzt die Versionskennung der geparsten Seite.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Ergänzt den Titel des geparsten Wikitextes.",
"apihelp-parse-param-section": "Gibt nur den Inhalt dieses Abschnittes zurück oder erstellt einen neuen Abschnitt, wenn <kbd>new</kbd> angegeben wird.\n\n<kbd>new</kbd> wird nur ausgewertet, wenn auch <var>text</var> angegeben wurde.",
"apihelp-parse-param-sectiontitle": "Überschrift des neuen Abschnittes, wenn <var>section</var> = <kbd>new</kbd> ist.\n\nAnders als beim Bearbeiten der Seite wird der Parameter nicht durch die <var>summary</var> ersetzt, wenn er weggelassen oder leer ist.",
- "apihelp-parse-param-disableeditsection": "Deaktiviert Abschnittsbearbeitungslinks in der Parserausgabe.",
+ "apihelp-parse-param-disableeditsection": "Lässt Abschnittsbearbeitungslinks in der Parserausgabe weg.",
"apihelp-parse-param-preview": "Im Vorschaumodus parsen.",
- "apihelp-parse-param-disabletoc": "Inhaltsverzeichnis in der Ausgabe deaktivieren.",
+ "apihelp-parse-param-disabletoc": "Inhaltsverzeichnis in der Ausgabe weglassen.",
"apihelp-parse-example-page": "Eine Seite parsen.",
"apihelp-parse-example-text": "Wikitext parsen.",
"apihelp-parse-example-texttitle": "Parst den Wikitext über die Eingabe des Seitentitels.",
@@ -249,7 +264,7 @@
"apihelp-protect-param-protections": "Liste der Schutzebenen nach dem Format <kbd>Aktion=Ebene</kbd> (z.B. <kbd>edit=sysop</kbd>).\n\n<strong>HINWEIS:</strong> Wenn eine Aktion nicht angegeben wird, wird deren Schutz entfernt.",
"apihelp-protect-param-expiry": "Zeitstempel des Schutzablaufs. Wenn nur ein Zeitstempel übergeben wird, ist dieser für alle Seitenschutze gültig. Um eine unendliche Schutzdauer festzulegen, kannst du die Werte <kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd> oder <kbd>never</kbd> übergeben.",
"apihelp-protect-param-reason": "Grund für den Seitenschutz oder dessen Aufhebung.",
- "apihelp-protect-param-cascade": "Aktiviert den Kaskadenschutz (alle eingebundenen Seiten werden ebenfalls geschützt). Wenn die übergebenen Schutzebenen keinen Kaskadenschutz unterstützen, wird dieser Parameter ignoriert.",
+ "apihelp-protect-param-cascade": "Aktiviert den Kaskadenschutz (z.&nbsp;B. werden eingebundene Vorlagen und Bilder in dieser Seite geschützt). Wird ignoriert, falls keine der angegebenen Schutzebenen Kaskaden unterstützt.",
"apihelp-protect-param-watch": "Wenn vorhanden, fügt dieser Parameter die zu (ent-)sperrende Seite der Beobachtungsliste des aktuellen Benutzers hinzu.",
"apihelp-protect-param-watchlist": "Die Seite bedingungslos zur Beobachtungsliste des aktuellen Benutzers hinzufügen oder von ihr entfernen, Einstellungen verwenden oder Beobachtung nicht ändern.",
"apihelp-protect-example-protect": "Schützt eine Seite",
@@ -268,8 +283,7 @@
"apihelp-query-param-export": "Exportiert die aktuellen Versionen der angegebenen oder generierten Seiten.",
"apihelp-query-param-exportnowrap": "Gibt den XML-Export zurück, ohne ihn in ein XML-Ergebnis einzuschließen (gleiches Format wie durch [[Special:Export]]). Kann nur zusammen mit $1export genutzt werden.",
"apihelp-query-param-iwurl": "Gibt an, ob die komplette URL zurückgegeben werden soll, wenn der Titel ein Interwikilink ist.",
- "apihelp-query-param-continue": "Falls angegeben, wird query-continue als Schlüssel-Wert-Paar zurückgegeben, das anschließend an die Folgeabfrage gehängt werden kann. Dieser Parameter muss in der ersten Abfrage auf leer gesetzt werden.\n\nDieser Parameter ist für alle Neuentwicklungen empfohlen und wird in der nächsten API-Version Standard.",
- "apihelp-query-param-rawcontinue": "Momentan unbeachtet. In Zukunft wird <var>$1continue</var> Standard, dieser Parameter wird dann benötigt, um die rohen <samp>query-continue</samp>-Daten zu erhalten.",
+ "apihelp-query-param-rawcontinue": "Gibt <samp>query-continue</samp>-Rohdaten zur Fortsetzung zurück.",
"apihelp-query-example-revisions": "Bezieht [[Special:ApiHelp/query+siteinfo|Seiteninformationen]] und [[Special:ApiHelp/query+revisions|Versionen]] der <kbd>Main Page</kbd>.",
"apihelp-query-example-allpages": "Bezieht Versionen von Seiten, die mit <kbd>API/</kbd> beginnen.",
"apihelp-query+allcategories-description": "Alle Kategorien aufzählen.",
@@ -280,7 +294,9 @@
"apihelp-query+allcategories-param-min": "Gibt nur Kategorien zurück, die mindestens die angegebene Anzahl an Einträgen haben.",
"apihelp-query+allcategories-param-max": "Gibt nur Kategorien zurück, die höchstens die angegebene Anzahl an Einträgen haben.",
"apihelp-query+allcategories-param-limit": "Wie viele Kategorien zurückgegeben werden sollen.",
- "apihelp-query+allcategories-param-prop": "Zurückzugebende Eigenschaften:\n;size: Ergänzt die Anzahl der Einträge in der Antwort.\n;hidden: Markiert über _&#95;HIDDENCAT_&#95; versteckte Kategorien.",
+ "apihelp-query+allcategories-param-prop": "Zurückzugebende Eigenschaften:",
+ "apihelp-query+allcategories-paramvalue-prop-size": "Ergänzt die Anzahl der Einträge in der Antwort.",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "Markiert über <code>_&#95;HIDDENCAT_&#95;</code> versteckte Kategorien.",
"apihelp-query+allcategories-example-size": "Listet Kategorien mit der Anzahl ihrer Einträge auf.",
"apihelp-query+allcategories-example-generator": "Bezieht Informationen über die Kategorieseite selbst für Kategorien, die mit <kbd>List</kbd> beginnen.",
"apihelp-query+alldeletedrevisions-description": "Bezieht alle gelöschten Versionen eines Benutzers oder eines Namensraumes.",
@@ -295,17 +311,57 @@
"apihelp-query+alldeletedrevisions-param-user": "Nur Versionen von diesem Benutzer auflisten.",
"apihelp-query+alldeletedrevisions-param-excludeuser": "Schließt Bearbeitungen des angegebenen Benutzers aus.",
"apihelp-query+alldeletedrevisions-param-namespace": "Nur Seiten in diesem Namensraum auflisten.",
+ "apihelp-query+allfileusages-param-from": "Titel der Datei, bei der die Aufzählung beginnen soll.",
+ "apihelp-query+allfileusages-param-to": "Titel der Datei, bei der die Aufzählung enden soll.",
+ "apihelp-query+allfileusages-param-prop": "Informationsteile zum Einbinden:",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "Ergänzt den Titel der Datei.",
"apihelp-query+allfileusages-param-limit": "Wie viele Gesamtobjekte zurückgegeben werden sollen.",
+ "apihelp-query+allfileusages-param-dir": "Aufzählungsrichtung.",
"apihelp-query+allfileusages-example-unique": "Einheitliche Dateititel auflisten",
+ "apihelp-query+allfileusages-example-unique-generator": "Ruft alle Dateititel ab und markiert die fehlenden.",
"apihelp-query+allfileusages-example-generator": "Seiten abrufen, die die Dateien enthalten",
"apihelp-query+allimages-description": "Alle Bilder nacheinander auflisten.",
+ "apihelp-query+allimages-param-sort": "Eigenschaft, nach der sortiert werden soll.",
+ "apihelp-query+allimages-param-dir": "Aufzählungsrichtung.",
"apihelp-query+allimages-param-sha1": "SHA1-Hash des Bildes. Überschreibt $1sha1base36.",
"apihelp-query+allimages-param-sha1base36": "SHA1-Hash des Bildes (Basis 36; verwendet in MediaWiki).",
"apihelp-query+allimages-param-limit": "Wie viele Gesamtbilder zurückgegeben werden sollen.",
"apihelp-query+allimages-example-recent": "Zeigt eine Liste von kürzlich hochgeladenen Dateien ähnlich zu [[Special:NewFiles]].",
"apihelp-query+alllinks-example-unique": "Einheitlich verlinkte Titel auflisten",
+ "apihelp-query+allpages-description": "Listet alle Seiten in einem Namensraum nacheinander auf.",
+ "apihelp-query+allpages-param-from": "Seitentitel, bei dem die Auflistung beginnen soll.",
+ "apihelp-query+allpages-param-to": "Seitentitel, bei dem die Auflistung enden soll.",
+ "apihelp-query+allpages-param-prefix": "Nach Seitentiteln suchen, die mit diesem Wert beginnen.",
+ "apihelp-query+allpages-param-namespace": "Der zu untersuchende Namensraum.",
"apihelp-query+allpages-param-filterredir": "Welche Seiten aufgelistet werden sollen.",
+ "apihelp-query+allpages-param-minsize": "Nur Seiten auflisten, die mindestens diese Größe in Byte haben.",
+ "apihelp-query+allpages-param-maxsize": "Nur Seiten auflisten, die höchstens diese Größe in Byte haben.",
+ "apihelp-query+allpages-param-prtype": "Nur geschützte Seiten auflisten.",
+ "apihelp-query+allpages-param-prlevel": "Seitenschutze nach Schutzstufe filtern (muss zusammen mit $1prtype=parameter angegeben werden).",
+ "apihelp-query+allpages-param-prfiltercascade": "Seitenschutze nach Kaskadierung filtern (wird ignoriert, wenn $1prtype nicht gesetzt ist).",
+ "apihelp-query+allpages-param-limit": "Gesamtanzahl der aufzulistenden Seiten.",
+ "apihelp-query+allpages-param-dir": "Aufzählungsrichtung.",
+ "apihelp-query+allpages-param-filterlanglinks": "Nur Seiten auflisten, die Sprachlinks haben. Beachte, dass von Erweiterungen gesetzte Sprachlinks möglicherweise nicht beachtet werden.",
+ "apihelp-query+allpages-param-prexpiry": "Ablaufzeit des Seitenschutzes, nach dem die Auflistung gefiltert werden soll:\n; indefinite: Nur unbeschränkt geschützte Seiten auflisten.\n; definite: Nur für einen bestimmten Zeitraum geschützte Seiten auflisten.\n; all: geschützte Seiten unabhängig von der Schutzlänge auflisten.",
+ "apihelp-query+allpages-example-B": "Bezieht eine Liste von Seiten, die mit dem Buchstaben <kbd>B</kbd> beginnen.",
+ "apihelp-query+allpages-example-generator": "Gibt Informationen über vier Seiten mit dem Anfangsbuchstaben <kbd>T</kbd> zurück.",
+ "apihelp-query+allpages-example-generator-revisions": "Übermittelt den Inhalt der ersten beiden Seiten, die mit <kbd>Re</kbd> beginnen und keine Weiterleitungen sind.",
+ "apihelp-query+allredirects-description": "Bezieht alle Weiterleitungen in einem Namensraum.",
+ "apihelp-query+allredirects-param-from": "Titel der Weiterleitung, bei der die Auflistung beginnen soll.",
+ "apihelp-query+allredirects-param-to": "Titel der Weiterleitung, bei der die Auflistung enden soll.",
+ "apihelp-query+allredirects-param-prefix": "Weiterleitungen auflisten, deren Zielseiten mit diesem Wert beginnen.",
+ "apihelp-query+allredirects-param-unique": "Nur Weiterleitungen mit unterschiedlichen Zielseiten anzeigen. Kann nicht zusammen mit $1prop=ids|fragment|interwiki benutzt werden. Bei Nutzung als Generator werden die Zielseiten anstelle der Ursprungsseiten zurückgegeben.",
+ "apihelp-query+allredirects-param-prop": "Zu beziehende Informationen:",
+ "apihelp-query+allredirects-paramvalue-prop-ids": "Ergänzt die Seitenkennung der Weiterleitungsseite (kann nicht zusammen mit <var>$1unique</var> benutzt werden).",
+ "apihelp-query+allredirects-paramvalue-prop-title": "Ergänzt den Titel der Weiterleitung.",
+ "apihelp-query+allredirects-paramvalue-prop-fragment": "Ergänzt das Abschnittsziel der Weiterleitung, falls vorhanden (kann nicht zusammen mit <var>$1unique</var> benutzt werden).",
+ "apihelp-query+allredirects-paramvalue-prop-interwiki": "Ergänzt das Interwiki-Präfix der Weiterleitung, falls vorhanden (kann nicht zusammen mit <var>$1unique</var> benutzt werden).",
+ "apihelp-query+allredirects-param-namespace": "Der zu untersuchende Namensraum.",
+ "apihelp-query+allredirects-param-limit": "Gesamtanzahl der aufzulistenden Einträge.",
+ "apihelp-query+allredirects-param-dir": "Aufzählungsrichtung.",
+ "apihelp-query+allredirects-example-B": "Listet Zielseiten, auch fehlende, mit den Seitenkennungen der Weiterleitung auf, beginnend bei <kbd>B</kbd>.",
"apihelp-query+allredirects-example-unique": "Einzigartige Zielseiten auflisten.",
+ "apihelp-query+allredirects-example-unique-generator": "Bezieht alle Zielseiten und markiert die Fehlenden.",
"apihelp-query+allredirects-example-generator": "Seiten abrufen, die die Weiterleitungen enthalten",
"apihelp-query+alltransclusions-param-namespace": "Der aufzulistende Namensraum.",
"apihelp-query+alltransclusions-example-unique": "Einzigartige eingebundene Titel auflisten.",
@@ -318,7 +374,6 @@
"apihelp-query+categorymembers-param-endsortkey": "Stattdessen $1endhexsortkey verwenden.",
"apihelp-query+contributors-param-limit": "Wie viele Spender zurückgegeben werden sollen.",
"apihelp-query+deletedrevisions-param-user": "Nur Versionen von diesem Benutzer auflisten.",
- "apihelp-query+deletedrevisions-param-limit": "Die Maximalmenge der aufzulistenden Versionen.",
"apihelp-query+deletedrevs-param-from": "Auflistung bei diesem Titel beginnen.",
"apihelp-query+deletedrevs-param-to": "Auflistung bei diesem Titel beenden.",
"apihelp-query+duplicatefiles-param-localonly": "Sucht nur nach Dateien im lokalen Repositorium.",
@@ -332,6 +387,7 @@
"apihelp-query+filearchive-param-from": "Der Bildertitel, bei dem die Auflistung beginnen soll.",
"apihelp-query+filearchive-param-to": "Der Bildertitel, bei dem die Auflistung enden soll.",
"apihelp-query+filearchive-param-limit": "Wie viele Bilder insgesamt zurückgegeben werden sollen.",
+ "apihelp-query+filearchive-paramvalue-prop-sha1": "Ergänzt die SHA-1-Prüfsumme für das Bild.",
"apihelp-query+filearchive-example-simple": "Eine Liste aller gelöschten Dateien auflisten",
"apihelp-query+imageinfo-param-limit": "Wie viele Dateiversionen pro Datei zurückgegeben werden sollen.",
"apihelp-query+imageinfo-param-start": "Zeitstempel, von dem die Liste beginnen soll.",
@@ -344,18 +400,23 @@
"apihelp-query+links-example-simple": "Links von der <kbd>Hauptseite</kbd> abrufen",
"apihelp-query+linkshere-description": "Alle Seiten finden, die auf die angegebenen Seiten verlinken.",
"apihelp-query+logevents-description": "Ereignisse von den Logbüchern abrufen.",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "Fügt die Seitenkennung hinzu.",
"apihelp-query+prefixsearch-param-search": "Such-Zeichenfolge.",
+ "apihelp-query+search-param-prop": "Eigenschaften zur Rückgabe:",
"apihelp-query+search-example-simple": "Nach <kbd>meaning</kbd> suchen.",
"apihelp-query+search-example-text": "Texte nach <kbd>meaning</kbd> durchsuchen.",
"apihelp-query+siteinfo-example-simple": "Websiteinformationen abrufen",
"apihelp-query+tags-description": "Änderungs-Tags auflisten.",
"apihelp-query+tags-example-simple": "Verfügbare Tags auflisten",
"apihelp-query+usercontribs-description": "Alle Bearbeitungen von einem Benutzer abrufen.",
+ "apihelp-query+usercontribs-paramvalue-prop-ids": "Ergänzt die Seiten- und Versionskennung.",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "Fügt den bürgerlichen Namen des Benutzers hinzu.",
"apihelp-query+userinfo-example-simple": "Informationen über den aktuellen Benutzer abrufen",
"apihelp-query+users-description": "Informationen über eine Liste von Benutzern abrufen.",
"apihelp-rsd-description": "Ein RSD-Schema (Really Simple Discovery) exportieren.",
"apihelp-rsd-example-simple": "Das RSD-Schema exportieren",
"apihelp-setnotificationtimestamp-param-entirewatchlist": "An allen beobachteten Seiten arbeiten.",
+ "apihelp-tag-param-reason": "Grund für die Änderung.",
"apihelp-unblock-description": "Einen Benutzer freigeben.",
"apihelp-unblock-param-reason": "Grund für die Freigabe.",
"apihelp-unblock-example-id": "Sperrkennung #<kbd>105</kbd> freigeben.",
@@ -368,14 +429,12 @@
"apihelp-userrights-param-user": "Benutzername.",
"apihelp-userrights-param-userid": "Benutzerkennung.",
"apihelp-watch-example-watch": "Die Seite <kbd>Hauptseite</kbd> beobachten.",
- "apihelp-format-example-generic": "Das Abfrageergebnis im $1-Format formatieren",
+ "apihelp-format-example-generic": "Das Abfrageergebnis im $1-Format ausgeben.",
"apihelp-dbg-description": "Daten im PHP-<code>var_export()</code>-Format ausgeben.",
"apihelp-dbgfm-description": "Daten im PHP-<code>var_export()</code>-Format ausgeben (schöngedruckt in HTML).",
- "apihelp-dump-description": "Daten im PHP-<code>var_dump()</code>-Format ausgeben.",
- "apihelp-dumpfm-description": "Daten im PHP-<code>var_dump()</code>-Format ausgeben (schöngedruckt in HTML).",
"apihelp-json-description": "Daten im JSON-Format ausgeben.",
"apihelp-json-param-callback": "Falls angegeben, wird die Ausgabe in einen angegebenen Funktionsaufruf eingeschlossen. Aus Sicherheitsgründen sind benutzerspezifische Daten beschränkt.",
- "apihelp-json-param-utf8": "Falls angegeben, kodiert die meisten (aber nicht alle) Nicht-ASCII-Zeichen als UTF-8 anstatt sie mit hexadezimalen Escape-Sequenzen zu ersetzen.",
+ "apihelp-json-param-utf8": "Falls angegeben, kodiert die meisten (aber nicht alle) Nicht-ASCII-Zeichen als UTF-8 anstatt sie mit hexadezimalen Escape-Sequenzen zu ersetzen. Standard, wenn <var>formatversion</var> nicht <kbd>1</kbd> ist.",
"apihelp-jsonfm-description": "Daten im JSON-Format ausgeben (schöngedruckt in HTML).",
"apihelp-none-description": "Nichts ausgeben.",
"apihelp-php-description": "Daten im serialisierten PHP-Format ausgeben.",
@@ -383,8 +442,6 @@
"apihelp-rawfm-description": "Daten mit den Fehlerbehebungselementen im JSON-Format ausgeben (schöngedruckt in HTML).",
"apihelp-txt-description": "Daten im PHP-<code>print_r()</code>-Format ausgeben.",
"apihelp-txtfm-description": "Daten im PHP-<code>print_r()</code>-Format ausgeben (schöngedruckt in HTML).",
- "apihelp-wddx-description": "Daten im WDDX-Format ausgeben.",
- "apihelp-wddxfm-description": "Daten im WDDX-Format ausgeben (schöngedruckt in HTML).",
"apihelp-xml-description": "Daten im XML-Format ausgeben.",
"apihelp-xml-param-xslt": "Falls angegeben, fügt die benannte Seite als XSL-Stylesheet hinzu. Der Wert muss ein Titel im Namensraum „{{ns:mediawiki}}“ sein und mit <code>.xsl</code> enden.",
"apihelp-xml-param-includexmlnamespace": "Falls angegeben, ergänzt einen XML-Namensraum.",
@@ -392,7 +449,7 @@
"apihelp-yaml-description": "Daten im YAML-Format ausgeben.",
"apihelp-yamlfm-description": "Daten im YAML-Format ausgeben (schöngedruckt in HTML).",
"api-format-title": "MediaWiki-API-Ergebnis",
- "api-format-prettyprint-header": "Dies ist die HTML-Repräsentation des $1-Formats. HTML ist zur Fehlerbehebung gut, aber unpassend für den Anwendungsgebrauch.\n\nGib den Parameter <var>Format</var> an, um das Ausgabeformat zu ändern. Um die Nicht-HTML-Repräsentation des $1-Formats anzusehen, lege <kbd>format=$2</kbd> fest.\n\nSiehe die [[mw:API|vollständige Dokumentation]] oder die [[Special:ApiHelp/main|API-Hilfe]] für weitere Informationen.",
+ "api-format-prettyprint-header": "Dies ist die HTML-Repräsentation des $1-Formats. HTML ist zur Fehlerbehebung gut, aber unpassend für den Anwendungsgebrauch.\n\nGib den Parameter <var>format</var> an, um das Ausgabeformat zu ändern. Um die Nicht-HTML-Repräsentation des $1-Formats anzusehen, lege <kbd>format=$2</kbd> fest.\n\nSiehe die [[mw:API|vollständige Dokumentation]] oder die [[Special:ApiHelp/main|API-Hilfe]] für weitere Informationen.",
"api-orm-param-props": "Felder an die Anfrage.",
"api-orm-param-limit": "Maximale Anzahl zurückgegebender Zeilen.",
"api-pageset-param-titles": "Eine Liste der Titel, an denen gearbeitet werden soll.",
@@ -407,10 +464,16 @@
"api-help-flag-writerights": "Dieses Modul erfordert Schreibrechte.",
"api-help-flag-mustbeposted": "Dieses Modul akzeptiert nur POST-Anfragen.",
"api-help-flag-generator": "Dieses Modul kann als Generator verwendet werden.",
+ "api-help-source": "Quelle: $1",
+ "api-help-source-unknown": "Quelle: <span class=\"apihelp-unknown\">unbekannt</span>",
+ "api-help-license": "Lizenz: [[$1|$2]]",
+ "api-help-license-noname": "Lizenz: [[$1|Siehe Link]]",
+ "api-help-license-unknown": "Lizenz: <span class=\"apihelp-unknown\">unbekannt</span>",
"api-help-parameters": "{{PLURAL:$1|Parameter}}:",
"api-help-param-deprecated": "Veraltet.",
"api-help-param-required": "Dieser Parameter ist erforderlich.",
- "api-help-param-list": "{{PLURAL:$1|1=Ein Wert|2=Werte (mit <kbd>{{!}}</kbd> trennen)}}: $2",
+ "api-help-datatypes-header": "Datentypen",
+ "api-help-param-list": "{{PLURAL:$1|1=Einer der folgenden Werte|2=Werte (mit <kbd>{{!}}</kbd> trennen)}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Muss leer sein|Kann leer sein oder $2}}",
"api-help-param-limit": "Nicht mehr als $1 erlaubt.",
"api-help-param-limit2": "Nicht mehr als $1 ($2 für Bots) erlaubt.",
diff --git a/includes/api/i18n/el.json b/includes/api/i18n/el.json
index d4d239f4..281dd298 100644
--- a/includes/api/i18n/el.json
+++ b/includes/api/i18n/el.json
@@ -1,12 +1,97 @@
{
"@metadata": {
"authors": [
- "Glavkos"
+ "Glavkos",
+ "Protnet",
+ "Stam.nikos"
]
},
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Τεκμηρίωση]]\n* [[mw:API:FAQ|Συχνές ερωτήσεις]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Λίστα αλληλογραφίας]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Ανακοινώσεις API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Σφάλματα & αιτήματα]\n</div>\n<strong>Κατάσταση:</strong> Όλα τα χαρακτηριστικά που εμφανίζονται σε αυτή τη σελίδα πρέπει να λειτουργούν, αλλά το API είναι ακόμα σε ενεργό ανάπτυξη, και μπορεί να αλλάξει ανά πάσα στιγμή. Εγγραφείτε στη [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce λίστα αλληλογραφίας] για να ειδοποιείστε για ενημερώσεις.\n\n<strong>Εσφαλμένα αιτήματα:</strong> Όταν στέλνονται εσφαλμένα αιτήματα στο API, επιστρέφεται μία κεφαλίδα HTTP (header) με το κλειδί \"MediaWiki-API-Error\" κι έπειτα η τιμή της κεφαλίδας και ο κωδικός σφάλματος που επιστρέφονται ορίζονται στην ίδια τιμή. Για περισσότερες πληροφορίες, δείτε [[mw:API:Errors_and_warnings|API: Σφάλματα και προειδοποιήσεις]].",
+ "apihelp-main-param-action": "Ποια ενέργει να εκτελεστεί.",
+ "apihelp-main-param-format": "Η μορφή των δεδομένων εξόδου.",
+ "apihelp-main-param-curtimestamp": "Συμπερίληψη της τρέχουσας χρονοσφραγίδας στο αποτέλεσμα.",
+ "apihelp-main-param-uselang": "Γλώσσα για τις μεταφράσεις μηνυμάτων. Μία λίστα κωδικών μπορεί να αντληθεί από το <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> με το <kbd>siprop=languages</kbd>, ή καθορίστε <kbd>user</kbd> για να χρησιμοποιήσετε την προτίμηση γλώσσας του τρέχοντα χρήστη, ή καθορίστε <kbd>content</kbd> για να χρησιμοποιήσετε τη γλώσσα περιεχομένου αυτού του wiki.",
"apihelp-block-description": "Φραγή χρήστη",
"apihelp-block-param-user": "Όνομα χρήστη, διεύθυνση IP ή εύρος διευθύνσεων IP που θέλετε να επιβάλετε φραγή.",
+ "apihelp-block-param-expiry": "Ώρα λήξης. Μπορεί να είναι σχετική (π.χ. <kbd>σε 5 μήνες</kbd> ή <kbd>σε 2 εβδομάδες</kbd>) ή απόλυτη (π.χ. <kbd>2014-09-18T12:34:56Z</kbd>). Αν οριστεί σε <kbd>άπειρη</kbd>, <kbd>απεριόριστη</kbd>, ή <kbd>ποτέ</kbd>, ο αποκλεισμός δεν θα λήξει ποτέ.",
"apihelp-block-param-reason": "Λόγος φραγής.",
+ "apihelp-block-param-anononly": "Αποκλείστε ανώνυμους χρήστες μόνο (δηλ. απενεργοποιήστε ανώνυμες επεξεργασίες για αυτή τη διεύθυνση IP).",
+ "apihelp-block-param-nocreate": "Αποτροπή δημιουργίας λογαριασμού.",
+ "apihelp-block-param-autoblock": "Αποκλείστε αυτόματα την τελευταία χρησιμοποιημένη διεύθυνση IP και κάθε συνακόλουθη διεύθυνση IP από την οποία γίνεται προσπάθεια σύνδεσης.",
+ "apihelp-createaccount-description": "Δημιουργήστε νέο λογαριασμό χρήστη.",
"apihelp-createaccount-param-name": "Όνομα χρήστη.",
- "apihelp-delete-description": "Διαγραφή σελίδας."
+ "apihelp-createaccount-param-password": "Κωδικός πρόσβασης (αγνοείται, αν έχει οριστεί το <var>$1mailpassword</var>).",
+ "apihelp-createaccount-param-email": "Διεύθυνση ηλεκτρονικού ταχυδρομείου χρήστη (προαιρετικό).",
+ "apihelp-createaccount-param-realname": "Πραγματικό όνομα χρήστη (προαιρετικό).",
+ "apihelp-createaccount-param-mailpassword": "Εάν οριστεί σε οποιαδήποτε τιμή, ένας τυχαίος κωδικός πρόσβασης θα αποσταλεί μέσω ηλεκτρονικού ταχυδρομείου στο χρήστη.",
+ "apihelp-createaccount-param-language": "Κωδικός γλώσσας που να οριστεί ως προεπιλογή για το χρήστη (προαιρετικό, έχει ως προεπιλογή τη γλώσσα περιεχομένου).",
+ "apihelp-delete-description": "Διαγραφή σελίδας.",
+ "apihelp-delete-example-simple": "Διαγραφή <kbd>Αρχικής Σελίδας</kbd>.",
+ "apihelp-edit-description": "Δημιουργία και επεξεργασία σελίδων.",
+ "apihelp-edit-param-sectiontitle": "Ο τίτλος νέας ενότητας.",
+ "apihelp-edit-param-text": "Περιεχόμενο σελίδας.",
+ "apihelp-edit-param-minor": "Μικροεπεξεργασία.",
+ "apihelp-edit-param-notminor": "Μη ήσσονος σημασίας επεξεργασία.",
+ "apihelp-edit-param-bot": "Σήμανση αυτής της επεξεργασίας ως επεξεργασία από ρομπότ.",
+ "apihelp-edit-param-createonly": "Να μην γίνει επεξεργασία της σελίδας εάν υπάρχει ήδη.",
+ "apihelp-edit-param-nocreate": "Να εμφανιστεί μήνυμα σφάλματος εάν η σελίδα δεν υπάρχει.",
+ "apihelp-edit-param-watch": "Να προστεθεί η σελίδα στη λίστα παρακολούθησης του τρέχοντα χρήστη.",
+ "apihelp-edit-param-unwatch": "Να αφαιρεθεί η σελίδα από τη λίστα παρακολούθησης του τρέχοντα χρήστη.",
+ "apihelp-edit-param-contentmodel": "Μοντέλο περιεχομένου για το νέο περιεχόμενο.",
+ "apihelp-edit-example-edit": "Επεξεργασία κάποιας σελίδας.",
+ "apihelp-emailuser-description": "Αποστολή μηνύματος ηλεκτρονικού ταχυδρομείου σε χρήστη.",
+ "apihelp-emailuser-param-target": "Χρήστης στον οποίον να σταλεί το μήνυμα ηλεκτρονικού ταχυδρομείου.",
+ "apihelp-emailuser-param-subject": "Κεφαλίδα θέματος.",
+ "apihelp-emailuser-param-text": "Σώμα μηνύματος.",
+ "apihelp-emailuser-param-ccme": "Αποστολή αντιγράφου αυτού του μηνύματος σε εμένα.",
+ "apihelp-expandtemplates-description": "Επεκτείνει όλα τα πρότυπα στον κώδικα wiki.",
+ "apihelp-expandtemplates-param-title": "Τίτλος σελίδας.",
+ "apihelp-expandtemplates-param-text": "Κώδικας wiki προς μετατροπή.",
+ "apihelp-feedcontributions-param-feedformat": "Η μορφή της ροής.",
+ "apihelp-feedcontributions-param-deletedonly": "Εμφάνιση μόνο διαγεγραμμένων συνεισφορών.",
+ "apihelp-feedcontributions-param-toponly": "Εμφάνιση μόνο των επεξεργασιών που είναι οι πιο πρόσφατες αναθεωρήσεις.",
+ "apihelp-feedcontributions-param-newonly": "Εμφάνιση μόνο των επεξεργασιών που είναι δημιουργία σελίδας.",
+ "apihelp-feedcontributions-param-showsizediff": "Εμφάνιση της διαφοράς μεγέθους μεταξύ αναθεωρήσεων.",
+ "apihelp-feedrecentchanges-param-from": "Εμφάνιση αλλαγών από τότε.",
+ "apihelp-feedrecentchanges-param-hideminor": "Απόκρυψη μικρών αλλαγών.",
+ "apihelp-feedrecentchanges-param-hidebots": "Απόκρυψη αλλαγών που έγιναν από ρομπότ.",
+ "apihelp-feedrecentchanges-param-hideanons": "Απόκρυψη αλλαγών που έγιναν από ανώνυμους χρήστες.",
+ "apihelp-feedrecentchanges-param-hideliu": "Απόκρυψη αλλαγών που έγιναν από εγγεγραμμένους χρήστες.",
+ "apihelp-feedrecentchanges-param-hidepatrolled": "Απόκρυψη ελεγμένων αλλαγών.",
+ "apihelp-feedrecentchanges-param-hidemyself": "Απόκρυψη αλλαγών που έγιναν από τον τρέχοντα χρήστη.",
+ "apihelp-feedrecentchanges-param-tagfilter": "Φιλτράρισμα κατά ετικέτα.",
+ "apihelp-feedrecentchanges-param-target": "Εμφάνιση μόνο των αλλαγών σε σελίδες που συνδέονται με αυτή τη σελίδα.",
+ "apihelp-feedrecentchanges-example-simple": "Εμφάνιση πρόσφατων αλλαγών.",
+ "apihelp-feedrecentchanges-example-30days": "Εμφάνιση πρόσφατων αλλαγών για 30 ημέρες.",
+ "apihelp-feedwatchlist-description": "Επιστρέφει μια ροή λίστας παρακολούθησης.",
+ "apihelp-feedwatchlist-param-feedformat": "Η μορφή της ροής.",
+ "apihelp-filerevert-param-comment": "Σχόλιο ανεβάσματος.",
+ "apihelp-help-example-recursive": "Όλη η βοήθεια σε μια σελίδα.",
+ "apihelp-imagerotate-description": "Περιστροφή μίας ή περισσοτέρων εικόνων.",
+ "apihelp-imagerotate-param-rotation": "Μοίρες με τις οποίες να περιστραφεί η εικόνα ωρολογιακά.",
+ "apihelp-import-param-summary": "Εισαγωγή σύνοψης.",
+ "apihelp-login-param-name": "Όνομα χρήστη.",
+ "apihelp-login-param-password": "Κωδικός πρόσβασης.",
+ "apihelp-login-param-domain": "Τομέας (προαιρετικό).",
+ "apihelp-login-example-login": "Σύνδεση.",
+ "apihelp-logout-description": "Αποσύνδεση και διαγραφή δεδομένων περιόδου λειτουργίας.",
+ "apihelp-logout-example-logout": "Αποσύνδεση του τρέχοντα χρήστη.",
+ "apihelp-move-description": "Μετακίνηση σελίδας.",
+ "apihelp-move-param-reason": "Λόγος μετονομασίας.",
+ "apihelp-move-param-movetalk": "Μετονομασία της σελίδας συζήτησης, εάν υπάρχει.",
+ "apihelp-move-param-movesubpages": "Μετονομασία υποσελίδων, εφόσον συντρέχει περίπτωση.",
+ "apihelp-move-param-noredirect": "Να μην δημιουργηθεί ανακατεύθυνση.",
+ "apihelp-move-param-ignorewarnings": "Να αγνοηθούν τυχόν προειδοποιήσεις.",
+ "apihelp-opensearch-param-search": "Συμβολοσειρά αναζήτησης.",
+ "apihelp-opensearch-param-limit": "Μέγιστος αριθμός αποτελεσμάτων που θα επιστραφούν.",
+ "apihelp-opensearch-param-namespace": "Ονοματοχώροι προς αναζήτηση.",
+ "apihelp-opensearch-param-format": "Η μορφή των δεδομένων εξόδου.",
+ "apihelp-options-example-reset": "Επαναφορά όλων των προτιμήσεων.",
+ "apihelp-paraminfo-param-helpformat": "Μορφή των συμβολοσειρών βοήθειας.",
+ "apihelp-patrol-example-revid": "Περιπολία αναθεώρησης.",
+ "apihelp-protect-example-protect": "Προστασία σελίδας.",
+ "apihelp-query+users-paramvalue-prop-gender": "Επισημαίνει το φύλο του χρήστη. Επιστρέφει «αρσενικό», «θηλυκό» ή «άγνωστο»",
+ "api-help-param-type-limit": "Τύπος: ακέραιος ή <kbd>max</kbd>",
+ "api-help-param-type-boolean": "Τύπος: boolean ([[Special:ApiHelp/main#main/datatypes|λεπτομέρειες]])",
+ "api-help-param-type-user": "Τύπος: {{PLURAL:$1|1=όνομα χρήστη|2=λίστα με ονόματα χρήστη}}"
}
diff --git a/includes/api/i18n/en-gb.json b/includes/api/i18n/en-gb.json
index 929ec7e0..374521ec 100644
--- a/includes/api/i18n/en-gb.json
+++ b/includes/api/i18n/en-gb.json
@@ -6,7 +6,7 @@
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentation]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailing list]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API Announcements]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bugs & requests]\n</div>\n<strong>Status:</strong> All features shown on this page should be working, but the API is still in active development, and may change at any time. Subscribe to [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce mailing list] for notice of updates.\n\n<strong>Erroneous requests:</strong> When erroneous requests are sent to the API, an HTTP header will be sent with the key \"MediaWiki-API-Error\" and then both the value of the header and the error code sent back will be set to the same value. For more information see [[mw:API:Errors_and_warnings|API: Errors and warnings]].",
- "apihelp-main-param-maxage": "Set the <code>max-age</code> header to this many seconds. Errors are never cached.",
+ "apihelp-main-param-maxage": "Set the <code>max-age</code> HTTP cache control header to this many seconds. Errors are never cached.",
"apihelp-main-param-assert": "Verify the user is logged in if set to <kbd>user</kbd>, or has the bot userright if <kbd>bot</kbd>.",
"apihelp-block-param-user": "Username, IP address, or IP range to block.",
"apihelp-block-param-allowusertalk": "Allow the user to edit their own talk page (depends on <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
diff --git a/includes/api/i18n/en.json b/includes/api/i18n/en.json
index 36a4d812..78f05685 100644
--- a/includes/api/i18n/en.json
+++ b/includes/api/i18n/en.json
@@ -10,9 +10,9 @@
"apihelp-main-param-action": "Which action to perform.",
"apihelp-main-param-format": "The format of the output.",
"apihelp-main-param-maxlag": "Maximum lag can be used when MediaWiki is installed on a database replicated cluster. To save actions causing any more site replication lag, this parameter can make the client wait until the replication lag is less than the specified value. In case of excessive lag, error code <samp>maxlag</samp> is returned with a message like <samp>Waiting for $host: $lag seconds lagged</samp>.<br />See [[mw:Manual:Maxlag_parameter|Manual: Maxlag parameter]] for more information.",
- "apihelp-main-param-smaxage": "Set the <code>s-maxage</code> header to this many seconds. Errors are never cached.",
- "apihelp-main-param-maxage": "Set the <code>max-age</code> header to this many seconds. Errors are never cached.",
- "apihelp-main-param-assert": "Verify the user is logged in if set to <kbd>user</kbd>, or has the bot userright if <kbd>bot</kbd>.",
+ "apihelp-main-param-smaxage": "Set the <code>s-maxage</code> HTTP cache control header to this many seconds. Errors are never cached.",
+ "apihelp-main-param-maxage": "Set the <code>max-age</code> HTTP cache control header to this many seconds. Errors are never cached.",
+ "apihelp-main-param-assert": "Verify the user is logged in if set to <kbd>user</kbd>, or has the bot user right if <kbd>bot</kbd>.",
"apihelp-main-param-requestid": "Any value given here will be included in the response. May be used to distinguish requests.",
"apihelp-main-param-servedby": "Include the hostname that served the request in the results.",
"apihelp-main-param-curtimestamp": "Include the current timestamp in the result.",
@@ -115,13 +115,22 @@
"apihelp-emailuser-param-subject": "Subject header.",
"apihelp-emailuser-param-text": "Mail body.",
"apihelp-emailuser-param-ccme": "Send a copy of this mail to me.",
- "apihelp-emailuser-example-email": "Send an email to the User <kbd>WikiSysop</kbd> with the text <kbd>Content</kbd>.",
+ "apihelp-emailuser-example-email": "Send an email to user <kbd>WikiSysop</kbd> with the text <kbd>Content</kbd>.",
"apihelp-expandtemplates-description": "Expands all templates in wikitext.",
"apihelp-expandtemplates-param-title": "Title of page.",
"apihelp-expandtemplates-param-text": "Wikitext to convert.",
"apihelp-expandtemplates-param-revid": "Revision ID, for <nowiki>{{REVISIONID}}</nowiki> and similar variables.",
- "apihelp-expandtemplates-param-prop": "Which pieces of information to get:\n;wikitext:The expanded wikitext.\n;categories:Any categories present in the input that are not represented in the wikitext output.\n;properties:Page properties defined by expanded magic words in the wikitext.\n;volatile:Whether the output is volatile and should not be reused elsewhere within the page.\n;ttl:The maximum time after which caches of the result should be invalidated.\n;parsetree:The XML parse tree of the input.\nNote that if no values are selected, the result will contain the wikitext, but the output will be in a deprecated format.",
+ "apihelp-expandtemplates-param-prop": "Which pieces of information to get.\n\nNote that if no values are selected, the result will contain the wikitext, but the output will be in a deprecated format.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "The expanded wikitext.",
+ "apihelp-expandtemplates-paramvalue-prop-categories": "Any categories present in the input that are not represented in the wikitext output.",
+ "apihelp-expandtemplates-paramvalue-prop-properties": "Page properties defined by expanded magic words in the wikitext.",
+ "apihelp-expandtemplates-paramvalue-prop-volatile": "Whether the output is volatile and should not be reused elsewhere within the page.",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "The maximum time after which caches of the result should be invalidated.",
+ "apihelp-expandtemplates-paramvalue-prop-modules": "Any ResourceLoader modules that parser functions have requested be added to the output. Either <kbd>jsconfigvars</kbd> or <kbd>encodedjsconfigvars</kbd> must be requested jointly with <kbd>modules</kbd>.",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "Gives the JavaScript configuration variables specific to the page.",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "Gives the JavaScript configuration variables specific to the page as a JSON string.",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "The XML parse tree of the input.",
"apihelp-expandtemplates-param-includecomments": "Whether to include HTML comments in the output.",
"apihelp-expandtemplates-param-generatexml": "Generate XML parse tree (replaced by $1prop=parsetree).",
"apihelp-expandtemplates-example-simple": "Expand the wikitext <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
@@ -189,16 +198,16 @@
"apihelp-imagerotate-example-simple": "Rotate <kbd>File:Example.png</kbd> by <kbd>90</kbd> degrees.",
"apihelp-imagerotate-example-generator": "Rotate all images in <kbd>Category:Flip</kbd> by <kbd>180</kbd> degrees.",
- "apihelp-import-description": "Import a page from another wiki, or an XML file.\n\nNote that the HTTP POST must be done as a file upload (i.e. using multipart/form-data) when sending a file for the <var>xml</var> parameter.",
+ "apihelp-import-description": "Import a page from another wiki, or from an XML file.\n\nNote that the HTTP POST must be done as a file upload (i.e. using multipart/form-data) when sending a file for the <var>xml</var> parameter.",
"apihelp-import-param-summary": "Import summary.",
"apihelp-import-param-xml": "Uploaded XML file.",
"apihelp-import-param-interwikisource": "For interwiki imports: wiki to import from.",
"apihelp-import-param-interwikipage": "For interwiki imports: page to import.",
"apihelp-import-param-fullhistory": "For interwiki imports: import the full history, not just the current version.",
"apihelp-import-param-templates": "For interwiki imports: import all included templates as well.",
- "apihelp-import-param-namespace": "For interwiki imports: import to this namespace.",
- "apihelp-import-param-rootpage": "Import as subpage of this page.",
- "apihelp-import-example-import": "Import [[meta:Help:Parserfunctions]] to namespace 100 with full history.",
+ "apihelp-import-param-namespace": "Import to this namespace. Cannot be used together with <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Import as subpage of this page. Cannot be used together with <var>$1namespace</var>.",
+ "apihelp-import-example-import": "Import [[meta:Help:ParserFunctions]] to namespace 100 with full history.",
"apihelp-login-description": "Log in and get authentication cookies.\n\nIn the event of a successful log-in, the needed cookies will be included in the HTTP response headers. In the event of a failed log-in, further attempts may be throttled to limit automated password guessing attacks.",
"apihelp-login-param-name": "User name.",
@@ -245,12 +254,12 @@
"apihelp-opensearch-param-warningsaserror": "If warnings are raised with <kbd>format=json</kbd>, return an API error instead of ignoring them.",
"apihelp-opensearch-example-te": "Find pages beginning with <kbd>Te</kbd>.",
- "apihelp-options-description": "Change preferences of the current user.\n\nOnly options which are registered in core or in one of installed extensions, or options with keys prefixed with \"userjs-\" (intended to be used by user scripts), can be set.",
+ "apihelp-options-description": "Change preferences of the current user.\n\nOnly options which are registered in core or in one of installed extensions, or options with keys prefixed with <code>userjs-</code> (intended to be used by user scripts), can be set.",
"apihelp-options-param-reset": "Resets preferences to the site defaults.",
"apihelp-options-param-resetkinds": "List of types of options to reset when the <var>$1reset</var> option is set.",
"apihelp-options-param-change": "List of changes, formatted name=value (e.g. skin=vector). Value cannot contain pipe characters. If no value is given (not even an equals sign), e.g., optionname|otheroption|..., the option will be reset to its default value.",
- "apihelp-options-param-optionname": "A name of a option which should be set to the value given by <var>$1optionvalue</var>.",
- "apihelp-options-param-optionvalue": "A value of the option specified by <var>$1optionname</var>, can contain pipe characters.",
+ "apihelp-options-param-optionname": "The name of the option that should be set to the value given by <var>$1optionvalue</var>.",
+ "apihelp-options-param-optionvalue": "The value for the option specified by <var>$1optionname</var>, can contain pipe characters.",
"apihelp-options-example-reset": "Reset all preferences.",
"apihelp-options-example-change": "Change <kbd>skin</kbd> and <kbd>hideminor</kbd> preferences.",
"apihelp-options-example-complex": "Reset all preferences, then set <kbd>skin</kbd> and <kbd>nickname</kbd>.",
@@ -272,18 +281,43 @@
"apihelp-parse-param-pageid": "Parse the content of this page. Overrides <var>$1page</var>.",
"apihelp-parse-param-redirects": "If <var>$1page</var> or <var>$1pageid</var> is set to a redirect, resolve it.",
"apihelp-parse-param-oldid": "Parse the content of this revision. Overrides <var>$1page</var> and <var>$1pageid</var>.",
- "apihelp-parse-param-prop": "Which pieces of information to get:\n;text:Gives the parsed text of the wikitext.\n;langlinks:Gives the language links in the parsed wikitext.\n;categories:Gives the categories in the parsed wikitext.\n;categorieshtml:Gives the HTML version of the categories.\n;links:Gives the internal links in the parsed wikitext.\n;templates:Gives the templates in the parsed wikitext.\n;images:Gives the images in the parsed wikitext.\n;externallinks:Gives the external links in the parsed wikitext.\n;sections:Gives the sections in the parsed wikitext.\n;revid:Adds the revision ID of the parsed page.\n;displaytitle:Adds the title of the parsed wikitext.\n;headitems:Gives items to put in the &lt;head&gt; of the page.\n;headhtml:Gives parsed &lt;head&gt; of the page.\n;modules:Gives the ResourceLoader modules used on the page.\n;indicators:Gives the HTML of page status indicators used on the page.\n;iwlinks:Gives interwiki links in the parsed wikitext.\n;wikitext:Gives the original wikitext that was parsed.\n;properties:Gives various properties defined in the parsed wikitext.\n;limitreportdata:Gives the limit report in a structured way. Gives no data, when $1disablepp is set.\n;limitreporthtml:Gives the HTML version of the limit report. Gives no data, when $1disablepp is set.",
+ "apihelp-parse-param-prop": "Which pieces of information to get:",
+ "apihelp-parse-paramvalue-prop-text": "Gives the parsed text of the wikitext.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Gives the language links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-categories": "Gives the categories in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Gives the HTML version of the categories.",
+ "apihelp-parse-paramvalue-prop-links": "Gives the internal links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-templates": "Gives the templates in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-images": "Gives the images in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Gives the external links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-sections": "Gives the sections in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-revid": "Adds the revision ID of the parsed page.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Adds the title of the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-headitems": "Gives items to put in the <code>&lt;head&gt;</code> of the page.",
+ "apihelp-parse-paramvalue-prop-headhtml": "Gives parsed <code>&lt;head&gt;</code> of the page.",
+ "apihelp-parse-paramvalue-prop-modules": "Gives the ResourceLoader modules used on the page. Either <kbd>jsconfigvars</kbd> or <kbd>encodedjsconfigvars</kbd> must be requested jointly with <kbd>modules</kbd>.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Gives the JavaScript configuration variables specific to the page.",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Gives the JavaScript configuration variables specific to the page as a JSON string.",
+ "apihelp-parse-paramvalue-prop-indicators": "Gives the HTML of page status indicators used on the page.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "Gives interwiki links in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Gives the original wikitext that was parsed.",
+ "apihelp-parse-paramvalue-prop-properties": "Gives various properties defined in the parsed wikitext.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "Gives the limit report in a structured way. Gives no data, when <var>$1disablelimitreport</var> is set.",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "Gives the HTML version of the limit report. Gives no data, when <var>$1disablelimitreport</var> is set.",
+ "apihelp-parse-paramvalue-prop-parsetree": "The XML parse tree of revision content (requires content model <code>$1</code>)",
"apihelp-parse-param-pst": "Do a pre-save transform on the input before parsing it. Only valid when used with text.",
"apihelp-parse-param-onlypst": "Do a pre-save transform (PST) on the input, but don't parse it. Returns the same wikitext, after a PST has been applied. Only valid when used with <var>$1text</var>.",
"apihelp-parse-param-effectivelanglinks": "Includes language links supplied by extensions (for use with <kbd>$1prop=langlinks</kbd>).",
"apihelp-parse-param-section": "Only retrieve the content of this section number or when <kbd>new</kbd> generate a new section.\n\n<kbd>new</kbd> section is only honored when specifying <var>text</var>.",
"apihelp-parse-param-sectiontitle": "New section title when <var>section</var> is <kbd>new</kbd>.\n\nUnlike page editing, this does not fall back to <var>summary</var> when omitted or empty.",
- "apihelp-parse-param-disablepp": "Disable the PP Report from the parser output.",
- "apihelp-parse-param-disableeditsection": "Disable edit section links from the parser output.",
- "apihelp-parse-param-generatexml": "Generate XML parse tree (requires content model <code>$1</code>).",
+ "apihelp-parse-param-disablelimitreport": "Omit the limit report (\"NewPP limit report\") from the parser output.",
+ "apihelp-parse-param-disablepp": "Use <var>$1disablelimitreport</var> instead.",
+ "apihelp-parse-param-disableeditsection": "Omit edit section links from the parser output.",
+ "apihelp-parse-param-disabletidy": "Do not run HTML cleanup (e.g. tidy) on the parser output.",
+ "apihelp-parse-param-generatexml": "Generate XML parse tree (requires content model <code>$1</code>; replaced by <kbd>$2prop=parsetree</kbd>).",
"apihelp-parse-param-preview": "Parse in preview mode.",
"apihelp-parse-param-sectionpreview": "Parse in section preview mode (enables preview mode too).",
- "apihelp-parse-param-disabletoc": "Disable table of contents in output.",
+ "apihelp-parse-param-disabletoc": "Omit table of contents in output.",
"apihelp-parse-param-contentformat": "Content serialization format used for the input text. Only valid when used with $1text.",
"apihelp-parse-param-contentmodel": "Content model of the input text. If omitted, $1title must be specified, and default will be the model of the specified title. Only valid when used with $1text.",
"apihelp-parse-example-page": "Parse a page.",
@@ -303,7 +337,7 @@
"apihelp-protect-param-protections": "List of protection levels, formatted <kbd>action=level</kbd> (e.g. <kbd>edit=sysop</kbd>).\n\n<strong>Note:</strong> Any actions not listed will have restrictions removed.",
"apihelp-protect-param-expiry": "Expiry timestamps. If only one timestamp is set, it'll be used for all protections. Use <kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd>, or <kbd>never</kbd>, for a never-expiring protection.",
"apihelp-protect-param-reason": "Reason for (un)protecting.",
- "apihelp-protect-param-cascade": "Enable cascading protection (i.e. protect pages included in this page). Ignored if all protection levels given do not support cascading.",
+ "apihelp-protect-param-cascade": "Enable cascading protection (i.e. protect transcluded templates and images used in this page). Ignored if none of the given protection levels support cascading.",
"apihelp-protect-param-watch": "If set, add the page being (un)protected to the current user's watchlist.",
"apihelp-protect-param-watchlist": "Unconditionally add or remove the page from the current user's watchlist, use preferences or do not change watch.",
"apihelp-protect-example-protect": "Protect a page.",
@@ -324,8 +358,7 @@
"apihelp-query-param-export": "Export the current revisions of all given or generated pages.",
"apihelp-query-param-exportnowrap": "Return the export XML without wrapping it in an XML result (same format as [[Special:Export]]). Can only be used with $1export.",
"apihelp-query-param-iwurl": "Whether to get the full URL if the title is an interwiki link.",
- "apihelp-query-param-continue": "When present, formats query-continue as key-value pairs that should simply be merged into the original request. This parameter must be set to an empty string in the initial query.\n\nThis parameter is recommended for all new development, and will be made default in the next API version.",
- "apihelp-query-param-rawcontinue": "Currently ignored. In the future, <var>$1continue</var> will become the default and this will be needed to receive the raw <samp>query-continue</samp> data.",
+ "apihelp-query-param-rawcontinue": "Return raw <samp>query-continue</samp> data for continuation.",
"apihelp-query-example-revisions": "Fetch [[Special:ApiHelp/query+siteinfo|site info]] and [[Special:ApiHelp/query+revisions|revisions]] of <kbd>Main Page</kbd>.",
"apihelp-query-example-allpages": "Fetch revisions of pages beginning with <kbd>API/</kbd>.",
@@ -337,7 +370,9 @@
"apihelp-query+allcategories-param-min": "Only return categories with at least this many members.",
"apihelp-query+allcategories-param-max": "Only return categories with at most this many members.",
"apihelp-query+allcategories-param-limit": "How many categories to return.",
- "apihelp-query+allcategories-param-prop": "Which properties to get:\n;size:Adds number of pages in the category.\n;hidden:Tags categories that are hidden with _&#95;HIDDENCAT_&#95;.",
+ "apihelp-query+allcategories-param-prop": "Which properties to get:",
+ "apihelp-query+allcategories-paramvalue-prop-size": "Adds number of pages in the category.",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "Tags categories that are hidden with <code>_&#95;HIDDENCAT_&#95;</code>.",
"apihelp-query+allcategories-example-size": "List categories with information on the number of pages in each.",
"apihelp-query+allcategories-example-generator": "Retrieve info about the category page itself for categories beginning <kbd>List</kbd>.",
@@ -363,7 +398,9 @@
"apihelp-query+allfileusages-param-to": "The title of the file to stop enumerating at.",
"apihelp-query+allfileusages-param-prefix": "Search for all file titles that begin with this value.",
"apihelp-query+allfileusages-param-unique": "Only show distinct file titles. Cannot be used with $1prop=ids.\nWhen used as a generator, yields target pages instead of source pages.",
- "apihelp-query+allfileusages-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID of the using page (cannot be used with $1unique).\n;title:Adds the title of the file.",
+ "apihelp-query+allfileusages-param-prop": "Which pieces of information to include:",
+ "apihelp-query+allfileusages-paramvalue-prop-ids": "Adds the page IDs of the using pages (cannot be used with $1unique).",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "Adds the title of the file.",
"apihelp-query+allfileusages-param-limit": "How many total items to return.",
"apihelp-query+allfileusages-param-dir": "The direction in which to list.",
"apihelp-query+allfileusages-example-B": "List file titles, including missing ones, with page IDs they are from, starting at <kbd>B</kbd>.",
@@ -397,7 +434,9 @@
"apihelp-query+alllinks-param-to": "The title of the link to stop enumerating at.",
"apihelp-query+alllinks-param-prefix": "Search for all linked titles that begin with this value.",
"apihelp-query+alllinks-param-unique": "Only show distinct linked titles. Cannot be used with <kbd>$1prop=ids</kbd>.\nWhen used as a generator, yields target pages instead of source pages.",
- "apihelp-query+alllinks-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID of the linking page (cannot be used with <var>$1unique</var>).\n;title:Adds the title of the link.",
+ "apihelp-query+alllinks-param-prop": "Which pieces of information to include:",
+ "apihelp-query+alllinks-paramvalue-prop-ids": "Adds the page ID of the linking page (cannot be used with <var>$1unique</var>).",
+ "apihelp-query+alllinks-paramvalue-prop-title": "Adds the title of the link.",
"apihelp-query+alllinks-param-namespace": "The namespace to enumerate.",
"apihelp-query+alllinks-param-limit": "How many total items to return.",
"apihelp-query+alllinks-param-dir": "The direction in which to list.",
@@ -447,7 +486,11 @@
"apihelp-query+allredirects-param-to": "The title of the redirect to stop enumerating at.",
"apihelp-query+allredirects-param-prefix": "Search for all target pages that begin with this value.",
"apihelp-query+allredirects-param-unique": "Only show distinct target pages. Cannot be used with $1prop=ids|fragment|interwiki.\nWhen used as a generator, yields target pages instead of source pages.",
- "apihelp-query+allredirects-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID of the redirecting page (cannot be used with <var>$1unique</var>).\n;title:Adds the title of the redirect.\n;fragment:Adds the fragment from the redirect, if any (cannot be used with <var>$1unique</var>).\n;interwiki:Adds the interwiki prefix from the redirect, if any (cannot be used with <var>$1unique</var>).",
+ "apihelp-query+allredirects-param-prop": "Which pieces of information to include:",
+ "apihelp-query+allredirects-paramvalue-prop-ids": "Adds the page ID of the redirecting page (cannot be used with <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-title": "Adds the title of the redirect.",
+ "apihelp-query+allredirects-paramvalue-prop-fragment": "Adds the fragment from the redirect, if any (cannot be used with <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-interwiki": "Adds the interwiki prefix from the redirect, if any (cannot be used with <var>$1unique</var>).",
"apihelp-query+allredirects-param-namespace": "The namespace to enumerate.",
"apihelp-query+allredirects-param-limit": "How many total items to return.",
"apihelp-query+allredirects-param-dir": "The direction in which to list.",
@@ -461,7 +504,9 @@
"apihelp-query+alltransclusions-param-to": "The title of the transclusion to stop enumerating at.",
"apihelp-query+alltransclusions-param-prefix": "Search for all transcluded titles that begin with this value.",
"apihelp-query+alltransclusions-param-unique": "Only show distinct transcluded titles. Cannot be used with $1prop=ids.\nWhen used as a generator, yields target pages instead of source pages.",
- "apihelp-query+alltransclusions-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID of the transcluding page (cannot be used with $1unique).\n;title:Adds the title of the transclusion.",
+ "apihelp-query+alltransclusions-param-prop": "Which pieces of information to include:",
+ "apihelp-query+alltransclusions-paramvalue-prop-ids": "Adds the page ID of the transcluding page (cannot be used with $1unique).",
+ "apihelp-query+alltransclusions-paramvalue-prop-title": "Adds the title of the transclusion.",
"apihelp-query+alltransclusions-param-namespace": "The namespace to enumerate.",
"apihelp-query+alltransclusions-param-limit": "How many total items to return.",
"apihelp-query+alltransclusions-param-dir": "The direction in which to list.",
@@ -478,7 +523,13 @@
"apihelp-query+allusers-param-group": "Only include users in the given groups.",
"apihelp-query+allusers-param-excludegroup": "Exclude users in the given groups.",
"apihelp-query+allusers-param-rights": "Only include users with the given rights. Does not include rights granted by implicit or auto-promoted groups like *, user, or autoconfirmed.",
- "apihelp-query+allusers-param-prop": "Which pieces of information to include:\n;blockinfo:Adds the information about a current block on the user.\n;groups:Lists groups that the user is in. This uses more server resources and may return fewer results than the limit.\n;implicitgroups:Lists all the groups the user is automatically in.\n;rights:Lists rights that the user has.\n;editcount:Adds the edit count of the user.\n;registration:Adds the timestamp of when the user registered if available (may be blank).",
+ "apihelp-query+allusers-param-prop": "Which pieces of information to include:",
+ "apihelp-query+allusers-paramvalue-prop-blockinfo": "Adds the information about a current block on the user.",
+ "apihelp-query+allusers-paramvalue-prop-groups": "Lists groups that the user is in. This uses more server resources and may return fewer results than the limit.",
+ "apihelp-query+allusers-paramvalue-prop-implicitgroups": "Lists all the groups the user is automatically in.",
+ "apihelp-query+allusers-paramvalue-prop-rights": "Lists rights that the user has.",
+ "apihelp-query+allusers-paramvalue-prop-editcount": "Adds the edit count of the user.",
+ "apihelp-query+allusers-paramvalue-prop-registration": "Adds the timestamp of when the user registered if available (may be blank).",
"apihelp-query+allusers-param-limit": "How many total user names to return.",
"apihelp-query+allusers-param-witheditsonly": "Only list users who have made edits.",
"apihelp-query+allusers-param-activeusers": "Only list users active in the last $1 {{PLURAL:$1|day|days}}.",
@@ -490,7 +541,7 @@
"apihelp-query+backlinks-param-namespace": "The namespace to enumerate.",
"apihelp-query+backlinks-param-dir": "The direction in which to list.",
"apihelp-query+backlinks-param-filterredir": "How to filter for redirects. If set to <kbd>nonredirects</kbd> when <var>$1redirect</var> is enabled, this is only applied to the second level.",
- "apihelp-query+backlinks-param-limit": "How many total pages to return. If <var>$1redirect</var> is enabled, limit applies to each level separately (which means up to 2 * <var>$1limit</var> results may be returned).",
+ "apihelp-query+backlinks-param-limit": "How many total pages to return. If <var>$1redirect</var> is enabled, the limit applies to each level separately (which means up to 2 * <var>$1limit</var> results may be returned).",
"apihelp-query+backlinks-param-redirect": "If linking page is a redirect, find all pages that link to that redirect as well. Maximum limit is halved.",
"apihelp-query+backlinks-example-simple": "Show links to <kbd>Main page<kbd>.",
"apihelp-query+backlinks-example-generator": "Get information about pages linking to <kbd>Main page<kbd>.",
@@ -502,13 +553,26 @@
"apihelp-query+blocks-param-users": "List of users to search for (optional).",
"apihelp-query+blocks-param-ip": "Get all blocks applying to this IP or CIDR range, including range blocks.\nCannot be used together with <var>$3users</var>. CIDR ranges broader than IPv4/$1 or IPv6/$2 are not accepted.",
"apihelp-query+blocks-param-limit": "The maximum number of blocks to list.",
- "apihelp-query+blocks-param-prop": "Which properties to get:\n;id:Adds the ID of the block.\n;user:Adds the username of the blocked user.\n;userid:Adds the user ID of the blocked user.\n;by:Adds the username of the blocking user.\n;byid:Adds the user ID of the blocking user.\n;timestamp:Adds the timestamp of when the block was given.\n;expiry:Adds the timestamp of when the block expires.\n;reason:Adds the reason given for the block.\n;range:Adds the range of IP addresses affected by the block.\n;flags:Tags the ban with (autoblock, anononly, etc.).",
+ "apihelp-query+blocks-param-prop": "Which properties to get:",
+ "apihelp-query+blocks-paramvalue-prop-id": "Adds the ID of the block.",
+ "apihelp-query+blocks-paramvalue-prop-user": "Adds the username of the blocked user.",
+ "apihelp-query+blocks-paramvalue-prop-userid": "Adds the user ID of the blocked user.",
+ "apihelp-query+blocks-paramvalue-prop-by": "Adds the username of the blocking user.",
+ "apihelp-query+blocks-paramvalue-prop-byid": "Adds the user ID of the blocking user.",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "Adds the timestamp of when the block was given.",
+ "apihelp-query+blocks-paramvalue-prop-expiry": "Adds the timestamp of when the block expires.",
+ "apihelp-query+blocks-paramvalue-prop-reason": "Adds the reason given for the block.",
+ "apihelp-query+blocks-paramvalue-prop-range": "Adds the range of IP addresses affected by the block.",
+ "apihelp-query+blocks-paramvalue-prop-flags": "Tags the ban with (autoblock, anononly, etc.).",
"apihelp-query+blocks-param-show": "Show only items that meet these criteria.\nFor example, to see only indefinite blocks on IP addresses, set <kbd>$1show=ip|!temp</kbd>.",
"apihelp-query+blocks-example-simple": "List blocks.",
"apihelp-query+blocks-example-users": "List blocks of users <kbd>Alice</kbd> and <kbd>Bob</kbd>.",
"apihelp-query+categories-description": "List all categories the pages belong to.",
- "apihelp-query+categories-param-prop": "Which additional properties to get for each category:\n;sortkey:Adds the sortkey (hexadecimal string) and sortkey prefix (human-readable part) for the category.\n;timestamp:Adds timestamp of when the category was added.\n;hidden:Tags categories that are hidden with _&#95;HIDDENCAT_&#95;.",
+ "apihelp-query+categories-param-prop": "Which additional properties to get for each category:",
+ "apihelp-query+categories-paramvalue-prop-sortkey": "Adds the sortkey (hexadecimal string) and sortkey prefix (human-readable part) for the category.",
+ "apihelp-query+categories-paramvalue-prop-timestamp": "Adds timestamp of when the category was added.",
+ "apihelp-query+categories-paramvalue-prop-hidden": "Tags categories that are hidden with <code>_&#95;HIDDENCAT_&#95;</code>.",
"apihelp-query+categories-param-show": "Which kind of categories to show.",
"apihelp-query+categories-param-limit": "How many categories to return.",
"apihelp-query+categories-param-categories": "Only list these categories. Useful for checking whether a certain page is in a certain category.",
@@ -522,7 +586,13 @@
"apihelp-query+categorymembers-description": "List all pages in a given category.",
"apihelp-query+categorymembers-param-title": "Which category to enumerate (required). Must include the <kbd>{{ns:category}}:</kbd> prefix. Cannot be used together with <var>$1pageid</var>.",
"apihelp-query+categorymembers-param-pageid": "Page ID of the category to enumerate. Cannot be used together with <var>$1title</var>.",
- "apihelp-query+categorymembers-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID.\n;title:Adds the title and namespace ID of the page.\n;sortkey:Adds the sortkey used for sorting in the category (hexadecimal string).\n;sortkeyprefix:Adds the sortkey prefix used for sorting in the category (human-readable part of the sortkey).\n;type:Adds the type that the page has been categorised as (page, subcat or file).\n;timestamp:Adds the timestamp of when the page was included.",
+ "apihelp-query+categorymembers-param-prop": "Which pieces of information to include:",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "Adds the page ID.",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "Adds the title and namespace ID of the page.",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkey": "Adds the sortkey used for sorting in the category (hexadecimal string).",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "Adds the sortkey prefix used for sorting in the category (human-readable part of the sortkey).",
+ "apihelp-query+categorymembers-paramvalue-prop-type": "Adds the type that the page has been categorised as (page, subcat or file).",
+ "apihelp-query+categorymembers-paramvalue-prop-timestamp": "Adds the timestamp of when the page was included.",
"apihelp-query+categorymembers-param-namespace": "Only include pages in these namespaces. Note that <kbd>$1type=subcat</kbd> or <kbd>$1type=file</kbd> may be used instead of <kbd>$1namespace=14</kbd> or <kbd>6</kbd>.",
"apihelp-query+categorymembers-param-type": "Which type of category members to include. Ignored when <kbd>$1sort=timestamp</kbd> is set.",
"apihelp-query+categorymembers-param-limit": "The maximum number of pages to return.",
@@ -531,9 +601,9 @@
"apihelp-query+categorymembers-param-start": "Timestamp to start listing from. Can only be used with <kbd>$1sort=timestamp</kbd>.",
"apihelp-query+categorymembers-param-end": "Timestamp to end listing at. Can only be used with <kbd>$1sort=timestamp</kbd>.",
"apihelp-query+categorymembers-param-starthexsortkey": "Sortkey to start listing from, as returned by <kbd>$1prop=sortkey</kbd>. Can only be used with <kbd>$1sort=sortkey</kbd>.",
- "apihelp-query+categorymembers-param-endhexsortkey": "Sortkey to end listing from, as returned by <kbd>$1prop=sortkey</kbd>. Can only be used with <kbd>$1sort=sortkey</kbd>.",
+ "apihelp-query+categorymembers-param-endhexsortkey": "Sortkey to end listing at, as returned by <kbd>$1prop=sortkey</kbd>. Can only be used with <kbd>$1sort=sortkey</kbd>.",
"apihelp-query+categorymembers-param-startsortkeyprefix": "Sortkey prefix to start listing from. Can only be used with <kbd>$1sort=sortkey</kbd>. Overrides <var>$1starthexsortkey</var>.",
- "apihelp-query+categorymembers-param-endsortkeyprefix": "Sortkey prefix to end listing BEFORE (not at, if this value occurs it will not be included!). Can only be used with $1sort=sortkey. Overrides $1endhexsortkey.",
+ "apihelp-query+categorymembers-param-endsortkeyprefix": "Sortkey prefix to end listing <strong>before</strong> (not <strong>at</strong>; if this value occurs it will not be included!). Can only be used with $1sort=sortkey. Overrides $1endhexsortkey.",
"apihelp-query+categorymembers-param-startsortkey": "Use $1starthexsortkey instead.",
"apihelp-query+categorymembers-param-endsortkey": "Use $1endhexsortkey instead.",
"apihelp-query+categorymembers-example-simple": "Get first 10 pages in <kbd>Category:Physics</kbd>.",
@@ -553,8 +623,6 @@
"apihelp-query+deletedrevisions-param-tag": "Only list revisions tagged with this tag.",
"apihelp-query+deletedrevisions-param-user": "Only list revisions by this user.",
"apihelp-query+deletedrevisions-param-excludeuser": "Don't list revisions by this user.",
- "apihelp-query+deletedrevisions-param-limit": "The maximum amount of revisions to list.",
- "apihelp-query+deletedrevisions-param-prop": "Which properties to get:\n;revid:Adds the revision ID of the deleted revision.\n;parentid:Adds the revision ID of the previous revision to the page.\n;user:Adds the user who made the revision.\n;userid:Adds the user ID who made the revision.\n;comment:Adds the comment of the revision.\n;parsedcomment:Adds the parsed comment of the revision.\n;minor:Tags if the revision is minor.\n;len:Adds the length (bytes) of the revision.\n;sha1:Adds the SHA-1 (base 16) of the revision.\n;content:Adds the content of the revision.\n;tags:Tags for the revision.",
"apihelp-query+deletedrevisions-example-titles": "List the deleted revisions of the pages <kbd>Main Page</kbd> and <kbd>Talk:Main Page</kbd>, with content.",
"apihelp-query+deletedrevisions-example-revids": "List the information for deleted revision <kbd>123456</kbd>.",
@@ -571,7 +639,7 @@
"apihelp-query+deletedrevs-param-excludeuser": "Don't list revisions by this user.",
"apihelp-query+deletedrevs-param-namespace": "Only list pages in this namespace.",
"apihelp-query+deletedrevs-param-limit": "The maximum amount of revisions to list.",
- "apihelp-query+deletedrevs-param-prop": "Which properties to get:\n;revid:Adds the revision ID of the deleted revision.\n;parentid:Adds the revision ID of the previous revision to the page.\n;user:Adds the user who made the revision.\n;userid:Adds the user ID whom made the revision.\n;comment:Adds the comment of the revision.\n;parsedcomment:Adds the parsed comment of the revision.\n;minor:Tags if the revision is minor.\n;len:Adds the length (bytes) of the revision.\n;sha1:Adds the SHA-1 (base 16) of the revision.\n;content:Adds the content of the revision.\n;token:<span class=\"apihelp-deprecated\">Deprecated.</span> Gives the edit token.\n;tags:Tags for the revision.",
+ "apihelp-query+deletedrevs-param-prop": "Which properties to get:\n;revid:Adds the revision ID of the deleted revision.\n;parentid:Adds the revision ID of the previous revision to the page.\n;user:Adds the user who made the revision.\n;userid:Adds the ID of the user who made the revision.\n;comment:Adds the comment of the revision.\n;parsedcomment:Adds the parsed comment of the revision.\n;minor:Tags if the revision is minor.\n;len:Adds the length (bytes) of the revision.\n;sha1:Adds the SHA-1 (base 16) of the revision.\n;content:Adds the content of the revision.\n;token:<span class=\"apihelp-deprecated\">Deprecated.</span> Gives the edit token.\n;tags:Tags for the revision.",
"apihelp-query+deletedrevs-example-mode1": "List the last deleted revisions of the pages <kbd>Main Page</kbd> and <kbd>Talk:Main Page</kbd>, with content (mode 1).",
"apihelp-query+deletedrevs-example-mode2": "List the last 50 deleted contributions by <kbd>Bob</kbd> (mode 2).",
"apihelp-query+deletedrevs-example-mode3-main": "List the first 50 deleted revisions in the main namespace (mode 3).",
@@ -604,8 +672,11 @@
"apihelp-query+extlinks-example-simple": "Get a list of external links on <kbd>Main Page<kbd>.",
"apihelp-query+exturlusage-description": "Enumerate pages that contain a given URL.",
- "apihelp-query+exturlusage-param-prop": "Which pieces of information to include:\n;ids:Adds the ID of page.\n;title:Adds the title and namespace ID of the page.\n;url:Adds the URL used in the page.",
- "apihelp-query+exturlusage-param-protocol": "Protocol of the URL. If empty and <var>$1query</var> set, the protocol is <kbd>http</kbd>. Leave both this and <var>$1query</var> empty to list all external links.",
+ "apihelp-query+exturlusage-param-prop": "Which pieces of information to include:",
+ "apihelp-query+exturlusage-paramvalue-prop-ids": "Adds the ID of page.",
+ "apihelp-query+exturlusage-paramvalue-prop-title": "Adds the title and namespace ID of the page.",
+ "apihelp-query+exturlusage-paramvalue-prop-url": "Adds the URL used in the page.",
+ "apihelp-query+exturlusage-param-protocol": "Protocol of the URL. If empty and <var>$1query</var> is set, the protocol is <kbd>http</kbd>. Leave both this and <var>$1query</var> empty to list all external links.",
"apihelp-query+exturlusage-param-query": "Search string without protocol. See [[Special:LinkSearch]]. Leave empty to list all external links.",
"apihelp-query+exturlusage-param-namespace": "The page namespaces to enumerate.",
"apihelp-query+exturlusage-param-limit": "How many pages to return.",
@@ -620,7 +691,19 @@
"apihelp-query+filearchive-param-dir": "The direction in which to list.",
"apihelp-query+filearchive-param-sha1": "SHA1 hash of image. Overrides $1sha1base36.",
"apihelp-query+filearchive-param-sha1base36": "SHA1 hash of image in base 36 (used in MediaWiki).",
- "apihelp-query+filearchive-param-prop": "Which image information to get:\n;sha1:Adds SHA-1 hash for the image.\n;timestamp:Adds timestamp for the uploaded version.\n;user:Adds user who uploaded the image version.\n;size:Adds the size of the image in bytes and the height, width and page count (if applicable).\n;dimensions:Alias for size.\n;description:Adds description the image version.\n;parseddescription:Parse the description on the version.\n;mime:Adds MIME of the image.\n;mediatype:Adds the media type of the image.\n;metadata:Lists Exif metadata for the version of the image.\n;bitdepth:Adds the bit depth of the version.\n;archivename:Adds the filename of the archive version for non-latest versions.",
+ "apihelp-query+filearchive-param-prop": "Which image information to get:",
+ "apihelp-query+filearchive-paramvalue-prop-sha1": "Adds SHA-1 hash for the image.",
+ "apihelp-query+filearchive-paramvalue-prop-timestamp": "Adds timestamp for the uploaded version.",
+ "apihelp-query+filearchive-paramvalue-prop-user": "Adds user who uploaded the image version.",
+ "apihelp-query+filearchive-paramvalue-prop-size": "Adds the size of the image in bytes and the height, width and page count (if applicable).",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "Alias for size.",
+ "apihelp-query+filearchive-paramvalue-prop-description": "Adds description of the image version.",
+ "apihelp-query+filearchive-paramvalue-prop-parseddescription": "Parse the description of the version.",
+ "apihelp-query+filearchive-paramvalue-prop-mime": "Adds MIME of the image.",
+ "apihelp-query+filearchive-paramvalue-prop-mediatype": "Adds the media type of the image.",
+ "apihelp-query+filearchive-paramvalue-prop-metadata": "Lists Exif metadata for the version of the image.",
+ "apihelp-query+filearchive-paramvalue-prop-bitdepth": "Adds the bit depth of the version.",
+ "apihelp-query+filearchive-paramvalue-prop-archivename": "Adds the filename of the archive version for non-latest versions.",
"apihelp-query+filearchive-example-simple": "Show a list of all deleted files.",
"apihelp-query+filerepoinfo-description": "Return meta information about image repositories configured on the wiki.",
@@ -628,7 +711,10 @@
"apihelp-query+filerepoinfo-example-simple": "Get information about file repositories.",
"apihelp-query+fileusage-description": "Find all pages that use the given files.",
- "apihelp-query+fileusage-param-prop": "Which properties to get:\n;pageid:Page ID of each page.\n;title:Title of each page.\n;redirect:Flag if the page is a redirect.",
+ "apihelp-query+fileusage-param-prop": "Which properties to get:",
+ "apihelp-query+fileusage-paramvalue-prop-pageid": "Page ID of each page.",
+ "apihelp-query+fileusage-paramvalue-prop-title": "Title of each page.",
+ "apihelp-query+fileusage-paramvalue-prop-redirect": "Flag if the page is a redirect.",
"apihelp-query+fileusage-param-namespace": "Only include pages in these namespaces.",
"apihelp-query+fileusage-param-limit": "How many to return.",
"apihelp-query+fileusage-param-show": "Show only items that meet these criteria:\n;redirect:Only show redirects.\n;!redirect:Only show non-redirects.",
@@ -638,24 +724,24 @@
"apihelp-query+imageinfo-description": "Returns file information and upload history.",
"apihelp-query+imageinfo-param-prop": "Which file information to get:",
"apihelp-query+imageinfo-paramvalue-prop-timestamp": "Adds timestamp for the uploaded version.",
- "apihelp-query+imageinfo-paramvalue-prop-user":"Adds the user who uploaded each file version.",
- "apihelp-query+imageinfo-paramvalue-prop-userid":"Add the user ID that uploaded each file version.",
- "apihelp-query+imageinfo-paramvalue-prop-comment":"Comment on the version.",
- "apihelp-query+imageinfo-paramvalue-prop-parsedcomment":"Parse the comment on the version.",
- "apihelp-query+imageinfo-paramvalue-prop-canonicaltitle":"Adds the canonical title of the file.",
- "apihelp-query+imageinfo-paramvalue-prop-url":"Gives URL to the file and the description page.",
- "apihelp-query+imageinfo-paramvalue-prop-size":"Adds the size of the file in bytes and the height, width and page count (if applicable).",
- "apihelp-query+imageinfo-paramvalue-prop-dimensions":"Alias for size.",
- "apihelp-query+imageinfo-paramvalue-prop-sha1":"Adds SHA-1 hash for the file.",
- "apihelp-query+imageinfo-paramvalue-prop-mime":"Adds MIME type of the file.",
- "apihelp-query+imageinfo-paramvalue-prop-thumbmime":"Adds MIME type of the image thumbnail (requires url and param $1urlwidth).",
- "apihelp-query+imageinfo-paramvalue-prop-mediatype":"Adds the media type of the file.",
- "apihelp-query+imageinfo-paramvalue-prop-metadata":"Lists Exif metadata for the version of the file.",
- "apihelp-query+imageinfo-paramvalue-prop-commonmetadata":"Lists file format generic metadata for the version of the file.",
- "apihelp-query+imageinfo-paramvalue-prop-extmetadata":"Lists formatted metadata combined from multiple sources. Results are HTML formatted.",
- "apihelp-query+imageinfo-paramvalue-prop-archivename":"Adds the filename of the archive version for non-latest versions.",
- "apihelp-query+imageinfo-paramvalue-prop-bitdepth":"Adds the bit depth of the version.",
- "apihelp-query+imageinfo-paramvalue-prop-uploadwarning":"Used by the Special:Upload page to get information about an existing file. Not intended for use outside MediaWiki core.",
+ "apihelp-query+imageinfo-paramvalue-prop-user": "Adds the user who uploaded each file version.",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "Add the ID of the user that uploaded each file version.",
+ "apihelp-query+imageinfo-paramvalue-prop-comment": "Comment on the version.",
+ "apihelp-query+imageinfo-paramvalue-prop-parsedcomment": "Parse the comment on the version.",
+ "apihelp-query+imageinfo-paramvalue-prop-canonicaltitle": "Adds the canonical title of the file.",
+ "apihelp-query+imageinfo-paramvalue-prop-url": "Gives URL to the file and the description page.",
+ "apihelp-query+imageinfo-paramvalue-prop-size": "Adds the size of the file in bytes and the height, width and page count (if applicable).",
+ "apihelp-query+imageinfo-paramvalue-prop-dimensions": "Alias for size.",
+ "apihelp-query+imageinfo-paramvalue-prop-sha1": "Adds SHA-1 hash for the file.",
+ "apihelp-query+imageinfo-paramvalue-prop-mime": "Adds MIME type of the file.",
+ "apihelp-query+imageinfo-paramvalue-prop-thumbmime": "Adds MIME type of the image thumbnail (requires url and param $1urlwidth).",
+ "apihelp-query+imageinfo-paramvalue-prop-mediatype": "Adds the media type of the file.",
+ "apihelp-query+imageinfo-paramvalue-prop-metadata": "Lists Exif metadata for the version of the file.",
+ "apihelp-query+imageinfo-paramvalue-prop-commonmetadata": "Lists file format generic metadata for the version of the file.",
+ "apihelp-query+imageinfo-paramvalue-prop-extmetadata": "Lists formatted metadata combined from multiple sources. Results are HTML formatted.",
+ "apihelp-query+imageinfo-paramvalue-prop-archivename": "Adds the filename of the archive version for non-latest versions.",
+ "apihelp-query+imageinfo-paramvalue-prop-bitdepth": "Adds the bit depth of the version.",
+ "apihelp-query+imageinfo-paramvalue-prop-uploadwarning": "Used by the Special:Upload page to get information about an existing file. Not intended for use outside MediaWiki core.",
"apihelp-query+imageinfo-param-limit": "How many file revisions to return per file.",
"apihelp-query+imageinfo-param-start": "Timestamp to start listing from.",
"apihelp-query+imageinfo-param-end": "Timestamp to stop listing at.",
@@ -699,7 +785,7 @@
"apihelp-query+info-paramvalue-prop-url": "Gives a full URL, an edit URL, and the canonical URL for each page.",
"apihelp-query+info-paramvalue-prop-readable": "Whether the user can read this page.",
"apihelp-query+info-paramvalue-prop-preload": "Gives the text returned by EditFormPreloadText.",
- "apihelp-query+info-paramvalue-prop-displaytitle": "Gives the way the page title is actually displayed.",
+ "apihelp-query+info-paramvalue-prop-displaytitle": "Gives the manner in which the page title is actually displayed.",
"apihelp-query+info-param-testactions": "Test whether the current user can perform certain actions on the page.",
"apihelp-query+info-param-token": "Use [[Special:ApiHelp/query+tokens|action=query&meta=tokens]] instead.",
"apihelp-query+info-example-simple": "Get information about the page <kbd>Main Page</kbd>.",
@@ -709,14 +795,17 @@
"apihelp-query+iwbacklinks-param-prefix": "Prefix for the interwiki.",
"apihelp-query+iwbacklinks-param-title": "Interwiki link to search for. Must be used with <var>$1blprefix</var>.",
"apihelp-query+iwbacklinks-param-limit": "How many total pages to return.",
- "apihelp-query+iwbacklinks-param-prop": "Which properties to get:\n;iwprefix:Adds the prefix of the interwiki.\n;iwtitle:Adds the title of the interwiki.",
+ "apihelp-query+iwbacklinks-param-prop": "Which properties to get:",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Adds the prefix of the interwiki.",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Adds the title of the interwiki.",
"apihelp-query+iwbacklinks-param-dir": "The direction in which to list.",
"apihelp-query+iwbacklinks-example-simple": "Get pages linking to [[wikibooks:Test]].",
"apihelp-query+iwbacklinks-example-generator": "Get information about pages linking to [[wikibooks:Test]].",
"apihelp-query+iwlinks-description": "Returns all interwiki links from the given pages.",
"apihelp-query+iwlinks-param-url": "Whether to get the full URL (cannot be used with $1prop).",
- "apihelp-query+iwlinks-param-prop": "Which additional properties to get for each interlanguage link:\n;url:Adds the full URL.",
+ "apihelp-query+iwlinks-param-prop": "Which additional properties to get for each interlanguage link:",
+ "apihelp-query+iwlinks-paramvalue-prop-url": "Adds the full URL.",
"apihelp-query+iwlinks-param-limit": "How many interwiki links to return.",
"apihelp-query+iwlinks-param-prefix": "Only return interwiki links with this prefix.",
"apihelp-query+iwlinks-param-title": "Interwiki link to search for. Must be used with <var>$1prefix</var>.",
@@ -727,7 +816,9 @@
"apihelp-query+langbacklinks-param-lang": "Language for the language link.",
"apihelp-query+langbacklinks-param-title": "Language link to search for. Must be used with $1lang.",
"apihelp-query+langbacklinks-param-limit": "How many total pages to return.",
- "apihelp-query+langbacklinks-param-prop": "Which properties to get:\n;lllang:Adds the language code of the language link.\n;lltitle:Adds the title of the language link.",
+ "apihelp-query+langbacklinks-param-prop": "Which properties to get:",
+ "apihelp-query+langbacklinks-paramvalue-prop-lllang": "Adds the language code of the language link.",
+ "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Adds the title of the language link.",
"apihelp-query+langbacklinks-param-dir": "The direction in which to list.",
"apihelp-query+langbacklinks-example-simple": "Get pages linking to [[:fr:Test]].",
"apihelp-query+langbacklinks-example-generator": "Get information about pages linking to [[:fr:Test]].",
@@ -735,7 +826,10 @@
"apihelp-query+langlinks-description": "Returns all interlanguage links from the given pages.",
"apihelp-query+langlinks-param-limit": "How many langlinks to return.",
"apihelp-query+langlinks-param-url": "Whether to get the full URL (cannot be used with <var>$1prop</var>).",
- "apihelp-query+langlinks-param-prop": "Which additional properties to get for each interlanguage link:\n;url:Adds the full URL.\n;langname:Adds the localised language name (best effort). Use <var>$1inlanguagecode</var> to control the language.\n;autonym:Adds the native language name.",
+ "apihelp-query+langlinks-param-prop": "Which additional properties to get for each interlanguage link:",
+ "apihelp-query+langlinks-paramvalue-prop-url": "Adds the full URL.",
+ "apihelp-query+langlinks-paramvalue-prop-langname": "Adds the localised language name (best effort). Use <var>$1inlanguagecode</var> to control the language.",
+ "apihelp-query+langlinks-paramvalue-prop-autonym": "Adds the native language name.",
"apihelp-query+langlinks-param-lang": "Only return language links with this language code.",
"apihelp-query+langlinks-param-title": "Link to search for. Must be used with <var>$1lang</var>.",
"apihelp-query+langlinks-param-dir": "The direction in which to list.",
@@ -752,7 +846,10 @@
"apihelp-query+links-example-namespaces": "Get links from the page <kbd>Main Page</kbd> in the {{ns:user}} and {{ns:template}} namespaces.",
"apihelp-query+linkshere-description": "Find all pages that link to the given pages.",
- "apihelp-query+linkshere-param-prop": "Which properties to get:\n;pageid:Page ID of each page.\n;title:Title of each page.\n;redirect:Flag if the page is a redirect.",
+ "apihelp-query+linkshere-param-prop": "Which properties to get:",
+ "apihelp-query+linkshere-paramvalue-prop-pageid": "Page ID of each page.",
+ "apihelp-query+linkshere-paramvalue-prop-title": "Title of each page.",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "Flag if the page is a redirect.",
"apihelp-query+linkshere-param-namespace": "Only include pages in these namespaces.",
"apihelp-query+linkshere-param-limit": "How many to return.",
"apihelp-query+linkshere-param-show": "Show only items that meet these criteria:\n;redirect:Only show redirects.\n;!redirect:Only show non-redirects.",
@@ -760,9 +857,19 @@
"apihelp-query+linkshere-example-generator": "Get information about pages linking to the [[Main Page]].",
"apihelp-query+logevents-description": "Get events from logs.",
- "apihelp-query+logevents-param-prop": "Which properties to get:\n;ids:Adds the ID of the log event.\n;title:Adds the title of the page for the log event.\n;type:Adds the type of log event.\n;user:Adds the user responsible for the log event.\n;userid:Adds the user ID who was responsible for the log event.\n;timestamp:Adds the timestamp for the event.\n;comment:Adds the comment of the event.\n;parsedcomment:Adds the parsed comment of the event.\n;details:Lists additional details about the event.\n;tags:Lists tags for the event.",
+ "apihelp-query+logevents-param-prop": "Which properties to get:",
+ "apihelp-query+logevents-paramvalue-prop-ids": "Adds the ID of the log event.",
+ "apihelp-query+logevents-paramvalue-prop-title": "Adds the title of the page for the log event.",
+ "apihelp-query+logevents-paramvalue-prop-type": "Adds the type of log event.",
+ "apihelp-query+logevents-paramvalue-prop-user": "Adds the user responsible for the log event.",
+ "apihelp-query+logevents-paramvalue-prop-userid": "Adds the user ID who was responsible for the log event.",
+ "apihelp-query+logevents-paramvalue-prop-timestamp": "Adds the timestamp for the log event.",
+ "apihelp-query+logevents-paramvalue-prop-comment": "Adds the comment of the log event.",
+ "apihelp-query+logevents-paramvalue-prop-parsedcomment": "Adds the parsed comment of the log event.",
+ "apihelp-query+logevents-paramvalue-prop-details": "Lists additional details about the log event.",
+ "apihelp-query+logevents-paramvalue-prop-tags": "Lists tags for the log event.",
"apihelp-query+logevents-param-type": "Filter log entries to only this type.",
- "apihelp-query+logevents-param-action": "Filter log actions to only this action. Overrides <var>$1type</var>. Wildcard actions like <kbd>action/*</kbd> allows to specify any string for the asterisk.",
+ "apihelp-query+logevents-param-action": "Filter log actions to only this action. Overrides <var>$1type</var>. In the list of possible values, values with the asterisk wildcard such as <kbd>action/*</kbd> can have different strings after the slash (/).",
"apihelp-query+logevents-param-start": "The timestamp to start enumerating from.",
"apihelp-query+logevents-param-end": "The timestamp to end enumerating.",
"apihelp-query+logevents-param-user": "Filter entries to those made by the given user.",
@@ -779,15 +886,18 @@
"apihelp-query+pageprops-description": "Get various properties defined in the page content.",
"apihelp-query+pageprops-param-prop": "Only list these props. Useful for checking whether a certain page uses a certain page prop.",
- "apihelp-query+pageprops-example-simple": "Get properties for <kbd>Category:Foo</kbd>.",
+ "apihelp-query+pageprops-example-simple": "Get properties for the pages <kbd>Main Page</kbd> and <kbd>MediaWiki</kbd>.",
"apihelp-query+pageswithprop-description": "List all pages using a given page property.",
"apihelp-query+pageswithprop-param-propname": "Page prop for which to enumerate pages.",
- "apihelp-query+pageswithprop-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID.\n;title:Adds the title and namespace ID of the page.\n;value:Adds the value of the page prop.",
+ "apihelp-query+pageswithprop-param-prop": "Which pieces of information to include:",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "Adds the page ID.",
+ "apihelp-query+pageswithprop-paramvalue-prop-title": "Adds the title and namespace ID of the page.",
+ "apihelp-query+pageswithprop-paramvalue-prop-value": "Adds the value of the page prop.",
"apihelp-query+pageswithprop-param-limit": "The maximum number of pages to return.",
"apihelp-query+pageswithprop-param-dir": "In which direction to sort.",
"apihelp-query+pageswithprop-example-simple": "List the first 10 pages using <code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code>.",
- "apihelp-query+pageswithprop-example-generator": "Get page info about first 10 pages using <code>_&#95;NOTOC_&#95;</code>.",
+ "apihelp-query+pageswithprop-example-generator": "Get additional information about the first 10 pages using <code>_&#95;NOTOC_&#95;</code>.",
"apihelp-query+prefixsearch-description": "Perform a prefix search for page titles.",
"apihelp-query+prefixsearch-param-search": "Search string.",
@@ -795,13 +905,21 @@
"apihelp-query+prefixsearch-param-limit": "Maximum number of results to return.",
"apihelp-query+prefixsearch-param-offset": "Number of results to skip.",
"apihelp-query+prefixsearch-example-simple": "Search for page titles beginning with <kbd>meaning</kbd>.",
+
"apihelp-query+protectedtitles-description": "List all titles protected from creation.",
"apihelp-query+protectedtitles-param-namespace": "Only list titles in these namespaces.",
"apihelp-query+protectedtitles-param-level": "Only list titles with these protection levels.",
"apihelp-query+protectedtitles-param-limit": "How many total pages to return.",
"apihelp-query+protectedtitles-param-start": "Start listing at this protection timestamp.",
"apihelp-query+protectedtitles-param-end": "Stop listing at this protection timestamp.",
- "apihelp-query+protectedtitles-param-prop": "Which properties to get:\n;timestamp:Adds the timestamp of when protection was added.\n;user:Adds the user that added the protection.\n;userid:Adds the user ID that added the protection.\n;comment:Adds the comment for the protection.\n;parsedcomment:Adds the parsed comment for the protection.\n;expiry:Adds the timestamp of when the protection will be lifted.\n;level:Adds the protection level.",
+ "apihelp-query+protectedtitles-param-prop": "Which properties to get:",
+ "apihelp-query+protectedtitles-paramvalue-prop-timestamp": "Adds the timestamp of when protection was added.",
+ "apihelp-query+protectedtitles-paramvalue-prop-user": "Adds the user that added the protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-userid": "Adds the user ID that added the protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-comment": "Adds the comment for the protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-parsedcomment": "Adds the parsed comment for the protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-expiry": "Adds the timestamp of when the protection will be lifted.",
+ "apihelp-query+protectedtitles-paramvalue-prop-level": "Adds the protection level.",
"apihelp-query+protectedtitles-example-simple": "List protected titles.",
"apihelp-query+protectedtitles-example-generator": "Find links to protected titles in the main namespace.",
@@ -810,10 +928,11 @@
"apihelp-query+querypage-param-limit": "Number of results to return.",
"apihelp-query+querypage-example-ancientpages": "Return results from [[Special:Ancientpages]].",
- "apihelp-query+random-description": "Get a set of random pages.\n\nPages are listed in a fixed sequence, only the starting point is random. This means that if, for example, <samp>Main Page</samp> is the first random page in the list, <samp>List of fictional monkeys</samp> will <em>always</em> be second, <samp>List of people on stamps of Vanuatu</samp> third, etc.\n\nIf the number of pages in the namespace is lower than <var>$1limit</var>, fewer pages will be returned. The same page will not be returned twice.",
+ "apihelp-query+random-description": "Get a set of random pages.\n\nPages are listed in a fixed sequence, only the starting point is random. This means that if, for example, <samp>Main Page</samp> is the first random page in the list, <samp>List of fictional monkeys</samp> will <em>always</em> be second, <samp>List of people on stamps of Vanuatu</samp> third, etc.",
"apihelp-query+random-param-namespace": "Return pages in these namespaces only.",
"apihelp-query+random-param-limit": "Limit how many random pages will be returned.",
- "apihelp-query+random-param-redirect": "Load a random redirect instead of a random page.",
+ "apihelp-query+random-param-redirect": "Use <kbd>$1filterredir=redirects</kbd> instead.",
+ "apihelp-query+random-param-filterredir": "How to filter for redirects.",
"apihelp-query+random-example-simple": "Return two random pages from the main namespace.",
"apihelp-query+random-example-generator": "Return page info about two random pages from the main namespace.",
@@ -824,7 +943,21 @@
"apihelp-query+recentchanges-param-user": "Only list changes by this user.",
"apihelp-query+recentchanges-param-excludeuser": "Don't list changes by this user.",
"apihelp-query+recentchanges-param-tag": "Only list changes tagged with this tag.",
- "apihelp-query+recentchanges-param-prop": "Include additional pieces of information:\n;user:Adds the user responsible for the edit and tags if they are an IP.\n;userid:Adds the user ID responsible for the edit.\n;comment:Adds the comment for the edit.\n;parsedcomment:Adds the parsed comment for the edit.\n;flags:Adds flags for the edit.\n;timestamp:Adds timestamp of the edit.\n;title:Adds the page title of the edit.\n;ids:Adds the page ID, recent changes ID and the new and old revision ID.\n;sizes:Adds the new and old page length in bytes.\n;redirect:Tags edit if page is a redirect.\n;patrolled:Tags patrollable edits as being patrolled or unpatrolled.\n;loginfo:Adds log information (log ID, log type, etc) to log entries.\n;tags:Lists tags for the entry.\n;sha1:Adds the content checksum for entries associated with a revision.",
+ "apihelp-query+recentchanges-param-prop": "Include additional pieces of information:",
+ "apihelp-query+recentchanges-paramvalue-prop-user": "Adds the user responsible for the edit and tags if they are an IP.",
+ "apihelp-query+recentchanges-paramvalue-prop-userid": "Adds the user ID responsible for the edit.",
+ "apihelp-query+recentchanges-paramvalue-prop-comment": "Adds the comment for the edit.",
+ "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "Adds the parsed comment for the edit.",
+ "apihelp-query+recentchanges-paramvalue-prop-flags": "Adds flags for the edit.",
+ "apihelp-query+recentchanges-paramvalue-prop-timestamp": "Adds timestamp of the edit.",
+ "apihelp-query+recentchanges-paramvalue-prop-title": "Adds the page title of the edit.",
+ "apihelp-query+recentchanges-paramvalue-prop-ids": "Adds the page ID, recent changes ID and the new and old revision ID.",
+ "apihelp-query+recentchanges-paramvalue-prop-sizes": "Adds the new and old page length in bytes.",
+ "apihelp-query+recentchanges-paramvalue-prop-redirect": "Tags edit if page is a redirect.",
+ "apihelp-query+recentchanges-paramvalue-prop-patrolled": "Tags patrollable edits as being patrolled or unpatrolled.",
+ "apihelp-query+recentchanges-paramvalue-prop-loginfo": "Adds log information (log ID, log type, etc) to log entries.",
+ "apihelp-query+recentchanges-paramvalue-prop-tags": "Lists tags for the entry.",
+ "apihelp-query+recentchanges-paramvalue-prop-sha1": "Adds the content checksum for entries associated with a revision.",
"apihelp-query+recentchanges-param-token": "Use <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> instead.",
"apihelp-query+recentchanges-param-show": "Show only items that meet these criteria. For example, to see only minor edits done by logged-in users, set $1show=minor|!anon.",
"apihelp-query+recentchanges-param-limit": "How many total changes to return.",
@@ -834,7 +967,10 @@
"apihelp-query+recentchanges-example-generator": "Get page info about recent unpatrolled changes.",
"apihelp-query+redirects-description": "Returns all redirects to the given pages.",
- "apihelp-query+redirects-param-prop": "Which properties to get:\n;pageid:Page ID of each redirect.\n;title:Title of each redirect.\n;fragment:Fragment of each redirect, if any.",
+ "apihelp-query+redirects-param-prop": "Which properties to get:",
+ "apihelp-query+redirects-paramvalue-prop-pageid": "Page ID of each redirect.",
+ "apihelp-query+redirects-paramvalue-prop-title": "Title of each redirect.",
+ "apihelp-query+redirects-paramvalue-prop-fragment": "Fragment of each redirect, if any.",
"apihelp-query+redirects-param-namespace": "Only include pages in these namespaces.",
"apihelp-query+redirects-param-limit": "How many redirects to return.",
"apihelp-query+redirects-param-show": "Show only items that meet these criteria:\n;fragment:Only show redirects with a fragment.\n;!fragment:Only show redirects without a fragment.",
@@ -857,31 +993,81 @@
"apihelp-query+revisions-example-first5-after": "Get first 5 revisions of the <kbd>Main Page</kbd> made after 2006-05-01.",
"apihelp-query+revisions-example-first5-not-localhost": "Get first 5 revisions of the <kbd>Main Page</kbd> that were not made by anonymous user <kbd>127.0.0.1</kbd>.",
"apihelp-query+revisions-example-first5-user": "Get first 5 revisions of the <kbd>Main Page</kbd> that were made by the user <kbd>MediaWiki default</kbd>.",
- "apihelp-query+revisions+base-param-prop": "Which properties to get for each revision:\n;ids:The ID of the revision.\n;flags:Revision flags (minor).\n;timestamp:The timestamp of the revision.\n;user:User that made the revision.\n;userid:User ID of the revision creator.\n;size:Length (bytes) of the revision.\n;sha1:SHA-1 (base 16) of the revision.\n;contentmodel:Content model ID of the revision.\n;comment:Comment by the user for the revision.\n;parsedcomment:Parsed comment by the user for the revision.\n;content:Text of the revision.\n;tags:Tags for the revision.",
+
+ "apihelp-query+revisions+base-param-prop": "Which properties to get for each revision:",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "The ID of the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-flags": "Revision flags (minor).",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "The timestamp of the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "User that made the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-userid": "User ID of the revision creator.",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "Length (bytes) of the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "SHA-1 (base 16) of the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "Content model ID of the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-comment": "Comment by the user for the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-parsedcomment": "Parsed comment by the user for the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-content": "Text of the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-tags": "Tags for the revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-parsetree": "The XML parse tree of revision content (requires content model <code>$1</code>).",
"apihelp-query+revisions+base-param-limit": "Limit how many revisions will be returned.",
"apihelp-query+revisions+base-param-expandtemplates": "Expand templates in revision content (requires $1prop=content).",
- "apihelp-query+revisions+base-param-generatexml": "Generate XML parse tree for revision content (requires $1prop=content).",
+ "apihelp-query+revisions+base-param-generatexml": "Generate XML parse tree for revision content (requires $1prop=content; replaced by <kbd>$1prop=parsetree</kbd>).",
"apihelp-query+revisions+base-param-parse": "Parse revision content (requires $1prop=content). For performance reasons, if this option is used, $1limit is enforced to 1.",
"apihelp-query+revisions+base-param-section": "Only retrieve the content of this section number.",
"apihelp-query+revisions+base-param-diffto": "Revision ID to diff each revision to. Use <kbd>prev</kbd>, <kbd>next</kbd> and <kbd>cur</kbd> for the previous, next and current revision respectively.",
- "apihelp-query+revisions+base-param-difftotext": "Text to diff each revision to. Only diffs a limited number of revisions. Overrides <var>$1diffto</var>. If <var>$1section</var> is set, only that section will be diffed against this text",
+ "apihelp-query+revisions+base-param-difftotext": "Text to diff each revision to. Only diffs a limited number of revisions. Overrides <var>$1diffto</var>. If <var>$1section</var> is set, only that section will be diffed against this text.",
"apihelp-query+revisions+base-param-contentformat": "Serialization format used for <var>$1difftotext</var> and expected for output of content.",
"apihelp-query+search-description": "Perform a full text search.",
- "apihelp-query+search-param-search": "Search for all page titles (or content) that have this value.",
+ "apihelp-query+search-param-search": "Search for page titles or content matching this value. You can use the search string to invoke special search features, depending on what the wiki's search backend implements.",
"apihelp-query+search-param-namespace": "Search only within these namespaces.",
"apihelp-query+search-param-what": "Which type of search to perform.",
"apihelp-query+search-param-info": "Which metadata to return.",
- "apihelp-query+search-param-prop": "Which properties to return:\n;size:Adds the size of the page in bytes.\n;wordcount:Adds the word count of the page.\n;timestamp:Adds the timestamp of when the page was last edited.\n;snippet:Adds a parsed snippet of the page.\n;titlesnippet:Adds a parsed snippet of the page title.\n;redirectsnippet:Adds a parsed snippet of the redirect title.\n;redirecttitle:Adds the title of the matching redirect.\n;sectionsnippet:Adds a parsed snippet of the matching section title.\n;sectiontitle:Adds the title of the matching section.\n;score:<span class=\"apihelp-deprecated\">Deprecated and ignored.</span>\n;hasrelated:<span class=\"apihelp-deprecated\">Deprecated and ignored.</span>",
+ "apihelp-query+search-param-prop": "Which properties to return:",
+ "apihelp-query+search-paramvalue-prop-size": "Adds the size of the page in bytes.",
+ "apihelp-query+search-paramvalue-prop-wordcount": "Adds the word count of the page.",
+ "apihelp-query+search-paramvalue-prop-timestamp": "Adds the timestamp of when the page was last edited.",
+ "apihelp-query+search-paramvalue-prop-snippet": "Adds a parsed snippet of the page.",
+ "apihelp-query+search-paramvalue-prop-titlesnippet": "Adds a parsed snippet of the page title.",
+ "apihelp-query+search-paramvalue-prop-redirectsnippet": "Adds a parsed snippet of the redirect title.",
+ "apihelp-query+search-paramvalue-prop-redirecttitle": "Adds the title of the matching redirect.",
+ "apihelp-query+search-paramvalue-prop-sectionsnippet": "Adds a parsed snippet of the matching section title.",
+ "apihelp-query+search-paramvalue-prop-sectiontitle": "Adds the title of the matching section.",
+ "apihelp-query+search-paramvalue-prop-categorysnippet": "Adds a parsed snippet of the matching category.",
+ "apihelp-query+search-paramvalue-prop-isfilematch": "Adds a boolean indicating if the search matched file content.",
+ "apihelp-query+search-paramvalue-prop-score": "<span class=\"apihelp-deprecated\">Deprecated and ignored.</span>",
+ "apihelp-query+search-paramvalue-prop-hasrelated": "<span class=\"apihelp-deprecated\">Deprecated and ignored.</span>",
"apihelp-query+search-param-limit": "How many total pages to return.",
"apihelp-query+search-param-interwiki": "Include interwiki results in the search, if available.",
"apihelp-query+search-param-backend": "Which search backend to use, if not the default.",
+ "apihelp-query+search-param-enablerewrites": "Enable internal query rewriting. Some search backends can rewrite the query into one its thinks gives better results, such as correcting spelling errors.",
"apihelp-query+search-example-simple": "Search for <kbd>meaning</kbd>.",
"apihelp-query+search-example-text": "Search texts for <kbd>meaning</kbd>.",
- "apihelp-query+search-example-generator": "Ger page info about the pages returned for a search for <kbd>meaning</kbd>.",
+ "apihelp-query+search-example-generator": "Get page info about the pages returned for a search for <kbd>meaning</kbd>.",
"apihelp-query+siteinfo-description": "Return general information about the site.",
- "apihelp-query+siteinfo-param-prop": "Which information to get:\n;general:Overall system information.\n;namespaces:List of registered namespaces and their canonical names.\n;namespacealiases:List of registered namespace aliases.\n;specialpagealiases:List of special page aliases.\n;magicwords:List of magic words and their aliases.\n;statistics:Returns site statistics.\n;interwikimap:Returns interwiki map (optionally filtered, optionally localised by using <var>$1inlanguagecode</var>).\n;dbrepllag:Returns database server with the highest replication lag.\n;usergroups:Returns user groups and the associated permissions.\n;libraries:Returns libraries installed on the wiki.\n;extensions:Returns extensions installed on the wiki.\n;fileextensions:Returns list of file extensions allowed to be uploaded.\n;rightsinfo:Returns wiki rights (license) information if available.\n;restrictions:Returns information on available restriction (protection) types.\n;languages:Returns a list of languages MediaWiki supports (optionally localised by using <var>$1inlanguagecode</var>).\n;skins:Returns a list of all enabled skins (optionally localised by using <var>$1inlanguagecode</var>, otherwise in the content language).\n;extensiontags:Returns a list of parser extension tags.\n;functionhooks:Returns a list of parser function hooks.\n;showhooks:Returns a list of all subscribed hooks (contents of <var>[[mw:Manual:$wgHooks|$wgHooks]]</var>).\n;variables:Returns a list of variable IDs.\n;protocols:Returns a list of protocols that are allowed in external links.\n;defaultoptions:Returns the default values for user preferences.",
+ "apihelp-query+siteinfo-param-prop": "Which information to get:",
+ "apihelp-query+siteinfo-paramvalue-prop-general": "Overall system information.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespaces": "List of registered namespaces and their canonical names.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespacealiases": "List of registered namespace aliases.",
+ "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "List of special page aliases.",
+ "apihelp-query+siteinfo-paramvalue-prop-magicwords": "List of magic words and their aliases.",
+ "apihelp-query+siteinfo-paramvalue-prop-statistics": "Returns site statistics.",
+ "apihelp-query+siteinfo-paramvalue-prop-interwikimap": "Returns interwiki map (optionally filtered, optionally localised by using <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-dbrepllag": "Returns database server with the highest replication lag.",
+ "apihelp-query+siteinfo-paramvalue-prop-usergroups": "Returns user groups and the associated permissions.",
+ "apihelp-query+siteinfo-paramvalue-prop-libraries": "Returns libraries installed on the wiki.",
+ "apihelp-query+siteinfo-paramvalue-prop-extensions": "Returns extensions installed on the wiki.",
+ "apihelp-query+siteinfo-paramvalue-prop-fileextensions": "Returns list of file extensions allowed to be uploaded.",
+ "apihelp-query+siteinfo-paramvalue-prop-rightsinfo": "Returns wiki rights (license) information if available.",
+ "apihelp-query+siteinfo-paramvalue-prop-restrictions": "Returns information on available restriction (protection) types.",
+ "apihelp-query+siteinfo-paramvalue-prop-languages": "Returns a list of languages MediaWiki supports (optionally localised by using <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-skins": "Returns a list of all enabled skins (optionally localised by using <var>$1inlanguagecode</var>, otherwise in the content language).",
+ "apihelp-query+siteinfo-paramvalue-prop-extensiontags": "Returns a list of parser extension tags.",
+ "apihelp-query+siteinfo-paramvalue-prop-functionhooks": "Returns a list of parser function hooks.",
+ "apihelp-query+siteinfo-paramvalue-prop-showhooks": "Returns a list of all subscribed hooks (contents of <var>[[mw:Manual:$wgHooks|$wgHooks]]</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-variables": "Returns a list of variable IDs.",
+ "apihelp-query+siteinfo-paramvalue-prop-protocols": "Returns a list of protocols that are allowed in external links.",
+ "apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Returns the default values for user preferences.",
"apihelp-query+siteinfo-param-filteriw": "Return only local or only nonlocal entries of the interwiki map.",
"apihelp-query+siteinfo-param-showalldb": "List all database servers, not just the one lagging the most.",
"apihelp-query+siteinfo-param-numberingroup": "Lists the number of users in user groups.",
@@ -898,7 +1084,14 @@
"apihelp-query+tags-description": "List change tags.",
"apihelp-query+tags-param-limit": "The maximum number of tags to list.",
- "apihelp-query+tags-param-prop": "Which properties to get:\n;name:Adds name of tag.\n;displayname:Adds system message for the tag.\n;description:Adds description of the tag.\n;hitcount:Adds the number of revisions and log entries that have this tag.\n;defined:Indicate whether the tag is defined.\n;source:Gets the sources of the tag, which may include <samp>extension</samp> for extension-defined tags and <samp>manual</samp> for tags that may be applied manually by users.\n;active:Whether the tag is still being applied.",
+ "apihelp-query+tags-param-prop": "Which properties to get:",
+ "apihelp-query+tags-paramvalue-prop-name": "Adds name of tag.",
+ "apihelp-query+tags-paramvalue-prop-displayname": "Adds system message for the tag.",
+ "apihelp-query+tags-paramvalue-prop-description": "Adds description of the tag.",
+ "apihelp-query+tags-paramvalue-prop-hitcount": "Adds the number of revisions and log entries that have this tag.",
+ "apihelp-query+tags-paramvalue-prop-defined": "Indicate whether the tag is defined.",
+ "apihelp-query+tags-paramvalue-prop-source": "Gets the sources of the tag, which may include <samp>extension</samp> for extension-defined tags and <samp>manual</samp> for tags that may be applied manually by users.",
+ "apihelp-query+tags-paramvalue-prop-active": "Whether the tag is still being applied.",
"apihelp-query+tags-example-simple": "List available tags.",
"apihelp-query+templates-description": "Returns all pages transcluded on the given pages.",
@@ -916,7 +1109,10 @@
"apihelp-query+tokens-example-types": "Retrieve a watch token and a patrol token.",
"apihelp-query+transcludedin-description": "Find all pages that transclude the given pages.",
- "apihelp-query+transcludedin-param-prop": "Which properties to get:\n;pageid:Page ID of each page.\n;title:Title of each page.\n;redirect:Flag if the page is a redirect.",
+ "apihelp-query+transcludedin-param-prop": "Which properties to get:",
+ "apihelp-query+transcludedin-paramvalue-prop-pageid": "Page ID of each page.",
+ "apihelp-query+transcludedin-paramvalue-prop-title": "Title of each page.",
+ "apihelp-query+transcludedin-paramvalue-prop-redirect": "Flag if the page is a redirect.",
"apihelp-query+transcludedin-param-namespace": "Only include pages in these namespaces.",
"apihelp-query+transcludedin-param-limit": "How many to return.",
"apihelp-query+transcludedin-param-show": "Show only items that meet these criteria:\n;redirect:Only show redirects.\n;!redirect:Only show non-redirects.",
@@ -930,7 +1126,17 @@
"apihelp-query+usercontribs-param-user": "The users to retrieve contributions for.",
"apihelp-query+usercontribs-param-userprefix": "Retrieve contributions for all users whose names begin with this value. Overrides $1user.",
"apihelp-query+usercontribs-param-namespace": "Only list contributions in these namespaces.",
- "apihelp-query+usercontribs-param-prop": "Include additional pieces of information:\n;ids:Adds the page ID and revision ID.\n;title:Adds the title and namespace ID of the page.\n;timestamp:Adds the timestamp of the edit.\n;comment:Adds the comment of the edit.\n;parsedcomment:Adds the parsed comment of the edit.\n;size:Adds the new size of the edit.\n;sizediff:Adds the size delta of the edit against its parent.\n;flags:Adds flags of the edit.\n;patrolled:Tags patrolled edits.\n;tags:Lists tags for the edit.",
+ "apihelp-query+usercontribs-param-prop": "Include additional pieces of information:",
+ "apihelp-query+usercontribs-paramvalue-prop-ids": "Adds the page ID and revision ID.",
+ "apihelp-query+usercontribs-paramvalue-prop-title": "Adds the title and namespace ID of the page.",
+ "apihelp-query+usercontribs-paramvalue-prop-timestamp": "Adds the timestamp of the edit.",
+ "apihelp-query+usercontribs-paramvalue-prop-comment": "Adds the comment of the edit.",
+ "apihelp-query+usercontribs-paramvalue-prop-parsedcomment": "Adds the parsed comment of the edit.",
+ "apihelp-query+usercontribs-paramvalue-prop-size": "Adds the new size of the edit.",
+ "apihelp-query+usercontribs-paramvalue-prop-sizediff": "Adds the size delta of the edit against its parent.",
+ "apihelp-query+usercontribs-paramvalue-prop-flags": "Adds flags of the edit.",
+ "apihelp-query+usercontribs-paramvalue-prop-patrolled": "Tags patrolled edits.",
+ "apihelp-query+usercontribs-paramvalue-prop-tags": "Lists tags for the edit.",
"apihelp-query+usercontribs-param-show": "Show only items that meet these criteria, e.g. non minor edits only: <kbd>$2show=!minor</kbd>.\n\nIf <kbd>$2show=patrolled</kbd> or <kbd>$2show=!patrolled</kbd> is set, revisions older than <var>[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|second|seconds}}) won't be shown.",
"apihelp-query+usercontribs-param-tag": "Only list revisions tagged with this tag.",
"apihelp-query+usercontribs-param-toponly": "Only list changes which are the latest revision.",
@@ -938,12 +1144,35 @@
"apihelp-query+usercontribs-example-ipprefix": "Show contributions from all IP addresses with prefix <kbd>192.0.2.</kbd>.",
"apihelp-query+userinfo-description": "Get information about the current user.",
- "apihelp-query+userinfo-param-prop": "Which pieces of information to include:\n;blockinfo:Tags if the current user is blocked, by whom, and for what reason.\n;hasmsg:Adds a tag <samp>message</samp> if the current user has pending messages.\n;groups:Lists all the groups the current user belongs to.\n;implicitgroups:Lists all the groups the current user is automatically a member of.\n;rights:Lists all the rights the current user has.\n;changeablegroups:Lists the groups the current user can add to and remove from.\n;options:Lists all preferences the current user has set.\n;preferencestoken:<span class=\"apihelp-deprecated\">Deprecated.</span> Get a token to change current user's preferences.\n;editcount:Adds the current user's edit count.\n;ratelimits:Lists all rate limits applying to the current user.\n;realname:Adds the user's real name.\n;email:Adds the user's email address and email authentication date.\n;acceptlang:Echoes the <code>Accept-Language</code> header sent by the client in a structured format.\n;registrationdate:Adds the user's registration date.\n;unreadcount:Adds the count of unread pages on the user's watchlist (maximum $1; returns <samp>$2</samp> if more).",
+ "apihelp-query+userinfo-param-prop": "Which pieces of information to include:",
+ "apihelp-query+userinfo-paramvalue-prop-blockinfo": "Tags if the current user is blocked, by whom, and for what reason.",
+ "apihelp-query+userinfo-paramvalue-prop-hasmsg": "Adds a tag <samp>messages</samp> if the current user has pending messages.",
+ "apihelp-query+userinfo-paramvalue-prop-groups": "Lists all the groups the current user belongs to.",
+ "apihelp-query+userinfo-paramvalue-prop-implicitgroups": "Lists all the groups the current user is automatically a member of.",
+ "apihelp-query+userinfo-paramvalue-prop-rights": "Lists all the rights the current user has.",
+ "apihelp-query+userinfo-paramvalue-prop-changeablegroups": "Lists the groups the current user can add to and remove from.",
+ "apihelp-query+userinfo-paramvalue-prop-options": "Lists all preferences the current user has set.",
+ "apihelp-query+userinfo-paramvalue-prop-preferencestoken": "<span class=\"apihelp-deprecated\">Deprecated.</span> Get a token to change current user's preferences.",
+ "apihelp-query+userinfo-paramvalue-prop-editcount": "Adds the current user's edit count.",
+ "apihelp-query+userinfo-paramvalue-prop-ratelimits": "Lists all rate limits applying to the current user.",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "Adds the user's real name.",
+ "apihelp-query+userinfo-paramvalue-prop-email": "Adds the user's email address and email authentication date.",
+ "apihelp-query+userinfo-paramvalue-prop-acceptlang": "Echoes the <code>Accept-Language</code> header sent by the client in a structured format.",
+ "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Adds the user's registration date.",
+ "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Adds the count of unread pages on the user's watchlist (maximum $1; returns <samp>$2</samp> if more).",
"apihelp-query+userinfo-example-simple": "Get information about the current user.",
"apihelp-query+userinfo-example-data": "Get additional information about the current user.",
"apihelp-query+users-description": "Get information about a list of users.",
- "apihelp-query+users-param-prop": "Which pieces of information to include:\n;blockinfo:Tags if the user is blocked, by whom, and for what reason.\n;groups:Lists all the groups each user belongs to.\n;implicitgroups:Lists all the groups a user is automatically a member of.\n;rights:Lists all the rights each user has.\n;editcount:Adds the user's edit count.\n;registration:Adds the user's registration timestamp.\n;emailable:Tags if the user can and wants to receive email through [[Special:Emailuser]].\n;gender:Tags the gender of the user. Returns \"male\", \"female\", or \"unknown\".",
+ "apihelp-query+users-param-prop": "Which pieces of information to include:",
+ "apihelp-query+users-paramvalue-prop-blockinfo": "Tags if the user is blocked, by whom, and for what reason.",
+ "apihelp-query+users-paramvalue-prop-groups": "Lists all the groups each user belongs to.",
+ "apihelp-query+users-paramvalue-prop-implicitgroups": "Lists all the groups a user is automatically a member of.",
+ "apihelp-query+users-paramvalue-prop-rights": "Lists all the rights each user has.",
+ "apihelp-query+users-paramvalue-prop-editcount": "Adds the user's edit count.",
+ "apihelp-query+users-paramvalue-prop-registration": "Adds the user's registration timestamp.",
+ "apihelp-query+users-paramvalue-prop-emailable": "Tags if the user can and wants to receive email through [[Special:Emailuser]].",
+ "apihelp-query+users-paramvalue-prop-gender": "Tags the gender of the user. Returns \"male\", \"female\", or \"unknown\".",
"apihelp-query+users-param-users": "A list of users to obtain information for.",
"apihelp-query+users-param-token": "Use <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> instead.",
"apihelp-query+users-example-simple": "Return information for user <kbd>Example</kbd>.",
@@ -956,7 +1185,19 @@
"apihelp-query+watchlist-param-user": "Only list changes by this user.",
"apihelp-query+watchlist-param-excludeuser": "Don't list changes by this user.",
"apihelp-query+watchlist-param-limit": "How many total results to return per request.",
- "apihelp-query+watchlist-param-prop": "Which additional items to get:\n;ids:Adds revision IDs and page IDs.\n;title:Adds title of the page.\n;flags:Adds flags for the edit.\n;user:Adds the user who made the edit.\n;userid:Adds user ID of whom made the edit.\n;comment:Adds comment of the edit.\n;parsedcomment:Adds parsed comment of the edit.\n;timestamp:Adds timestamp of the edit.\n;patrol:Tags edits that are patrolled.\n;sizes:Adds the old and new lengths of the page.\n;notificationtimestamp:Adds timestamp of when the user was last notified about the edit.\n;loginfo:Adds log information where appropriate.",
+ "apihelp-query+watchlist-param-prop": "Which additional properties to get:",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "Adds revision IDs and page IDs.",
+ "apihelp-query+watchlist-paramvalue-prop-title": "Adds title of the page.",
+ "apihelp-query+watchlist-paramvalue-prop-flags": "Adds flags for the edit.",
+ "apihelp-query+watchlist-paramvalue-prop-user": "Adds the user who made the edit.",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "Adds user ID of whoever made the edit.",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "Adds comment of the edit.",
+ "apihelp-query+watchlist-paramvalue-prop-parsedcomment": "Adds parsed comment of the edit.",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "Adds timestamp of the edit.",
+ "apihelp-query+watchlist-paramvalue-prop-patrol": "Tags edits that are patrolled.",
+ "apihelp-query+watchlist-paramvalue-prop-sizes": "Adds the old and new lengths of the page.",
+ "apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "Adds timestamp of when the user was last notified about the edit.",
+ "apihelp-query+watchlist-paramvalue-prop-loginfo": "Adds log information where appropriate.",
"apihelp-query+watchlist-param-show": "Show only items that meet these criteria. For example, to see only minor edits done by logged-in users, set $1show=minor|!anon.",
"apihelp-query+watchlist-param-type": "Which types of changes to show:\n;edit:Regular page edits.\n;external:External changes.\n;new:Page creations.\n;log:Log entries.",
"apihelp-query+watchlist-param-owner": "Used along with $1token to access a different user's watchlist.",
@@ -971,10 +1212,13 @@
"apihelp-query+watchlistraw-description": "Get all pages on the current user's watchlist.",
"apihelp-query+watchlistraw-param-namespace": "Only list pages in the given namespaces.",
"apihelp-query+watchlistraw-param-limit": "How many total results to return per request.",
- "apihelp-query+watchlistraw-param-prop": "Which additional properties to get:\n;changed:Adds timestamp of when the user was last notified about the edit.",
+ "apihelp-query+watchlistraw-param-prop": "Which additional properties to get:",
+ "apihelp-query+watchlistraw-paramvalue-prop-changed": "Adds timestamp of when the user was last notified about the edit.",
"apihelp-query+watchlistraw-param-show": "Only list items that meet these criteria.",
"apihelp-query+watchlistraw-param-owner": "Used along with $1token to access a different user's watchlist.",
"apihelp-query+watchlistraw-param-token": "A security token (available in the user's [[Special:Preferences#mw-prefsection-watchlist|preferences]]) to allow access to another user's watchlist.",
+ "apihelp-query+watchlistraw-param-fromtitle": "Title (with namespace prefix) to begin enumerating from.",
+ "apihelp-query+watchlistraw-param-totitle": "Title (with namespace prefix) to stop enumerating at.",
"apihelp-query+watchlistraw-example-simple": "List pages on the current user's watchlist.",
"apihelp-query+watchlistraw-example-generator": "Fetch page info for pages on the current user's watchlist.",
@@ -1002,7 +1246,7 @@
"apihelp-rsd-description": "Export an RSD (Really Simple Discovery) schema.",
"apihelp-rsd-example-simple": "Export the RSD schema.",
- "apihelp-setnotificationtimestamp-description": "Update the notification timestamp for watched pages.\n\nThis affects the highlighting of changed pages in the watchlist and history, and the sending of email when the \"Email me when a page on my watchlist is changed\" preference is enabled.",
+ "apihelp-setnotificationtimestamp-description": "Update the notification timestamp for watched pages.\n\nThis affects the highlighting of changed pages in the watchlist and history, and the sending of email when the \"{{int:tog-enotifwatchlistpages}}\" preference is enabled.",
"apihelp-setnotificationtimestamp-param-entirewatchlist": "Work on all watched pages.",
"apihelp-setnotificationtimestamp-param-timestamp": "Timestamp to which to set the notification timestamp.",
"apihelp-setnotificationtimestamp-param-torevid": "Revision to set the notification timestamp to (one page only).",
@@ -1012,6 +1256,15 @@
"apihelp-setnotificationtimestamp-example-pagetimestamp": "Set the notification timestamp for <kbd>Main page</kbd> so all edits since 1 January 2012 are unviewed.",
"apihelp-setnotificationtimestamp-example-allpages": "Reset the notification status for pages in the <kbd>{{ns:user}}</kbd> namespace.",
+ "apihelp-stashedit-description": "Prepare an edit in shared cache.\n\nThis is intended to be used via AJAX from the edit form to improve the performance of the page save.",
+ "apihelp-stashedit-param-title": "Title of the page being edited.",
+ "apihelp-stashedit-param-section": "Section number. <kbd>0</kbd> for the top section, <kbd>new</kbd> for a new section.",
+ "apihelp-stashedit-param-sectiontitle": "The title for a new section.",
+ "apihelp-stashedit-param-text": "Page content.",
+ "apihelp-stashedit-param-contentmodel": "Content model of the new content.",
+ "apihelp-stashedit-param-contentformat": "Content serialization format used for the input text.",
+ "apihelp-stashedit-param-baserevid": "Revision ID of the base revision.",
+
"apihelp-tag-description": "Add or remove change tags from individual revisions or log entries.",
"apihelp-tag-param-rcid": "One or more recent changes IDs from which to add or remove the tag.",
"apihelp-tag-param-revid": "One or more revision IDs from which to add or remove the tag.",
@@ -1019,7 +1272,7 @@
"apihelp-tag-param-add": "Tags to add. Only manually defined tags can be added.",
"apihelp-tag-param-remove": "Tags to remove. Only tags that are either manually defined or completely undefined can be removed.",
"apihelp-tag-param-reason": "Reason for the change.",
- "apihelp-tag-example-rev": "Add the <kbd>vandalism</kbd> tag from revision ID 123 without specifying a reason",
+ "apihelp-tag-example-rev": "Add the <kbd>vandalism</kbd> tag to revision ID 123 without specifying a reason",
"apihelp-tag-example-log": "Remove the <kbd>spam</kbd> tag from log entry ID 123 with the reason <kbd>Wrongly applied</kbd>",
"apihelp-tokens-description": "Get tokens for data-modifying actions.\n\nThis module is deprecated in favor of [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
@@ -1043,7 +1296,7 @@
"apihelp-undelete-example-page": "Undelete page <kbd>Main Page</kbd>.",
"apihelp-undelete-example-revisions": "Undelete two revisions of page <kbd>Main Page</kbd>.",
- "apihelp-upload-description": "Upload a file, or get the status of pending uploads.\n\nSeveral methods are available:\n* Upload file contents directly, using the <var>$1file</var> parameter.\n* Upload the file in pieces, using the <var>$1filesize</var>, <var>$1chunk</var>, and <var>$1offset</var> parameters.* Have the MediaWiki server fetch a file from a URL, using the <var>$1url</var> parameter.\n* Complete an earlier upload that failed due to warnings, using the <var>$1filekey</var> parameter.\nNote that the HTTP POST must be done as a file upload (i.e. using <code>multipart/form-data</code>) when sending the <var>$1file</var>.",
+ "apihelp-upload-description": "Upload a file, or get the status of pending uploads.\n\nSeveral methods are available:\n* Upload file contents directly, using the <var>$1file</var> parameter.\n* Upload the file in pieces, using the <var>$1filesize</var>, <var>$1chunk</var>, and <var>$1offset</var> parameters.\n* Have the MediaWiki server fetch a file from a URL, using the <var>$1url</var> parameter.\n* Complete an earlier upload that failed due to warnings, using the <var>$1filekey</var> parameter.\nNote that the HTTP POST must be done as a file upload (i.e. using <code>multipart/form-data</code>) when sending the <var>$1file</var>.",
"apihelp-upload-param-filename": "Target filename.",
"apihelp-upload-param-comment": "Upload comment. Also used as the initial page text for new files if <var>$1text</var> is not specified.",
"apihelp-upload-param-text": "Initial page text for new files.",
@@ -1082,11 +1335,9 @@
"apihelp-watch-example-unwatch": "Unwatch the page <kbd>Main Page</kbd>.",
"apihelp-watch-example-generator": "Watch the first few pages in the main namespace.",
- "apihelp-format-example-generic": "Format the query result in the $1 format.",
+ "apihelp-format-example-generic": "Return the query result in the $1 format.",
"apihelp-dbg-description": "Output data in PHP's <code>var_export()</code> format.",
"apihelp-dbgfm-description": "Output data in PHP's <code>var_export()</code> format (pretty-print in HTML).",
- "apihelp-dump-description": "Output data in PHP's <code>var_dump()</code> format.",
- "apihelp-dumpfm-description": "Output data in PHP's <code>var_dump()</code> format (pretty-print in HTML).",
"apihelp-json-description": "Output data in JSON format.",
"apihelp-json-param-callback": "If specified, wraps the output into a given function call. For safety, all user-specific data will be restricted.",
"apihelp-json-param-utf8": "If specified, encodes most (but not all) non-ASCII characters as UTF-8 instead of replacing them with hexadecimal escape sequences. Default when <var>formatversion</var> is not <kbd>1</kbd>.",
@@ -1100,8 +1351,6 @@
"apihelp-rawfm-description": "Output data with the debugging elements in JSON format (pretty-print in HTML).",
"apihelp-txt-description": "Output data in PHP's <code>print_r()</code> format.",
"apihelp-txtfm-description": "Output data in PHP's <code>print_r()</code> format (pretty-print in HTML).",
- "apihelp-wddx-description": "Output data in WDDX format.",
- "apihelp-wddxfm-description": "Output data in WDDX format (pretty-print in HTML).",
"apihelp-xml-description": "Output data in XML format.",
"apihelp-xml-param-xslt": "If specified, adds the named page as an XSL stylesheet. The value must be a title in the {{ns:mediawiki}} namespace ending in <code>.xsl</code>.",
"apihelp-xml-param-includexmlnamespace": "If specified, adds an XML namespace.",
@@ -1111,6 +1360,7 @@
"api-format-title": "MediaWiki API result",
"api-format-prettyprint-header": "This is the HTML representation of the $1 format. HTML is good for debugging, but is unsuitable for application use.\n\nSpecify the <var>format</var> parameter to change the output format. To see the non-HTML representation of the $1 format, set <kbd>format=$2</kbd>.\n\nSee the [[mw:API|complete documentation]], or the [[Special:ApiHelp/main|API help]] for more information.",
+ "api-format-prettyprint-header-only-html": "This is an HTML representation intended for debugging, and is unsuitable for application use.\n\nSee the [[mw:API|complete documentation]], or the [[Special:ApiHelp/main|API help]] for more information.",
"api-orm-param-props": "Fields to query.",
"api-orm-param-limit": "Max amount of rows to return.",
@@ -1136,11 +1386,24 @@
"api-help-flag-writerights": "This module requires write rights.",
"api-help-flag-mustbeposted": "This module only accepts POST requests.",
"api-help-flag-generator": "This module can be used as a generator.",
+ "api-help-source": "Source: $1",
+ "api-help-source-unknown": "Source: <span class=\"apihelp-unknown\">unknown</span>",
+ "api-help-license": "License: [[$1|$2]]",
+ "api-help-license-noname": "License: [[$1|See link]]",
+ "api-help-license-unknown": "License: <span class=\"apihelp-unknown\">unknown</span>",
"api-help-help-urls": "",
"api-help-parameters": "{{PLURAL:$1|Parameter|Parameters}}:",
"api-help-param-deprecated": "Deprecated.",
"api-help-param-required": "This parameter is required.",
- "api-help-param-list": "{{PLURAL:$1|1=One value|2=Values (separate with <kbd>{{!}}</kbd>)}}: $2",
+ "api-help-datatypes-header": "Data types",
+ "api-help-datatypes": "Some parameter types in API requests need further explanation:\n;boolean\n:Boolean parameters work like HTML checkboxes: if the parameter is specified, regardless of value, it is considered true. For a false value, omit the parameter entirely.\n;timestamp\n:Timestamps may be specified in several formats. ISO 8601 date and time is recommended. All times are in UTC, any included timezone is ignored.\n:* ISO 8601 date and time, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (punctuation and <kbd>Z</kbd> are optional)\n:* ISO 8601 date and time with (ignored) fractional seconds, <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> (dashes, colons, and <kbd>Z</kbd> are optional)\n:* MediaWiki format, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Generic numeric format, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (optional timezone of <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd>, or <kbd>-<var>##</var></kbd> is ignored)\n:* EXIF format, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:*RFC 2822 format (timezone may be omitted), <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 format (timezone may be omitted), <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* C ctime format, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* Seconds since 1970-01-01T00:00:00Z as a 1 to 13 digit integer (excluding <kbd>0</kbd>)\n:* The string <kbd>now</kbd>",
+ "api-help-param-type-limit": "Type: integer or <kbd>max</kbd>",
+ "api-help-param-type-integer": "Type: {{PLURAL:$1|1=integer|2=list of integers}}",
+ "api-help-param-type-boolean": "Type: boolean ([[Special:ApiHelp/main#main/datatypes|details]])",
+ "api-help-param-type-password": "",
+ "api-help-param-type-timestamp": "Type: {{PLURAL:$1|1=timestamp|2=list of timestamps}} ([[Special:ApiHelp/main#main/datatypes|allowed formats]])",
+ "api-help-param-type-user": "Type: {{PLURAL:$1|1=user name|2=list of user names}}",
+ "api-help-param-list": "{{PLURAL:$1|1=One of the following values|2=Values (separate with <kbd>{{!}}</kbd>)}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Must be empty|Can be empty, or $2}}",
"api-help-param-limit": "No more than $1 allowed.",
"api-help-param-limit2": "No more than $1 ($2 for bots) allowed.",
@@ -1165,5 +1428,5 @@
"api-help-right-apihighlimits": "Use higher limits in API queries (slow queries: $1; fast queries: $2). The limits for slow queries also apply to multivalue parameters.",
"api-credits-header": "Credits",
- "api-credits": "API developers:\n* Roan Kattouw (lead developer Sep 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (creator, lead developer Sep 2006–Sep 2007)\n* Brad Jorsch (lead developer 2013–present)\n\nPlease send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org\nor file a bug report at https://phabricator.wikimedia.org/."
+ "api-credits": "API developers:\n* Yuri Astrakhan (creator, lead developer Sep 2006–Sep 2007)\n* Roan Kattouw (lead developer Sep 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Brad Jorsch (lead developer 2013–present)\n\nPlease send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org\nor file a bug report at https://phabricator.wikimedia.org/."
}
diff --git a/includes/api/i18n/es.json b/includes/api/i18n/es.json
index d0974772..06478f68 100644
--- a/includes/api/i18n/es.json
+++ b/includes/api/i18n/es.json
@@ -6,33 +6,82 @@
"Alan",
"Fitoschido",
"JasterTDC",
- "Edslov"
+ "Edslov",
+ "Carlos Cristia",
+ "Ryo567",
+ "Csbotero",
+ "Chris TR",
+ "Ncontinanza",
+ "Poco a poco"
]
},
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentación]]\n* [[mw:API:FAQ|Preguntas frecuentes]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lista de correos]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API de anuncios]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Errores y peticiones]\n</div>\n<strong>Estado:</strong> Todas las características que se muestran en esta página debería funcionar, pero la API aún está en desarrollo activo y puede cambiar en cualquier momento. Suscríbete a [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la lista de correo de mediawiki-api-announce] para estar al día de las actualizaciones.\n\n<strong>Solicitudes erróneas:</strong> Cuando se envían solicitudes erróneas a la API, se envía un encabezado HTTP con la clave \"MediaWiki-API-Error\" y ambos valores, del encabezado y el código de error, se establecerán en el mismo valor. Para más información, véase [[mw:API:Errors_and_warnings|API: Errores y advertencias]].",
"apihelp-main-param-action": "Qué acción se realizará.",
"apihelp-main-param-format": "El formato de la salida.",
+ "apihelp-main-param-smaxage": "Establece el encabezado <code>s-maxage</code> durante estos segundos. Los errores nunca se almacenan en caché.",
+ "apihelp-main-param-maxage": "Establece el encabezado <code>max-age</code> durante estos segundos. Los errores nunca se almacenan en caché.",
+ "apihelp-main-param-assert": "Comprobar que el usuario haya iniciado sesión si el valor es <kbd>user</kbd> o si tiene el permiso de bot si es <kbd>bot</kbd>.",
+ "apihelp-main-param-requestid": "Cualquier valor dado aquí se incluirá en la respuesta. Se puede utilizar para distinguir solicitudes.",
+ "apihelp-main-param-servedby": "Incluir el nombre del host que ha servido la solicitud en los resultados.",
"apihelp-main-param-curtimestamp": "Incluir la marca de tiempo actual en el resultado.",
- "apihelp-block-description": "Bloquear usuario",
+ "apihelp-block-description": "Bloquear a un usuario.",
"apihelp-block-param-user": "El nombre de usuario, dirección IP o intervalo de IP que quieres bloquear.",
+ "apihelp-block-param-expiry": "Fecha de expiración. Puede ser relativa (por ejemplo, <kbd>5 meses</kbd> o <kbd>2 semanas</kbd>) o absoluta (por ejemplo, <kbd>2014-09-18T12:34:56Z</kbd>). Si se establece en <kbd>infinito</kbd>, <kbd>indefinido</kbd>, o <kbd>nunca</kbd>, el bloqueo será permanente.",
"apihelp-block-param-reason": "Razón para el bloqueo.",
"apihelp-block-param-anononly": "Bloquear solo usuarios anónimos (es decir, desactivar ediciones anónimas de esta dirección IP).",
"apihelp-block-param-nocreate": "Prevenir la creación de cuentas.",
+ "apihelp-block-param-autoblock": "Bloquear automáticamente la última dirección IP y todas las direcciones IP que traten de iniciar sesión posteriormente.",
+ "apihelp-block-param-noemail": "Evitar que el usuario envíe correos a través de la wiki (es necesario el derecho <code>blockemail</code>).",
+ "apihelp-block-param-hidename": "Ocultar el nombre de usuario del registro de bloqueo (es necesario el derecho <coɗe>hideuser</code>).",
+ "apihelp-block-param-allowusertalk": "Permitir que el usuario edite su propia página de discusión (depende de <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
"apihelp-block-param-reblock": "Si la cuenta ya está bloqueada, sobrescribir el bloqueo existente.",
"apihelp-block-param-watchuser": "Vigilar las páginas de usuario y de discusión del usuario o de la dirección IP.",
+ "apihelp-block-example-ip-simple": "Bloquear la dirección IP <kbd>192.0.2.5</kbd> durante 3 días por el motivo: <kbd>Primer ataque</kbd>.",
+ "apihelp-block-example-user-complex": "Bloquear a usuario <kbd>vándalo</kbd> indefinidamente por el motivo <kbd>Vandalismo</kbd> y evitar que se cree nuevas cuentas o envíe correos.",
+ "apihelp-checktoken-description": "Comprueba la validez de una ficha desde <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
+ "apihelp-checktoken-param-type": "Tipo de ficha a probar.",
+ "apihelp-checktoken-param-token": "Ficha a probar.",
+ "apihelp-checktoken-param-maxtokenage": "Duración máxima de la ficha, en segundos.",
+ "apihelp-checktoken-example-simple": "Probar la validez de una ficha <kbd>csrf</kbd>.",
+ "apihelp-clearhasmsg-description": "Limpia la marca <code>hasmsg</code> del usuario actual.",
+ "apihelp-clearhasmsg-example-1": "Limpiar la marca <code>hasmsg</code> del usuario actual.",
+ "apihelp-compare-description": "Obtener la diferencia entre 2 páginas.\n\nSe debe pasar un número de revisión, un título de página o una ID tanto desde \"de\" hasta \"a\".",
"apihelp-compare-param-fromtitle": "Primer título para comparar",
+ "apihelp-compare-param-fromid": "ID de la primera página a comparar.",
+ "apihelp-compare-param-fromrev": "Primera revisión para comparar.",
+ "apihelp-compare-param-totitle": "Segundo título para comparar.",
+ "apihelp-compare-param-toid": "Segunda identificador de página para comparar.",
+ "apihelp-compare-param-torev": "Segunda revisión para comparar.",
+ "apihelp-compare-example-1": "Crear una diferencia entre las revisiones 1 y 2.",
"apihelp-createaccount-description": "Crear una nueva cuenta de usuario.",
"apihelp-createaccount-param-name": "Nombre de usuario.",
+ "apihelp-createaccount-param-password": "Contraseña (ignorada si está establecido <var>$1mailpassword</var>).",
+ "apihelp-createaccount-param-domain": "Dominio de autenticación externa (opcional).",
+ "apihelp-createaccount-param-token": "La clave de creación de cuenta se obtiene en la primera solicitud.",
"apihelp-createaccount-param-email": "Dirección de correo electrónico del usuario (opcional).",
"apihelp-createaccount-param-realname": "Nombre verdadero del usuario (opcional).",
+ "apihelp-createaccount-param-mailpassword": "Si está puesto cualquier valor se enviará una contraseña aleatoria al usuario.",
+ "apihelp-createaccount-param-reason": "Motivo opcional por el que crear una cuenta puesta en los registros.",
+ "apihelp-createaccount-param-language": "Código de idioma a establecer como predeterminado para el usuario (opcional, predeterminado al contenido del idioma).",
"apihelp-createaccount-example-pass": "Crear usuario <kbd>testuser</kbd> con la contraseña <kbd>test123</kbd>.",
+ "apihelp-createaccount-example-mail": "Crear usuario <kbd>testmailuser</kbd> y enviar una contraseña generada aleatoriamente.",
"apihelp-delete-description": "Borrar una página.",
+ "apihelp-delete-param-title": "Título de la página a eliminar. No se puede utilizar junto a <var>$1pageid</var>.",
+ "apihelp-delete-param-pageid": "ID de la página a eliminar. No se puede utilizar junto a <var>$1title</var>.",
+ "apihelp-delete-param-reason": "Motivo de la eliminación. Si no se especifica, se generará uno automáticamente.",
"apihelp-delete-param-watch": "Añadir esta página a la lista de seguimiento del usuario actual.",
"apihelp-delete-param-unwatch": "Quitar la página de la lista de seguimiento del usuario actual.",
"apihelp-delete-example-simple": "Borrar la <kbd>Página principal</kbd>",
+ "apihelp-delete-example-reason": "Eliminar <kbd>Página principal</kbd> por el motivo: <kbd>Preparando para moverla</kbd>.",
"apihelp-disabled-description": "Se desactivó este módulo.",
"apihelp-edit-description": "Crear y editar páginas.",
+ "apihelp-edit-param-title": "Título de la página a editar. No se puede utilizar junto a <var>$1pageid</var>.",
+ "apihelp-edit-param-pageid": "ID de la página a editar. No se puede utilizar junto a <var>$1title</var>.",
+ "apihelp-edit-param-section": "Número de la sección. <kbd>0</kbd> para una sección superior, <kbd>nuevo</kbd> para una nueva sección.",
"apihelp-edit-param-sectiontitle": "El título de una sección nueva.",
"apihelp-edit-param-text": "Contenido de la página.",
+ "apihelp-edit-param-summary": "Editar resumen. Además de la sección del título cuando $1section=new y $1sectiontitle no están establecidos.",
+ "apihelp-edit-param-tags": "Cambia las etiquetas para aplicarlas a la revisión.",
"apihelp-edit-param-minor": "Edición menor.",
"apihelp-edit-param-notminor": "Edición no menor.",
"apihelp-edit-param-bot": "Marcar esta edición como de bot.",
@@ -40,6 +89,14 @@
"apihelp-edit-param-nocreate": "Producir un error si la página no existe.",
"apihelp-edit-param-watch": "Añadir la página a la lista de seguimiento del usuario actual.",
"apihelp-edit-param-unwatch": "Quitar la página de la lista de seguimiento del usuario actual.",
+ "apihelp-edit-param-prependtext": "Añadir este texto al principio de la página. Reemplaza $1text.",
+ "apihelp-edit-param-appendtext": "Añadir este texto al principio de la página. Reemplaza $1text.\n\nUtiliza $1section=new para añadir una nueva sección, en lugar de este parámetro.",
+ "apihelp-edit-param-undo": "Deshacer esta revisión. Reemplaza $1text, $1prependtext y $1appendtext.",
+ "apihelp-edit-param-undoafter": "Deshacer todas las revisiones desde $1undo a esta. Si no está establecido solo se deshace una revisión.",
+ "apihelp-edit-param-redirect": "Resolver redirecciones automáticamente.",
+ "apihelp-edit-param-contentformat": "Formato de serialización de contenido utilizado para el texto de entrada.",
+ "apihelp-edit-param-contentmodel": "Modelo de contenido del nuevo contenido.",
+ "apihelp-edit-param-token": "La clave debe enviarse siempre como el último parámetro o, al menos, después del parámetro $1text.",
"apihelp-edit-example-edit": "Editar una página",
"apihelp-edit-example-prepend": "Anteponer <kbd>_&#95;NOTOC_&#95;</kbd> a una página.",
"apihelp-edit-example-undo": "Deshacer intervalo de revisiones 13579-13585 con resumen automático",
@@ -48,10 +105,22 @@
"apihelp-emailuser-param-subject": "Encabezamiento de asunto.",
"apihelp-emailuser-param-text": "Cuerpo del mensaje.",
"apihelp-emailuser-param-ccme": "Enviarme una copia de este mensaje.",
+ "apihelp-emailuser-example-email": "Enviar un correo al usuario <kbd>WikiSysop</kbd> con el texto <kbd>Contenido</kbd>.",
+ "apihelp-expandtemplates-description": "Expande todas las plantillas en wikitexto.",
"apihelp-expandtemplates-param-title": "Título de la página.",
"apihelp-expandtemplates-param-text": "Sintaxis wiki que se convertirá.",
+ "apihelp-expandtemplates-param-revid": "Revisión de ID, para <nowiki>{{REVISIONID}}</nowiki> y variables similares.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "El wikitexto expandido.",
+ "apihelp-expandtemplates-paramvalue-prop-properties": "Propiedades de página definidas por palabras mágicas en el wikitexto.",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "El tiempo máximo tras el cual deberían invalidarse los resultados en caché.",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "Da las variables de configuración JavaScript específicas para la página.",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "Da las variables de configuración JavaScript específicas para la página como una cadena JSON.",
+ "apihelp-expandtemplates-param-generatexml": "Generar un árbol de análisis XML (remplazado por $1prop=parsetree).",
+ "apihelp-expandtemplates-example-simple": "Expandir el wikitexto <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
"apihelp-feedcontributions-description": "Devuelve el canal de contribuciones de un usuario.",
"apihelp-feedcontributions-param-feedformat": "El formato del canal.",
+ "apihelp-feedcontributions-param-user": "De qué usuarios recibir contribuciones.",
+ "apihelp-feedcontributions-param-namespace": "Espacio de nombre para filtrar las contribuciones.",
"apihelp-feedcontributions-param-year": "A partir del año (y anteriores).",
"apihelp-feedcontributions-param-month": "A partir del mes (y anteriores).",
"apihelp-feedcontributions-param-tagfilter": "Filtrar las contribuciones que tienen estas etiquetas.",
@@ -62,15 +131,17 @@
"apihelp-feedcontributions-example-simple": "Devolver las contribuciones del usuario <kbd>Ejemplo</kbd>.",
"apihelp-feedrecentchanges-description": "Devuelve un canal de cambios recientes.",
"apihelp-feedrecentchanges-param-feedformat": "El formato del canal.",
+ "apihelp-feedrecentchanges-param-namespace": "Espacio de nombres al cual limitar los resultados.",
"apihelp-feedrecentchanges-param-invert": "Todos los espacios de nombres menos el que está seleccionado.",
"apihelp-feedrecentchanges-param-associated": "Incluir el espacio de nombres asociado (discusión o principal).",
+ "apihelp-feedrecentchanges-param-days": "Días a los que limitar los resultados.",
"apihelp-feedrecentchanges-param-limit": "Número máximo de resultados que devolver.",
"apihelp-feedrecentchanges-param-from": "Mostrar los cambios realizados a partir de entonces.",
"apihelp-feedrecentchanges-param-hideminor": "Ocultar cambios menores.",
"apihelp-feedrecentchanges-param-hidebots": "Ocultar los cambios realizados por bots.",
"apihelp-feedrecentchanges-param-hideanons": "Ocultar los cambios realizados por usuarios anónimos.",
"apihelp-feedrecentchanges-param-hideliu": "Ocultar los cambios realizados por usuarios registrados.",
- "apihelp-feedrecentchanges-param-hidepatrolled": "Ocultar los cambios patrullados.",
+ "apihelp-feedrecentchanges-param-hidepatrolled": "Ocultar los cambios verificados.",
"apihelp-feedrecentchanges-param-hidemyself": "Ocultar los cambios realizados por el usuario actual.",
"apihelp-feedrecentchanges-param-tagfilter": "Filtrar por etiquetas.",
"apihelp-feedrecentchanges-param-target": "Mostrar solo los cambios en las páginas enlazadas en esta.",
@@ -79,32 +150,59 @@
"apihelp-feedrecentchanges-example-30days": "Mostrar los cambios recientes limitados a 30 días",
"apihelp-feedwatchlist-description": "Devuelve el canal de una lista de seguimiento.",
"apihelp-feedwatchlist-param-feedformat": "El formato del canal.",
+ "apihelp-feedwatchlist-param-hours": "Listar las páginas modificadas desde estas horas hasta ahora.",
"apihelp-feedwatchlist-param-linktosections": "Enlazar directamente a las secciones cambiadas de ser posible.",
"apihelp-feedwatchlist-example-default": "Mostrar el canal de la lista de seguimiento.",
"apihelp-feedwatchlist-example-all6hrs": "Mostrar todos los cambios en páginas vigiladas en las últimas 6 horas.",
"apihelp-filerevert-description": "Revertir el archivo a una versión anterior.",
"apihelp-filerevert-param-filename": "Nombre de archivo final, sin el prefijo Archivo:",
"apihelp-filerevert-param-comment": "Comentario de carga.",
+ "apihelp-filerevert-param-archivename": "Nombre del archivo de la revisión para deshacerla.",
+ "apihelp-filerevert-example-revert": "Devolver <kbd>Wiki.png</kbd> a la versión del <kbd>5 de marzo de 2011T15:27:40Z</kbd>.",
"apihelp-help-description": "Mostrar la ayuda para los módulos especificados.",
+ "apihelp-help-param-modules": "Módulos para mostrar ayuda (valores de los parámetros <var>action</var> y <var>format</var> o <kbd>main</kbd>). Se puede especificar submódulos <kbd>+</kbd>.",
+ "apihelp-help-param-submodules": "Incluir ayuda para submódulos del módulo con nombre.",
+ "apihelp-help-param-recursivesubmodules": "Incluir ayuda para submódulos recursivamente.",
+ "apihelp-help-param-helpformat": "Formato de la ayuda de salida.",
+ "apihelp-help-param-toc": "Incluir una tabla de contenidos en la salida HTML.",
"apihelp-help-example-main": "Ayuda del módulo principal",
"apihelp-help-example-recursive": "Toda la ayuda en una página",
"apihelp-help-example-help": "Ayuda del módulo de ayuda en sí",
+ "apihelp-help-example-query": "Ayuda para dos submódulos de consulta.",
"apihelp-imagerotate-description": "Girar una o más imágenes.",
"apihelp-imagerotate-param-rotation": "Grados que rotar una imagen en sentido horario.",
"apihelp-imagerotate-example-simple": "Rotar <kbd>File:Ejemplo.png</kbd> <kbd>90</kbd> grados.",
"apihelp-imagerotate-example-generator": "Rotar todas las imágenes en la <kbd>Categoría:Girar</kbd> <kbd>180</kbd> grados.",
"apihelp-import-param-summary": "Resumen de importación.",
"apihelp-import-param-xml": "Se cargó el archivo XML.",
- "apihelp-import-param-rootpage": "Importar como subpágina de esta página.",
+ "apihelp-import-param-interwikisource": "Para importaciones interwiki: wiki desde la que importar.",
+ "apihelp-import-param-interwikipage": "Para importaciones interwiki: página a importar.",
+ "apihelp-import-param-fullhistory": "Para importaciones interwiki: importar todo el historial, no solo la versión actual.",
+ "apihelp-import-param-templates": "Para importaciones interwiki: importar también todas las plantillas incluidas.",
+ "apihelp-import-param-namespace": "Importar a este espacio de nombres. No puede usarse simultáneamente con <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Importar como subpágina de esta página. No puede usarse simultáneamente con <var>$1namespace</var>.",
+ "apihelp-import-example-import": "Importar [[meta:Help:ParserFunctions]] al espacio de nombres 100 con todo el historial.",
+ "apihelp-login-description": "Iniciar sesión y obtener cookies de autenticación.\n\nSi inicias sesión sin problemas, las cookies necesarias se incluirán en los encabezados de respuesta HTTP. Si se produce algún error al iniciar sesión y este persiste, se puede regular para evitar los ataques masivos automatizados para adivinar contraseñas.",
"apihelp-login-param-name": "Nombre de usuario.",
"apihelp-login-param-password": "Contraseña.",
"apihelp-login-param-domain": "Dominio (opcional).",
+ "apihelp-login-param-token": "La clave de inicio de sesión se obtiene en la primera solicitud.",
+ "apihelp-login-example-gettoken": "Recuperar clave de inicio de sesión.",
"apihelp-login-example-login": "Acceder",
"apihelp-logout-description": "Salir y vaciar los datos de la sesión.",
- "apihelp-logout-example-logout": "Cerrar la sesión del usuario actual",
+ "apihelp-logout-example-logout": "Cerrar la sesión del usuario actual.",
+ "apihelp-managetags-description": "Realizar tareas de administración relacionadas con el cambio de etiquetas.",
+ "apihelp-managetags-param-operation": "Qué operación realizar:\n;create: Crear una nueva etiqueta de cambio de uso manual.\n;delete: Eliminar una etiqueta de cambio de la base de datos, eliminando la etiqueta de todas las revisiones, cambios en entradas recientes y registros en los que se ha utilizado.\n;activate: Activar una etiqueta de cambio, permitiendo a los usuarios aplicarla manualmente.\n;deactivate: Desactivar una etiqueta de cambio, evitando que los usuarios la apliquen manualmente.",
+ "apihelp-managetags-param-tag": "Etiqueta para crear, eliminar, activar o desactivar. Para crear una etiqueta, esta debe no existir. Para eliminarla, debe existir. Para activarla, debe existir y no estar en uso por ninguna extensión. Para desactivarla, debe estar activada y definida manualmente.",
"apihelp-managetags-param-reason": "Un motivo opcional para crear, eliminar, activar o desactivar la etiqueta.",
+ "apihelp-managetags-example-create": "Crear una etiqueta llamada <kbd>spam</kbd> con el motivo <kbd>Para utilizar en patrullaje de edición</kbd>",
"apihelp-managetags-example-delete": "Eliminar la etiqueta <kbd>vandlaismo</kbd> con el motivo <kbd>mal deletreado</kbd>",
- "apihelp-move-description": "Mover una página.",
+ "apihelp-managetags-example-activate": "Activar una etiqueta llamada <kbd>spam</kbd> con el motivo <kbd>Para utilizar en patrullaje de edición</kbd>",
+ "apihelp-managetags-example-deactivate": "Desactivar una etiqueta llamada <kbd>spam</kbd> con el motivo <kbd>Para utilizar en patrullaje de edición</kbd>",
+ "apihelp-move-description": "Trasladar una página.",
+ "apihelp-move-param-from": "Título de la página a renombrar. No se puede utilizar con <var>$1fromid</var>.",
+ "apihelp-move-param-fromid": "ID de la página a renombrar. No se puede utilizar con <var>$1from</var>.",
+ "apihelp-move-param-to": "Título para cambiar el nombre de la página.",
"apihelp-move-param-reason": "Motivo del cambio de nombre.",
"apihelp-move-param-movetalk": "Renombrar la página de discusión si existe.",
"apihelp-move-param-movesubpages": "Renombrar las subpáginas si procede.",
@@ -112,18 +210,109 @@
"apihelp-move-param-watch": "Añadir la página y su redirección a la lista de seguimiento del usuario actual.",
"apihelp-move-param-unwatch": "Eliminar la página y la redirección de la lista de seguimiento del usuario.",
"apihelp-move-param-ignorewarnings": "Ignorar cualquier aviso.",
+ "apihelp-move-example-move": "Mover <kbd>Badtitle</kbd> a <kbd>Goodtitle</kbd> sin dejar una redirección.",
"apihelp-opensearch-description": "Buscar en el wiki mediante el protocolo OpenSearch.",
"apihelp-opensearch-param-search": "Buscar cadena.",
+ "apihelp-opensearch-param-limit": "Número máximo de resultados que devolver.",
+ "apihelp-opensearch-param-namespace": "Espacio de nombres que buscar.",
+ "apihelp-opensearch-param-suggest": "No hacer nada si <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> es falso.",
+ "apihelp-opensearch-param-redirects": "Cómo manejar las redirecciones:\n;return: Volver a la propia redirección.\n;resolve: Volver a la página de destino. Puede devolver menos de $1limit resultados.\nPor motivos históricos, se utiliza \"return\" para $1format=json y \"resolve\" para otros formatos.",
+ "apihelp-opensearch-param-format": "El formato de salida.",
+ "apihelp-opensearch-param-warningsaserror": "Si las advertencias están planteadas con <kbd>format=json</kbd>, devolver un error de API en lugar de hacer caso omiso de ellas.",
+ "apihelp-opensearch-example-te": "Buscar páginas que empiecen por <kbd>Te</kbd>.",
+ "apihelp-options-description": "Cambiar preferencias del usuario actual.\n\nSolo se pueden establecer opciones que estén registradas en el núcleo o en una de las extensiones instaladas u opciones con claves predefinidas con <code>userjs-</code> (diseñadas para utilizarse con scripts de usuario).",
+ "apihelp-options-param-reset": "Restablece las preferencias de la página web a sus valores predeterminados.",
+ "apihelp-options-param-resetkinds": "Lista de tipos de opciones a restablecer cuando la opción <var>$1reset</var> esté establecida.",
+ "apihelp-options-param-change": "Lista de cambios con el formato name=value (por ejemplo: skin=vector). El valor no puede contener caracteres de barras verticales. Si no se da ningún valor (ni siquiera un signo de igual), por ejemplo: optionname|otheroption|..., la opción se restablecerá a sus valores predeterminados.",
+ "apihelp-options-param-optionname": "El nombre de la opción que debe establecerse en el valor dado por <var>$1optionvalue</var>.",
+ "apihelp-options-param-optionvalue": "El valor de la opción especificada por <var>$1optionname</var>, puede contener barras verticales.",
"apihelp-options-example-reset": "Restablecer todas las preferencias",
+ "apihelp-options-example-change": "Cambiar las preferencias <kbd>skin</kbd> y <kbd>hideminor</kbd>.",
+ "apihelp-options-example-complex": "Restablecer todas las preferencias y establecer <kbd>skin</kbd> y <kbd>nickname</kbd>.",
"apihelp-paraminfo-description": "Obtener información acerca de los módulos de la API.",
+ "apihelp-paraminfo-param-modules": "Lista de los nombres de los módulos (valores de los parámetros <var>action</var> y <var>format</var> o <kbd>main</kbd>). Se pueden especificar los submódulos con un <kbd>+</kbd>.",
"apihelp-paraminfo-param-helpformat": "Formato de las cadenas de ayuda.",
- "apihelp-patrol-example-rcid": "Patrullar un cambio reciente",
- "apihelp-patrol-example-revid": "Patrullar una revisión",
+ "apihelp-paraminfo-param-querymodules": "Lista de los nombres de los módulos de consulta (valor de los parámetros <var>prop</var>, <var>meta</var> or <var>list</var>). Utiliza <kbd>$1modules=query+foo</kbd> en vez de <kbd>$1querymodules=foo</kbd>.",
+ "apihelp-paraminfo-param-formatmodules": "Lista de los nombres del formato de los módulos (valor del parámetro <var>format</var>). Utiliza <var>$1modules</var> en su lugar.",
+ "apihelp-paraminfo-example-1": "Mostrar información para <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>, <kbd>[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>, <kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd> y <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd>.",
+ "apihelp-parse-param-title": "Título de la página a la que pertenece el texto. Si se omite se debe especificar <var>$1contentmodel</var> y se debe utilizar el [[API]] como título.",
+ "apihelp-parse-param-text": "Texto a analizar. Utiliza <var>$1title</var> or <var>$1contentmodel</var> para controlar el modelo del contenido.",
+ "apihelp-parse-param-summary": "Resumen a analizar.",
+ "apihelp-parse-param-page": "Analizar el contenido de esta página. No se puede utilizar con <var>$1text</var> y <var>$1title</var>.",
+ "apihelp-parse-param-pageid": "Analizar el contenido de esta página. Remplaza <var>$1page</var>.",
+ "apihelp-parse-param-redirects": "Si <var>$1page</var> o <var>$1pageid</var> contienen una redirección, soluciónalo.",
+ "apihelp-parse-param-oldid": "Analizar el contenido de esta revisión. Remplaza <var>$1page</var> y <var>$1pageid</var>.",
+ "apihelp-parse-param-prop": "Qué piezas de información obtener:",
+ "apihelp-parse-paramvalue-prop-text": "Da el texto analizado en wikitexto.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Da el idioma de los enlaces en el wikitexto analizado.",
+ "apihelp-parse-paramvalue-prop-categories": "Da las categorías en el wikitexto analizado.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Da la versión HTML de las categorías.",
+ "apihelp-parse-paramvalue-prop-links": "Da los enlaces internos del wikitexto analizado.",
+ "apihelp-parse-paramvalue-prop-templates": "Da las plantillas del wikitexto analizado.",
+ "apihelp-parse-paramvalue-prop-images": "Da las imágenes del wikitexto analizado.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Da los enlaces externos del wikitexto analizado.",
+ "apihelp-parse-paramvalue-prop-sections": "Da las secciones del wikitexto analizado.",
+ "apihelp-parse-paramvalue-prop-revid": "Añade la ID de revisión de la página analizada.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Añade el título del wikitexto analizado.",
+ "apihelp-parse-paramvalue-prop-headitems": "Da elementos para colocar en el <code>&lt;encabezado&gt;</code> de la página.",
+ "apihelp-parse-paramvalue-prop-headhtml": "Da el <code>&lt;encabezado&gt;</code> analizado de la página.",
+ "apihelp-parse-paramvalue-prop-modules": "Da los módulos ResourceLoader utilizados en la página.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Da la configuración JavaScript de variables específica para la página.",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Da la configuración JavaScript de variables específica para la página como cadena JSON.",
+ "apihelp-parse-paramvalue-prop-indicators": "Da el HTML de los indicadores de estado utilizados en la página.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "Da los enlaces interwiki del texto analizado.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Da el wikitexto original que se había analizado.",
+ "apihelp-parse-paramvalue-prop-properties": "Da varias propiedades definidas en el wikitexto analizado.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "Da el informe del límite de forma estructurada. No da datos si <var>$1disablelimitreport</var> está establecido.",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "Da la versión HTML del informe del límite. No da datos si <var>$1disablelimitreport</var> está establecido.",
+ "apihelp-parse-param-effectivelanglinks": "Incluye enlaces de idiomas proporcionados por las extensiones (para utilizar con <kbd>$1prop=langlinks</kbd>).",
+ "apihelp-parse-param-disablepp": "Usa <var>$1disablelimitreport</var> en su lugar.",
+ "apihelp-parse-param-preview": "Analizar en modo de vista previa.",
+ "apihelp-parse-param-sectionpreview": "Analizar sección en modo de vista previa (activa el modo de vista previa).",
+ "apihelp-parse-param-disabletoc": "Omitir la tabla de contenidos en la salida.",
+ "apihelp-parse-example-page": "Analizar una página.",
+ "apihelp-parse-example-text": "Analizar wikitexto.",
+ "apihelp-parse-example-texttitle": "Analizar wikitexto, especificando el título de la página.",
+ "apihelp-parse-example-summary": "Analizar un resumen.",
+ "apihelp-patrol-description": "Verificar una página o revisión.",
+ "apihelp-patrol-param-rcid": "Identificador de cambios recientes que verificar.",
+ "apihelp-patrol-example-rcid": "Verificar un cambio reciente.",
+ "apihelp-patrol-example-revid": "Verificar una revisión.",
+ "apihelp-protect-description": "Cambiar el nivel de protección de una página.",
+ "apihelp-protect-param-title": "Título de la página a (des)proteger. No se puede utilizar con $1pageid.",
+ "apihelp-protect-param-pageid": "ID de la página a (des)proteger. No se puede utilizar con $1title.",
+ "apihelp-protect-param-protections": "Lista de los niveles de protección, con formato <kbd>action=level</kbd> (por ejemplo: <kbd>edit=sysop</kbd>).\n\n<strong>Nota:</strong> Cualquier acción no mencionada tendrá las restricciones eliminadas.",
"apihelp-protect-param-reason": "Motivo de la (des)protección.",
+ "apihelp-protect-param-cascade": "Activar la protección en cascada (o sea, proteger plantillas e imágenes transcluidas usadas en esta página). Se ignorará si ninguno de los niveles de protección dados son compatibles con la función de cascada.",
"apihelp-protect-example-protect": "Proteger una página",
+ "apihelp-protect-example-unprotect": "Desproteger una página estableciendo la restricción a <kbd>todos</kbd>.",
+ "apihelp-protect-example-unprotect2": "Desproteger una página anulando las restricciones.",
+ "apihelp-purge-param-forcelinkupdate": "Actualizar las tablas de enlaces.",
+ "apihelp-purge-param-forcerecursivelinkupdate": "Actualizar la tabla de enlaces y todas las tablas de enlaces de cualquier página que use esta página como una plantilla.",
+ "apihelp-purge-example-simple": "Depurar la <kbd>Página principal</kbd> y la página <kbd>API</kbd>.",
+ "apihelp-purge-example-generator": "Purgar las 10 primeras páginas del espacio de nombres principal.",
+ "apihelp-query-param-prop": "Qué propiedades obtener para las páginas consultadas.",
+ "apihelp-query-param-list": "Qué listas obtener.",
+ "apihelp-query-param-meta": "Qué metadatos obtener.",
+ "apihelp-query-param-indexpageids": "Incluir una sección de ID de páginas adicional en la que se muestran todas las ID de páginas.",
+ "apihelp-query-param-export": "Exportar las revisiones actuales de las páginas dadas o generadas.",
"apihelp-query+allcategories-description": "Enumerar todas las categorías.",
+ "apihelp-query+allcategories-param-from": "La categoría para comenzar la enumeración",
+ "apihelp-query+allcategories-param-to": "La categoría para detener la enumeración",
+ "apihelp-query+allcategories-param-prefix": "Buscar todos los títulos de las categorías que comiencen con este valor.",
+ "apihelp-query+allcategories-param-dir": "Dirección de ordenamiento.",
+ "apihelp-query+allcategories-param-min": "Devolver solo categorías con al menos este número de miembros.",
+ "apihelp-query+allcategories-param-max": "Devolver solo categorías con como mucho este número de miembros.",
+ "apihelp-query+allcategories-param-limit": "Cuántas categorías se devolverán.",
+ "apihelp-query+allcategories-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+allcategories-paramvalue-prop-size": "Añade el número de páginas en la categoría.",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "Etiqueta las categorías que están ocultas con <code>_&#95;HIDDENCAT_&#95;</code>.",
+ "apihelp-query+allcategories-example-size": "Lista las categorías con información sobre el número de páginas de cada una.",
+ "apihelp-query+alldeletedrevisions-description": "Listar todas las revisiones eliminadas por un usuario o en un espacio de nombres.",
"apihelp-query+alldeletedrevisions-paraminfo-useronly": "Solo puede usarse con <var>$3user</var>.",
- "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "No puede ser utilizado con <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "No puede utilizarse con <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-param-start": "El sello de tiempo para comenzar la enumeración",
+ "apihelp-query+alldeletedrevisions-param-end": "El sello de tiempo para detener la enumeración",
"apihelp-query+alldeletedrevisions-param-from": "Empezar a listar en este título.",
"apihelp-query+alldeletedrevisions-param-to": "Terminar de listar en este título.",
"apihelp-query+alldeletedrevisions-param-prefix": "Buscar todos los títulos de las páginas que comiencen con este valor.",
@@ -134,73 +323,424 @@
"apihelp-query+alldeletedrevisions-example-user": "Listar las últimas 50 contribuciones borradas del usuario <kbd>Ejemplo<kbd>.",
"apihelp-query+alldeletedrevisions-example-ns-main": "Listar las primeras 50 revisiones borradas en el espacio de nombres principal.",
"apihelp-query+allfileusages-description": "Listar todos los usos del archivo, incluyendo los que no existen.",
+ "apihelp-query+allfileusages-param-from": "El título del archivo para comenzar la enumeración.",
+ "apihelp-query+allfileusages-param-to": "El título del archivo para detener la enumeración.",
+ "apihelp-query+allfileusages-param-prefix": "Buscar todos los títulos de los archivos que comiencen con este valor.",
+ "apihelp-query+allfileusages-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "Agrega el título del archivo.",
+ "apihelp-query+allfileusages-param-limit": "Cuántos elementos en total se devolverán.",
+ "apihelp-query+allfileusages-param-dir": "La dirección en la que se listará.",
+ "apihelp-query+allfileusages-example-B": "Listar títulos de archivos, incluyendo los desaparecidos, con las ID de páginas a las que pertenecen, empezando por la <kbd>B</kbd>.",
+ "apihelp-query+allfileusages-example-unique": "Listar títulos de archivos únicos.",
+ "apihelp-query+allfileusages-example-unique-generator": "Recupera los títulos de todos los archivos y marca los faltantes.",
+ "apihelp-query+allfileusages-example-generator": "Recupera las páginas que contienen los archivos.",
+ "apihelp-query+allimages-description": "Enumerar todas las imágenes secuencialmente.",
+ "apihelp-query+allimages-param-from": "El título de la imagen para comenzar la enumeración. Solo puede utilizarse con $1sort=name.",
+ "apihelp-query+allimages-param-to": "El título de la imagen para detener la enumeración. Solo puede utilizarse con $1sort=name.",
+ "apihelp-query+allimages-param-start": "El sello de tiempo para comenzar la enumeración. Solo puede utilizarse con $1sort=timestamp.",
+ "apihelp-query+allimages-param-end": "El sello de tiempo para detener la enumeración. Solo puede utilizarse con $1sort=timestamp.",
+ "apihelp-query+allimages-param-prefix": "Buscar todos los títulos de imágenes que empiecen por este valor. Solo puede utilizarse con $1sort=name.",
+ "apihelp-query+allimages-param-minsize": "Limitar a imágenes con al menos este número de bytes.",
+ "apihelp-query+allimages-param-maxsize": "Limitar a imágenes con como mucho este número de bytes.",
"apihelp-query+allimages-param-sha1": "Suma SHA1 de la imagen. Invalida $1sha1base36.",
"apihelp-query+allimages-param-sha1base36": "Suma SHA1 de la imagen en base 36 (usada en MediaWiki).",
+ "apihelp-query+allimages-param-limit": "Cuántas imágenes en total se devolverán.",
+ "apihelp-query+allimages-example-B": "Mostrar una lista de archivos que empiecen por la letra <kbd>B</kbd>.",
+ "apihelp-query+allimages-example-recent": "Mostrar una lista de archivos subidos recientemente, similar a [[Special:NewFiles]].",
+ "apihelp-query+allimages-example-mimetypes": "Mostrar una lista de archivos tipo MIME <kbd>image/png</kbd> o <kbd>image/gif</kbd>",
+ "apihelp-query+allimages-example-generator": "Mostrar información acerca de 4 archivos que empiecen por la letra <kbd>T</kbd>.",
+ "apihelp-query+alllinks-description": "Enumerar todos los enlaces que apunten a un determinado espacio de nombres.",
+ "apihelp-query+alllinks-param-from": "El título del enlace para comenzar la enumeración.",
+ "apihelp-query+alllinks-param-to": "El título del enlace para detener la enumeración.",
+ "apihelp-query+alllinks-param-prefix": "Buscar todos los títulos vinculados que comiencen con este valor.",
+ "apihelp-query+alllinks-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+alllinks-paramvalue-prop-title": "Añade el título del enlace.",
+ "apihelp-query+alllinks-param-namespace": "El espacio de nombres que enumerar.",
+ "apihelp-query+alllinks-param-limit": "Cuántos elementos en total se devolverán.",
"apihelp-query+alllinks-example-unique-generator": "Obtiene todos los títulos enlazados, marcando los que falten.",
+ "apihelp-query+allmessages-param-prop": "Qué propiedades se obtendrán.",
+ "apihelp-query+allmessages-param-filter": "Devolver solo mensajes con nombres que contengan esta cadena.",
+ "apihelp-query+allmessages-param-customised": "Devolver solo mensajes en este estado de personalización.",
+ "apihelp-query+allmessages-param-lang": "Devolver mensajes en este idioma.",
+ "apihelp-query+allmessages-param-from": "Devolver mensajes que empiecen por este mensaje.",
+ "apihelp-query+allmessages-param-to": "Devolver mensajes que acaben por este mensaje.",
+ "apihelp-query+allmessages-param-prefix": "Devolver mensajes con este prefijo.",
+ "apihelp-query+allmessages-example-ipb": "Mostrar mensajes que empiecen por <kbd>ipb-</kbd>.",
+ "apihelp-query+allmessages-example-de": "Mostrar mensajes <kbd>august</kbd> y <kbd>mainpage</kbd> en alemán.",
+ "apihelp-query+allpages-description": "Enumerar todas las páginas secuencialmente en un espacio de nombres determinado.",
+ "apihelp-query+allpages-param-from": "El título de página para comenzar la enumeración",
+ "apihelp-query+allpages-param-to": "El título de página para detener la enumeración.",
+ "apihelp-query+allpages-param-prefix": "Buscar todos los títulos de las páginas que comiencen con este valor.",
+ "apihelp-query+allpages-param-namespace": "El espacio de nombres que enumerar.",
+ "apihelp-query+allpages-param-filterredir": "Qué páginas listar.",
+ "apihelp-query+allpages-param-minsize": "Limitar a páginas con al menos este número de bytes.",
+ "apihelp-query+allpages-param-maxsize": "Limitar a páginas con este número máximo de bytes.",
+ "apihelp-query+allpages-param-prtype": "Limitar a páginas protegidas.",
+ "apihelp-query+allpages-param-limit": "Cuántas páginas en total se devolverán.",
"apihelp-query+allpages-example-B": "Mostrar una lista de páginas que empiecen con la letra <kbd>B</kbd>.",
+ "apihelp-query+allpages-example-generator": "Mostrar información acerca de 4 páginas que empiecen por la letra <kbd>T</kbd>.",
+ "apihelp-query+allpages-example-generator-revisions": "Mostrar el contenido de las 2 primeras páginas que no redirijan y empiecen por <kbd>Re</kbd>.",
+ "apihelp-query+allredirects-param-prefix": "Buscar todas las páginas de destino que empiecen con este valor.",
+ "apihelp-query+allredirects-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+allredirects-paramvalue-prop-title": "Añade el título de la redirección.",
+ "apihelp-query+allredirects-param-limit": "Cuántos elementos se devolverán.",
+ "apihelp-query+alltransclusions-param-prefix": "Buscar todos los títulos transcluídos que comiencen con este valor.",
+ "apihelp-query+alltransclusions-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+alltransclusions-example-unique": "Listar títulos transcluidos de forma única.",
+ "apihelp-query+alltransclusions-example-unique-generator": "Obtiene todos los títulos transcluídos, marcando los que faltan.",
+ "apihelp-query+allusers-description": "Enumerar todos los usuarios registrados.",
+ "apihelp-query+allusers-param-prefix": "Buscar todos los usuarios que empiecen con este valor.",
+ "apihelp-query+allusers-param-group": "Incluir solo usuarios en los grupos dados.",
+ "apihelp-query+allusers-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+allusers-paramvalue-prop-blockinfo": "Añade información sobre un bloque actual al usuario.",
+ "apihelp-query+allusers-paramvalue-prop-groups": "Lista los grupos a los que el usuario pertenece. Esto utiliza más recursos del servidor y puede devolver menos resultados que el límite.",
+ "apihelp-query+allusers-paramvalue-prop-rights": "Lista los permisos que tiene el usuario.",
+ "apihelp-query+allusers-param-limit": "Cuántos nombres de usuario se devolverán.",
"apihelp-query+allusers-param-activeusers": "Solo listar usuarios activos en {{PLURAL:$1|el último día|los $1 últimos días}}.",
+ "apihelp-query+allusers-example-Y": "Listar usuarios que empiecen por <kbd>Y</kbd>.",
"apihelp-query+backlinks-param-pageid": "Identificador de página que buscar. No puede usarse junto con <var>$1title</var>",
+ "apihelp-query+backlinks-param-limit": "Cuántas páginas en total se devolverán. Si está activo <var>$1redirect</var>, el límite aplica a cada nivel por separado (lo que significa que se pueden devolver hasta 2 * <var>$1limit</var> resultados).",
"apihelp-query+backlinks-example-simple": "Mostrar enlaces a la <kbd>Portada<kbd>.",
+ "apihelp-query+blocks-description": "Listar todos los usuarios y direcciones IP bloqueadas.",
+ "apihelp-query+blocks-param-users": "Lista de usuarios a buscar (opcional).",
+ "apihelp-query+blocks-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+blocks-paramvalue-prop-userid": "Añade el identificador del usuario bloqueado.",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "Añade la fecha y hora de cuando se aplicó el bloque.",
"apihelp-query+blocks-example-simple": "Listar bloques.",
+ "apihelp-query+categories-param-prop": "Qué propiedades adicionales obtener para cada categoría:",
+ "apihelp-query+categories-param-show": "Qué tipo de categorías mostrar.",
+ "apihelp-query+categories-param-limit": "Cuántas categorías se devolverán.",
+ "apihelp-query+categories-example-generator": "Obtener información acerca de todas las categorías utilizadas en la página <kbd>Albert Einstein</kbd>.",
+ "apihelp-query+categoryinfo-description": "Devuelve información acerca de las categorías dadas.",
"apihelp-query+categoryinfo-example-simple": "Obtener información acerca de <kbd>Category:Foo</kbd> y <kbd>Category:Bar</kbd>",
+ "apihelp-query+categorymembers-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "Añade el identificador de página.",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "Agrega el título y el identificador del espacio de nombres de la página.",
+ "apihelp-query+categorymembers-param-startsortkey": "Utilizar $1starthexsortkey en su lugar.",
+ "apihelp-query+categorymembers-param-endsortkey": "Utilizar $1endhexsortkey en su lugar.",
+ "apihelp-query+categorymembers-example-simple": "Obtener las primeras 10 páginas de la <kbd>Categoría:Física</kbd>",
"apihelp-query+categorymembers-example-generator": "Obtener información sobre las primeras 10 páginas de la <kbd>Categoría:Física</kbd>",
+ "apihelp-query+contributors-param-limit": "Cuántas contribuyentes se devolverán.",
+ "apihelp-query+contributors-example-simple": "Mostrar los contribuyentes de la <kbd>página principal</kbd>.",
+ "apihelp-query+deletedrevisions-param-tag": "Listar solo las revisiones con esta etiqueta.",
+ "apihelp-query+deletedrevisions-param-user": "Listar solo las revisiones de este usuario.",
+ "apihelp-query+deletedrevisions-param-excludeuser": "No listar las revisiones de este usuario.",
"apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|Modo|Modos}}: $2",
+ "apihelp-query+deletedrevs-param-from": "Empezar a listar en este título.",
+ "apihelp-query+deletedrevs-param-to": "Terminar de listar en este título.",
+ "apihelp-query+deletedrevs-param-prefix": "Buscar todas las páginas que empiecen con este valor.",
+ "apihelp-query+deletedrevs-param-unique": "Listar solo una revisión por cada página.",
+ "apihelp-query+deletedrevs-param-tag": "Listar solo las revisiones con esta etiqueta.",
+ "apihelp-query+deletedrevs-param-user": "Listar solo las revisiones de este usuario.",
+ "apihelp-query+deletedrevs-param-excludeuser": "No listar las revisiones de este usuario.",
+ "apihelp-query+deletedrevs-param-namespace": "Listar solo las páginas en este espacio de nombres.",
+ "apihelp-query+deletedrevs-param-limit": "La cantidad máxima de revisiones que listar.",
"apihelp-query+deletedrevs-example-mode3-talk": "Listar las primeras 50 páginas en el espacio de nombres {{ns:talk}} (modo 3).",
+ "apihelp-query+disabled-description": "Se ha desactivado el módulo de consulta.",
"apihelp-query+duplicatefiles-example-simple": "Buscar duplicados de [[:File:Alber Einstein Head.jpg]].",
- "apihelp-query+duplicatefiles-example-generated": "Buscar duplicados en todos los ficheros.",
+ "apihelp-query+duplicatefiles-example-generated": "Buscar duplicados en todos los archivos.",
+ "apihelp-query+embeddedin-description": "Encuentra todas las páginas que transcluyen el título dado.",
+ "apihelp-query+embeddedin-param-title": "Título a buscar. No puede usarse en conjunto con $1pageid.",
+ "apihelp-query+embeddedin-param-filterredir": "Cómo filtrar las redirecciones.",
+ "apihelp-query+embeddedin-param-limit": "Cuántas páginas se devolverán.",
+ "apihelp-query+extlinks-param-limit": "Cuántos enlaces se devolverán.",
+ "apihelp-query+exturlusage-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+exturlusage-paramvalue-prop-ids": "Añade el identificado de la página.",
+ "apihelp-query+exturlusage-paramvalue-prop-title": "Agrega el título y el identificador del espacio de nombres de la página.",
+ "apihelp-query+exturlusage-param-protocol": "Protocolo del URL. Si está vacío y se establece <var>$1query</var>, el protocolo es <kbd>http</kbd>. Deja vacío esto y <var>$1query</var> para listar todos los enlaces externos.",
+ "apihelp-query+exturlusage-param-limit": "Cuántas páginas se devolverán.",
"apihelp-query+exturlusage-example-simple": "Mostrar páginas que enlacen con <kbd>http://www.mediawiki.org</kbd>.",
+ "apihelp-query+filearchive-param-from": "El título de imagen para comenzar la enumeración",
+ "apihelp-query+filearchive-param-to": "El título de imagen para detener la enumeración.",
+ "apihelp-query+filearchive-param-prefix": "Buscar todos los títulos de las imágenes que comiencen con este valor.",
+ "apihelp-query+filearchive-param-prop": "Qué información de imagen se obtendrá:",
+ "apihelp-query+filearchive-paramvalue-prop-size": "Agrega el tamaño de la imagen en bytes y la altura, la anchura y el número de páginas (si es aplicable).",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "Alias del tamaño.",
+ "apihelp-query+filearchive-paramvalue-prop-description": "Añade la descripción de la versión de la imagen.",
+ "apihelp-query+filearchive-paramvalue-prop-parseddescription": "Analizar la descripción de la versión.",
+ "apihelp-query+filearchive-paramvalue-prop-mime": "Añade el MIME de la imagen.",
+ "apihelp-query+filearchive-paramvalue-prop-mediatype": "Añade el tipo multimedia de la imagen.",
+ "apihelp-query+filearchive-paramvalue-prop-archivename": "Añade el nombre de archivo de la versión archivada para las versiones que no son las últimas.",
+ "apihelp-query+filearchive-example-simple": "Mostrar una lista de todos los archivos eliminados.",
"apihelp-query+filerepoinfo-example-simple": "Obtener información acerca de los repositorios de archivos.",
+ "apihelp-query+fileusage-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+fileusage-paramvalue-prop-pageid": "Identificador de cada página.",
+ "apihelp-query+fileusage-paramvalue-prop-title": "Título de cada página.",
+ "apihelp-query+fileusage-param-limit": "Cuántos se devolverán.",
+ "apihelp-query+fileusage-example-simple": "Obtener una lista de páginas que utilicen [[:File:Example.jpg]].",
+ "apihelp-query+fileusage-example-generator": "Obtener información acerca de las páginas que utilicen [[:File:Example.jpg]].",
+ "apihelp-query+imageinfo-description": "Devuelve información del archivo y su historial de subida.",
+ "apihelp-query+imageinfo-param-prop": "Qué información del archivo se obtendrá:",
+ "apihelp-query+imageinfo-paramvalue-prop-user": "Añade el usuario que subió cada versión del archivo.",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "Añade la ID de usuario que subió cada versión del archivo.",
+ "apihelp-query+imageinfo-param-limit": "Cuántos revisiones de archivos se devolverán por perfil.",
+ "apihelp-query+imageinfo-param-urlheight": "Similar a $1urlwidth.",
+ "apihelp-query+imageinfo-param-localonly": "Buscar solo archivos en el repositorio local.",
"apihelp-query+images-description": "Devuelve todos los archivos contenidos en las páginas dadas.",
+ "apihelp-query+images-param-limit": "Cuántos archivos se devolverán.",
"apihelp-query+images-example-simple": "Obtener una lista de los archivos usados en la [[Main Page|Portada]].",
+ "apihelp-query+imageusage-param-title": "Título a buscar. No puede usarse en conjunto con $1pageid.",
+ "apihelp-query+imageusage-param-pageid": "ID de página a buscar. No puede usarse con $1title.",
+ "apihelp-query+imageusage-param-namespace": "El espacio de nombres que enumerar.",
"apihelp-query+imageusage-example-simple": "Mostrar las páginas que usan [[:File:Albert Einstein Head.jpg]].",
"apihelp-query+imageusage-example-generator": "Obtener información sobre las páginas que empleen [[:File:Albert Einstein Head.jpg]].",
+ "apihelp-query+info-description": "Obtener información básica de la página.",
+ "apihelp-query+info-param-prop": "Qué propiedades adicionales se obtendrán:",
+ "apihelp-query+info-paramvalue-prop-protection": "Listar el nivel de protección de cada página.",
+ "apihelp-query+info-paramvalue-prop-subjectid": "La ID de página de la página principal de cada página de discusión.",
+ "apihelp-query+info-paramvalue-prop-readable": "Si el usuario puede leer esta página.",
+ "apihelp-query+info-paramvalue-prop-displaytitle": "Proporciona la manera en que se muestra realmente el título de la página",
+ "apihelp-query+info-param-token": "Usa [[Special:ApiHelp/query+tokens|action=query&meta=tokens]] en su lugar.",
+ "apihelp-query+info-example-simple": "Obtener información acerca de la página <kbd>Main Page</kbd>.",
"apihelp-query+info-example-protection": "Obtén información general y protección acerca de la página <kb>Página principal</kbd>.",
+ "apihelp-query+iwbacklinks-param-limit": "Cuántas páginas se devolverán.",
+ "apihelp-query+iwbacklinks-param-prop": "Qué propiedades se obtendrán:",
"apihelp-query+iwbacklinks-example-simple": "Obtener las páginas enlazadas a [[wikibooks:Test]]",
+ "apihelp-query+iwlinks-param-prop": "Qué propiedades adicionales obtener para cada enlace interlingüe:",
+ "apihelp-query+iwlinks-paramvalue-prop-url": "Añade el URL completo.",
+ "apihelp-query+langbacklinks-param-lang": "Idioma del enlace de idioma.",
+ "apihelp-query+langbacklinks-param-limit": "Cuántas páginas en total se devolverán.",
+ "apihelp-query+langbacklinks-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+langbacklinks-paramvalue-prop-lllang": "Agrega el código de idioma del enlace de idioma.",
+ "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Añade el título del enlace de idioma.",
"apihelp-query+langbacklinks-example-simple": "Obtener las páginas enlazadas a [[:fr:Test]]",
+ "apihelp-query+langbacklinks-example-generator": "Obtener información acerca de las páginas enlazadas a [[:fr:Test]].",
+ "apihelp-query+langlinks-param-prop": "Qué propiedades adicionales obtener para cada enlace interlingüe:",
+ "apihelp-query+langlinks-paramvalue-prop-url": "Añade el URL completo.",
+ "apihelp-query+langlinks-paramvalue-prop-autonym": "Añade el nombre del idioma nativo.",
+ "apihelp-query+langlinks-param-lang": "Devolver solo enlaces de idioma con este código de idioma.",
+ "apihelp-query+links-param-limit": "Cuántos enlaces se devolverán.",
+ "apihelp-query+linkshere-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+linkshere-paramvalue-prop-pageid": "Identificador de cada página.",
+ "apihelp-query+linkshere-paramvalue-prop-title": "Título de cada página.",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "Indicar si la página es una redirección.",
+ "apihelp-query+linkshere-param-limit": "Cuántos se devolverán.",
+ "apihelp-query+linkshere-example-simple": "Obtener una lista de páginas que enlacen a la [[Main Page]].",
"apihelp-query+linkshere-example-generator": "Obtener información acerca de las páginas enlazadas a la [[Main Page|Portada]].",
+ "apihelp-query+logevents-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+logevents-paramvalue-prop-ids": "Agrega el identificador del evento de registro.",
+ "apihelp-query+logevents-paramvalue-prop-type": "Añade el tipo del evento de registro.",
+ "apihelp-query+logevents-paramvalue-prop-parsedcomment": "Añade el comentario analizado del evento de registro.",
+ "apihelp-query+pageswithprop-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "Añade el identificador de página.",
+ "apihelp-query+pageswithprop-paramvalue-prop-title": "Agrega el título y el identificador del espacio de nombres de la página.",
+ "apihelp-query+pageswithprop-param-limit": "El máximo número de páginas que se devolverán.",
+ "apihelp-query+pageswithprop-example-simple": "Listar las 10 primeras páginas que utilicen <code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code>.",
+ "apihelp-query+pageswithprop-example-generator": "Obtener información adicional acerca de las 10 primeras páginas que utilicen <code>_&#95;NOTOC_&#95;</code>.",
+ "apihelp-query+prefixsearch-param-search": "Buscar cadena.",
+ "apihelp-query+prefixsearch-param-namespace": "Espacio de nombres que buscar.",
+ "apihelp-query+prefixsearch-param-limit": "Número máximo de resultados que devolver.",
+ "apihelp-query+prefixsearch-param-offset": "Número de resultados que omitir.",
+ "apihelp-query+prefixsearch-example-simple": "Buscar títulos de páginas que empiecen con <kbd>meaning</kbd>.",
+ "apihelp-query+protectedtitles-param-namespace": "Listar solo los títulos en estos espacios de nombres.",
+ "apihelp-query+protectedtitles-param-level": "Listar solo títulos con estos niveles de protección.",
+ "apihelp-query+protectedtitles-param-limit": "Cuántas páginas se devolverán.",
+ "apihelp-query+protectedtitles-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+protectedtitles-paramvalue-prop-user": "Agrega el usuario que agregó la protección.",
+ "apihelp-query+protectedtitles-paramvalue-prop-userid": "Agrega el identificador de usuario que agregó la protección.",
+ "apihelp-query+protectedtitles-paramvalue-prop-expiry": "Añade la fecha y hora de cuando se levantará la protección.",
+ "apihelp-query+protectedtitles-paramvalue-prop-level": "Agrega el nivel de protección.",
+ "apihelp-query+protectedtitles-example-simple": "Listar títulos protegidos.",
"apihelp-query+protectedtitles-example-generator": "Encuentra enlaces a títulos protegidos en el espacio de nombres principal.",
+ "apihelp-query+querypage-param-page": "El nombre de la página especial. Recuerda, es sensible a mayúsculas y minúsculas.",
+ "apihelp-query+querypage-param-limit": "Número de resultados que se devolverán.",
+ "apihelp-query+querypage-example-ancientpages": "Devolver resultados de [[Special:Ancientpages]].",
+ "apihelp-query+recentchanges-description": "Enumerar cambios recientes.",
+ "apihelp-query+recentchanges-param-start": "El sello de tiempo para comenzar la enumeración.",
+ "apihelp-query+recentchanges-param-end": "El sello de tiempo para finalizar la enumeración.",
+ "apihelp-query+recentchanges-param-user": "Listar solo los cambios de este usuario.",
+ "apihelp-query+recentchanges-param-excludeuser": "No listar cambios de este usuario.",
+ "apihelp-query+recentchanges-param-tag": "Listar solo los cambios con esta etiqueta.",
+ "apihelp-query+recentchanges-param-prop": "Incluir piezas adicionales de información:",
+ "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "Añade el comentario analizado para la edición.",
+ "apihelp-query+recentchanges-paramvalue-prop-flags": "Añade marcas para la edición.",
+ "apihelp-query+recentchanges-paramvalue-prop-patrolled": "Etiqueta ediciones verificables como verificadas o no verificadas.",
+ "apihelp-query+recentchanges-param-token": "Usa <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> en su lugar.",
+ "apihelp-query+recentchanges-param-limit": "Cuántos cambios en total se devolverán.",
+ "apihelp-query+recentchanges-param-type": "Cuántos tipos de cambios se mostrarán.",
"apihelp-query+recentchanges-example-simple": "Lista de cambios recientes.",
+ "apihelp-query+redirects-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+redirects-paramvalue-prop-pageid": "Identificador de página de cada redirección.",
+ "apihelp-query+redirects-paramvalue-prop-title": "Título de cada redirección.",
+ "apihelp-query+redirects-paramvalue-prop-fragment": "Fragmento de cada redirección, si los hubiere.",
+ "apihelp-query+redirects-param-limit": "Cuántas redirecciones se devolverán.",
"apihelp-query+redirects-example-simple": "Mostrar una lista de las redirecciones a la [[Main Page|Portada]]",
"apihelp-query+revisions-example-last5": "Mostrar las últimas 5 revisiones de la <kbd>Portada</kbd>.",
+ "apihelp-query+revisions+base-param-prop": "Las propiedades que se obtendrán para cada revisión:",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "El identificador de la revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-flags": "Marcas de revisión (menor).",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "La fecha y hora de la revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "Usuario que realizó la revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-userid": "Identificador de usuario del creador de la revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "Longitud (en bytes) de la revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "SHA-1 (base 16) de la revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "Identificador del modelo de contenido de la revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-comment": "Comentario del usuario para la revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-content": "Texto de la revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-tags": "Etiquetas para la revisión.",
"apihelp-query+search-param-info": "Qué metadatos devolver.",
+ "apihelp-query+search-param-prop": "Qué propiedades se devolverán:",
+ "apihelp-query+search-paramvalue-prop-redirecttitle": "Añade el título de la redirección coincidente.",
+ "apihelp-query+search-paramvalue-prop-score": "<span class=\"apihelp-deprecated\">Desaconsejado e ignorado.</span>",
+ "apihelp-query+search-paramvalue-prop-hasrelated": "<span class=\"apihelp-deprecated\">Desaconsejado e ignorado.</span>",
+ "apihelp-query+search-param-limit": "Cuántas páginas en total se devolverán.",
+ "apihelp-query+search-param-interwiki": "Incluir resultados interwiki en la búsqueda, si es posible.",
+ "apihelp-query+search-example-simple": "Buscar <kbd>significado</kbd>.",
"apihelp-query+search-example-text": "Buscar <kbd>meaning</kbd> en los textos.",
+ "apihelp-query+search-example-generator": "Obtener información acerca de las páginas devueltas por una búsqueda de <kbd>meaning</kbd>.",
+ "apihelp-query+siteinfo-description": "Devolver información general acerca de la página web.",
+ "apihelp-query+siteinfo-param-prop": "Qué información se obtendrá:",
+ "apihelp-query+siteinfo-paramvalue-prop-general": "Información global del sistema.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespaces": "Lista de espacios de nombres registrados y sus nombres canónicos.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespacealiases": "Lista de alias registrados de espacios de nombres",
+ "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "Lista de alias de páginas especiales.",
+ "apihelp-query+siteinfo-paramvalue-prop-magicwords": "Lista de palabras mágicas y sus alias.",
+ "apihelp-query+siteinfo-paramvalue-prop-statistics": "Devuelve las estadísticas del sitio.",
+ "apihelp-query+siteinfo-paramvalue-prop-interwikimap": "Devuelve el mapa interwiki (opcionalmente filtrado, opcionalmente localizado mediante el uso de <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-dbrepllag": "Devuelve el servidor de base de datos con el retraso de replicación más grande.",
+ "apihelp-query+siteinfo-paramvalue-prop-usergroups": "Devuelve los grupos de usuarios y los permisos asociados.",
+ "apihelp-query+siteinfo-paramvalue-prop-libraries": "Devuelve las bibliotecas instaladas en el wiki.",
+ "apihelp-query+siteinfo-paramvalue-prop-extensions": "Devuelve las extensiones instaladas en el wiki.",
+ "apihelp-query+siteinfo-paramvalue-prop-fileextensions": "Devuelve una lista de extensiones de archivo permitidas para cargadarse.",
+ "apihelp-query+siteinfo-paramvalue-prop-rightsinfo": "Devuelve información de permisos (licencia) del wiki, si está disponible.",
+ "apihelp-query+siteinfo-paramvalue-prop-restrictions": "Devuelve información sobre tipos de restricciones (protección) disponible.",
+ "apihelp-query+siteinfo-paramvalue-prop-languages": "Devuelve una lista de los idiomas que admite MediaWiki (opcionalmente localizada mediante el uso de <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-skins": "Devuelve una lista de todos las apariencias habilitadas (opcionalmente localizada mediante el uso de <var>$1inlanguagecode</var>, de lo contrario en el idioma del contenido).",
+ "apihelp-query+siteinfo-paramvalue-prop-variables": "Devuelve una lista de identificadores variables.",
+ "apihelp-query+siteinfo-paramvalue-prop-protocols": "Devuelve una lista de los protocolos que se permiten en los enlaces externos.",
+ "apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Devuelve los valores predeterminados de las preferencias del usuario.",
"apihelp-query+siteinfo-example-simple": "Obtener información del sitio.",
+ "apihelp-query+stashimageinfo-description": "Devuelve información del archivo para archivos escondidos.",
+ "apihelp-query+stashimageinfo-param-sessionkey": "Alias de $1filekey, para retrocompatibilidad.",
+ "apihelp-query+stashimageinfo-example-simple": "Devuelve información para un archivo escondido.",
+ "apihelp-query+stashimageinfo-example-params": "Devuelve las miniaturas de dos archivos escondidos.",
+ "apihelp-query+tags-param-limit": "El número máximo de etiquetas para enumerar.",
+ "apihelp-query+tags-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+tags-paramvalue-prop-displayname": "Agrega el mensaje de sistema para la etiqueta.",
+ "apihelp-query+tags-paramvalue-prop-source": "Obtiene las fuentes de la etiqueta, que pueden incluir <samp>extension</samp> para etiquetas definidas por extensiones y <samp>manual</samp> para etiquetas que pueden aplicarse manualmente por los usuarios.",
+ "apihelp-query+tags-paramvalue-prop-active": "Si la etiqueta aún se sigue aplicando.",
+ "apihelp-query+templates-description": "Devuelve todas las páginas transcluídas en las páginas dadas.",
+ "apihelp-query+templates-param-limit": "Cuántas plantillas se devolverán.",
+ "apihelp-query+transcludedin-description": "Encuentra todas las páginas que transcluyan las páginas dadas.",
+ "apihelp-query+transcludedin-param-prop": "Qué propiedades se obtendrán:",
+ "apihelp-query+transcludedin-paramvalue-prop-pageid": "Identificador de cada página.",
+ "apihelp-query+transcludedin-paramvalue-prop-title": "Título de cada página.",
+ "apihelp-query+transcludedin-param-namespace": "Incluir solo las páginas en estos espacios de nombres.",
+ "apihelp-query+transcludedin-param-limit": "Cuántos se devolverán.",
+ "apihelp-query+transcludedin-example-simple": "Obtener una lista de páginas transcluyendo <kbd>Main Page</kbd>.",
+ "apihelp-query+usercontribs-param-limit": "Número máximo de contribuciones que se devolverán.",
+ "apihelp-query+usercontribs-param-prop": "Incluir piezas adicionales de información:",
+ "apihelp-query+usercontribs-paramvalue-prop-ids": "Añade el identificador de página y el de revisión.",
+ "apihelp-query+usercontribs-paramvalue-prop-title": "Agrega el título y el identificador del espacio de nombres de la página.",
+ "apihelp-query+usercontribs-paramvalue-prop-timestamp": "Añade fecha y hora de la edición.",
+ "apihelp-query+usercontribs-paramvalue-prop-comment": "Añade el comentario de la edición.",
+ "apihelp-query+usercontribs-paramvalue-prop-patrolled": "Etiqueta ediciones verificadas.",
+ "apihelp-query+usercontribs-paramvalue-prop-tags": "Lista las etiquetas para la edición.",
+ "apihelp-query+usercontribs-param-show": "Mostrar solo los elementos que coinciden con estos criterios. Por ejemplo, solo ediciones no menores: <kbd>$2show=!minor</kbd>.\n\nSi se establece <kbd>$2show=patrolled</kbd> o <kbd>$2show=!patrolled</kbd>, las revisiones más antiguas que <var>[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|segundo|segundos}}) no se mostrarán.",
"apihelp-query+usercontribs-example-user": "Mostrar contribuciones del usuario <kbd>Ejemplo</kbd>.",
"apihelp-query+usercontribs-example-ipprefix": "Mostrar las contribuciones de todas las direcciones IP con el prefijo <kbd>192.0.2.</kbd>.",
"apihelp-query+userinfo-description": "Obtener información sobre el usuario actual.",
+ "apihelp-query+userinfo-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+userinfo-paramvalue-prop-groups": "Lista todos los grupos al que pertenece el usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-rights": "Lista todos los permisos que tiene el usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-options": "Lista todas las preferencias que haya establecido el usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-editcount": "Añade el número de ediciones del usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-ratelimits": "Lista todos los límites de velocidad aplicados al usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "Añade el nombre real del usuario.",
+ "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Añade la fecha de registro del usuario.",
+ "apihelp-query+userinfo-example-simple": "Obtener información sobre el usuario actual.",
+ "apihelp-query+userinfo-example-data": "Obtener información adicional sobre el usuario actual.",
+ "apihelp-query+users-description": "Obtener información sobre una lista de usuarios.",
+ "apihelp-query+users-param-prop": "Qué piezas de información incluir:",
+ "apihelp-query+users-paramvalue-prop-blockinfo": "Etiqueta si el usuario está bloqueado, por quién y por qué razón.",
+ "apihelp-query+users-paramvalue-prop-groups": "Lista todos los grupos a los que pertenece cada usuario.",
+ "apihelp-query+users-paramvalue-prop-editcount": "Añade el número de ediciones del usuario.",
+ "apihelp-query+users-paramvalue-prop-gender": "Etiqueta el género del usuario. Devuelve \"masculino\", \"femenino\" o \"desconocido\".",
+ "apihelp-query+users-example-simple": "Devolver información del usuario <kbd>Ejemplo</kbd>.",
+ "apihelp-query+watchlist-param-start": "El sello de tiempo para comenzar la enumeración",
+ "apihelp-query+watchlist-param-end": "El sello de tiempo para finalizar la enumeración.",
"apihelp-query+watchlist-param-excludeuser": "No listar cambios de este usuario.",
+ "apihelp-query+watchlist-param-prop": "Qué propiedades adicionales se obtendrán:",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "Añade identificadores de revisiones y de páginas.",
+ "apihelp-query+watchlist-paramvalue-prop-title": "Añade el título de la página.",
+ "apihelp-query+watchlist-paramvalue-prop-flags": "Añade marcas para la edición.",
+ "apihelp-query+watchlist-paramvalue-prop-user": "Añade el usuario que hizo la edición.",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "Añade el identificador de usuario de quien hizo la edición.",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "Añade el comentario de la edición.",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "Añade fecha y hora de la edición.",
+ "apihelp-query+watchlist-paramvalue-prop-patrol": "Etiqueta las ediciones que están verificadas.",
+ "apihelp-query+watchlist-paramvalue-prop-sizes": "Añade la longitud vieja y la nueva de la página.",
+ "apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "Añade fecha y hora de cuando el usuario fue notificado por última vez acerca de la edición.",
+ "apihelp-query+watchlist-paramvalue-prop-loginfo": "Añade información del registro cuando corresponda.",
+ "apihelp-query+watchlist-param-type": "Qué tipos de cambios mostrar:\n;edit:ediciones comunes a páginas.\n;external:cambios externos.\n;new:creaciones de páginas.\n;log:entradas del registro.",
+ "apihelp-query+watchlistraw-param-prop": "Qué propiedades adicionales se obtendrán:",
"apihelp-query+watchlistraw-param-show": "Sólo listar los elementos que cumplen estos criterios.",
+ "apihelp-query+watchlistraw-param-fromtitle": "Título (con el prefijo de espacio de nombres) desde el que se empezará a enumerar.",
+ "apihelp-query+watchlistraw-param-totitle": "Título (con el prefijo de espacio de nombres) desde el que se dejará de enumerar.",
"apihelp-query+watchlistraw-example-simple": "Listar las páginas de la lista de seguimiento del usuario actual.",
+ "apihelp-revisiondelete-description": "Eliminar y restaurar revisiones",
+ "apihelp-revisiondelete-param-hide": "Qué ocultar en cada revisión.",
+ "apihelp-revisiondelete-param-show": "Qué mostrar en cada revisión.",
+ "apihelp-revisiondelete-param-reason": "Motivo de la eliminación o restauración.",
+ "apihelp-rollback-param-summary": "Resumen de edición personalizado. Si se deja vacío se utilizará el predeterminado.",
+ "apihelp-tag-param-logid": "Uno o más identificadores de entradas del registro a los que agregar o eliminar la etiqueta.",
+ "apihelp-tag-param-reason": "Motivo del cambio.",
+ "apihelp-tag-example-rev": "Añadir la etiqueta <kbd>vandalism</kbd> al identificador de revisión 123 sin especificar un motivo",
+ "apihelp-tag-example-log": "Eliminar la etiqueta <kbd>spam</kbd> de la entrada del registro con identificador 123 con el motivo <kbd>aplicada incorrectamente</kbd>",
+ "apihelp-unblock-description": "Desbloquear un usuario.",
+ "apihelp-unblock-param-reason": "Motivo del desbloqueo.",
"apihelp-unblock-example-user": "Desbloquear al usuario <kbd>Bob</kbd> con el motivo <kbd>Lo siento, Bob</kbd>",
+ "apihelp-undelete-param-reason": "Motivo de la restauración.",
"apihelp-undelete-example-revisions": "Restaurar dos revisiones de la página <kbd>Portada</kbd>.",
"apihelp-upload-param-watch": "Vigilar la página.",
"apihelp-upload-param-ignorewarnings": "Ignorar las advertencias.",
"apihelp-upload-example-url": "Subir desde una URL.",
"apihelp-userrights-param-user": "Nombre de usuario.",
+ "apihelp-userrights-param-userid": "ID de usuario.",
"apihelp-userrights-param-add": "Agregar el usuario a estos grupos.",
"apihelp-userrights-param-remove": "Eliminar el usuario de estos grupos.",
"apihelp-userrights-param-reason": "Motivo del cambio.",
"apihelp-userrights-example-user": "Agregar al usuario <kbd>FooBot</kbd> al grupo <kbd>bot</kbd> y eliminarlo de los grupos <kbd>sysop</kbd> y <kbd>burócrata</kbd>.",
"apihelp-watch-example-watch": "Vigilar la página <kbd>Portada</kbd>.",
"apihelp-watch-example-unwatch": "Dejar de vigilar la <kbd>Portada</kbd>.",
+ "apihelp-format-example-generic": "Devolver el resultado de la consulta en formato $1.",
"api-help-main-header": "Módulo principal",
"api-help-flag-deprecated": "Este módulo está en desuso.",
"api-help-flag-readrights": "Este módulo requiere permisos de lectura.",
"api-help-flag-writerights": "Este módulo requiere permisos de escritura.",
"api-help-flag-mustbeposted": "Este módulo solo acepta solicitudes POST.",
"api-help-flag-generator": "Este módulo puede utilizarse como un generador.",
+ "api-help-source": "Fuente: $1",
+ "api-help-source-unknown": "Fuente: <span class=\"apihelp-unknown\">desconocida</span>",
+ "api-help-license": "Licencia: [[$1|$2]]",
+ "api-help-license-noname": "Licencia: [[$1|Ver enlace]]",
+ "api-help-license-unknown": "Licencia: <span class=\"apihelp-unknown\">desconocida</span>",
"api-help-parameters": "{{PLURAL:$1|Parámetro|Parámetros}}:",
"api-help-param-deprecated": "En desuso.",
"api-help-param-required": "Este parámetro es obligatorio.",
- "api-help-param-list": "{{PLURAL:$1|1=Un valor|2=Valores (separados por <kbd>{{!}}</kbd>)}}: $2",
+ "api-help-datatypes-header": "Tipos de datos",
+ "api-help-datatypes": "Algunos tipos de parámetros en las solicitudes de API necesita más explicación:\n;booleano\n:Los parámetros booleanos trabajo como casillas de verificación HTML: si el parámetro se especifica, independientemente de su valor, se considera verdadero. Para un valor false, se omite el parámetro completo.\n;marca de tiempo\n:Las marcas de tiempo se puede especificar en varios formatos. ISO 8601 con la fecha y la hora, se recomienda. Todas las horas están en UTC, la inclusión de la zona horaria es ignorada.\n:* ISO 8601 con fecha y hora, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (signos de puntuación y <kbd>Z</kbd> son opcionales)\n:* ISO 8601 fecha y hora (se omite) fracciones de segundo, <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> (guiones, dos puntos y, <kbd>Z</kbd> son opcionales)\n:* Formato MediaWiki, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Formato numérico genérico, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (opcional en la zona horaria <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd>, o <kbd>-<var>##</var></kbd> se omite)\n:* Formato EXIF, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:*Formato RFC 2822 (zona horaria se puede omitir), <kbd><var>Mon</var>, <var>15</var> <var>Ene</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Formato RFC 850 (zona horaria se puede omitir), <kbd><var>lunes</var>, <var>15</var>-<var>enero</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Formato C ctime, <kbd><var>lunes</var> <var>enero</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>de 2001</var></kbd>\n:* Segundos desde 1970-01-01T00:00:00Z como de 1 a 13, dígito entero",
+ "api-help-param-type-limit": "Tipo: entero o <kbd>max</kbd>",
+ "api-help-param-type-integer": "Tipo: {{PLURAL:$1|1=entero|2=lista de enteros}}",
+ "api-help-param-type-boolean": "Tipo: booleano/lógico ([[Special:ApiHelp/main#main/datatypes|detalles]])",
+ "api-help-param-type-timestamp": "Tipo: {{PLURAL:$1|1=timestamp|2=lista de timestamps}} ([[Special:ApiHelp/main#main/datatypes|formatos permitidos]])",
+ "api-help-param-type-user": "Tipo: {{PLURAL:$1|1=nombre de usuario|2=lista de nombres de usuarios}}",
+ "api-help-param-list": "{{PLURAL:$1|1=Uno de los siguientes valores|2=Valores (separados por <kbd>{{!}}</kbd>)}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Debe estar vacío|Puede estar vacío, o $2}}",
+ "api-help-param-limit": "No se permite más de $1.",
+ "api-help-param-limit2": "No se permite más de $1 ($2 para los bots).",
+ "api-help-param-integer-min": "{{PLURAL:$1|1=El valor no debe ser menor|2=Los valores no deben ser menores}} a $2.",
+ "api-help-param-integer-max": "{{PLURAL:$1|1=El valor no debe ser mayor|2=Los valores no deben ser mayores}} a $3.",
+ "api-help-param-integer-minmax": "{{PLURAL:$1|1=El valor debe|2=Los valores deben}} estar entre $2 y $3.",
"api-help-param-multi-separate": "Separar los valores con <kbd>|</kbd>.",
+ "api-help-param-multi-max": "El número máximo de los valores es {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} para los bots).",
"api-help-param-default": "Predeterminado: $1",
"api-help-param-default-empty": "Predeterminado: <span class=\"apihelp-empty\">(vacío)</span>",
+ "api-help-param-continue": "Cuando haya más resultados disponibles, utiliza esto para continuar.",
"api-help-param-no-description": "<span class=\"apihelp-empty\">(sin descripción)</span>",
"api-help-examples": "{{PLURAL:$1|Ejemplo|Ejemplos}}:",
"api-help-permissions": "{{PLURAL:$1|Permiso|Permisos}}:",
"api-help-permissions-granted-to": "{{PLURAL:$1|Concedido a|Concedidos a}}: $2",
"api-credits-header": "Créditos",
- "api-credits": "Desarrolladores de la API:\n* Roan Kattouw (desarrollador principal sep 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (creador, desarrollador principal sep 2006–sep 2007)\n* Brad Jorsch (desarrollador principal 2013–actualidad)\n\nEnvía comentarios, sugerencias y preguntas a mediawiki-api@lists.wikimedia.org\no reporta un error en https://phabricator.wikimedia.org/."
+ "api-credits": "Desarrolladores de la API:\n* Roan Kattouw (desarrollador principal, sep. 2007-2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (creador y desarrollador principal, sep. 2006-sep. 2007)\n* Brad Jorsch (desarrollador principal, 2013-actualidad)\n\nEnvía comentarios, sugerencias y preguntas a mediawiki-api@lists.wikimedia.org\no informa de un error en https://phabricator.wikimedia.org/."
}
diff --git a/includes/api/i18n/et.json b/includes/api/i18n/et.json
new file mode 100644
index 00000000..15ddb3af
--- /dev/null
+++ b/includes/api/i18n/et.json
@@ -0,0 +1,42 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pikne"
+ ]
+ },
+ "apihelp-query+imageinfo-description": "Tagastab failiteabe ja üleslaadimisajaloo.",
+ "apihelp-query+imageinfo-param-prop": "Millist teavet faili kohta hankida:",
+ "apihelp-query+imageinfo-paramvalue-prop-timestamp": "Lisab üles laaditud versiooni ajatempli.",
+ "apihelp-query+imageinfo-paramvalue-prop-user": "Lisab kasutaja, kes iga failiversiooni üles laadis.",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "Lisab iga failiversiooni üles laadinud kasutaja identifikaatori.",
+ "apihelp-query+imageinfo-paramvalue-prop-comment": "Versioonikommentaar.",
+ "apihelp-query+imageinfo-paramvalue-prop-parsedcomment": "Parsib versioonikommentaari.",
+ "apihelp-query+imageinfo-paramvalue-prop-canonicaltitle": "Lisab faili kanoonilise pealkirja.",
+ "apihelp-query+imageinfo-paramvalue-prop-url": "Tagastab faili ja kirjelduslehekülje internetiaadressi.",
+ "apihelp-query+imageinfo-paramvalue-prop-size": "Lisab faili suuruse baitides, kõrguse ja laiuse ning lehekülgede arvu, kui see on kohane.",
+ "apihelp-query+imageinfo-paramvalue-prop-dimensions": "Elemendi \"size\" rööpnimi.",
+ "apihelp-query+imageinfo-paramvalue-prop-sha1": "Lisab faili SHA-1 räsiväärtuse.",
+ "apihelp-query+imageinfo-paramvalue-prop-mime": "Lisab faili MIME tüübi.",
+ "apihelp-query+imageinfo-paramvalue-prop-thumbmime": "Lisab faili pisipildi MIME tüübi (vaja elementi \"url\" ja parameetrit \"$1urlwidth\").",
+ "apihelp-query+imageinfo-paramvalue-prop-mediatype": "Lisab faili meediatüübi.",
+ "apihelp-query+imageinfo-paramvalue-prop-metadata": "Loetleb failiversiooni Exif-metaandmed.",
+ "apihelp-query+imageinfo-paramvalue-prop-commonmetadata": "Loetleb failiversiooni vormingu üldised metaandmed.",
+ "apihelp-query+imageinfo-paramvalue-prop-extmetadata": "Loetleb mitme allika vormindatud ühendmetaandmed. Tulemused on HTML-vormingus.",
+ "apihelp-query+imageinfo-paramvalue-prop-archivename": "Lisab praegusest versioonist vanemate arhiiviversioonide failinimed.",
+ "apihelp-query+imageinfo-paramvalue-prop-bitdepth": "Lisab versiooni bitisügavuse.",
+ "apihelp-query+imageinfo-paramvalue-prop-uploadwarning": "Kasutab lehekülg Special:Upload, et saada teavet olemasoleva faili kohta. Pole mõeldud kasutamiseks väljaspool MediaWiki keskosa.",
+ "apihelp-query+imageinfo-param-limit": "Kui palju redaktsioone faili kohta tagastada.",
+ "apihelp-query+imageinfo-param-start": "Ajatempel, millest loetlemist alustada.",
+ "apihelp-query+imageinfo-param-end": "Ajatempel, mille juures loetlemine lõpetada.",
+ "apihelp-query+imageinfo-param-urlwidth": "Kui $2prop=url on määratud, tagastatakse selle laiusega mastaabitud pildi internetiaadress.\nKui seda valikut kasutatakse, siis ei tagastata jõudluskaalutlusel rohkem kui $1 mastaabitud pilti.",
+ "apihelp-query+imageinfo-param-urlheight": "Analoogne parameetriga \"$1urlwidth\".",
+ "apihelp-query+imageinfo-param-metadataversion": "Kasutatavate metaandmete versioon. Kui määratud on <kbd>latest</kbd>, kasutatakse viimast versiooni. Vaikeväärtus on tagasiühilduvuse huvides <kbd>1</kbd>.",
+ "apihelp-query+imageinfo-param-extmetadatalanguage": "Millises keeles metaandmed välja võtta. Sellest oleneb väljavõtte tõlge, juhul kui saadaval on mitu tõlget, ning samuti numbrite ja muude väärtuste vorming.",
+ "apihelp-query+imageinfo-param-extmetadatamultilang": "Kui atribuudi \"extmetadata\" tõlked on saadaval, siis kasuta neid kõiki.",
+ "apihelp-query+imageinfo-param-extmetadatafilter": "Kui määratud ja mittetühi, tagastatakse atribuudi $1prop=extmetadata jaoks ainult need võtmed.",
+ "apihelp-query+imageinfo-param-urlparam": "Töötlusele omane parameetriväärtus. Näiteks PDF-i jaoks võib see olla <kbd>page15-100px</kbd>. Kasutatud peab olema atribuuti <var>$1urlwidth</var> ja see peab olema kooskõlas parameetriga <var>$1urlparam</var>.",
+ "apihelp-query+imageinfo-param-localonly": "Kaasa päringusse ainult kohaliku hoidla failid.",
+ "apihelp-query+imageinfo-example-simple": "Faili [[:File:Albert Einstein Head.jpg|Albert Einstein Head.jpg]] praeguse versiooni teabe väljavõtt.",
+ "apihelp-query+imageinfo-example-dated": "Faili [[:File:Test.jpg|Test.jpg]] teabe väljavõtt alates 2008. aasta versioonidest.",
+ "api-help-param-continue": "Kui saadaval on rohkem tulemusi, kasuta seda jätkamiseks."
+}
diff --git a/includes/api/i18n/eu.json b/includes/api/i18n/eu.json
index 574bd2fe..b6a64dd9 100644
--- a/includes/api/i18n/eu.json
+++ b/includes/api/i18n/eu.json
@@ -1,17 +1,21 @@
{
"@metadata": {
"authors": [
- "Subi"
+ "Subi",
+ "Sator"
]
},
"apihelp-block-description": "Blokeatu erabiltzaile bat.",
+ "apihelp-block-param-reason": "Blokeatzeko arrazoia.",
"apihelp-createaccount-description": "Erabiltzaile kontu berria sortu.",
+ "apihelp-createaccount-param-name": "Erabiltzaile izena.",
"apihelp-createaccount-param-email": "Erabiltzailearen helbide elektronikoa (aukerakoa).",
"apihelp-createaccount-param-realname": "Erabiltzailearen benetako izena (aukerakoa).",
"apihelp-delete-description": "Orrialde bat ezabatu.",
"apihelp-edit-description": "Orrialdeak sortu eta aldatu.",
"apihelp-edit-param-minor": "Aldaketa txikia.",
"apihelp-edit-example-edit": "Orrialde bat aldatu",
+ "apihelp-emailuser-description": "Erabiltzaileari e-maila bidali",
"apihelp-expandtemplates-param-title": "Orrialdearen izenburua.",
"apihelp-feedcontributions-param-year": "Urtetik aurrera (eta lehenagotik)",
"apihelp-feedcontributions-param-month": "Hilabetetik aurrera (eta lehenagotik)",
@@ -24,16 +28,21 @@
"apihelp-feedrecentchanges-param-tagfilter": "Iragazi etiketen arabera.",
"apihelp-feedrecentchanges-example-simple": "Erakutsi aldaketa berriak",
"apihelp-feedrecentchanges-example-30days": "Erakutsi aldaketa berriak 30 egunez",
+ "apihelp-filerevert-param-comment": "Iruzkina igo.",
"apihelp-imagerotate-description": "Irudi bat edo gehiago biratu.",
+ "apihelp-login-param-name": "Erabiltzaile izena.",
"apihelp-login-param-password": "Pasahitza.",
"apihelp-login-param-domain": "Domeinua (hautazkoa).",
"apihelp-login-example-login": "Saioa hasi",
"apihelp-move-description": "Orrialde bat mugitu",
+ "apihelp-move-param-reason": "Berrizenpenaren arrazoia.",
+ "apihelp-options-example-reset": "Berrezarri hobespen guztiak.",
"apihelp-protect-example-protect": "Orrialde bat babestu",
"apihelp-query+allusers-param-witheditsonly": "Bakarrik zerrendatu aldaketak egin dituzten erabiltzaileak.",
"apihelp-query+allusers-param-activeusers": "Bakarrik zerrendatu azken {{PLURAL:$1|eguneko|$1 egunetako}} erabiltzaile aktiboak.",
"apihelp-query+imageinfo-param-urlheight": "$1urlwidth-en antzekoa.",
"apihelp-query+imageusage-example-simple": "Erakutsi [[:File:Albert Einstein Head.jpg]] darabilten orriak",
+ "apihelp-query+langlinks-param-inlanguagecode": "Hizkuntza izenak aurkitzeko hizkuntza kodea.",
"apihelp-query+prefixsearch-param-search": "Bilatu katea.",
"apihelp-query+protectedtitles-example-simple": "Zerrendatu babestutako izenburuak",
"apihelp-query+recentchanges-example-simple": "Zerrendatu aldaketa berriak.",
diff --git a/includes/api/i18n/fa.json b/includes/api/i18n/fa.json
index d792fd6e..291ebdbf 100644
--- a/includes/api/i18n/fa.json
+++ b/includes/api/i18n/fa.json
@@ -8,7 +8,8 @@
"KhabarNegar",
"Sahehco",
"Signal89",
- "Mjbmr"
+ "Mjbmr",
+ "Ebraminio"
]
},
"apihelp-main-param-action": "کدام عملیات را انجام دهد.",
@@ -17,7 +18,7 @@
"apihelp-block-description": "بستن کاربر",
"apihelp-block-param-user": "نام کاربری، آدرس آی پی یا محدوده آی پی موردنظر شما برای بستن.",
"apihelp-block-param-reason": "دلیل بسته‌شدن",
- "apihelp-block-param-anononly": "فقط بستن کاربران ناشناس (مانند غیرفعال‌کردن ویرایش‌های ناشناس این آی‌پی).",
+ "apihelp-block-param-anononly": "فقط بستن کاربران ناشناس (مانند غیرفعال کردن ویرایش‌های ناشناس این آی‌پی).",
"apihelp-block-param-nocreate": "جلوگیری از ایجاد حساب.",
"apihelp-block-param-autoblock": "به طور خودکار آخرین نشانی آی‌پی استفاده‌شده، و هر نشانی پس از آن که سعی می‌کند از آن داخل شود را ببند.",
"apihelp-block-param-noemail": "از کاربر در برابر ارسال ایمیل از طریق ویکی جلوگیری شود. (نیازمند دسترسی <code>blockemail</code> است).",
@@ -40,7 +41,7 @@
"apihelp-createaccount-param-name": "نام کاربری.",
"apihelp-createaccount-param-password": "رمز عبور (نادیده گرفته می‌شود اگر <var>$1mailpassword</var> تنظیم شده‌باشد).",
"apihelp-createaccount-param-domain": "دامنه برای احراز هویت خارجی (اختیاری).",
- "apihelp-createaccount-param-email": "آدرس ایمیل کاربر (اختیاری)",
+ "apihelp-createaccount-param-email": "نشانی ایمیل کاربر (اختیاری)",
"apihelp-createaccount-param-realname": "نام واقعی کاربر (اختیاری).",
"apihelp-createaccount-param-mailpassword": "اگر به هر مقداری تنظیم شود، یک رمز عبور تصادفی به کاربر ایمیل خواهد شد.",
"apihelp-createaccount-param-reason": "دلیل اختیاری برای ایجاد حساب کاربری جهت قرارگرفتن در سیاهه‌ها.",
diff --git a/includes/api/i18n/fi.json b/includes/api/i18n/fi.json
index b1a7e8c4..ac466375 100644
--- a/includes/api/i18n/fi.json
+++ b/includes/api/i18n/fi.json
@@ -2,9 +2,15 @@
"@metadata": {
"authors": [
"Nike",
- "MrTapsa"
+ "MrTapsa",
+ "Pitke",
+ "Stryn"
]
},
+ "apihelp-block-description": "Estä käyttäjä.",
+ "apihelp-block-param-reason": "Eston syy.",
+ "apihelp-emailuser-example-email": "Lähetä käyttäjälle <kbd>WikiSysop</kbd> sähköposti, jossa lukee <kbd>Content</kbd>.",
"apihelp-query+linkshere-param-show": "Näytä vain kohteet, jotka täyttävät nämä kriteerit:\n;redirect:Näytä vain uudelleenohjaukset.\n;!redirect:Näytä vain ei-uudelleenohjaukset",
+ "apihelp-tag-example-rev": "Lisää tunniste <kbd>vandalism</kbd> versioon 123 antamatta perustelua.",
"apihelp-upload-param-stash": "Mikäli valittu, palvelin säilöö tiedoston väliaikaisesti tallentamisen sijaan."
}
diff --git a/includes/api/i18n/fo.json b/includes/api/i18n/fo.json
new file mode 100644
index 00000000..55229048
--- /dev/null
+++ b/includes/api/i18n/fo.json
@@ -0,0 +1,39 @@
+{
+ "@metadata": {
+ "authors": [
+ "EileenSanda"
+ ]
+ },
+ "apihelp-block-description": "Sperra ein brúkara.",
+ "apihelp-block-param-user": "Brúkaranavn, IP adressa ella IP interval ið tú ynskir at sperra.",
+ "apihelp-block-param-expiry": "Lokadagur. Kann vera relativt (t.d. <kbd>5 months</kbd> ella <kbd>2 weeks</kbd>) ella absolutt (t.d. <kbd>2014-09-18T12:34:56Z</kbd>). Um ásett til <kbd>infinite</kbd>, <kbd>indefinite</kbd>, ella <kbd>never</kbd>, so gongur sperringin aldri út.",
+ "apihelp-block-param-reason": "Orsøk til sperring.",
+ "apihelp-block-param-anononly": "Sperra bara dulnevndir brúkarar (t.d. ger rættingar frá dulnendum óvirknar fyri hesa IP adressuna).",
+ "apihelp-block-param-nocreate": "Forða fyri upprættan av konto.",
+ "apihelp-block-param-autoblock": "Sperrað sjálvvirkandi tað seinastu IP adressuna og allar fylgjandi IP adressur, sum viðkomandi roynir at rætta/skriva frá.",
+ "apihelp-block-param-noemail": "Forða brúkaranum í at senda teldupost gjøgnum wikiina. (Krevur <code>blockemail</code> rættindini).",
+ "apihelp-block-param-hidename": "Fjal brúkaranavnið frá sperringarlogginum. (Krevur <code>hideuser</code> rættindi).",
+ "apihelp-block-param-allowusertalk": "Loyv brúkaranum at skriva á sína egnu síðu (avhongur av <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
+ "apihelp-block-param-reblock": "Um brúkarin longu er sperraður, yvirskriva so tað verandi sperringina.",
+ "apihelp-block-example-ip-simple": "Sperra IP adressuna <kbd>192.0.2.5</kbd> í tríggjar dagar við orsøkini <kbd>First strike</kbd>.",
+ "apihelp-block-example-user-complex": "Sperra brúkara <kbd>Vandal</kbd> í óvissa tíð við orsøkini <kbd>Vandalism</kbd>, og forða fyri upprættan av nýggjum kontum og at senda teldupost.",
+ "apihelp-createaccount-description": "Upprætta eina nýggja brúkarakonto.",
+ "apihelp-createaccount-param-name": "Brúkaranavn.",
+ "apihelp-createaccount-param-password": "Loyniorð (síggj burtur frá <var>$1mailpassword</var> um er upplýst).",
+ "apihelp-createaccount-param-email": "Teldupostadressan hjá brúkaranum (valfrítt).",
+ "apihelp-createaccount-param-realname": "Veruliga navnið hjá brúkaranum (valfrítt).",
+ "apihelp-createaccount-example-pass": "Upprætta brúkara <kbd>testuser</kbd> við loyniorðinum <kbd>test123</kbd>.",
+ "apihelp-createaccount-example-mail": "Upprætta brúkaran <kbd>testmailuser</kbd> og send eitt tilvildarliga stovnað loyniorð við telduposti.",
+ "apihelp-delete-description": "Strika eina síðu.",
+ "apihelp-edit-example-edit": "Rætta eina síðu.",
+ "apihelp-emailuser-description": "Send t-post til ein brúkara.",
+ "apihelp-emailuser-param-subject": "Evni teigur.",
+ "apihelp-emailuser-param-text": "Innihaldið í teldubrævinum.",
+ "apihelp-emailuser-param-ccme": "Send mær eitt avrit av hesum telduposti.",
+ "apihelp-emailuser-example-email": "Send ein teldupost til brúkaran <kbd>WikiSysop</kbd> við tekstinum <kbd>Content</kbd>.",
+ "apihelp-expandtemplates-description": "Víðkar allar fyrimyndir í wikitekstinum.",
+ "apihelp-expandtemplates-param-title": "Heiti á síðuni.",
+ "apihelp-login-param-name": "Brúkaranavn.",
+ "apihelp-login-param-password": "Loyniorð.",
+ "apihelp-move-description": "Flyt eina síðu."
+}
diff --git a/includes/api/i18n/fr.json b/includes/api/i18n/fr.json
index 114e36c2..7e3c65cb 100644
--- a/includes/api/i18n/fr.json
+++ b/includes/api/i18n/fr.json
@@ -11,15 +11,25 @@
"Nicolapps",
"Raulel",
"Arkanosis",
- "Ltrlg"
+ "Ltrlg",
+ "Crochet.david",
+ "0x010C",
+ "Lucky",
+ "Freak2fast4u",
+ "Urhixidur",
+ "Wladek92",
+ "Ash Crow",
+ "L",
+ "Umherirrender",
+ "Elfix"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentation]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Liste de diffusion]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annonces de l’API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bogues et demandes]\n</div>\n<strong>État :</strong> Toutes les fonctionnalités affichées sur cette page devraient fonctionner, mais l’API est encore en cours de développement et peut changer à tout moment. Inscrivez-vous à [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la liste de diffusion mediawiki-api-announce] pour être informé des mises à jour.\n\n<strong>Requêtes erronées :</strong> Si des requêtes erronées sont envoyées à l’API, un en-tête HTTP sera renvoyé avec la clé « MediaWiki-API-Error ». La valeur de cet en-tête et le code d’erreur renvoyé prendront la même valeur. Pour plus d’information, voyez [[mw:API:Errors_and_warnings|API: Errors and warnings]].",
"apihelp-main-param-action": "Quelle action effectuer.",
"apihelp-main-param-format": "Le format de sortie.",
"apihelp-main-param-maxlag": "La latence maximale peut être utilisée quand MédiaWiki est installé sur un cluster de base de données répliqué. Pour éviter des actions provoquant un supplément de latence de réplication de site, ce paramètre peut faire attendre le client jusqu’à ce que la latence de réplication soit inférieure à une valeur spécifiée. En cas de latence excessive, le code d’erreur <samp>maxlag</samp> est renvoyé avec un message tel que <samp>Attente de $host : $lag secondes de délai</samp>.<br />Voyez [[mw:Manual:Maxlag_parameter|Manuel: Maxlag parameter]] pour plus d’information.",
- "apihelp-main-param-smaxage": "Fixer l’entête <code>s-maxage</code> à ce nombre de secondes. Les erreurs ne sont jamais mises en cache.",
- "apihelp-main-param-maxage": "Fixer l’entête <code>max-age</code> à ce nombre de secondes. Les erreurs ne sont jamais mises en cache.",
+ "apihelp-main-param-smaxage": "Fixer l’entête HTTP de contrôle de cache <code>s-maxage</code> à ce nombre de secondes. Les erreurs ne sont jamais mises en cache.",
+ "apihelp-main-param-maxage": "Fixer l’entête HTTP de contrôle de cache <code>max-age</code> à ce nombre de secondes. Les erreurs ne sont jamais mises en cache.",
"apihelp-main-param-assert": "Vérifier si l’utilisateur est connecté si positionné à <kbd>user</kbd>, ou a le droit utilisateur robot si positionné à <kbd>bot</kbd>.",
"apihelp-main-param-requestid": "Toute valeur fournie ici sera incluse dans la réponse. Peut être utilisé pour distinguer des demandes.",
"apihelp-main-param-servedby": "Inclure le nom d’hôte qui a renvoyé la requête dans les résultats.",
@@ -85,6 +95,7 @@
"apihelp-edit-param-sectiontitle": "Le titre pour une nouvelle section.",
"apihelp-edit-param-text": "Contenu de la page.",
"apihelp-edit-param-summary": "Modifier le résumé. Également le titre de la section quand $1section=new et $1sectiontitle n’est pas défini.",
+ "apihelp-edit-param-tags": "Modifier les balises à appliquer à la révision.",
"apihelp-edit-param-minor": "Modification mineure.",
"apihelp-edit-param-notminor": "Modification non mineure.",
"apihelp-edit-param-bot": "Marquer cette modification comme robot.",
@@ -118,7 +129,16 @@
"apihelp-expandtemplates-param-title": "Titre de la page.",
"apihelp-expandtemplates-param-text": "Wikitexte à convertir.",
"apihelp-expandtemplates-param-revid": "ID de révision, pour <nowiki>{{REVISIONID}}</nowiki> et les variables semblables.",
- "apihelp-expandtemplates-param-prop": "Quelles informations récupérer :\n;wikitext:Le wikitexte développé.\n;categories:Toutes les catégories présentes dans l’entrée qui ne sont pas représentées dans le wikitexte de sortie.\n;properties:Propriétés de page définies en développant les mots magiques dans le wikitexte.\n;volatile:Si la sortie est volatile et ne devrait pas être réutilisée ailleurs dans la page.\n;ttl:Le délai maximal après lequel les caches du résultat devraient être invalidés.\n;parsetree:L’arbre d’analyse XML de l’entrée.\nNoter que si aucune valeur n’est sélectionnée, le résultat contiendra le wikitexte, mais la sortie sera dans un format obsolète.",
+ "apihelp-expandtemplates-param-prop": "Quelles informations récupérer.\n\nNoter que si aucune valeur n’est sélectionnée, le résultat contiendra le wikitexte, mais la sortie sera dans un format obsolète.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "Le wikitexte développé",
+ "apihelp-expandtemplates-paramvalue-prop-categories": "Toutes les catégories présentes dans l’entrée qui ne sont pas représentées dans la sortie du wikitexte.",
+ "apihelp-expandtemplates-paramvalue-prop-properties": "Propriétés de la page définies par le développement des mots magiques dans le wikitexte.",
+ "apihelp-expandtemplates-paramvalue-prop-volatile": "Si la sortie est volatile et ne devrait pas être réutilisée ailleurs dans la page.",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "Le délai maximum après lequel la mise en cache de ce résultat doit être invalidée.",
+ "apihelp-expandtemplates-paramvalue-prop-modules": "Tous les modules ResourceLoader que les fonctions d’analyse ont demandé d’ajouter à la sortie. Soit <kbd>jsconfigvars</kbd> soit <kbd>encodedjsconfigvars</kbd> doit être demandé avec <kbd>modules</kbd>.",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "Donne les variables de configuration JavaScript spécifiques à la page.",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "Donne les variables de configuration JavaScript spécifiques à la page sous forme de chaîne JSON.",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "L’arbre d’analyse XML de l’entrée.",
"apihelp-expandtemplates-param-includecomments": "S’il faut inclure les commentaires HTML dans la sortie.",
"apihelp-expandtemplates-param-generatexml": "Générer l’arbre d’analyse XML (remplacé par $1prop=parsetree).",
"apihelp-expandtemplates-example-simple": "Développe le wikitexte <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
@@ -179,16 +199,16 @@
"apihelp-imagerotate-param-rotation": "Degrés de rotation de l’image dans le sens des aiguilles d’une montre.",
"apihelp-imagerotate-example-simple": "Faire pivoter <kbd>File:Example.png</kbd> de <kbd>90</kbd> degrés.",
"apihelp-imagerotate-example-generator": "Faire pivoter toutes les images de <kbd>Category:Flip</kbd> de <kbd>180</kbd> degrés.",
- "apihelp-import-description": "Importer une page depuis un autre wiki, ou un fichier XML.\n\nNoter que le POST HTTP doit être effectué comme un import de fichier (c’est-à-dire en utilisant multipart/form-data) lors de l’envoi d’un fichier pour le paramètre <var>xml</var>.",
+ "apihelp-import-description": "Importer une page depuis un autre wiki, ou depuis un fichier XML.\n\nNoter que le POST HTTP doit être effectué comme un import de fichier (c’est-à-dire en utilisant multipart/form-data) lors de l’envoi d’un fichier pour le paramètre <var>xml</var>.",
"apihelp-import-param-summary": "Importer le résumé.",
"apihelp-import-param-xml": "Fichier XML téléchargé.",
"apihelp-import-param-interwikisource": "Pour les importations interwiki : wiki depuis lequel importer.",
"apihelp-import-param-interwikipage": "Pour les importations interwiki : page à importer.",
"apihelp-import-param-fullhistory": "Pour les importations interwiki : importer tout l’historique, et pas seulement la version courante.",
"apihelp-import-param-templates": "Pour les importations interwiki : importer aussi tous les modèles inclus.",
- "apihelp-import-param-namespace": "Pour les importations interwiki : importer vers cet espace de noms.",
- "apihelp-import-param-rootpage": "Importer comme une sous-page de cette page.",
- "apihelp-import-example-import": "Importer [[meta:Help:Parserfunctions]] vers l’espace de noms 100 avec tout l’historique.",
+ "apihelp-import-param-namespace": "Importer vers cet espace de noms. Impossible à utiliser avec <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Importer comme une sous-page de cette page. Impossible à utiliser avec <var>$1namespace</var>.",
+ "apihelp-import-example-import": "Importer [[meta:Help:ParserFunctions]] vers l’espace de noms 100 avec tout l’historique.",
"apihelp-login-description": "Se connecter et obtenir les cookies d’authentification.\n\nDans le cas d’une connexion réussie, les cookies nécessaires seront inclus dans les entêtes de la réponse HTTP. Dans le cas d’une connexion en échec, les essais ultérieurs pourront être réduits afin de limiter les attaques automatisées de découverte du mot de passe.",
"apihelp-login-param-name": "Nom d’utilisateur.",
"apihelp-login-param-password": "Mot de passe.",
@@ -204,7 +224,7 @@
"apihelp-managetags-param-reason": "Un motif facultatif pour créer, supprimer, activer ou désactiver la balise.",
"apihelp-managetags-param-ignorewarnings": "S’il faut ignorer tout avertissement qui se produirait au cours de l’opération.",
"apihelp-managetags-example-create": "Créer une balise nommée <kbd>pourriel</kbd> avec le motif <kbd>À utiliser lors de la revue des modifications</kbd>",
- "apihelp-managetags-example-delete": "Supprimer la balise <kbd>vandlaisme</kbd> avec le motif <kbd>Mal épelé</kbd>",
+ "apihelp-managetags-example-delete": "Supprimer la balise <kbd>vandlaism</kbd> avec le motif <kbd>Misspelt</kbd>",
"apihelp-managetags-example-activate": "Activer une balise nommée <kbd>pourriel</kbd> avec le motif <kbd>À utiliser dans la revue des modifications</kbd>",
"apihelp-managetags-example-deactivate": "Désactiver une balise nommée <kbd>pourriel</kbd> avec le motif <kbd>Plus nécessaire</kbd>",
"apihelp-move-description": "Déplacer une page.",
@@ -227,8 +247,9 @@
"apihelp-opensearch-param-suggest": "Ne rien faire si <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> vaut faux.",
"apihelp-opensearch-param-redirects": "Comment gérer les redirections :\n;return:Renvoie la redirection elle-même.\n;resolve:Renvoie la page cible. Peut renvoyer moins de $1limit résultats.\nPour des raisons historiques, la valeur par défaut est « return » pour $1format=json et « resolve » pour les autres formats.",
"apihelp-opensearch-param-format": "Le format de sortie.",
+ "apihelp-opensearch-param-warningsaserror": "Si des avertissements sont levés avec <kbd>format=json</kbd>, renvoyer une erreur d’API au lieu de les ignorer.",
"apihelp-opensearch-example-te": "Trouver les pages commençant par <kbd>Te</kbd>.",
- "apihelp-options-description": "Modifier les préférences de l’utilisateur courant.\n\nSeules les options enregistrées dans le cœur ou dans l’une des extensions installées, ou les options avec une clé préfixée par « userjs- » (devant être utilisées dans les scripts utilisateur), peuvent être définies.",
+ "apihelp-options-description": "Modifier les préférences de l’utilisateur courant.\n\nSeules les options enregistrées dans le cœur ou dans l’une des extensions installées, ou les options avec des clés préfixées par <code>userjs-</code> (devant être utilisées dans les scripts utilisateur), peuvent être définies.",
"apihelp-options-param-reset": "Réinitialise les préférences aux valeurs par défaut du site.",
"apihelp-options-param-resetkinds": "Liste des types d’option à réinitialiser quand l’option <var>$1reset</var> est définie.",
"apihelp-options-param-change": "Liste des modifications, au format nom=valeur (par ex. skin=vector). La valeur ne peut pas contenir de caractère barre verticale. Si aucune valeur n’est fournie (pas même un signe égal), par ex., nomoption|autreoption|…, l’option sera réinitialisée à sa valeur par défaut.",
@@ -253,18 +274,43 @@
"apihelp-parse-param-pageid": "Analyser le contenu de cette page. Écrase <var>$1page</var>.",
"apihelp-parse-param-redirects": "Si le paramètre <var>$1page</var> ou <var>$1pageid</var> est positionné sur une redirection, la résoudre.",
"apihelp-parse-param-oldid": "Analyser le contenu de cette révision. Écrase <var>$1page</var> et <var>$1pageid</var>.",
- "apihelp-parse-param-prop": "Quelles informations obtenir :\n;text:Fournit le texte analysé du wikitexte.\n;langlinks:Fournit les liens de langue dans le wikitexte analysé.\n;categories:Fournit les catégories dans le wikitexte analysé.\n;categorieshtml:Fournit la version HTML des catégories.\n;links:Fournit les liens internes dans le wikitexte analysé.\n;templates:Fournit les modèles dans le wikitexte analysé.\n;images:Fournit les images dans le wikitexte analysé.\n;externallinks:Fournit les liens externes dans le wikitexte analysé.\n;sections:Fournit les sections dans le wikitexte analysé.\n;revid:Ajoute l’ID de révision de la page analysée.\n;displaytitle:Ajoute le titre du wikitexte analysé.\n;headitems:Fournit les éléments à mettre dans le &lt;head&gt; de la page.\n;headhtml:Fournit le &lt;head&gt; analysé de la page.\n;modules:Fournit les modules ResourceLoader utilisés sur la page.\n;indicators:Fournit le HTML des indicateurs d’état de la page utilisés dans la page.\n;iwlinks:Fournit les liens interwiki dans le wikitexte analysé.\n;wikitext:Fournit le wikitexte d’origine qui a été analysé.\n;properties:Fournit différentes propriétés définies dans le wikitexte analysé.\n;limitreportdata:Fournit le rapport de limite de façon structurée. Ne fournit aucune donnée, quand $1disablepp est activé.\n;limitreporthtml:Fournit la version HTML du rapport de limite. Ne fournit aucune donnée, quand $1disablepp est activé.",
+ "apihelp-parse-param-prop": "Quelles informations obtenir :",
+ "apihelp-parse-paramvalue-prop-text": "Fournit le texte analysé du wikitexte.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Fournit les liens de langue du wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-categories": "Fournit les catégories dans le wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Fournit la version HTML des catégories.",
+ "apihelp-parse-paramvalue-prop-links": "Fournit les liens internes dans le wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-templates": "Fournit les modèles dans le wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-images": "Fournit les images dans le wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Fournit les liens externes dans le wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-sections": "Fournit les sections dans le wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-revid": "Ajoute l’ID de révision de la page analysée.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Ajoute le titre du wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-headitems": "Fournit les éléments à mettre dans le <code>&lt;head&gt;</code> de la page.",
+ "apihelp-parse-paramvalue-prop-headhtml": "Fournit le <code>&lt;head&gt;</code> analysé de la page.",
+ "apihelp-parse-paramvalue-prop-modules": "Fournit les modules ResourceLoader utilisés sur la page. Soit <kbd>jsconfigvars</kbd> soit <kbd>encodedjsconfigvars</kbd> doit être demandé avec <kbd>modules</kbd>.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Fournit les variables de configuration JavaScript spécifiques à la page.",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Fournit les variables de configuration JavaScript spécifiques à la page comme chaîne JSON.",
+ "apihelp-parse-paramvalue-prop-indicators": "Fournit le HTML des indicateurs d’état de page utilisés sur la page.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "Fournit les liens interwikis dans le wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Fournit le wikitexte d’origine qui a été analysé.",
+ "apihelp-parse-paramvalue-prop-properties": "Fournit les diverses propriétés définies dans le wikitexte analysé.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "Fournit le rapport de limite d’une manière structurée. Ne fournit aucune donnée, si <var>$1disablelimitreport</var> est positionné.",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "Fournit la version HTML du rapport de limite. Ne fournit aucune donnée, si <var>$1disablelimitreport</var> est positionné.",
+ "apihelp-parse-paramvalue-prop-parsetree": "L’arbre d’analyse XML du contenu de la révision (nécessite le modèle de contenu <code>$1</code>)",
"apihelp-parse-param-pst": "Faire une transformation avant enregistrement de l’entrée avant de l’analyser. Valide uniquement quand utilisé avec du texte.",
"apihelp-parse-param-onlypst": "Faire une transformation avant enregistrement (PST) de l’entrée, mais ne pas l’analyser. Renvoie le même wikitexte, après que la PST a été appliquée. Valide uniquement quand utilisé avec <var>$1text</var>.",
"apihelp-parse-param-effectivelanglinks": "Inclut les liens de langue fournis par les extensions (à utiliser avec <kbd>$1prop=langlinks</kbd>).",
"apihelp-parse-param-section": "Récupérer uniquement le contenu de ce numéro de section ou quand <kbd>nouveau</kbd> génère une nouvelle section.\n\nLa <kbd>nouvelle</kbd> section est mise à l’honneur uniquement quand <var>text</var> est spécifié.",
"apihelp-parse-param-sectiontitle": "Nouveau titre de section quand <var>section</var> vaut <kbd>nouveau</kbd>.\n\nÀ la différence de la modification de page, cela ne revient pas à <var>summary</var> quand il est omis ou vide.",
- "apihelp-parse-param-disablepp": "Désactiver le rapport PP de la sortie de l’analyseur.",
- "apihelp-parse-param-disableeditsection": "Désactiver les liens de modification de section de la sortie de l’analyseur.",
- "apihelp-parse-param-generatexml": "Générer un arbre d’analyse XML (nécessite le modèle de contenu <code>$1</code>).",
+ "apihelp-parse-param-disablelimitreport": "Omettre le rapport de limite (« rapport de limite du nouveau PP ») de la sortie de l’analyseur.",
+ "apihelp-parse-param-disablepp": "Utiliser <var>$1disablelimitreport</var> à la place.",
+ "apihelp-parse-param-disableeditsection": "Omettre les liens de modification de section de la sortie de l’analyseur.",
+ "apihelp-parse-param-disabletidy": "Ne pas exécuter de nettoyage du code HTML (par exemple, réagencer) sur la sortie de l'analyseur.",
+ "apihelp-parse-param-generatexml": "Générer un arbre d’analyse XML (nécessite le modèle de contenu <code>$1</code> ; remplacé par <kbd>$2prop=parsetree</kbd>).",
"apihelp-parse-param-preview": "Analyser en mode aperçu.",
"apihelp-parse-param-sectionpreview": "Analyser en mode aperçu de section (active aussi le mode aperçu).",
- "apihelp-parse-param-disabletoc": "Désactiver la table des matières dans la sortie.",
+ "apihelp-parse-param-disabletoc": "Omettre la table des matières dans la sortie.",
"apihelp-parse-param-contentformat": "Format de sérialisation du contenu utilisé pour le texte d’entrée. Valide uniquement si utilisé avec $1text.",
"apihelp-parse-param-contentmodel": "Modèle de contenu du texte d’entrée. Si omis, $1title doit être spécifié, et la valeur par défaut sera le modèle du titre spécifié. Valide uniquement quand utilisé avec $1text.",
"apihelp-parse-example-page": "Analyser une page.",
@@ -282,7 +328,7 @@
"apihelp-protect-param-protections": "Liste des niveaux de protection, au format <kbd>action=niveau</kbd> (par ex. <kbd>edit=sysop</kbd>).\n\n<strong>NOTE :<strong> Toutes les actions non listées auront leur restrictions supprimées.",
"apihelp-protect-param-expiry": "Horodatages d’expiration. Si un seul horodatage est fourni, il sera utilisé pour toutes les protections. Utiliser <kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd> ou <kbd>never</kbd> pour une protection sans expiration.",
"apihelp-protect-param-reason": "Motif de (dé)protection.",
- "apihelp-protect-param-cascade": "Activer la protection en cascade (c’est-à-dire protéger les pages incluses dans cette page). Ignoré si tous les niveaux de protection fournis ne supportent pas la mise en cascade.",
+ "apihelp-protect-param-cascade": "Activer la protection en cascade (c’est-à-dire protéger les modèles transclus et les images utilisées dans cette page). Ignoré si aucun des niveaux de protection fournis ne supporte la mise en cascade.",
"apihelp-protect-param-watch": "Si activé, ajouter la page (dé)protégée à la liste de suivi de l'utilisateur actuel.",
"apihelp-protect-param-watchlist": "Ajouter ou supprimer sans condition la page de la liste de suivi de l'utilisateur actuel, utiliser les préférences ou ne pas modifier le suivi.",
"apihelp-protect-example-protect": "Protéger une page",
@@ -301,8 +347,7 @@
"apihelp-query-param-export": "Exporter les révisions actuelles de toutes les pages fournies ou générées.",
"apihelp-query-param-exportnowrap": "Renvoyer le XML exporté sans l’inclure dans un résultat XML (même format que [[Special:Export]]). Utilisable uniquement avec $1export.",
"apihelp-query-param-iwurl": "S’il faut obtenir l’URL complète si le titre est un lien interwiki.",
- "apihelp-query-param-continue": "Quand il est présent, met en forme query-continue sous forme de paires clé-valeur qui devrait simplement être fusionné dans la requête d’origine. Ce paramètre doit être fixé à une chaîne vide dans la requête initiale.\n\nCe paramètre est recommandé pour tout nouveau développement, et sera mis par défaut dans la prochaine version de l’API.",
- "apihelp-query-param-rawcontinue": "Actuellement ignoré. Plus tard, <var>$1continue</var> deviendra la valeur par défaut et sera nécessaire pour recevoir les données brutes de <samp>query-continue</samp>.",
+ "apihelp-query-param-rawcontinue": "Renvoyer les données <samp>query-continue</samp> brutes pour continuer.",
"apihelp-query-example-revisions": "Récupérer [[Special:ApiHelp/query+siteinfo|l’info du site]] et [[Special:ApiHelp/query+revisions|les révisions]] de <kbd>Page principale</kbd>.",
"apihelp-query-example-allpages": "Récupérer les révisions des pages commençant par <kbd>API/</kbd>.",
"apihelp-query+allcategories-description": "Énumérer toutes les catégories.",
@@ -313,7 +358,9 @@
"apihelp-query+allcategories-param-min": "Renvoyer uniquement les catégories avec au moins ce nombre de membres.",
"apihelp-query+allcategories-param-max": "Renvoyer uniquement les catégories avec au plus ce nombre de membres.",
"apihelp-query+allcategories-param-limit": "Combien de catégories renvoyer.",
- "apihelp-query+allcategories-param-prop": "Quelles propriétés récupérer :\n;size:Ajoute le nombre de pages dans la catégorie.\n;hidden:Marque les catégories qui sont cachées avec _&#95;HIDDENCAT_&#95;.",
+ "apihelp-query+allcategories-param-prop": "Quelles propriétés récupérer :",
+ "apihelp-query+allcategories-paramvalue-prop-size": "Ajoute le nombre de pages dans la catégorie.",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "Marque les catégories qui sont masquées avec <code>_&#95;HIDDENCAT_&#95;</code>.",
"apihelp-query+allcategories-example-size": "Lister les catégories avec l’information sur le nombre de pages dans chacune",
"apihelp-query+allcategories-example-generator": "Récupérer l’information sur la page de catégorie elle-même pour les catégories commençant par <kbd>List</kbd>.",
"apihelp-query+alldeletedrevisions-description": "Lister toutes les révisions supprimées par un utilisateur ou dans un espace de noms.",
@@ -337,7 +384,9 @@
"apihelp-query+allfileusages-param-to": "Le titre du fichier auquel arrêter l’énumération.",
"apihelp-query+allfileusages-param-prefix": "Rechercher tous les fichiers dont le titre commence par cette valeur.",
"apihelp-query+allfileusages-param-unique": "Afficher uniquement les titres de fichier distincts. Impossible à utiliser avec $1prop=ids.\nQuand utilisé comme générateur, produit les pages cibles au lieu des sources.",
- "apihelp-query+allfileusages-param-prop": "Quelles informations inclure :\n;ids:Ajoute l’ID de la page utilisatrice (impossible à utiliser avec $1unique).\n;title:Ajoute le titre du fichier.",
+ "apihelp-query+allfileusages-param-prop": "Quelles informations inclure :",
+ "apihelp-query+allfileusages-paramvalue-prop-ids": "Ajoute les IDs de page des pages l’utilisant (impossible à utiliser avec $1unique).",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "Ajoute le titre du fichier.",
"apihelp-query+allfileusages-param-limit": "Combien d’éléments renvoyer au total.",
"apihelp-query+allfileusages-param-dir": "La direction dans laquelle lister.",
"apihelp-query+allfileusages-example-B": "Lister les titres de fichier, y compris les manquants, avec les IDs de page d’où ils proviennent, en commençant à <kbd>B</kbd>.",
@@ -369,7 +418,9 @@
"apihelp-query+alllinks-param-to": "Le titre du lien auquel arrêter l’énumération.",
"apihelp-query+alllinks-param-prefix": "Rechercher tous les titres liés commençant par cette valeur.",
"apihelp-query+alllinks-param-unique": "Afficher uniquement les titres liés distincts. Impossible à utiliser avec <kbd>$1prop=ids</kbd>.\nUtilisé avec un générateur, produit les pages cible au lieu des pages source.",
- "apihelp-query+alllinks-param-prop": "Quelles informations inclure :\n;ids:Ajoute l’ID de la page de liaison (impossible à utiliser avec <var>$1unique</var>).\n;title:Ajoute le titre du lien.",
+ "apihelp-query+alllinks-param-prop": "Quelles informations inclure :",
+ "apihelp-query+alllinks-paramvalue-prop-ids": "Ajoute l’ID de la page avec le lien (impossible à utiliser avec <var>$1unique</var>).",
+ "apihelp-query+alllinks-paramvalue-prop-title": "Ajoute le titre du lien.",
"apihelp-query+alllinks-param-namespace": "L’espace de noms à énumérer.",
"apihelp-query+alllinks-param-limit": "Combien d’éléments renvoyer au total.",
"apihelp-query+alllinks-param-dir": "La direction dans laquelle lister.",
@@ -416,7 +467,11 @@
"apihelp-query+allredirects-param-to": "Le titre de la redirection auquel arrêter l’énumération.",
"apihelp-query+allredirects-param-prefix": "Rechercher toutes les pages cible commençant par cette valeur.",
"apihelp-query+allredirects-param-unique": "Afficher uniquement les pages cibles distinctes. Impossible à utiliser avec $1prop=ids|fragment|interwiki.\nUtilisé avec un générateur, produit les pages cible au lieu des pages source.",
- "apihelp-query+allredirects-param-prop": "Quelles informations inclure :\n;ids:Ajoute l’ID de la page de redirection (impossible à utiliser avec <var>$1unique</var>).\n;title:Ajoute le titre de la redirection.\n;fragment:Ajoute le fragment de la redirection, s’il y en a un (impossible à utiliser avec <var>$1unique</var>).\n;interwiki:Ajoute le préfixe interwiki de la redirection, s’il y en a un (impossible à utiliser avec <var>$1unique</var>).",
+ "apihelp-query+allredirects-param-prop": "Quelles informations inclure :",
+ "apihelp-query+allredirects-paramvalue-prop-ids": "Ajoute l’ID de la page de redirection (impossible à utiliser avec <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-title": "Ajoute le titre de la redirection.",
+ "apihelp-query+allredirects-paramvalue-prop-fragment": "Ajoute le fragment de la redirection, s’il existe (impossible à utiliser avec <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-interwiki": "Ajoute le préfixe interwiki de la redirection, s’il existe (impossible à utiliser avec <var>$1unique</var>).",
"apihelp-query+allredirects-param-namespace": "L’espace de noms à énumérer.",
"apihelp-query+allredirects-param-limit": "Combien d’éléments renvoyer au total.",
"apihelp-query+allredirects-param-dir": "La direction dans laquelle lister.",
@@ -429,7 +484,9 @@
"apihelp-query+alltransclusions-param-to": "Le titre de la transclusion auquel arrêter l’énumération.",
"apihelp-query+alltransclusions-param-prefix": "Rechercher tous les titres inclus qui commencent par cette valeur.",
"apihelp-query+alltransclusions-param-unique": "Afficher uniquement les titres inclus. Impossible à utiliser avec $1prop=ids.\nUtilisé avec un générateur, produit les pages cible plutôt que les pages source.",
- "apihelp-query+alltransclusions-param-prop": "Quelles informations inclure :\n;ids:Ajoute l’ID de la page incluse (impossible à utiliser avec $1unique).\n;title:Ajoute le titre de la transclusion.",
+ "apihelp-query+alltransclusions-param-prop": "Quelles informations inclure :",
+ "apihelp-query+alltransclusions-paramvalue-prop-ids": "Ajout l’ID de la page de transclusion (impossible à utiliser avec $1unique).",
+ "apihelp-query+alltransclusions-paramvalue-prop-title": "Ajoute le titre de la transclusion.",
"apihelp-query+alltransclusions-param-namespace": "L’espace de noms à énumérer.",
"apihelp-query+alltransclusions-param-limit": "Combien d’éléments renvoyer au total.",
"apihelp-query+alltransclusions-param-dir": "La direction dans laquelle lister.",
@@ -445,7 +502,13 @@
"apihelp-query+allusers-param-group": "Inclure uniquement les utilisateurs dans les groupes donnés.",
"apihelp-query+allusers-param-excludegroup": "Exclure les utilisateurs dans les groupes donnés.",
"apihelp-query+allusers-param-rights": "Inclure uniquement les utilisateurs avec les droits indiqués. Ne comprend pas les droits accordés par des groupes implicites ou auto-promus comme *, user ou autoconfirmed.",
- "apihelp-query+allusers-param-prop": "Quelles informations inclure :\n;blockinfo:Ajoute l’information sur le bloc actuel d’un utilisateur.\n;groups:Liste des groupes auxquels appartient l’utilisateur. Cela utilise beaucoup de ressources du serveur et peut renvoyer moins de résultats que la limite.\n;implicitgroups:Liste tous les groupes auxquels l’utilisateur est affecté automatiquement.\n;rights:Liste les droits qu’à l’utilisateur.\n;editcount:Ajoute le compteur de modifications de l’utilisateur.\n;registration:Ajoute l’horodatage de l’inscription de l’utilisateur, s’il est disponible (peut être vide).",
+ "apihelp-query+allusers-param-prop": "Quelles informations inclure :",
+ "apihelp-query+allusers-paramvalue-prop-blockinfo": "Ajoute l’information sur le bloc actuel d’un utilisateur.",
+ "apihelp-query+allusers-paramvalue-prop-groups": "Liste des groupes auxquels appartient l’utilisateur. Cela utilise beaucoup de ressources du serveur et peut renvoyer moins de résultats que la limite.",
+ "apihelp-query+allusers-paramvalue-prop-implicitgroups": "Liste tous les groupes auxquels l’utilisateur est affecté automatiquement.",
+ "apihelp-query+allusers-paramvalue-prop-rights": "Liste les droits qu’à l’utilisateur.",
+ "apihelp-query+allusers-paramvalue-prop-editcount": "Ajoute le compteur de modifications de l’utilisateur.",
+ "apihelp-query+allusers-paramvalue-prop-registration": "Ajoute l’horodatage de l’inscription de l’utilisateur, s’il est disponible (peut être vide).",
"apihelp-query+allusers-param-limit": "Combien de noms d’utilisateur renvoyer au total.",
"apihelp-query+allusers-param-witheditsonly": "Ne lister que les utilisateurs qui ont fait des modifications.",
"apihelp-query+allusers-param-activeusers": "Lister uniquement les utilisateurs actifs durant {{PLURAL:$1|le dernier jour|les $1 derniers jours}}.",
@@ -467,12 +530,25 @@
"apihelp-query+blocks-param-users": "Liste des utilisateurs à rechercher (facultatif).",
"apihelp-query+blocks-param-ip": "Obtenir tous les blocs s’appliquant à cette adresse IP ou à cette plage CIDR, y compris les blocs de plage.\nImpossible à utiliser avec <var>$3users</var>. Les plages CIDR plus larges que IPv4/$1 ou IPv6/$2 ne sont pas acceptées.",
"apihelp-query+blocks-param-limit": "Le nombre maximal de blocs à lister.",
- "apihelp-query+blocks-param-prop": "Quelles propriétés obtenir :\n;id:Ajoute l’ID du blocage.\n;user:Ajoute le nom de l’utilisateur bloqué.\n;userid:Ajoute l’ID de l’utilisateur bloqué.\n;by:Ajoute le nom de l’utilisateur ayant bloqué.\n;byid:Ajoute l’ID de l’utilisateur ayant bloqué.\n;timestamp:Ajoute l’horodatage du blocage.\n;expiry:Ajoute l’horodatage d’expiration du blocage.\n;reason:Ajoute le motif du blocage.\n;range:Ajoute la plage d’adresses IP affectée par le blocage.\n;flags:Marque le bannissement avec (autoblock, anononly, etc.).",
+ "apihelp-query+blocks-param-prop": "Quelles propriétés obtenir :",
+ "apihelp-query+blocks-paramvalue-prop-id": "Ajoute l’ID du blocage.",
+ "apihelp-query+blocks-paramvalue-prop-user": "Ajoute le nom de l’utilisateur bloqué.",
+ "apihelp-query+blocks-paramvalue-prop-userid": "Ajoute l’ID de l’utilisateur bloqué.",
+ "apihelp-query+blocks-paramvalue-prop-by": "Ajoute le nom de l’utilisateur ayant bloqué.",
+ "apihelp-query+blocks-paramvalue-prop-byid": "Ajoute l’ID de l’utilisateur ayant bloqué.",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "Ajoute l’horodatage du blocage.",
+ "apihelp-query+blocks-paramvalue-prop-expiry": "Ajoute l’horodatage d’expiration du blocage.",
+ "apihelp-query+blocks-paramvalue-prop-reason": "Ajoute le motif du blocage.",
+ "apihelp-query+blocks-paramvalue-prop-range": "Ajoute la plage d’adresses IP affectée par le blocage.",
+ "apihelp-query+blocks-paramvalue-prop-flags": "Marque le bannissement avec (autoblock, anononly, etc.).",
"apihelp-query+blocks-param-show": "Afficher uniquement les éléments correspondant à ces critères.\nPar exemple, pour voir uniquement les blocages infinis sur les adresses IP, mettre <kbd>$1show=ip|!temp</kbd>.",
"apihelp-query+blocks-example-simple": "Lister les blocages",
"apihelp-query+blocks-example-users": "Lister les blocages des utilisateurs <kbd>Alice</kbd> et <kbd>Bob</kbd>.",
"apihelp-query+categories-description": "Lister toutes les catégories auxquelles les pages appartiennent.",
- "apihelp-query+categories-param-prop": "Quelles propriétés supplémentaires obtenir de chaque catégorie :\n;sortkey:Ajoute la clé de tri (chaîne hexadécimale) et son préfixe (partie lisible) de la catégorie.\n;timestamp:Ajoute l’horodatage de l’ajout de la catégorie.\n;hidden:Marque les catégories cachées avec _&#95;HIDDENCAT_&#95;.",
+ "apihelp-query+categories-param-prop": "Quelles propriétés supplémentaires obtenir de chaque catégorie :",
+ "apihelp-query+categories-paramvalue-prop-sortkey": "Ajoute la clé de tri (chaîne hexadécimale) et son préfixe (partie lisible) de la catégorie.",
+ "apihelp-query+categories-paramvalue-prop-timestamp": "Ajoute l’horodatage de l’ajout de la catégorie.",
+ "apihelp-query+categories-paramvalue-prop-hidden": "Marque les catégories cachées avec <code>_&#95;HIDDENCAT_&#95;</code>.",
"apihelp-query+categories-param-show": "Quelle sorte de catégories afficher.",
"apihelp-query+categories-param-limit": "Combien de catégories renvoyer.",
"apihelp-query+categories-param-categories": "Lister uniquement ces catégories. Utile pour vérifier si une certaine page est dans une certaine catégorie.",
@@ -484,7 +560,13 @@
"apihelp-query+categorymembers-description": "Lister toutes les pages d’une catégorie donnée.",
"apihelp-query+categorymembers-param-title": "Quelle catégorie énumérer (obligatoire). Doit comprendre le préfixe <kbd>{{ns:category}}:</kbd>. Impossible à utiliser avec <var>$1pageid</var>.",
"apihelp-query+categorymembers-param-pageid": "ID de la page de la catégorie à énumérer. Impossible à utiliser avec <var>$1title</var>.",
- "apihelp-query+categorymembers-param-prop": "Quelles informations inclure :\n;ids:Ajoute l’ID de la page.\n;title:Ajoute le titre et l’ID de l’espace de noms de la page.\n;sortkey:Ajoute la clé de tri utilisée pour trier dans la catégorie (chaîne hexadécimale).\n;sortkeyprefix:Ajoute le préfixe de la clé de tri utilisé pour trier dans la catégorie (partie lisible de la clé de tri).\n;type:Ajoute le type dans lequel a été catégorisée la page (page, sous-catégorie ou fichier).\n;timestamp:Ajoute l’horodatage de l’inclusion de la page.",
+ "apihelp-query+categorymembers-param-prop": "Quelles informations inclure :",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "Ajoute l’ID de la page.",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "Ajoute le titre et l’ID de l’espace de noms de la page.",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkey": "Ajoute la clé de tri utilisée pour trier dans la catégorie (chaîne hexadécimale).",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "Ajoute le préfixe de la clé de tri utilisé pour trier dans la catégorie (partie lisible de la clé de tri).",
+ "apihelp-query+categorymembers-paramvalue-prop-type": "Ajoute le type dans lequel a été catégorisée la page (page, sous-catégorie ou fichier).",
+ "apihelp-query+categorymembers-paramvalue-prop-timestamp": "Ajoute l’horodatage de l’inclusion de la page.",
"apihelp-query+categorymembers-param-namespace": "Inclure uniquement les pages dans ces espaces de nom. Remarquez que <kbd>$1type=subcat</kbd> ou <kbd>$1type=file</kbd> peuvent être utilisés à la place de <kbd>$1namespace=14</kbd> ou <kbd>6</kbd>.",
"apihelp-query+categorymembers-param-type": "Quel type de membres de la catégorie inclure. Ignoré quand <kbd>$1sort=timestamp</kbd> est positionné.",
"apihelp-query+categorymembers-param-limit": "Le nombre maximal de pages à renvoyer.",
@@ -495,7 +577,7 @@
"apihelp-query+categorymembers-param-starthexsortkey": "Clé de tri à laquelle démarrer le listage, telle que renvoyée par <kbd>$1prop=sortkey</kbd>. Utilisable uniquement avec <kbd>$1sort=sortkey</kbd>.",
"apihelp-query+categorymembers-param-endhexsortkey": "Clé de tri à laquelle arrêter le listage, telle que renvoyée par <kbd>$1prop=sortkey</kbd>. Utilisable uniquement avec <kbd>$1sort=sortkey</kbd>.",
"apihelp-query+categorymembers-param-startsortkeyprefix": "Préfixe de la clé de tri à laquelle démarrer le listage. Utilisable uniquement avec <kbd>$1sort=sortkey</kbd>. Écrase <var>$1starthexsortkey</var>.",
- "apihelp-query+categorymembers-param-endsortkeyprefix": "Préfixe de la clé de tri AVANT laquelle se termine le listage (et non pas à, si cette valeur existe elle ne sera pas incluse !). Utilisable uniquement avec $1sort=sortkey. Écrase $1endhexsortkey.",
+ "apihelp-query+categorymembers-param-endsortkeyprefix": "Préfixe de la clé de tri <strong>avant</strong> laquelle se termine le listage (et non pas <strong>à</strong> ; si cette valeur existe elle ne sera pas incluse !). Utilisable uniquement avec $1sort=sortkey. Écrase $1endhexsortkey.",
"apihelp-query+categorymembers-param-startsortkey": "Utiliser plutôt $1starthexsortkey.",
"apihelp-query+categorymembers-param-endsortkey": "Utiliser plutôt $1endhexsortkey.",
"apihelp-query+categorymembers-example-simple": "Obtenir les 10 premières pages de <kbd>Category:Physics</kbd>.",
@@ -513,8 +595,6 @@
"apihelp-query+deletedrevisions-param-tag": "Lister uniquement les révisions marquées par cette balise.",
"apihelp-query+deletedrevisions-param-user": "Lister uniquement les révisions faites par cet utilisateur.",
"apihelp-query+deletedrevisions-param-excludeuser": "Ne pas lister les révisions faites par cet utilisateur.",
- "apihelp-query+deletedrevisions-param-limit": "Le nombre maximal de révisions à lister.",
- "apihelp-query+deletedrevisions-param-prop": "Quelles propriétés obtenir :\n;revid:Ajoute l’ID de la révision supprimée.\n;parentid:Ajoute l’ID de la révision précédente de la page.\n;user:Ajoute l’utilisateur ayant fait la révision.\n;userid:Ajoute l’ID de l’utilisateur ayant fait la révision.\n;comment:Ajoute le commentaire de la révision.\n;parsedcomment:Ajoute le commentaire analysé de la révision.\n;minor:Marque si une révision est mineure.\n;len:Ajoute la taille (en octets) de la révision.\n;sha1:Ajoute le SHA-1 (base 16) de la révision.\n;content:Ajoute le contenu de la révision.\n;tags:Balises pour la révision.",
"apihelp-query+deletedrevisions-example-titles": "Lister les révisions supprimées des pages <kbd>Main Page</kbd> et <kbd>Talk:Main Page</kbd>, avec leur contenu.",
"apihelp-query+deletedrevisions-example-revids": "Lister les informations pour la révision supprimée <kbd>123456</kbd>.",
"apihelp-query+deletedrevs-description": "Lister les révisions supprimées.\n\nOpère selon trois modes :\n# Lister les révisions supprimées pour les titres donnés, triées par horodatage.\n# Lister les contributions supprimées pour l’utilisateur donné, triées par horodatage (pas de titres spécifiés).\n# Lister toutes les révisions supprimées dans l’espace de noms donné, triées par titre et horodatage (aucun titre spécifié, $1user non positionné).\n\nCertains paramètres ne s’appliquent qu’à certains modes et sont ignorés dans les autres.",
@@ -558,7 +638,10 @@
"apihelp-query+extlinks-param-expandurl": "Étendre les URLs relatives au protocole avec le protocole canonique.",
"apihelp-query+extlinks-example-simple": "Obtenir une liste des liens externes de <kbd>Main Page<kbd>.",
"apihelp-query+exturlusage-description": "Énumérer les pages contenant une URL donnée.",
- "apihelp-query+exturlusage-param-prop": "Quelles informations inclure :\n;ids:Ajoute l’ID de la page.\n;title:Ajoute le titre et l’ID de l’espace de noms de la page.\n;url:Ajoute l’URL utilisée dans la page.",
+ "apihelp-query+exturlusage-param-prop": "Quelles informations inclure :",
+ "apihelp-query+exturlusage-paramvalue-prop-ids": "Ajoute l’ID de la page.",
+ "apihelp-query+exturlusage-paramvalue-prop-title": "Ajoute le titre et l’ID de l’espace de noms de la page.",
+ "apihelp-query+exturlusage-paramvalue-prop-url": "Ajoute l’URL utilisée dans la page.",
"apihelp-query+exturlusage-param-protocol": "Protocole de l’URL. Si vide et que <var>$1query</var> est rempli, le protocole est <kbd>http</kbd>. Le laisser avec <var>$1query</var> vide pour lister tous les liens externes.",
"apihelp-query+exturlusage-param-query": "Rechercher une chaîne sans protocole. Voyez [[Special:LinkSearch]]. Le laisser vide liste tous les liens externes.",
"apihelp-query+exturlusage-param-namespace": "Les espaces de nom à énumérer.",
@@ -573,13 +656,28 @@
"apihelp-query+filearchive-param-dir": "La direction dans laquelle lister.",
"apihelp-query+filearchive-param-sha1": "Hachage SHA1 de l’image. Écrase $1sha1base36.",
"apihelp-query+filearchive-param-sha1base36": "Hachage SHA1 de l’image en base 36 (utilisé dans MédiaWiki).",
- "apihelp-query+filearchive-param-prop": "Quelle information obtenir sur l’image :\n;sha1:Ajoute le hachage SHA-1 pour l’image.\n;timestamp:Ajoute l÷’horodatage pour la version téléchargée.\n;user:Ajoute l’utilisateur qui a téléchargé la version de l’image.\n;size:Ajoute la taille de l’image en octets et la hauteur, la largeur et le nombre de page (si c’est applicable).\n;dimensions:Alias pour la taille.\n;description:Ajoute la description de la version de l’image.\n;parseddescription:Analyser la description de la version.\n;mime:Ajoute le MIME de l’image.\n;mediatype:Ajoute le type de média de l’image.\n;metadata:Liste les métadonnées Exif pour la version de l’image.\n;bitdepth:Ajoute la profondeur de bit de la version.\n;archivename:Ajoute le nom de fichier de la version d’archive pour les versions autres que la dernière.",
+ "apihelp-query+filearchive-param-prop": "Quelle information obtenir sur l’image :",
+ "apihelp-query+filearchive-paramvalue-prop-sha1": "Ajoute le hachage SHA-1 pour l’image.",
+ "apihelp-query+filearchive-paramvalue-prop-timestamp": "Ajoute l÷’horodatage pour la version téléchargée.",
+ "apihelp-query+filearchive-paramvalue-prop-user": "Ajoute l’utilisateur qui a téléchargé la version de l’image.",
+ "apihelp-query+filearchive-paramvalue-prop-size": "Ajoute la taille de l’image en octets et la hauteur, la largeur et le nombre de page (si c’est applicable).",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "Alias pour la taille.",
+ "apihelp-query+filearchive-paramvalue-prop-description": "Ajoute la description de la version de l’image.",
+ "apihelp-query+filearchive-paramvalue-prop-parseddescription": "Analyser la description de la version.",
+ "apihelp-query+filearchive-paramvalue-prop-mime": "Ajoute le MIME de l’image.",
+ "apihelp-query+filearchive-paramvalue-prop-mediatype": "Ajoute le type de média de l’image.",
+ "apihelp-query+filearchive-paramvalue-prop-metadata": "Liste les métadonnées Exif pour la version de l’image.",
+ "apihelp-query+filearchive-paramvalue-prop-bitdepth": "Ajoute la profondeur de bit de la version.",
+ "apihelp-query+filearchive-paramvalue-prop-archivename": "Ajoute le nom de fichier de la version d’archive pour les versions autres que la dernière.",
"apihelp-query+filearchive-example-simple": "Afficher une liste de tous les fichiers supprimés",
"apihelp-query+filerepoinfo-description": "Renvoyer les méta-informations sur les référentiels d’image configurés dans le wiki.",
"apihelp-query+filerepoinfo-param-prop": "Quelles propriétés du référentiel récupérer (il peut y en avoir plus de disponibles sur certains wikis) :\n;apiurl:URL de l’API du référentiel - utile pour obtenir les infos de l’image depuis l’hôte.\n;name:La clé du référentiel - utilisé par ex. dans les valeurs de retour de <var>[[mw:Manual:$wgForeignFileRepos|$wgForeignFileRepos]]</var> et [[Special:ApiHelp/query+imageinfo|imageinfo]].\n;displayname:Le nom lisible du wiki référentiel.\n;rooturl:URL racine des chemins d’image.\n;local:Si ce référentiel est le référentiel local ou non.",
"apihelp-query+filerepoinfo-example-simple": "Obtenir l’information sur les référentiels de fichier",
"apihelp-query+fileusage-description": "Trouver toutes les pages qui utilisent les fichiers donnés.",
- "apihelp-query+fileusage-param-prop": "Quelles propriétés obtenir :\n;pageid:ID de chaque page.\n;title:Titre de chaque page.\n;redirect:Marque si la page est une redirection.",
+ "apihelp-query+fileusage-param-prop": "Quelles propriétés obtenir :",
+ "apihelp-query+fileusage-paramvalue-prop-pageid": "ID de chaque page.",
+ "apihelp-query+fileusage-paramvalue-prop-title": "Titre de chaque page.",
+ "apihelp-query+fileusage-paramvalue-prop-redirect": "Marque si la page est une redirection.",
"apihelp-query+fileusage-param-namespace": "Inclure uniquement les pages dans ces espaces de nom.",
"apihelp-query+fileusage-param-limit": "Combien renvoyer.",
"apihelp-query+fileusage-param-show": "Afficher uniquement les éléments qui correspondent à ces critères :\n;redirect:Afficher uniquement les redirections.\n;!redirect:Afficher uniquement les non-redirections.",
@@ -655,13 +753,16 @@
"apihelp-query+iwbacklinks-param-prefix": "Préfixe pour l’interwiki.",
"apihelp-query+iwbacklinks-param-title": "Lien interwiki à rechercher. Doit être utilisé avec <var>$1blprefix</var>.",
"apihelp-query+iwbacklinks-param-limit": "Combien de pages renvoyer.",
- "apihelp-query+iwbacklinks-param-prop": "Quelles propriétés obtenir :\n;iwprefix:Ajoute le préfixe de l’interwiki.\n;iwtitle:Ajoute le titre de l’interwiki.",
+ "apihelp-query+iwbacklinks-param-prop": "Quelles propriétés obtenir :",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Ajoute le préfixe de l’interwiki.",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Ajoute le titre de l’interwiki.",
"apihelp-query+iwbacklinks-param-dir": "La direction dans laquelle lister.",
"apihelp-query+iwbacklinks-example-simple": "Obtenir les pages ayant un lien vers [[wikibooks:Test]]",
"apihelp-query+iwbacklinks-example-generator": "Obtenir des informations sur les pages ayant un lien vers [[wikibooks:Test]]",
"apihelp-query+iwlinks-description": "Renvoie tous les liens interwiki des pages indiquées.",
"apihelp-query+iwlinks-param-url": "S&il faut obtenir l’URL complète (impossible à utiliser avec $1prop).",
- "apihelp-query+iwlinks-param-prop": "Quelles propriétés supplémentaires obtenir pour chaque lien interlangue :\n;url:Ajoute l’URL complète.",
+ "apihelp-query+iwlinks-param-prop": "Quelles propriétés supplémentaires obtenir pour chaque lien interlangue :",
+ "apihelp-query+iwlinks-paramvalue-prop-url": "Ajoute l’URL complète.",
"apihelp-query+iwlinks-param-limit": "Combien de liens interwiki renvoyer.",
"apihelp-query+iwlinks-param-prefix": "Renvoyer uniquement les liens interwiki avec ce préfixe.",
"apihelp-query+iwlinks-param-title": "Lien interwiki à rechercher. Doit être utilisé avec <var>$1prefix</var>.",
@@ -671,14 +772,19 @@
"apihelp-query+langbacklinks-param-lang": "Langue pour le lien de langue.",
"apihelp-query+langbacklinks-param-title": "Lien interlangue à rechercher. Doit être utilisé avec $1lang.",
"apihelp-query+langbacklinks-param-limit": "Combien de pages renvoyer au total.",
- "apihelp-query+langbacklinks-param-prop": "Quelles propriétés obtenir :\n;lllang:Ajoute le code de langue du lien de langue.\n;lltitle:Ajoute le titre du lien de langue.",
+ "apihelp-query+langbacklinks-param-prop": "Quelles propriétés obtenir :",
+ "apihelp-query+langbacklinks-paramvalue-prop-lllang": "Ajoute le code de langue du lien de langue.",
+ "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Ajoute le titre du lien de langue.",
"apihelp-query+langbacklinks-param-dir": "La direction dans laquelle lister.",
"apihelp-query+langbacklinks-example-simple": "Obtenir les pages avec un lien avec [[:fr:Test]]",
"apihelp-query+langbacklinks-example-generator": "Obtenir des informations sur les pages ayant un lien vers [[:fr:Test]]",
"apihelp-query+langlinks-description": "Renvoie tous les liens interlangue des pages fournies.",
"apihelp-query+langlinks-param-limit": "Combien de liens interlangue renvoyer.",
"apihelp-query+langlinks-param-url": "S’il faut récupérer l’URL complète (impossible à utiliser avec <var>$1prop</var>).",
- "apihelp-query+langlinks-param-prop": "Quelles propriétés supplémentaires obtenir pour chaque lien interlangue :\n;url:Ajoute l’URL complète.\n;langname:Ajoute le nom localisé de la langue (au mieux). Utiliser <var>$1inlanguagecode</var> pour contrôler la langue.\n;autonym:Ajoute le nom natif de la langue.",
+ "apihelp-query+langlinks-param-prop": "Quelles propriétés supplémentaires obtenir pour chaque lien interlangue :",
+ "apihelp-query+langlinks-paramvalue-prop-url": "Ajoute l’URL complète.",
+ "apihelp-query+langlinks-paramvalue-prop-langname": "Ajoute le nom localisé de la langue (au mieux). Utiliser <var>$1inlanguagecode</var> pour contrôler la langue.",
+ "apihelp-query+langlinks-paramvalue-prop-autonym": "Ajoute le nom natif de la langue.",
"apihelp-query+langlinks-param-lang": "Renvoyer uniquement les liens interlangue avec ce code de langue.",
"apihelp-query+langlinks-param-title": "Lien à rechercher. Doit être utilisé avec <var>$1lang</var>.",
"apihelp-query+langlinks-param-dir": "La direction dans laquelle énumérer.",
@@ -693,16 +799,29 @@
"apihelp-query+links-example-generator": "Obtenir des informations sur tous les liens de page dans <kbd>Main Page</kbd>.",
"apihelp-query+links-example-namespaces": "Obtenir les liens de la page <kbd>Accueil</kbd> dans les espaces de nom {{ns:user}} et {{ns:template}}.",
"apihelp-query+linkshere-description": "Trouver toutes les pages ayant un lien vers les pages données.",
- "apihelp-query+linkshere-param-prop": "Quelles propriétés obtenir :\n;pageid:ID de chaque page.\n;title:Titre de chaque page.\n;redirect:Indique si la page est une redirection.",
+ "apihelp-query+linkshere-param-prop": "Quelles propriétés obtenir :",
+ "apihelp-query+linkshere-paramvalue-prop-pageid": "ID de chaque page.",
+ "apihelp-query+linkshere-paramvalue-prop-title": "Titre de chaque page.",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "Indique si la page est une redirection.",
"apihelp-query+linkshere-param-namespace": "Inclure uniquement les pages dans ces espaces de nom.",
"apihelp-query+linkshere-param-limit": "Combien de résultats renvoyer.",
"apihelp-query+linkshere-param-show": "Afficher uniquement les éléments qui correspondent à ces critères :\n;redirect:Afficher uniquement les redirections.\n;!redirect:Afficher uniquement les non-redirections.",
"apihelp-query+linkshere-example-simple": "Obtenir une liste des pages liées à [[Main Page]]",
"apihelp-query+linkshere-example-generator": "Obtenir des informations sur les pages liées à [[Main Page]]",
"apihelp-query+logevents-description": "Obtenir des événements des journaux.",
- "apihelp-query+logevents-param-prop": "Quelles propriétés obtenir :\n;ids:Ajoute l’ID de l’événement.\n;title:Ajoute le titre de la page pour l’événement.\n;type:Ajoute le type de l’événement.\n;user:Ajoute l’utilisateur responsable de l’événement.\n;userid:Ajoute l’ID de l’utilisateur responsable de l’événement.\n;timestamp:Ajoute l’horodatage de l’événement.\n;comment:Ajoute le commentaire de l’événement.\n;parsedcomment:Ajoute le commentaire analysé de l’événement.\n;details:Liste les détails supplémentaires sur l’événement.\n;tags:Liste les balises de l’événement.",
+ "apihelp-query+logevents-param-prop": "Quelles propriétés obtenir :",
+ "apihelp-query+logevents-paramvalue-prop-ids": "Ajoute l’ID de l’événement.",
+ "apihelp-query+logevents-paramvalue-prop-title": "Ajoute le titre de la page pour l’événement.",
+ "apihelp-query+logevents-paramvalue-prop-type": "Ajoute le type de l’événement.",
+ "apihelp-query+logevents-paramvalue-prop-user": "Ajoute l’utilisateur responsable de l’événement.",
+ "apihelp-query+logevents-paramvalue-prop-userid": "Ajoute l’ID de l’utilisateur responsable de l’événement.",
+ "apihelp-query+logevents-paramvalue-prop-timestamp": "Ajoute l’horodatage de l’événement.",
+ "apihelp-query+logevents-paramvalue-prop-comment": "Ajoute le commentaire de l’événement.",
+ "apihelp-query+logevents-paramvalue-prop-parsedcomment": "Ajoute le commentaire analysé de l’événement.",
+ "apihelp-query+logevents-paramvalue-prop-details": "Liste les détails supplémentaires sur l’événement.",
+ "apihelp-query+logevents-paramvalue-prop-tags": "Liste les balises de l’événement.",
"apihelp-query+logevents-param-type": "Filtrer les entrées du journal à ce seul type.",
- "apihelp-query+logevents-param-action": "Filtrer les actions du journal à cette seule action. Écrase <var>$1type</var>. Des actions avec une astérisque de la forme <var>$1type</var> sont autorisées pour spécifier n’importe quelle chaîne à la place de l’astérisque.",
+ "apihelp-query+logevents-param-action": "Filtrer les actions du journal à cette seule action. Écrase <var>$1type</var>. La présence d'une valeur avec un astérisque dans la liste, comme <var>$1type</var>, indique qu'une chaîne arbitraire peut être passée dans dans la requête à la place de l'astérisque.",
"apihelp-query+logevents-param-start": "L’horodatage auquel démarrer l’énumération.",
"apihelp-query+logevents-param-end": "L’horodatage auquel arrêter l’énumération.",
"apihelp-query+logevents-param-user": "Restreindre aux entrées générées par l’utilisateur spécifié.",
@@ -717,14 +836,17 @@
"apihelp-query+pagepropnames-example-simple": "Obtenir les 10 premiers noms de propriété.",
"apihelp-query+pageprops-description": "Obtenir diverses propriétés définies dans le contenu de la page.",
"apihelp-query+pageprops-param-prop": "Lister uniquement ces propriétés. Utile pour vérifier si une certaine page utilise une certaine propriété de page.",
- "apihelp-query+pageprops-example-simple": "Obtenir les propriétés de <kbd>Category:Foo</kbd>.",
+ "apihelp-query+pageprops-example-simple": "Obtenir les propriétés des pages <kbd>Accueil</kbd> et <kbd>MédiaWiki</kbd>.",
"apihelp-query+pageswithprop-description": "Lister toutes les pages utilisant une propriété de page donnée.",
"apihelp-query+pageswithprop-param-propname": "Propriété de page pour laquelle énumérer les pages.",
- "apihelp-query+pageswithprop-param-prop": "Quelles informations inclure :\n;ids:Ajoute l’ID de la page.\n;title:Ajoute le titre et l’ID de l’espace de noms de la page.\n;value:Ajoute la valeur de la propriété de page.",
+ "apihelp-query+pageswithprop-param-prop": "Quelles informations inclure :",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "Ajoute l’ID de la page.",
+ "apihelp-query+pageswithprop-paramvalue-prop-title": "Ajoute le titre et l’ID de l’espace de noms de la page.",
+ "apihelp-query+pageswithprop-paramvalue-prop-value": "Ajoute la valeur de la propriété de page.",
"apihelp-query+pageswithprop-param-limit": "Le nombre maximal de pages à renvoyer.",
"apihelp-query+pageswithprop-param-dir": "Dans quelle direction trier.",
"apihelp-query+pageswithprop-example-simple": "Lister les 10 premières pages en utilisant <code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code>.",
- "apihelp-query+pageswithprop-example-generator": "Obtenir des informations sur les 10 premières pages utilisant <code>_&#95;NOTOC_&#95;</code>.",
+ "apihelp-query+pageswithprop-example-generator": "Obtenir des informations supplémentaires sur les 10 premières pages utilisant <code>_&#95;NOTOC_&#95;</code>.",
"apihelp-query+prefixsearch-description": "Effectuer une recherche de préfixe sur les titres de page.",
"apihelp-query+prefixsearch-param-search": "Chaîne de recherche.",
"apihelp-query+prefixsearch-param-namespace": "Espaces de nom à rechercher.",
@@ -737,17 +859,25 @@
"apihelp-query+protectedtitles-param-limit": "Combien de pages renvoyer au total.",
"apihelp-query+protectedtitles-param-start": "Démarrer la liste à cet horodatage de protection.",
"apihelp-query+protectedtitles-param-end": "Arrêter la liste à cet horodatage de protection.",
- "apihelp-query+protectedtitles-param-prop": "Quelles propriétés obtenir :\n;timestamp:Ajoute l’horodatage de l’ajout de la protection.\n;user:Ajoute l’utilisateur ayant ajouté la protection.\n;userid:Ajoute l’ID de l’utilisateur ayant ajouté la protection.\n;comment:Ajoute le commentaire de la protection.\n;parsedcomment:Ajoute le commentaire analysé de la protection.\n;expiry:Ajoute l’horodatage de levée de la protection.\n;level:Ajoute le niveau de protection.",
+ "apihelp-query+protectedtitles-param-prop": "Quelles propriétés obtenir :",
+ "apihelp-query+protectedtitles-paramvalue-prop-timestamp": "Ajoute l’horodatage de l’ajout de la protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-user": "Ajoute l’utilisateur ayant ajouté la protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-userid": "Ajoute l’ID de l’utilisateur ayant ajouté la protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-comment": "Ajoute le commentaire pour la protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-parsedcomment": "Ajoute le commentaire analysé de la protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-expiry": "Ajoute l’horodatage de levée de la protection.",
+ "apihelp-query+protectedtitles-paramvalue-prop-level": "Ajoute le niveau de protection.",
"apihelp-query+protectedtitles-example-simple": "Lister les titres protégés",
"apihelp-query+protectedtitles-example-generator": "Trouver les liens vers les titres protégés dans l’espace de noms principal",
"apihelp-query+querypage-description": "Obtenir une liste fournie par une page spéciale basée sur QueryPage",
"apihelp-query+querypage-param-page": "Le nom de la page spéciale. Remarque, ce nom est sensible à la casse.",
"apihelp-query+querypage-param-limit": "Nombre de résultats à renvoyer.",
"apihelp-query+querypage-example-ancientpages": "Renvoyer les résultats de [[Special:Ancientpages]].",
- "apihelp-query+random-description": "Obtenir un ensemble de pages au hasard.\n\nLes pages sont listées dans un ordre prédéterminé, seul le point de départ est aléatoire. Par exemple, cela signifie que si la première page dans la liste est <samp>Accueil</samp>, la seconde sera <em>toujours</em> <samp>Liste des singes de fiction</samp>, la troisième <samp>Liste de personnes figurant sur les timbres de Vanuatu</samp>, etc.\n\nSi le nombre de page dans l’espace de nom est inférieur à <var>$1limit</var>, moins de pages seront renvoyées. La même page ne sera jamais renvoyée deux fois.",
+ "apihelp-query+random-description": "Obtenir un ensemble de pages au hasard.\n\nLes pages sont listées dans un ordre prédéterminé, seul le point de départ est aléatoire. Par exemple, cela signifie que si la première page dans la liste est <samp>Accueil</samp>, la seconde sera <em>toujours</em> <samp>Liste des singes de fiction</samp>, la troisième <samp>Liste de personnes figurant sur les timbres de Vanuatu</samp>, etc.",
"apihelp-query+random-param-namespace": "Renvoyer seulement des pages de ces espaces de noms.",
"apihelp-query+random-param-limit": "Limite sur le nombre de pages aléatoires renvoyées.",
- "apihelp-query+random-param-redirect": "Charger une redirection aléatoire plutôt qu’une page aléatoire.",
+ "apihelp-query+random-param-redirect": "Utilisez <kbd>$1filterredir=redirects</kbd> au lieu de ce paramètre.",
+ "apihelp-query+random-param-filterredir": "Comment filtrer les redirections.",
"apihelp-query+random-example-simple": "Obtenir deux pages aléatoires de l’espace principal",
"apihelp-query+random-example-generator": "Renvoyer les informations de la page sur deux pages au hasard de l’espace de noms principal",
"apihelp-query+recentchanges-description": "Énumérer les modifications récentes.",
@@ -757,7 +887,21 @@
"apihelp-query+recentchanges-param-user": "Lister uniquement les modifications par cet utilisateur.",
"apihelp-query+recentchanges-param-excludeuser": "Ne pas lister les modifications par cet utilisateur.",
"apihelp-query+recentchanges-param-tag": "Lister uniquement les modifications marquées avec cette balise.",
- "apihelp-query+recentchanges-param-prop": "Inclure des informations supplémentaires :\n;user:Ajoute l’utilisateur responsable de la modification et marque si c’est une adresse IP.\n;userid:Ajoute l’ID de l’utilisateur responsable de la modification.\n;comment:Ajoute le commentaire de la modification.\n;parsedcomment:Ajoute le commentaire analysé pour la modification.\n;flags:Ajoute les balises de la modification.\n;timestamp:Ajoute l’horodatage de la modification.\n;title:Ajoute le titre de la page modifiée.\n;ids:Ajoute l’ID de la page, l’ID des modifications récentes et l’ID de l’ancienne et la nouvelle révisions.\n;sizes:Ajoute l’ancienne et la nouvelle tailles de la page en octets.\n;redirect:Marque la modification si la page est une redirection.\n;patrolled:Marque les modifications patrouillables comme patrouillées ou non.\n;loginfo:Ajoute les informations du journal (Id du journal, type de trace, etc.) aux entrées du journal.\n;tags:Liste les balises de l’entrée.\n;sha1:Ajoute la somme de contrôle du contenu pour les entrées associées à une révision.",
+ "apihelp-query+recentchanges-param-prop": "Inclure des informations supplémentaires :",
+ "apihelp-query+recentchanges-paramvalue-prop-user": "Ajoute l’utilisateur responsable de la modification et marque si c’est une adresse IP.",
+ "apihelp-query+recentchanges-paramvalue-prop-userid": "Ajoute l’ID de l’utilisateur responsable de la modification.",
+ "apihelp-query+recentchanges-paramvalue-prop-comment": "Ajoute le commentaire de la modification.",
+ "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "Ajoute le commentaire analysé pour la modification.",
+ "apihelp-query+recentchanges-paramvalue-prop-flags": "Ajoute les balises de la modification.",
+ "apihelp-query+recentchanges-paramvalue-prop-timestamp": "Ajoute l’horodatage de la modification.",
+ "apihelp-query+recentchanges-paramvalue-prop-title": "Ajoute le titre de la page modifiée.",
+ "apihelp-query+recentchanges-paramvalue-prop-ids": "Ajoute l’ID de la page, l’ID des modifications récentes et l’ID de l’ancienne et la nouvelle révisions.",
+ "apihelp-query+recentchanges-paramvalue-prop-sizes": "Ajoute l’ancienne et la nouvelle tailles de la page en octets.",
+ "apihelp-query+recentchanges-paramvalue-prop-redirect": "Marque la modification si la page est une redirection.",
+ "apihelp-query+recentchanges-paramvalue-prop-patrolled": "Marque les modifications patrouillables comme patrouillées ou non.",
+ "apihelp-query+recentchanges-paramvalue-prop-loginfo": "Ajoute les informations du journal (Id du journal, type de trace, etc.) aux entrées du journal.",
+ "apihelp-query+recentchanges-paramvalue-prop-tags": "Liste les balises de l’entrée.",
+ "apihelp-query+recentchanges-paramvalue-prop-sha1": "Ajoute la somme de contrôle du contenu pour les entrées associées à une révision.",
"apihelp-query+recentchanges-param-token": "Utiliser plutôt <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
"apihelp-query+recentchanges-param-show": "Afficher uniquement les éléments correspondant à ces critères. Par exemple, pour voir uniquement les modifications mineures par des utilisateurs connectés, mettre $1show=minor|!anon.",
"apihelp-query+recentchanges-param-limit": "Combien de modifications renvoyer au total.",
@@ -766,13 +910,16 @@
"apihelp-query+recentchanges-example-simple": "Lister les modifications récentes",
"apihelp-query+recentchanges-example-generator": "Obtenir l’information de page sur les modifications récentes non patrouillées",
"apihelp-query+redirects-description": "Renvoie toutes les redirections vers les pages données.",
- "apihelp-query+redirects-param-prop": "Quelles propriétés récupérer :\n;pageid:ID de page de chaque redirection.\n;title:Titre de chaque redirection.\n;fragment:Fragment de chaque redirection, s’il y en a un.",
+ "apihelp-query+redirects-param-prop": "Quelles propriétés récupérer :",
+ "apihelp-query+redirects-paramvalue-prop-pageid": "ID de page de chaque redirection.",
+ "apihelp-query+redirects-paramvalue-prop-title": "Titre de chaque redirection.",
+ "apihelp-query+redirects-paramvalue-prop-fragment": "Fragment de chaque redirection, s’il y en a un.",
"apihelp-query+redirects-param-namespace": "Inclure uniquement les pages dans ces espaces de nom.",
"apihelp-query+redirects-param-limit": "Combien de redirections renvoyer.",
"apihelp-query+redirects-param-show": "Afficher uniquement les éléments correspondant à ces critères :\n;fragment:Afficher uniquement les redirections avec un fragment.\n;!fragment:Afficher uniquement les redirections sans fragment.",
"apihelp-query+redirects-example-simple": "Obtenir une liste des redirections vers [[Main Page]]",
"apihelp-query+redirects-example-generator": "Obtenir des informations sur toutes les redirections vers [[Main Page]]",
- "apihelp-query+revisions-description": "Obtenir des informations sur la révision.\n\nPeut être utilisé de différentes manières :\n# Obtenir des données sur un ensemble de pages (dernière révision), en mettant les titres ou les ids de page.\n# Obtenir les révisions d’une page donnée, en utilisant les titres ou les ids de page avec début, fin ou limite.\n# Obtenir des données sur un ensemble de révisions en donnant leurs IDs et leurs ids de révision.",
+ "apihelp-query+revisions-description": "Obtenir des informations sur la révision.\n\nPeut être utilisé de différentes manières :\n# Obtenir des données sur un ensemble de pages (dernière révision), en mettant les titres ou les ids de page.\n# Obtenir les révisions d’une page donnée, en utilisant les titres ou les ids de page avec rvstart, rvend ou rvlimit.\n# Obtenir des données sur un ensemble de révisions en donnant leurs IDs avec revids.",
"apihelp-query+revisions-paraminfo-singlepageonly": "Utilisable uniquement avec une seule page (mode #2).",
"apihelp-query+revisions-param-startid": "À quel ID de révision démarrer l’énumération.",
"apihelp-query+revisions-param-endid": "Arrêter l’énumération des révisions à cet ID.",
@@ -788,29 +935,78 @@
"apihelp-query+revisions-example-first5-after": "Obtenir les 5 premières révisions de la <kbd>Page principale</kbd> faites après le 01/05/2006.",
"apihelp-query+revisions-example-first5-not-localhost": "Obtenir les 5 premières révisions de la <kbd>Page principale</kbd> qui n’ont pas été faites par l’utilisateur anonyme <kbd>127.0.0.1</kbd>.",
"apihelp-query+revisions-example-first5-user": "Obtenir les 5 premières révisions de la <kbd>Page principale</kbd> qui ont été faites par l’utilisateur <kbd>MédiaWiki par défaut</kbd>.",
- "apihelp-query+revisions+base-param-prop": "Quelles propriétés obtenir pour chaque révision :\n;ids:L’ID de la révision.\n;flags:Marques de la révision (mineure).\n;timestamp:L’horodatage de la révision.\n;user:Utilisateur ayant fait la révision.\n;userid:ID de l’utilisateur ayant créé la révision.\n;size:Taille (en octets) de la révision.\n;sha1:SHA-1 (base 16) de la révision.\n;contentmodel:ID du modèle de contenu de la révision.\n;comment:Commentaire par l’utilisateur de la révision.\n;parsedcomment:Commentaire analysé par l’utilisateur de la révision.\n;content:Texte de la révision.\n;tags:Balises de la révision.",
+ "apihelp-query+revisions+base-param-prop": "Quelles propriétés obtenir pour chaque révision :",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "L’ID de la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-flags": "Marques de la révision (mineure).",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "L’horodatage de la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "L’utilisateur qui a fait la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-userid": "L’ID de l’utilisateur créateur de la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "Longueur (en octets) de la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "Hachage SHA-1 (base 16) de la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "ID du modèle de contenu de la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-comment": "Commentaire de l’utilisateur sur la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-parsedcomment": "Commentaire analysé de l’utilisateur sur la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-content": "Texte de la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-tags": "Balises de la révision.",
+ "apihelp-query+revisions+base-paramvalue-prop-parsetree": "L’arbre d’analyse XML du contenu de la révision (nécessite le modèle de contenu <code>$1</code>).",
"apihelp-query+revisions+base-param-limit": "Limiter le nombre de révisions retournées.",
"apihelp-query+revisions+base-param-expandtemplates": "Développer les modèles dans le contenu de la révision (nécessite $1prop=content).",
- "apihelp-query+revisions+base-param-generatexml": "Générer l’arbre d’analyse XML pour le contenu de la révision (nécessite $1prop=content).",
+ "apihelp-query+revisions+base-param-generatexml": "Générer l’arbre d’analyse XML pour le contenu de la révision (nécessite $1prop=content ; remplacé par <kbd>$1prop=parsetree</kbd>).",
"apihelp-query+revisions+base-param-parse": "Analyser le contenu de la révision (nécessite $1prop=content). Pour des raisons de performance, si cette option est utilisée, $1limit est forcé à 1.",
"apihelp-query+revisions+base-param-section": "Récupérer uniquement le contenu de ce numéro de section.",
"apihelp-query+revisions+base-param-diffto": "ID de révision à comparer à chaque révision. Utiliser <kbd>prev</kbd>, <kbd>next</kbd> et <kbd>cur</kbd> pour la version précédente, suivante et actuelle respectivement.",
"apihelp-query+revisions+base-param-difftotext": "Texte auquel comparer chaque révision. Compare uniquement un nombre limité de révisions. Écrase <var>$1diffto</var>. Si <var>$1section</var> est positionné, seule cette section sera comparée avec ce texte",
"apihelp-query+revisions+base-param-contentformat": "Format de sérialisation utilisé pour <var>$1difftotext</var> et attendu pour la sortie du contenu.",
"apihelp-query+search-description": "Effectuer une recherche en texte intégral.",
- "apihelp-query+search-param-search": "Rechercher les titres (ou le contenu) de toutes les pages ayant cette valeur.",
+ "apihelp-query+search-param-search": "Rechercher les titres de page ou le contenu correspondant à cette valeur. Vous pouvez utiliser la chaîne de recherche pour invoquer des fonctionnalités de recherche spéciales, selon ce que le serveur de recherche du wiki implémente.",
"apihelp-query+search-param-namespace": "Rechercher uniquement dans ces espaces de nom.",
"apihelp-query+search-param-what": "Quel type de recherche effectuer.",
"apihelp-query+search-param-info": "Quelles métadonnées renvoyer.",
- "apihelp-query+search-param-prop": "Quelles propriétés renvoyer :\n;size:Ajoute la taille de la page en octets.\n;wordcount:Ajoute le nombre de mots de la page.\n;timestamp:Ajoute l’horodatage de la dernière modification de la page.\n;snippet:Ajoute un extrait analysé de la page.\n;titlesnippet:Ajoute un extrait analysé du titre de la page.\n;redirectsnippet:Ajoute un extrait analysé du titre de la redirection.\n;redirecttitle:Ajoute le titre de la redirection correspondante.\n;sectionsnippet:Ajoute un extrait analysé du titre de la section correspondante.\n;sectiontitle:Ajoute le titre de la section correspondante.\n;score:<span class=\"apihelp-deprecated\">Obsolète et ignoré.</span>\n;hasrelated:<span class=\"apihelp-deprecated\">Obsolète et ignoré.</span>",
+ "apihelp-query+search-param-prop": "Quelles propriétés renvoyer :",
+ "apihelp-query+search-paramvalue-prop-size": "Ajoute la taille de la page en octets.",
+ "apihelp-query+search-paramvalue-prop-wordcount": "Ajoute le nombre de mots de la page.",
+ "apihelp-query+search-paramvalue-prop-timestamp": "Ajoute l’horodatage de la dernière modification de la page.",
+ "apihelp-query+search-paramvalue-prop-snippet": "Ajoute un extrait analysé de la page.",
+ "apihelp-query+search-paramvalue-prop-titlesnippet": "Ajoute un extrait analysé du titre de la page.",
+ "apihelp-query+search-paramvalue-prop-redirectsnippet": "Ajoute un extrait analysé du titre de la redirection.",
+ "apihelp-query+search-paramvalue-prop-redirecttitle": "Ajoute le titre de la redirection correspondante.",
+ "apihelp-query+search-paramvalue-prop-sectionsnippet": "Ajoute un extrait analysé du titre de la section correspondante.",
+ "apihelp-query+search-paramvalue-prop-sectiontitle": "Ajoute le titre de la section correspondante.",
+ "apihelp-query+search-paramvalue-prop-categorysnippet": "Ajoute un extrait analysé de la catégorie correspondante.",
+ "apihelp-query+search-paramvalue-prop-isfilematch": "Ajoute un booléen indiquant si la recherche correspond au contenu du fichier.",
+ "apihelp-query+search-paramvalue-prop-score": "<span class=\"apihelp-deprecated\">Obsolète et ignoré.</span>",
+ "apihelp-query+search-paramvalue-prop-hasrelated": "<span class=\"apihelp-deprecated\">Obsolète et ignoré.</span>",
"apihelp-query+search-param-limit": "Combien de pages renvoyer au total.",
"apihelp-query+search-param-interwiki": "Inclure les résultats interwiki dans la recherche, s’ils sont disponibles.",
"apihelp-query+search-param-backend": "Quel serveur de recherche utiliser, si ce n’est pas celui par défaut.",
+ "apihelp-query+search-param-enablerewrites": "Activer la réécriture interne de la requête. Les serveurs de recherche peuvent changer la requête en une autre dont ils estiment qu'elle donne de meilleurs résultats, par exemple en corrigeant l'orthographe.",
"apihelp-query+search-example-simple": "Rechercher <kbd>signification </kbd>.",
"apihelp-query+search-example-text": "Rechercher des textes pour <kbd>signification</kbd>.",
"apihelp-query+search-example-generator": "Obtenir les informations sur les pages renvoyées par une recherche de <kbd>signification</kbd>.",
"apihelp-query+siteinfo-description": "Renvoyer les informations générales sur le site.",
- "apihelp-query+siteinfo-param-prop": "Quelles informations obtenir :\n;general:Information globale du système.\n;namespaces:Liste des espaces de nom déclarés et leur nom canonique.\n;namespacealiases:Liste des alias des espaces de nom déclarés.\n;specialpagealiases:Liste des alias des pages spéciales.\n;magicwords:Liste des mots magiques et leurs alias.\n;statistics:Renvoie les statistiques du site.\n;interwikimap:Renvoie la correspondance interwiki (éventuellement filtrée, éventuellement localisée en utilisant <var>$1inlanguagecode</var>).\n;dbrepllag:Renvoie le serveur de base de donnée avec la plus grande latence de réplication.\n;usergroups:Renvoie les groupes utilisateur et les droits associés.\n;libraries:Renvoie les bibliothèques installées sur le wiki.\n;extensions:Renvoie les extensions installées sur le wiki.\n;fileextensions:Renvoie la liste des extensions de fichier autorisées au téléchargement.\n;rightsinfo:Renvoie l’information sur les droits du wiki (sa licence), si elle est disponible.\n;restrictions:Renvoie l’information sur les types de restriction disponibles (protection).\n;languages:Renvoie une liste des langues que supporte MédiaWiki (éventuellement localisé en utilisant <var>$1inlanguagecode</var>).\n;skins:Renvoie une liste de tous les habillages activés (éventuellement localisé en utilisant <var>$1inlanguagecode</var>, sinon dans la langue du contenu).\n;extensiontags:Renvoie une liste des balises d’extension de l’analyseur.\n;functionhooks:Renvoie une liste des accroches de fonction de l’analyseur.\n;showhooks:Renvoie une liste de toutes les accroches souscrites (contenu de <var>[[mw:Manual:$wgHooks|$wgHooks]]</var>).\n;variables:Renvoie une liste des IDs de variable.\n;protocols:Renvoie une liste des protocoles qui sont autorisés dans les liens externes.\n;defaultoptions:Renvoie les valeurs par défaut pour les préférences utilisateur.",
+ "apihelp-query+siteinfo-param-prop": "Quelles informations obtenir :",
+ "apihelp-query+siteinfo-paramvalue-prop-general": "Information globale du système.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespaces": "Liste des espaces de nom déclarés et leur nom canonique.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespacealiases": "Liste des alias des espaces de nom déclarés.",
+ "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "Liste des alias des pages spéciales.",
+ "apihelp-query+siteinfo-paramvalue-prop-magicwords": "Liste des mots magiques et leurs alias.",
+ "apihelp-query+siteinfo-paramvalue-prop-statistics": "Renvoie les statistiques du site.",
+ "apihelp-query+siteinfo-paramvalue-prop-interwikimap": "Renvoie la correspondance interwiki (éventuellement filtrée, éventuellement localisée en utilisant <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-dbrepllag": "Renvoie le serveur de base de donnée avec la plus grande latence de réplication.",
+ "apihelp-query+siteinfo-paramvalue-prop-usergroups": "Renvoie les groupes utilisateur et les droits associés.",
+ "apihelp-query+siteinfo-paramvalue-prop-libraries": "Renvoie les bibliothèques installées sur le wiki.",
+ "apihelp-query+siteinfo-paramvalue-prop-extensions": "Renvoie les extensions installées sur le wiki.",
+ "apihelp-query+siteinfo-paramvalue-prop-fileextensions": "Renvoie la liste des extensions de fichier autorisées au téléchargement.",
+ "apihelp-query+siteinfo-paramvalue-prop-rightsinfo": "Renvoie l’information sur les droits du wiki (sa licence), si elle est disponible.",
+ "apihelp-query+siteinfo-paramvalue-prop-restrictions": "Renvoie l’information sur les types de restriction disponibles (protection).",
+ "apihelp-query+siteinfo-paramvalue-prop-languages": "Renvoie une liste des langues que supporte MédiaWiki (éventuellement localisé en utilisant <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-skins": "Renvoie une liste de tous les habillages activés (éventuellement localisé en utilisant <var>$1inlanguagecode</var>, sinon dans la langue du contenu).",
+ "apihelp-query+siteinfo-paramvalue-prop-extensiontags": "Renvoie une liste des balises d’extension de l’analyseur.",
+ "apihelp-query+siteinfo-paramvalue-prop-functionhooks": "Renvoie une liste des accroches de fonction de l’analyseur.",
+ "apihelp-query+siteinfo-paramvalue-prop-showhooks": "Renvoie une liste de toutes les accroches souscrites (contenu de <var>[[mw:Manual:$wgHooks|$wgHooks]]</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-variables": "Renvoie une liste des IDs de variable.",
+ "apihelp-query+siteinfo-paramvalue-prop-protocols": "Renvoie une liste des protocoles qui sont autorisés dans les liens externes.",
+ "apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Renvoie les valeurs par défaut pour les préférences utilisateur.",
"apihelp-query+siteinfo-param-filteriw": "Renvoyer uniquement les entrées locales ou uniquement les non locales de la correspondance interwiki.",
"apihelp-query+siteinfo-param-showalldb": "Lister tous les serveurs de base de données, pas seulement celui avec la plus grande latence.",
"apihelp-query+siteinfo-param-numberingroup": "Liste le nombre d’utilisateurs dans les groupes.",
@@ -825,7 +1021,14 @@
"apihelp-query+stashimageinfo-example-params": "Renvoie les vignettes pour deux fichiers mis en réserve",
"apihelp-query+tags-description": "Lister les balises de modification.",
"apihelp-query+tags-param-limit": "Le nombre maximal de balises à lister.",
- "apihelp-query+tags-param-prop": "Quelles propriétés récupérer :\n;name:Ajoute le nom de la balise.\n;displayname:Ajoute le message système pour la balise.\n;description:Ajoute la description de la balise.\n;hitcount:Ajoute le nombre de révisions et d’entrées du journal qui ont cette balise.\n;defined:Indique si la balise est définie.\n;source:Obtient les sources de la balise, ce qui comprend <samp>extension</samp> pour les balises définies par une extension et <samp>manual</samp> pour les balises pouvant être appliquées manuellement par les utilisateurs.\n;active:Si la balise est encore appliquée.",
+ "apihelp-query+tags-param-prop": "Quelles propriétés récupérer :",
+ "apihelp-query+tags-paramvalue-prop-name": "Ajoute le nom de la balise.",
+ "apihelp-query+tags-paramvalue-prop-displayname": "Ajoute le message système pour la balise.",
+ "apihelp-query+tags-paramvalue-prop-description": "Ajoute la description de la balise.",
+ "apihelp-query+tags-paramvalue-prop-hitcount": "Ajoute le nombre de révisions et d’entrées du journal qui ont cette balise.",
+ "apihelp-query+tags-paramvalue-prop-defined": "Indique si la balise est définie.",
+ "apihelp-query+tags-paramvalue-prop-source": "Obtient les sources de la balise, ce qui comprend <samp>extension</samp> pour les balises définies par une extension et <samp>manual</samp> pour les balises pouvant être appliquées manuellement par les utilisateurs.",
+ "apihelp-query+tags-paramvalue-prop-active": "Si la balise est encore appliquée.",
"apihelp-query+tags-example-simple": "Lister les balises disponibles",
"apihelp-query+templates-description": "Renvoie toutes les pages incluses dans les pages fournies.",
"apihelp-query+templates-param-namespace": "Afficher les modèles uniquement dans ces espaces de nom.",
@@ -840,7 +1043,10 @@
"apihelp-query+tokens-example-simple": "Récupérer un jeton csrf (par défaut)",
"apihelp-query+tokens-example-types": "Récupérer un jeton de suivi et un de patrouille",
"apihelp-query+transcludedin-description": "Trouver toutes les pages qui incluent les pages données.",
- "apihelp-query+transcludedin-param-prop": "Quelles propriétés obtenir :\n;pageid:ID de page de chaque page.\n;title:Titre de chaque page.\n;redirect:Marque si cette page est une redirection.",
+ "apihelp-query+transcludedin-param-prop": "Quelles propriétés obtenir :",
+ "apihelp-query+transcludedin-paramvalue-prop-pageid": "ID de page de chaque page.",
+ "apihelp-query+transcludedin-paramvalue-prop-title": "Titre de chaque page.",
+ "apihelp-query+transcludedin-paramvalue-prop-redirect": "Marque si cette page est une redirection.",
"apihelp-query+transcludedin-param-namespace": "Inclure uniquement les pages dans ces espaces de nom.",
"apihelp-query+transcludedin-param-limit": "Combien en renvoyer.",
"apihelp-query+transcludedin-param-show": "Afficher uniquement les éléments qui correspondent à ces critères:\n;redirect:Afficher uniquement les redirections.\n;!redirect:Afficher uniquement les non-redirections.",
@@ -853,18 +1059,51 @@
"apihelp-query+usercontribs-param-user": "Les utilisateurs pour lesquels récupérer les contributions.",
"apihelp-query+usercontribs-param-userprefix": "Récupérer les contributions pour tous les utilisateurs dont les noms commencent par cette valeur. Écrase $1user.",
"apihelp-query+usercontribs-param-namespace": "Lister uniquement les contributions dans ces espaces de nom.",
- "apihelp-query+usercontribs-param-prop": "Inclure des informations supplémentaires:\n;ids:Ajoute l’ID de page et l’ID de révision.\n;title:Ajoute le titre et l’ID d’espace de noms de la page.\n;timestamp:Ajoute l’horodatage de la modification.\n;comment:Ajoute le commentaire de la modification.\n;parsedcomment:Ajoute le commentaire analysé de la modification.\n;size:Ajoute la nouvelle taille de la modification.\n;sizediff:Ajoute le delta de taille de la modification par rapport à son parent.\n;flags:Ajoute les marques de la modification.\n;patrolled:Marque les modifications patrouillées.\n;tags:Liste les balises de la modification.",
+ "apihelp-query+usercontribs-param-prop": "Inclure des informations supplémentaires:",
+ "apihelp-query+usercontribs-paramvalue-prop-ids": "Ajoute l’ID de page et l’ID de révision.",
+ "apihelp-query+usercontribs-paramvalue-prop-title": "Ajoute le titre et l’ID d’espace de noms de la page.",
+ "apihelp-query+usercontribs-paramvalue-prop-timestamp": "Ajoute l’horodatage de la modification.",
+ "apihelp-query+usercontribs-paramvalue-prop-comment": "Ajoute le commentaire de la modification.",
+ "apihelp-query+usercontribs-paramvalue-prop-parsedcomment": "Ajoute le commentaire analysé de la modification.",
+ "apihelp-query+usercontribs-paramvalue-prop-size": "Ajoute la nouvelle taille de la modification.",
+ "apihelp-query+usercontribs-paramvalue-prop-sizediff": "Ajoute le delta de taille de la modification par rapport à son parent.",
+ "apihelp-query+usercontribs-paramvalue-prop-flags": "Ajoute les marques de la modification.",
+ "apihelp-query+usercontribs-paramvalue-prop-patrolled": "Marque les modifications patrouillées.",
+ "apihelp-query+usercontribs-paramvalue-prop-tags": "Liste les balises de la modification.",
"apihelp-query+usercontribs-param-show": "Afficher uniquement les éléments correspondant à ces critères, par ex. les modifications non mineures uniquement : <kbd>$2show=!minor</kbd>.\n\nSi <kbd>$2show=patrolled</kbd> ou <kbd>$2show=!patrolled</kbd> est positionné, les révisions plus anciennes que <var>[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|seconde|secondes}}) ne seront pas affichées.",
"apihelp-query+usercontribs-param-tag": "Lister uniquement les révisions marquées avec cette balise.",
"apihelp-query+usercontribs-param-toponly": "Lister uniquement les modifications qui sont la dernière révision.",
"apihelp-query+usercontribs-example-user": "Afficher les contributions de l'utilisateur <kbd>Exemple</kbd>.",
"apihelp-query+usercontribs-example-ipprefix": "Afficher les contributions de toutes les adresses IP avec le préfixe <kbd>192.0.2.</kbd>.",
"apihelp-query+userinfo-description": "Obtenir de l’information sur l’utilisateur courant.",
- "apihelp-query+userinfo-param-prop": "Quelles informations inclure :\n;blockinfo:Marque si l’utilisateur actuel est bloqué, par qui, et pour quelle raison.\n;hasmsg:Ajoute une balise <samp>message</samp> si l’utilisateur actuel a des messages en cours.\n;groups:Liste tous les groupes auxquels appartient l’utilisateur actuel.\n;implicitgroups:Liste tous les groupes dont l’utilisateur actuel est automatiquement membre.\n;rights:Liste tous les droits qu’a l’utilisateur actuel.\n;changeablegroups:Liste les groupes pour lesquels l’utilisateur actuel peut ajouter ou supprimer.\n;options:Liste toutes les préférences qu’a défini l’utilisateur actuel.\n;preferencestoken:<span class=\"apihelp-deprecated\">Obsolete.</span> Obtient un jeton pour modifier les préférences de l’utilisateur actuel.\n;editcount:Ajoute le compteur de modifications de l’utilisateur actuel.\n;ratelimits:Liste toutes les limites de débit s’appliquant à l’utilisateur actuel.\n;realname:Ajoute le vrai nom de l’utilisateur actuel.\n;email:Ajoute l’adresse de courriel de l’utilisateur et sa date d’authentification.\n;acceptlang:Renvoie en écho l’entête <code>Accept-Language</code> envoyé par le client dans un format structuré.\n;registrationdate:Ajoute la date d’inscription de l’utilisateur.\n;unreadcount:Ajoute le compteur de pages non lues de la liste de suivi de l’utilisateur (au maximum $1 ; renvoie <samp>$2</samp> s’il y en a plus).",
+ "apihelp-query+userinfo-param-prop": "Quelles informations inclure :",
+ "apihelp-query+userinfo-paramvalue-prop-blockinfo": "Marque si l’utilisateur actuel est bloqué, par qui, et pour quelle raison.",
+ "apihelp-query+userinfo-paramvalue-prop-hasmsg": "Ajoute une balise <samp>messages</samp> si l’utilisateur actuel a des messages en cours.",
+ "apihelp-query+userinfo-paramvalue-prop-groups": "Liste tous les groupes auxquels appartient l’utilisateur actuel.",
+ "apihelp-query+userinfo-paramvalue-prop-implicitgroups": "Liste tous les groupes dont l’utilisateur actuel est automatiquement membre.",
+ "apihelp-query+userinfo-paramvalue-prop-rights": "Liste tous les droits qu’a l’utilisateur actuel.",
+ "apihelp-query+userinfo-paramvalue-prop-changeablegroups": "Liste les groupes pour lesquels l’utilisateur actuel peut ajouter ou supprimer.",
+ "apihelp-query+userinfo-paramvalue-prop-options": "Liste toutes les préférences qu’a défini l’utilisateur actuel.",
+ "apihelp-query+userinfo-paramvalue-prop-preferencestoken": "<span class=\"apihelp-deprecated\">Obsolete.</span> Obtenir un jeton pour modifier les préférences de l’utilisateur actuel.",
+ "apihelp-query+userinfo-paramvalue-prop-editcount": "Ajoute le compteur de modifications de l’utilisateur actuel.",
+ "apihelp-query+userinfo-paramvalue-prop-ratelimits": "Liste toutes les limites de débit s’appliquant à l’utilisateur actuel.",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "Ajoute le vrai nom de l’utilisateur actuel.",
+ "apihelp-query+userinfo-paramvalue-prop-email": "Ajoute l’adresse de courriel de l’utilisateur et sa date d’authentification.",
+ "apihelp-query+userinfo-paramvalue-prop-acceptlang": "Renvoie en écho l’entête <code>Accept-Language</code> envoyé par le client dans un format structuré.",
+ "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Ajoute la date d’inscription de l’utilisateur.",
+ "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Ajoute le compteur de pages non lues de la liste de suivi de l’utilisateur (au maximum $1 ; renvoie <samp>$2</samp> s’il y en a plus).",
"apihelp-query+userinfo-example-simple": "Obtenir de l’information sur l’utilisateur actuel",
"apihelp-query+userinfo-example-data": "Obtenir des informations supplémentaires sur l’utilisateur actuel",
"apihelp-query+users-description": "Obtenir des information sur une liste d’utilisateurs",
- "apihelp-query+users-param-prop": "Quelles informations inclure :\n;blockinfo:Marque si l’utilisateur est bloqué, par qui, et pour quelle raison.\n;groups:Liste tous les groupes auquel appartient chaque utilisateur.\n;implicitgroups:Liste tous les groupes dont un utilisateur est automatiquement membre.\n;rights:Liste tous les droits qu’a un utilisateur.\n;editcount:Ajoute le compteur de modifications de l’utilisateur.\n;registration:Ajoute l’horodatage d’inscription de l’utilisateur.\n;emailable:Marque si l’utilisateur peut et veut recevoir des courriels via [[Special:Emailuser]].\n;gender:Marque le sexe de l’utilisateur. Renvoie « male », « female », ou « unknown ».",
+ "apihelp-query+users-param-prop": "Quelles informations inclure :",
+ "apihelp-query+users-paramvalue-prop-blockinfo": "Marque si l’utilisateur est bloqué, par qui, et pour quelle raison.",
+ "apihelp-query+users-paramvalue-prop-groups": "Liste tous les groupes auquel appartient chaque utilisateur.",
+ "apihelp-query+users-paramvalue-prop-implicitgroups": "Liste tous les groupes dont un utilisateur est automatiquement membre.",
+ "apihelp-query+users-paramvalue-prop-rights": "Liste tous les droits qu’a un utilisateur.",
+ "apihelp-query+users-paramvalue-prop-editcount": "Ajoute le compteur de modifications de l’utilisateur.",
+ "apihelp-query+users-paramvalue-prop-registration": "Ajoute l’horodatage d’inscription de l’utilisateur.",
+ "apihelp-query+users-paramvalue-prop-emailable": "Marque si l’utilisateur peut et veut recevoir des courriels via [[Special:Emailuser]].",
+ "apihelp-query+users-paramvalue-prop-gender": "Marque le sexe de l’utilisateur. Renvoie « male », « female », ou « unknown ».",
"apihelp-query+users-param-users": "Une liste des utilisateurs sur lesquels obtenir de l’information.",
"apihelp-query+users-param-token": "Utiliser plutôt <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
"apihelp-query+users-example-simple": "Renvoyer des informations pour l'utilisateur <kbd>Exemple</kbd>.",
@@ -876,9 +1115,21 @@
"apihelp-query+watchlist-param-user": "Lister uniquement les modifications par cet utilisateur.",
"apihelp-query+watchlist-param-excludeuser": "Ne pas lister les modifications faites par cet utilisateur.",
"apihelp-query+watchlist-param-limit": "Combien de résultats au total renvoyer par demande.",
- "apihelp-query+watchlist-param-prop": "Quels éléments supplémentaires obtenir :\n;ids:Ajoute les IDs de révision et de page.\n;title:Ajoute le titre de la page.\n;flags:Ajoute les marques de la modification.\n;user:Ajoute l’utilisateur ayant fait la modification.\n;userid:Ajoute l’ID de l’utilisateur ayant fait la modification.\n;comment:Ajoute le commentaire de la modification.\n;parsedcomment:Ajoute le commentaire analysé de la modification.\n;timestamp:Ajoute l’horodatage de la modification.\n;patrol:Marque les modifications patrouillées.\n;sizes:Ajoute les ancienne et nouvelle tailles de la page.\n;notificationtimestamp:Ajoute l’horodatage de quand l’utilisateur a été notifié de la modification la dernière fois.\n;loginfo:Ajoute l’information du journal quand c’est approprié.",
+ "apihelp-query+watchlist-param-prop": "Quelles propriétés supplémentaires obtenir :",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "Ajoute les IDs de révision et de page",
+ "apihelp-query+watchlist-paramvalue-prop-title": "Ajoute le titre de la page.",
+ "apihelp-query+watchlist-paramvalue-prop-flags": "Ajoute les marqueurs de la modification.",
+ "apihelp-query+watchlist-paramvalue-prop-user": "Ajoute l’utilisateur ayant fait la modification.",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "Ajoute l’ID de l’utilisateur ayant fait la modification.",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "Ajoute le commentaire de la modification.",
+ "apihelp-query+watchlist-paramvalue-prop-parsedcomment": "Ajoute le commentaire analysé de la modification.",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "Ajoute l’horodatage de la modification.",
+ "apihelp-query+watchlist-paramvalue-prop-patrol": "Marque les modifications patrouillées.",
+ "apihelp-query+watchlist-paramvalue-prop-sizes": "Ajoute les tailles ancienne et nouvelle de la page.",
+ "apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "Ajoute l’horodatage de la dernière notification de la modification à l’utilisateur.",
+ "apihelp-query+watchlist-paramvalue-prop-loginfo": "Ajoute l’information de trace le cas échéant.",
"apihelp-query+watchlist-param-show": "Afficher uniquement les éléments qui correspondent à ces critères. Par exemple, pour voir uniquement les modifications mineures faites par des utilisateurs connectés, mettre $1show=minor|!anon.",
- "apihelp-query+watchlist-param-type": "Quels types de modification afficher :\n;edit:Modifications de page normale.\n;external:Modifications externes.\n;new:Créations de page.\n;log:Entrées du journal.",
+ "apihelp-query+watchlist-param-type": "Quels types de modification afficher :\n;edit:Modifications ordinaires de page.\n;external:Modifications externes.\n;new:Créations de page.\n;log:Entrées du journal.",
"apihelp-query+watchlist-param-owner": "Utilisé avec $1token pour accéder à la liste de suivi d’un autre utilisateur.",
"apihelp-query+watchlist-param-token": "Un jeton de sécurité (disponible dans les [[Special:Preferences#mw-prefsection-watchlist|préférences]] de l’utilsiateur) pour autoriser l’accès à la liste de suivi d&un autre utilisateur.",
"apihelp-query+watchlist-example-simple": "Lister la révision de tête des pages récemment modifiées dans la liste de suivi de l’utilisateur actuel",
@@ -890,10 +1141,13 @@
"apihelp-query+watchlistraw-description": "Obtenir toutes les pages de la liste de suivi de l’utilisateur actuel.",
"apihelp-query+watchlistraw-param-namespace": "Lister uniquement les pages dans les espaces de nom fournis.",
"apihelp-query+watchlistraw-param-limit": "Combien de résultats renvoyer au total par requête.",
- "apihelp-query+watchlistraw-param-prop": "Quelles propriétés supplémentaires obtenir :\n;changed:Ajoute l’horodatage de la dernière notification de l’utilisateur à propos de la modification.",
+ "apihelp-query+watchlistraw-param-prop": "Quelles propriétés supplémentaires obtenir :",
+ "apihelp-query+watchlistraw-paramvalue-prop-changed": "Ajoute l’horodatage de la dernière notification de l’utilisateur à propos de la modification.",
"apihelp-query+watchlistraw-param-show": "Lister uniquement les éléments correspondant à ces critères.",
"apihelp-query+watchlistraw-param-owner": "Utilisé avec $1token pour accéder à la liste de suivi d’un autre utilisateur.",
"apihelp-query+watchlistraw-param-token": "Un jeton de sécurité (disponible dans les [[Special:Preferences#mw-prefsection-watchlist|préférences]] de l’utilisateur) pour permettre l’accès à la liste de suivi d’un autre utilisateur.",
+ "apihelp-query+watchlistraw-param-fromtitle": "Démarrer l'énumération avec ce Titre (inclure le préfixe d'espace de noms) :",
+ "apihelp-query+watchlistraw-param-totitle": "Terminer l'énumération avec ce Titre (inclure le préfixe d'espace de noms) :",
"apihelp-query+watchlistraw-example-simple": "Lister les pages dans la liste de suivi de l’utilisateur actuel",
"apihelp-query+watchlistraw-example-generator": "Chercher l’information sur les pages de la liste de suivi de l’utilisateur actuel",
"apihelp-revisiondelete-description": "Supprimer et annuler la suppression des révisions.",
@@ -917,7 +1171,7 @@
"apihelp-rollback-example-summary": "Annuler les dernières modifications de la page <kbd>Main Page</kbd> par l’utilisateur à l’adresse IP <kbd>192.0.2.5</kbd> avec le résumé <kbd>Annulation de vandalisme<kbd>, et marquer ces modifications et l’annulation comme modifications de robots.",
"apihelp-rsd-description": "Exporter un schéma RSD (Découverte Très Simple).",
"apihelp-rsd-example-simple": "Exporter le schéma RSD",
- "apihelp-setnotificationtimestamp-description": "Mettre à jour l’horodatage de notification pour les pages suivies.\n\nCela affecte la mise en évidence des pages modifiées dans la liste de suivi et l’historique, et l’envoi de courriel quand la préférence « M’envoyer un courriel quand une page de ma liste de suivi est modifiée » est activée.",
+ "apihelp-setnotificationtimestamp-description": "Mettre à jour l’horodatage de notification pour les pages suivies.\n\nCela affecte la mise en évidence des pages modifiées dans la liste de suivi et l’historique, et l’envoi de courriel quand la préférence « {{int:tog-enotifwatchlistpages}} » est activée.",
"apihelp-setnotificationtimestamp-param-entirewatchlist": "Travailler sur toutes les pages suivies.",
"apihelp-setnotificationtimestamp-param-timestamp": "Horodatage auquel dater la notification.",
"apihelp-setnotificationtimestamp-param-torevid": "Révision pour laquelle fixer l’horodatage de notification (une page uniquement).",
@@ -926,6 +1180,15 @@
"apihelp-setnotificationtimestamp-example-page": "Réinitialiser l’état de notification pour la <kbd>Page principale<kbd>.",
"apihelp-setnotificationtimestamp-example-pagetimestamp": "Fixer l’horodatage de notification pour <kbd>Page principale</kbd> afin que toutes les modifications depuis le 1 janvier 2012 soient non vues",
"apihelp-setnotificationtimestamp-example-allpages": "Réinitialiser l’état de notification sur les pages dans l’espace de noms <kbd>{{ns:user}}</kbd>.",
+ "apihelp-tag-description": "Ajouter ou enlever des balises de modification aux révisions ou ou aux entrées de journal individuelles.",
+ "apihelp-tag-param-rcid": "Un ou plus IDs de modification récente à partir desquels ajouter ou supprimer la balise.",
+ "apihelp-tag-param-revid": "Un ou plus IDs de révision à partir desquels ajouter ou supprimer la balise.",
+ "apihelp-tag-param-logid": "Un ou plus IDs d’entrée de journal à partir desquels ajouter ou supprimer la balise.",
+ "apihelp-tag-param-add": "Balises à ajouter. Seules les balises définies manuellement peuvent être ajoutées.",
+ "apihelp-tag-param-remove": "Balises à supprimer. Seules les balises qui sont soit définies manuellement soit pas du tout définies peuvent être supprimées.",
+ "apihelp-tag-param-reason": "Motif de la modification.",
+ "apihelp-tag-example-rev": "Ajoute la balise <kbd>vandalism</kbd> à partir de l’ID de révision 123 sans indiquer de motif",
+ "apihelp-tag-example-log": "Supprimer la balise <kbd>spam</kbd> à partir de l’ID d’entrée de journal 123 avec le motif <kbd>Wrongly applied</kbd>",
"apihelp-tokens-description": "Obtenir les jetons pour les actions modifiant les données.\n\nCe module est obsolète, remplacé par [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
"apihelp-tokens-param-type": "Types de jeton à demander.",
"apihelp-tokens-example-edit": "Récupérer un jeton de modification (par défaut).",
@@ -944,7 +1207,7 @@
"apihelp-undelete-param-watchlist": "Ajouter ou supprimer la page de la liste de suivi de l’utilisateur actuel sans condition, utiliser les préférences ou ne pas modifier le suivi.",
"apihelp-undelete-example-page": "Annuler la suppression de la page <kbd>Main Page</kbd>.",
"apihelp-undelete-example-revisions": "Annuler la suppression de deux révisions de la page <kbd>Main Page</kbd>.",
- "apihelp-upload-description": "Télécharger un fichier, ou obtenir l’état des téléchargements en cours.\n\nPlusieurs méthodes sont disponibles :\n* Télécharger directement le contenu du fichier, en utilisant le paramètre <var>$1file</var>.\n* Télécharger le fichier par morceaux, en utilsiant les paramètres <var>$1filesize</var>, <var>$1chunk</var>, and <var>$1offset</var>.* Pour que le serveur MédiaWiki cherche un fichier depuis une URL, utiliser le paramètre <var>$1url</var>.\n* Terminer un téléchargement précédent qui a échoué à cause d’avertissements, en utilisant le paramètre <var>$1filekey</var>.\nNoter que le POST HTTP doit être fait comme un téléchargement de fichier (par ex. en utilisant <code>multipart/form-data</code>) en envoyant le <code>multipart/form-data</code>.",
+ "apihelp-upload-description": "Téléverser un fichier, ou obtenir l’état des téléversements en cours.\n\nPlusieurs méthodes sont disponibles :\n* Téléverser directement le contenu du fichier, en utilisant le paramètre <var>$1file</var>.\n* Téléverser le fichier par morceaux, en utilisant les paramètres <var>$1filesize</var>, <var>$1chunk</var>, and <var>$1offset</var>.\n* Pour que le serveur MédiaWiki cherche un fichier depuis une URL, utilisez le paramètre <var>$1url</var>.\n* Terminer un téléversement précédent qui a échoué à cause d’avertissements, en utilisant le paramètre <var>$1filekey</var>.\nNoter que le POST HTTP doit être fait comme un téléversement de fichier (par ex. en utilisant <code>multipart/form-data</code>) en envoyant le <code>multipart/form-data</code>.",
"apihelp-upload-param-filename": "Nom de fichier cible.",
"apihelp-upload-param-comment": "Télécharger le commentaire. Utilisé aussi comme texte de la page initiale pour les nouveaux fichiers si <var>$1text</var> n’est pas spécifié.",
"apihelp-upload-param-text": "Texte de page initiale pour les nouveaux fichiers.",
@@ -980,31 +1243,31 @@
"apihelp-watch-example-watch": "Suivre la page <kbd>Page principale</kbd>.",
"apihelp-watch-example-unwatch": "Ne plus suivre la page <kbd>Page principale</kbd>.",
"apihelp-watch-example-generator": "Suivre les quelques premières pages de l’espace de nom principal",
- "apihelp-format-example-generic": "Mettre en forme le résultat de la requête dans le format $1",
+ "apihelp-format-example-generic": "Renvoyer le résultat de la requête dans le format $1.",
"apihelp-dbg-description": "Extraire les données au format de <code>var_export()</code> de PHP.",
"apihelp-dbgfm-description": "Extraire les données au format de <code>var_export()</code> de PHP (affiché proprement en HTML).",
- "apihelp-dump-description": "Extraire les données au format de <code>var_dump()</code> de PHP.",
- "apihelp-dumpfm-description": "Extraire les données au format de <code>var_dump()</code> de PHP (affiché proprement en HTML).",
"apihelp-json-description": "Extraire les données au format JSON.",
"apihelp-json-param-callback": "Si spécifié, inclut la sortie dans l’appel d’une fonction fournie. Pour plus de sûreté, toutes les données spécifiques à l’utilisateur seront restreintes.",
- "apihelp-json-param-utf8": "Si spécifié, encode la plupart (mais pas tous) des caractères non ASCII en URF-8 au lieu de les remplacer par leur séquence d’échappement hexadécimale.",
+ "apihelp-json-param-utf8": "Si spécifié, encode la plupart (mais pas tous) des caractères non ASCII en URF-8 au lieu de les remplacer par leur séquence d’échappement hexadécimale. Valeur par défaut quand <var>formatversion</var> ne vaut pas <kbd>1</kbd>.",
+ "apihelp-json-param-ascii": "Si spécifié, encode toutes ses séquences d’échappement non ASCII utilisant l’hexadécimal. Valeur par défaut quand <var>formatversion</var> vaut <kbd>1</kbd>.",
+ "apihelp-json-param-formatversion": "Mise en forme de sortie :\n;1:Format rétro-compatible (booléens de style XML, clés <samp>*</samp> pour les nœuds de contenu, etc.).\n;2:Format moderne expérimental. Des détails peuvent changer !\n;latest:Utilise le dernier format (actuellement <kbd>2</kbd>), peut changer sans avertissement.",
"apihelp-jsonfm-description": "Extraire les données au format JSON (affiché proprement en HTML).",
"apihelp-none-description": "Ne rien extraire.",
"apihelp-php-description": "Extraire les données au format sérialisé de PHP.",
+ "apihelp-php-param-formatversion": "Mise en forme de la sortie :\n;1:Format rétro-compatible (bool&ens de style XML, clés <samp>*</samp> pour les nœuds de contenu, etc.).\n;2:Format moderne expérimental. Des détails peuvent changer !\n;latest:Utilise le dernier format (actuellement <kbd>2</kbd>), peut changer sans avertissement.",
"apihelp-phpfm-description": "Extraire les données au format sérialisé de PHP (affiché proprement en HTML).",
"apihelp-rawfm-description": "Extraire les données avec les éléments de débogage au format JSON (affiché proprement en HTML).",
"apihelp-txt-description": "Extraire les données au format de <code>print_r()</code> de PHP.",
"apihelp-txtfm-description": "Extraire les données au format de <code>print_r()</code> de PHP (affiché proprement en HTML).",
- "apihelp-wddx-description": "Extraire les données au format WDDX.",
- "apihelp-wddxfm-description": "Extraire les données au format WDDX (affiché proprement en HTML).",
"apihelp-xml-description": "Extraire les données au format XML.",
"apihelp-xml-param-xslt": "Si spécifié, ajoute la page nommée comme une feuille de style XSL. La valeur doit être un titre dans l’espace de noms {{ns:mediawiki}} se terminant par <code>.xsl</code>.",
"apihelp-xml-param-includexmlnamespace": "Si spécifié, ajoute un espace de noms XML.",
"apihelp-xmlfm-description": "Extraire les données au format XML (affiché proprement en HTML).",
"apihelp-yaml-description": "Extraire les données au format YAML.",
"apihelp-yamlfm-description": "Extraire les données YAML (affiché proprement en HTML).",
- "api-format-title": "Résultat de l’API de MédiaWiki",
+ "api-format-title": "Résultat de l’API de MediaWiki",
"api-format-prettyprint-header": "Voici la représentation HTML du format $1. HTML est utile pour le débogage, mais inapproprié pour être utilisé dans une application.\n\nSpécifiez le paramètre <var>format</var> pour modifier le format de sortie. Pour voir la représentation non HTML du format $1, mettez <kbd>format=$2</kbd>.\n\nVoyez la [[mw:API|documentation complète]], ou l’[[Special:ApiHelp/main|aide de l’API]] pour plus d’information.",
+ "api-format-prettyprint-header-only-html": "Ceci est une représentation HTML à des fins de déboguage, et n’est pas approprié à une utilisation applicative.\n\nVoir la [[mw:API|documentation complète]], ou l’[[Special:ApiHelp/main|aide de l’API]] pour plus d’information.",
"api-orm-param-props": "Champs à rechercher.",
"api-orm-param-limit": "Nombre maximal de lignes à renvoyer.",
"api-pageset-param-titles": "Une liste des titres sur lesquels travailler.",
@@ -1015,7 +1278,7 @@
"api-pageset-param-redirects-nogenerator": "Résoudre automatiquement les redirections dans <var>$1titles</var>, <var>$1pageids</var> et <var>$1revids</var>.",
"api-pageset-param-converttitles": "Convertir les titres dans d’autres variantes si nécessaire. Fonctionne uniquement si la langue de contenu du wiki supporte la conversion en variantes. Les langues qui supportent la conversion en variante incluent $1.",
"api-help-title": "Aide de l’API de MediaWiki",
- "api-help-lead": "Ceci est une page d’aide de l’API de MédiaWiki générée automatiquement.\n\nDocumentation et exemples : https://www.mediawiki.org/wiki/API",
+ "api-help-lead": "Ceci est une page d’aide de l’API de MediaWiki générée automatiquement.\n\nDocumentation et exemples : https://www.mediawiki.org/wiki/API",
"api-help-main-header": "Module principal",
"api-help-flag-deprecated": "Ce module est obsolète.",
"api-help-flag-internal": "<strong>Ce module est interne ou instable.</strong> Son fonctionnement peut être modifié sans préavis.",
@@ -1023,10 +1286,22 @@
"api-help-flag-writerights": "Ce module nécessite des droits d’écriture.",
"api-help-flag-mustbeposted": "Ce module n’accepte que les requêtes POST.",
"api-help-flag-generator": "Ce module peut être utilisé comme générateur.",
+ "api-help-source": "Source : $1",
+ "api-help-source-unknown": "Source : <span class=\"apihelp-unknown\">inconnue</span>",
+ "api-help-license": "Licence : [[$1|$2]]",
+ "api-help-license-noname": "Licence : [[$1|Voir le lien]]",
+ "api-help-license-unknown": "Licence : <span class=\"apihelp-unknown\">inconnue</span>",
"api-help-parameters": "{{PLURAL:$1|Paramètre|Paramètres}} :",
"api-help-param-deprecated": "Obsolète.",
"api-help-param-required": "Ce paramètre est obligatoire.",
- "api-help-param-list": "{{PLURAL:$1|1=Une valeur|2=Valeurs (séparées par <kbd>{{!}}</kbd>)}} : $2",
+ "api-help-datatypes-header": "Type de données",
+ "api-help-datatypes": "Certains types de paramètre dans les requêtes de l’API nécessitent plus d’explication :\n;boolean\n:Les paramètres booléens fonctionnent comme des cases à cocher HTML : si le paramètre est spécifié, quelle que soit sa valeur, il est considéré comme vrai. Pour une valeur fausse, enlever complètement le paramètre.\n;timestamp\n:Les horodatages peuvent être spécifiés sous différentes formes. Date et heure ISO 8601 est recommandé. Toutes les heures sont en UTC, tout fuseau horaire inclus est ignoré.\n:* Date et heure ISO 8601, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (la ponctuation et <kbd>Z</kbd> sont facultatifs)\n:* Date et heure ISO 8601 avec fractions de seconde (ignorées), <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> (tirets, deux-points et <kbd>Z</kbd> sont facultatifs)\n:* Format MédiaWiki, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Format numérique générique, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (fuseau horaire facultatif en <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd>, ou <kbd>-<var>##</var></kbd> sont ignorés)\n:* Format EXIF, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:*Format RFC 2822 (le fuseau horaire est facultatif), <kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Format RFC 850 (le fuseau horaire est facultatif), <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Format 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:* Secondes depuis 1970-01-01T00:00:00Z sous forme d’entier de 1 à 13 chiffres (sans <kbd>0</kbd>)\n:* La chaîne <kbd>now</kbd>",
+ "api-help-param-type-limit": "Type : entier ou <kbd>max</kbd>",
+ "api-help-param-type-integer": "Type : {{PLURAL:$1|1=entier|2=liste d’entiers}}",
+ "api-help-param-type-boolean": "Type : booléen ([[Special:ApiHelp/main#main/datatypes|détails]])",
+ "api-help-param-type-timestamp": "Type : {{PLURAL:$1|1=horodatage|2=liste d’horodatages}} ([[Special:ApiHelp/main#main/datatypes|formats autorisés]])",
+ "api-help-param-type-user": "Type : {{PLURAL:$1|1=nom d’utilisateur|2=liste de noms d’utilisateur}}",
+ "api-help-param-list": "{{PLURAL:$1|1=Une des valeurs suivantes|2=Valeurs (séparées par <kbd>{{!}}</kbd>)}} : $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Doit être vide|Peut être vide, ou $2}}",
"api-help-param-limit": "Pas plus de $1 autorisé.",
"api-help-param-limit2": "Pas plus de $1 autorisé ($2 pour les robots).",
diff --git a/includes/api/i18n/gl.json b/includes/api/i18n/gl.json
index 065ced32..6b6345d0 100644
--- a/includes/api/i18n/gl.json
+++ b/includes/api/i18n/gl.json
@@ -6,15 +6,18 @@
"Chairego apc",
"VaiPolaSombra",
"Banjo",
- "Fisterraeomar"
+ "Fisterraeomar",
+ "Toliño",
+ "Umherirrender",
+ "Amire80"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentación]]\n* [[mw: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 funcionanado, 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:API:Errors_and_warnings|API: Erros e avisos]].",
"apihelp-main-param-action": "Que acción se realizará.",
"apihelp-main-param-format": "O formato de saída.",
"apihelp-main-param-maxlag": "O retardo máximo pode usarse cando MediaWiki está instalada nun cluster de base de datos replicadas. Para gardar accións que causen calquera retardo máis de replicación do sitio, este parámetro pode facer que o cliente espere ata que o retardo de replicación sexa menor que o valor especificado. No caso de retardo excesivo, é devolto o código de erro <samp>maxlag</samp> cunha mensaxe como <samp>esperando por $host: $lag segundos de retardo</samp>.<br />Para máis información, ver [[mw:Manual:Maxlag_parameter|Manual: Maxlag parameter]].",
- "apihelp-main-param-smaxage": "Fixar a cabeceira <code>s-maxage</code> a esos segundos. Os erros nunca se gardan na caché.",
- "apihelp-main-param-maxage": "Fixar a cabeceira <code>max-age</code> a esos segundos. Os erros nunca se gardan na caché.",
+ "apihelp-main-param-smaxage": "Fixar a cabeceira HTTP de control de caché <code>s-maxage</code> a esos segundos. Os erros nunca se gardan na caché.",
+ "apihelp-main-param-maxage": "Fixar a cabeceira HTTP de control de caché <code>max-age</code> a esos segundos. Os erros nunca se gardan na caché.",
"apihelp-main-param-assert": "Verificar se o usuario está conectado como <kbd>usuario</kbd> ou ten a marca de <kbd>bot</kbd>.",
"apihelp-main-param-requestid": "Calquera valor dado aquí será incluído na resposta. Pode usarse para distingir peticións.",
"apihelp-main-param-servedby": "Inclúa o nome do servidor que servía a solicitude nos resultados.",
@@ -80,6 +83,7 @@
"apihelp-edit-param-sectiontitle": "Título para unha nova sección.",
"apihelp-edit-param-text": "Contido da páxina.",
"apihelp-edit-param-summary": "Resumo de edición. Tamén título de sección cando $1section=new e $1sectiontitle non está definido.",
+ "apihelp-edit-param-tags": "Cambio de etiquetas a aplicar á revisión.",
"apihelp-edit-param-minor": "Edición pequena.",
"apihelp-edit-param-notminor": "Edición non pequena.",
"apihelp-edit-param-bot": "Marcar esta edición como de bot.",
@@ -113,7 +117,16 @@
"apihelp-expandtemplates-param-title": "Título da páxina.",
"apihelp-expandtemplates-param-text": "Sintaxis wiki a converter.",
"apihelp-expandtemplates-param-revid": "ID de revisión, para <nowiki>{{REVISIONID}}</nowiki> e variables similares.",
- "apihelp-expandtemplates-param-prop": "Pezas de información a retornar:\n;wikitext:O texto wiki expandido.\n;categories:Calquer categoría presente na entrada que non estea representada na saída do texto wiki\n;properties:Propiedades da páxina definidas por palabras máxicas expandidas no texto wiki\n;volatile:Definir se a saída é volátil e se non debe usarse noutra parte da páxina.\n;ttl:Tempo máximo a partir do cal os cachés do resultado deben invalidarse.\n;parsetree:O análise sintáctico en árbore do XML de entrada.\nTeña en conta que se non se selecciona ningún valor o resultado conterá o texto wiki, pero a saída estará nun formato desprezado.",
+ "apihelp-expandtemplates-param-prop": "Pezas de información a retornar.\n\nTeña en conta que se non se selecciona ningún valor o resultado conterá o texto wiki, pero a saída estará nun formato obsoleto.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "O wikitexto expandido.",
+ "apihelp-expandtemplates-paramvalue-prop-categories": "Calquera categoría presente na entrada que non estea representada na saída do texto wiki.",
+ "apihelp-expandtemplates-paramvalue-prop-properties": "Propiedades da páxina definidas por palabras máxicas expandidas no texto wiki.",
+ "apihelp-expandtemplates-paramvalue-prop-volatile": "Definir se a saída é volátil e se non debe usarse noutra parte da páxina.",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "Tempo máximo a partir do cal os cachés do resultado deben invalidarse.",
+ "apihelp-expandtemplates-paramvalue-prop-modules": "Calquera módulo ResourceLoader que as funcións de análise teñan solicitado engadir á saída. <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> deben ser solicitadas xunto con <kbd>modules</kbd>.",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina.",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina como unha cadea de texto JSON.",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "A árbore de análise XML da entrada.",
"apihelp-expandtemplates-param-includecomments": "Cando queria incluír comentarios HTML na saída.",
"apihelp-expandtemplates-param-generatexml": "Xenerar árbore de análise XML (reemprazado por $1prop=parsetree).",
"apihelp-expandtemplates-example-simple": "Expandir o wikitexto <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
@@ -174,16 +187,16 @@
"apihelp-imagerotate-param-rotation": "Graos a rotar a imaxe no sentido do reloxio.",
"apihelp-imagerotate-example-simple": "Rotar <kbd>File:Example.png</kbd> <kbd>90</kbd> graos.",
"apihelp-imagerotate-example-generator": "Rotar tódalas imaxes en <kbd>Category:Flip</kbd> <kbd>180</kbd> graos",
- "apihelp-import-description": "Importar unha páxina doutra wiki, ou nun ficheiro XML.\n\nDecátese de que o POST HTTP debe facerse como unha carga de ficheiro (p. ex. usando multipart/form-data) cando se envíe un ficheiro para o parámetro <var>xml</var>.",
+ "apihelp-import-description": "Importar unha páxina doutra wiki, ou dun ficheiro XML.\n\nDecátese de que o POST HTTP debe facerse como unha carga de ficheiro (p. ex. usando multipart/form-data) cando se envíe un ficheiro para o parámetro <var>xml</var>.",
"apihelp-import-param-summary": "Resume de importación.",
"apihelp-import-param-xml": "Subido ficheiro XML.",
"apihelp-import-param-interwikisource": "Para importacións interwiki: wiki da que importar.",
"apihelp-import-param-interwikipage": "Para importacións interwiki: páxina a importar.",
"apihelp-import-param-fullhistory": "Para importacións interwiki: importar o historial completo, non só a versión actual.",
"apihelp-import-param-templates": "Para importacións interwiki: importar tódolos modelos incluídos.",
- "apihelp-import-param-namespace": "Para importacións interwiki: importar a este espazo de nomes.",
- "apihelp-import-param-rootpage": "Importar como subpáxina desta páxina.",
- "apihelp-import-example-import": "Importar [[meta:Help:Parserfunctions]] ó espazo de nomes 100 con todo o historial.",
+ "apihelp-import-param-namespace": "Importar a este espazo de nomes. Non se pode usar de forma conxunta con <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Importar como subpáxina desta páxina. Non se pode usar de forma conxunta con <var>$1namespace</var>.",
+ "apihelp-import-example-import": "Importar [[meta:Help:ParserFunctions]] ó espazo de nomes 100 con todo o historial.",
"apihelp-login-description": "No caso dunha conexión correcta, as cookies necesarias incluiranse nas cabeceiras HTTP de resposta. No caso dunha conexión fallida, os intentos posteriores poden ser reducidos para limitar ataques automaticos de roubo de contrasinais.",
"apihelp-login-param-name": "Nome de usuario.",
"apihelp-login-param-password": "Contrasinal",
@@ -222,14 +235,15 @@
"apihelp-opensearch-param-suggest": "Non facer nada se <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> é falso.",
"apihelp-opensearch-param-redirects": "Como xestionar as redireccións:\n;return:Devolve a mesma redirección.\n;resolve:Devolve a páxina á que apunta. Pode devolver menos de $1limit resultados.\nPor razóns históricas, o valor por defecto para $1format=json é \"return\" e \"resolve\" para outros formatos.",
"apihelp-opensearch-param-format": "O formato de saída.",
+ "apihelp-opensearch-param-warningsaserror": "Se os avisos son recibidos con <kbd>format=json</kbd>, devolver un erro de API no canto de ignoralos.",
"apihelp-opensearch-example-te": "Atopar páxinas que comezan por <kbd>Te</kbd>.",
- "apihelp-options-description": "Cambiar as preferencias do usuario actual.\n\nSó se poden cambiar opcións que estean rexistradas no núcleo ou nunha das extensións instaladas, ou opcións con claves prefixadas con \"userjs-\" (previstas para ser usadas por scripts de usuario).",
- "apihelp-options-param-reset": "Reiniciar preferencias ás iniciais do sitio.",
+ "apihelp-options-description": "Cambiar as preferencias do usuario actual.\n\nSó se poden cambiar opcións que estean rexistradas no núcleo ou nunha das extensións instaladas, ou aquelas opcións con claves prefixadas con <code>userjs-</code> (previstas para ser usadas por escrituras de usuario).",
+ "apihelp-options-param-reset": "Reinicia as preferencias ás iniciais do sitio.",
"apihelp-options-param-resetkinds": "Lista de tipos de opcións a reinicializar cando a opción <var>$1reset</var> está definida.",
"apihelp-options-param-change": "Lista de cambios, con formato nome=valor (p. ex. skin=vector). O valor non pode ter caracteres de barra vertical. Se non se indica un valor (sen u signo igual), p. ex. nomeopcion|outraopcion|..., a opción será gardada co seu valor por defecto.",
- "apihelp-options-param-optionname": "Nome dunha opción que debe ser fixado ó valor dado por <var>$1optionvalue</var>.",
- "apihelp-options-param-optionvalue": "Valor da opción especificada por <var>$1optionname</var>, pode conter o caracter da barra vertical.",
- "apihelp-options-example-reset": "Restablecer tódaalas preferencias",
+ "apihelp-options-param-optionname": "O nome da opción que debe fixarse no valor dado por <var>$1optionvalue</var>.",
+ "apihelp-options-param-optionvalue": "O valor para a opción especificada por <var>$1optionname</var>. Pode conter barras verticais.",
+ "apihelp-options-example-reset": "Restablecer todas as preferencias.",
"apihelp-options-example-change": "Cambiar as preferencias <kbd>skin</kbd> and <kbd>hideminor</kbd>.",
"apihelp-options-example-complex": "Restaurar todas as preferencias, logo fixar <kbd>skin</kbd> e <kbd>nickname</kbd>.",
"apihelp-paraminfo-description": "Obter información sobre módulos API.",
@@ -240,6 +254,7 @@
"apihelp-paraminfo-param-pagesetmodule": "Obter información sobre o módulo pageset (proporcionando títulos= e amigos).",
"apihelp-paraminfo-param-formatmodules": "Lista dos nomes de módulo de formato (valores do parámetro <var>formato</var>). No canto use <var>$1modules</var>.",
"apihelp-paraminfo-example-1": "Amosar información para <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>, <kbd>[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>, <kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd>, e <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd>.",
+ "apihelp-parse-description": "Analiza o contido e devolve o resultado do analizador.\n\nVexa varios módulos propostos de <kbd>[[Special:ApiHelp/query|action=query]]</kbd> para obter información sobre a versión actual dunha páxina.\n\nHai varias formas de especificar o texto a analizar:\n# Especificar unha páxina ou revisión, usando <var>$1page</var>, <var>$1pageid</var>, ou <var>$1oldid</var>.\n# Especificando contido explícitamente, usando <var>$1text</var>, <var>$1title</var>, and <var>$1contentmodel</var>.\n# Especificando só un resumo a analizar. <var>$1prop</var> debe ter un valor baleiro.",
"apihelp-parse-param-title": "Título da páxina á que pertence o texto. Se non se indica, debe especificarse <var>$1contentmodel</var>, e [[API]] usarase como o título.",
"apihelp-parse-param-text": "Texto a analizar. Use <var>$1title</var> ou <var>$1contentmodel</var> para controlar o modelo de contido.",
"apihelp-parse-param-summary": "Resumo a analizar.",
@@ -247,17 +262,43 @@
"apihelp-parse-param-pageid": "Analizar o contido desta páxina. Ignora <var>$1page</var>.",
"apihelp-parse-param-redirects": "Se <var>$1page</var> ou <var>$1pageid</var> apuntar a unha redirección, resólvea.",
"apihelp-parse-param-oldid": "Analizar o contido desta revisión. Ignora <var>$1page</var> e <var>$1pageid</var>.",
+ "apihelp-parse-param-prop": "Que información obter:",
+ "apihelp-parse-paramvalue-prop-text": "Devolve o texto analizado do texto wiki.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Devolve as interwikis do texto analizado.",
+ "apihelp-parse-paramvalue-prop-categories": "Devolve as categoría do texto analizado.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Devolve a versión HTML das categorías.",
+ "apihelp-parse-paramvalue-prop-links": "Devolve as ligazóns internas do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-templates": "Devolve os modelos do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-images": "Devolve as imaxes do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Devolve as ligazóns externas no texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-sections": "Devolve as seccións do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-revid": "Engade o identificador de edición do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Engade o título do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-headitems": "Devolve os elementos a poñer na <code>&lt;cabeceira&gt;</code> da páxina.",
+ "apihelp-parse-paramvalue-prop-headhtml": "Devolve <code>&lt;cabeceira&gt;</code> analizada da páxina.",
+ "apihelp-parse-paramvalue-prop-modules": "Devolve os módulos ResourceLoader usados na páxina. <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> deben ser solicitados xunto con <kbd>modules</kbd>.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina.",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Devolve as variables específicas de configuración JavaScript da páxina como unha cadea de texto JSON.",
+ "apihelp-parse-paramvalue-prop-indicators": "Devolve o HTML dos indicadores de estado de páxina usados na páxina.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "Devolve as ligazóns interwiki do texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Devolve o texto wiki orixinal que foi analizado.",
+ "apihelp-parse-paramvalue-prop-properties": "Obter varias propiedades definidas no texto wiki analizado.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "Devolve o informe de límite de forma estruturada. Non devolve datos cando <var>$1disablelimitreport</var> está fixado.",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "Devolve a versión HTML do informe de límite. Non devolve datos cando <var>$1disablelimitreport</var> está fixado.",
+ "apihelp-parse-paramvalue-prop-parsetree": "Árbores de análise XML do contido da revisión (precisa o modelo de contido <code>$1</code>)",
"apihelp-parse-param-pst": "Fai unha transformación antes de gardar a entrada antes de analizala. Válida unicamente para usar con texto.",
"apihelp-parse-param-onlypst": "Facer unha transformación antes de gardar (PST) a entrada, pero sen analizala. Devolve o mesmo wikitexto, despois de que a PST foi aplicada. Só válida cando se usa con <var>$1text</var>.",
"apihelp-parse-param-effectivelanglinks": "Inclúe ligazóns de idioma proporcionadas polas extensións (para usar con <kbd>$1prop=langlinks</kbd>).",
"apihelp-parse-param-section": "Recuperar unicamente o contido deste número de sección ou cando <kbd>new</kbd> xera unha nova sección.\n\nA sección <kbd>new</kbd> só é atendida cando se especifica <var>text</var>.",
"apihelp-parse-param-sectiontitle": "Novo título de sección cando <var>section</var> é <kbd>new</kbd>.\n\nA diferenza da edición de páxinas, non se oculta no <var>summary</var> cando se omite ou está baleiro.",
- "apihelp-parse-param-disablepp": "Desactivar o informe PP da saída do analizador.",
- "apihelp-parse-param-disableeditsection": "Desactivar as ligazóns de edición de sección da saída do analizador.",
- "apihelp-parse-param-generatexml": "Xenerar unha árbore de análise XML (necesita o modelo de contido <code>$1</code>).",
+ "apihelp-parse-param-disablelimitreport": "Omitir o informe de límite (\"Informe de límite NewPP\") da saída do analizador.",
+ "apihelp-parse-param-disablepp": "Use <var>$1disablelimitreport</var> no seu lugar.",
+ "apihelp-parse-param-disableeditsection": "Omitir as ligazóns de edición de sección da saída do analizador.",
+ "apihelp-parse-param-disabletidy": "Non executar limpeza de HTML no retorno da análise.",
+ "apihelp-parse-param-generatexml": "Xenerar unha árbore de análise XML (necesita o modelo de contido <code>$1</code>; substituído por <kbd>$2prop=parsetree</kbd>).",
"apihelp-parse-param-preview": "Analizar en modo vista previa.",
"apihelp-parse-param-sectionpreview": "Analizar en modo vista previa de sección (activa tamén o modo de vista previa).",
- "apihelp-parse-param-disabletoc": "Desactiva o índice na saída.",
+ "apihelp-parse-param-disabletoc": "Omitir o índice na saída.",
"apihelp-parse-param-contentformat": "Formato de serialización do contido usado para o texto de entrada. Só válido cando se usa con $1text.",
"apihelp-parse-param-contentmodel": "Modelo de contido do texto de entrada. Se se omite, debe especificarse $1title, e o valor por defecto será o modelo do título especificado. Só válido cando se usa con $1text.",
"apihelp-parse-example-page": "Analizar unha páxina.",
@@ -275,7 +316,7 @@
"apihelp-protect-param-protections": "Lista dos niveis de protección, con formato <kbd>action=level</kbd> (p.ex. <kbd>edit=sysop</kbd>).\n\n<strong>Nota:</strong> Todas as accións que non estean listadas terán restriccións para ser eliminadas.",
"apihelp-protect-param-expiry": "Selos de tempo de caducidade. Se só se indica un selo de tempo, usarase para todas as proteccións. Use <kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd>, ou <kbd>never</kbd>, para unha protección sen caducidade.",
"apihelp-protect-param-reason": "Razón para (des)protexer.",
- "apihelp-protect-param-cascade": "Activar protección en cascada (p. ex. protexer páxinas incluídas nesta páxina). Ignorado se todos os niveis de protección proporcionados non permiten o uso en cascada.",
+ "apihelp-protect-param-cascade": "Activar a protección en cascada (por exemplo, protexer os modelos transcluídos e as imaxes usadas nesta páxina). Ignórase se ningún dos niveis de protección soporta a protección en cascada.",
"apihelp-protect-param-watch": "Se se define este parámetro, engadir a páxina que se (des)protexe á lista de vixilancia do usuario actual.",
"apihelp-protect-param-watchlist": "Engadir ou eliminar sen condicións a páxina da lista de vixiancia do usuario actual, use as preferencias ou non cambie a vixiancia.",
"apihelp-protect-example-protect": "Protexer unha páxina",
@@ -294,8 +335,7 @@
"apihelp-query-param-export": "Exportar as revisións actuais de todas as páxinas dadas ou xeneradas.",
"apihelp-query-param-exportnowrap": "Devolver o XML exportado sen incluílo nun resultado XML (mesmo formato que [[Special:Export]]). Só pode usarse con $1export.",
"apihelp-query-param-iwurl": "Se fai falta obter a URL completa se o título é unha ligazón interwiki.",
- "apihelp-query-param-continue": "Cando está presente, formatea query-continue como pares clave-valor que simplemente serán mesturados na consulta orixinal. Este parámetro debe fixarse a unha cadea baleira na consulta inicial.\n\nEste parámetro está recomendado para todos os novos desenvolvementos, e será o usado por defecto na seguinte versión da API.",
- "apihelp-query-param-rawcontinue": "Actualmente ignorado. No futuro, <var>$1continue</var> virá por defecto e será necesario para recibir os datos en bruto de <samp>query-continue</samp>.",
+ "apihelp-query-param-rawcontinue": "Devolver os datos en bruto de <samp>query-continue</samp> para continuar.",
"apihelp-query-example-revisions": "Consultar [[Special:ApiHelp/query+siteinfo|información do sitio]] e [[Special:ApiHelp/query+revisions|as revisións]] da <kbd>Páxina Principal</kbd>.",
"apihelp-query-example-allpages": "Buscar revisións de páxinas que comecen por <kbd>API/</kbd>.",
"apihelp-query+allcategories-description": "Numerar tódalas categorías",
@@ -306,7 +346,9 @@
"apihelp-query+allcategories-param-min": "Devolver só categorías con polo menos este número de membros.",
"apihelp-query+allcategories-param-max": "Devolver só categorías con como moito este número de membros.",
"apihelp-query+allcategories-param-limit": "Cantas categorías devolver.",
- "apihelp-query+allcategories-param-prop": "Que propiedades recuperar:\n;size: Engade o número de páxinas na categoría.\n;hidden: Marca as categorías que están ocultas con _&#95;HIDDENCAT_&#95;.",
+ "apihelp-query+allcategories-param-prop": "Que propiedades recuperar:",
+ "apihelp-query+allcategories-paramvalue-prop-size": "Engade o número de páxinas na categoría.",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "Marca as categorías que están ocultas con <code>_&#95;HIDDENCAT_&#95;</code>.",
"apihelp-query+allcategories-example-size": "Listar categorías con información do número de páxinas en cada unha.",
"apihelp-query+allcategories-example-generator": "Obter información sobre a páxina de categoría para categorías que comezan por <kbd>List</kbd>.",
"apihelp-query+alldeletedrevisions-description": "Listar todas as revisións borradas por un usuario ou nun espazo de nomes.",
@@ -330,7 +372,9 @@
"apihelp-query+allfileusages-param-to": "Título do ficheiro no que rematar de enumerar.",
"apihelp-query+allfileusages-param-prefix": "Buscar tódolos títulos de ficheiro que comezan con este valor.",
"apihelp-query+allfileusages-param-unique": "Mostrar só nomes de ficheiro distintos. Non pode usarse con $1prop=ids.\nCando se usa como xenerador, produce páxinas obxectivo no canto de páxinas fonte.",
- "apihelp-query+allfileusages-param-prop": "Que partes de información incluír:\n;ids:Engade o ID de páxina usada (non pode usarse con $1unique).\n;title:Engade o nome do ficheiro.",
+ "apihelp-query+allfileusages-param-prop": "Que partes de información incluír:",
+ "apihelp-query+allfileusages-paramvalue-prop-ids": "Engade os IDs das páxinas usadas (non pode usarse con $1unique).",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "Engade o nome do ficheiro.",
"apihelp-query+allfileusages-param-limit": "Número total de obxectos a devolver.",
"apihelp-query+allfileusages-param-dir": "Dirección na cal listar.",
"apihelp-query+allfileusages-example-B": "Lista títulos de ficheiro, incluíndo os eliminados, cos IDs de páxina dos que proveñen, comezando en <kbd>B</kbd>.",
@@ -362,7 +406,9 @@
"apihelp-query+alllinks-param-to": "Título da ligazón na que rematar de enumerar.",
"apihelp-query+alllinks-param-prefix": "Buscar tódolos títulos ligados que comezan con este valor.",
"apihelp-query+alllinks-param-unique": "Mostrar só títulos ligados distintos. Non pode usarse con <kbd>$1prop=ids</kbd>.\nCando se usa como xenerador, produce páxinas obxectivo no canto de páxinas fonte.",
- "apihelp-query+alllinks-param-prop": "Que partes de información incluír:\n;ids: Engade o ID da páxina da ligazón (non pode usarse con <var>$1unique</var>).\n;título: Engade o título da ligazón.",
+ "apihelp-query+alllinks-param-prop": "Que partes de información incluír:",
+ "apihelp-query+alllinks-paramvalue-prop-ids": "Engade o ID da páxina da ligazón (non pode usarse con <var>$1unique</var>).",
+ "apihelp-query+alllinks-paramvalue-prop-title": "Engade o título da ligazón.",
"apihelp-query+alllinks-param-namespace": "Espazo de nomes a enumerar.",
"apihelp-query+alllinks-param-limit": "Número total de obxectos a devolver.",
"apihelp-query+alllinks-param-dir": "Dirección na cal listar.",
@@ -409,7 +455,11 @@
"apihelp-query+allredirects-param-to": "Título da redirección na que rematar de enumerar.",
"apihelp-query+allredirects-param-prefix": "Buscar todas as páxinas que comecen con este valor.",
"apihelp-query+allredirects-param-unique": "Só mostrar páxinas obxectivo distintas. Non pode usarse con $1prop=ids|fragment|interwiki.\nCando se usa como xenerador, produce páxinas obxectivo no canto de páxinas fonte.",
- "apihelp-query+allredirects-param-prop": "Que información incluír:\n;ids:Engade o ID da páxina da redirección (non pode usarse con <var>$1unique</var>).\n;title:Engade o título da redirección.\n;fragment:Engade o fragmento da redirección, se o hai (non pode usarse con <var>$1unique</var>).\n;interwiki:Engade o prefixo interwiki da redirección, se o hai (non pode usarse con <var>$1unique</var>).",
+ "apihelp-query+allredirects-param-prop": "Que información incluír:",
+ "apihelp-query+allredirects-paramvalue-prop-ids": "Engade o ID da páxina da redirección (non pode usarse con <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-title": "Engade o título da redirección.",
+ "apihelp-query+allredirects-paramvalue-prop-fragment": "Engade o fragmento da redirección, se o hai (non pode usarse con <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-interwiki": "Engade o prefixo interwiki da redirección, se o hai (non pode usarse con <var>$1unique</var>).",
"apihelp-query+allredirects-param-namespace": "Espazo de nomes a enumerar.",
"apihelp-query+allredirects-param-limit": "Número total de obxectos a devolver.",
"apihelp-query+allredirects-param-dir": "Dirección na cal listar.",
@@ -422,7 +472,9 @@
"apihelp-query+alltransclusions-param-to": "Título da transclusión na que rematar de enumerar.",
"apihelp-query+alltransclusions-param-prefix": "Buscar todos os títulos transcluídos que comezan con este valor.",
"apihelp-query+alltransclusions-param-unique": "Mostrar só títulos transcluídos distintos. Non pode usarse con <kbd>$1prop=ids</kbd>.\nCando se usa como xenerador, produce páxinas obxectivo no canto de páxinas fonte.",
- "apihelp-query+alltransclusions-param-prop": "Que partes de información incluír:\n;ids: Engade o ID da páxina da páxina transcluída (non pode usarse con $1unique).\n;title: Engade o título da transclusión.",
+ "apihelp-query+alltransclusions-param-prop": "Que partes de información incluír:",
+ "apihelp-query+alltransclusions-paramvalue-prop-ids": "Engade o ID da páxina da páxina transcluída (non pode usarse con $1unique).",
+ "apihelp-query+alltransclusions-paramvalue-prop-title": "Engade o título da transclusión.",
"apihelp-query+alltransclusions-param-namespace": "Nome de espazos a numerar.",
"apihelp-query+alltransclusions-param-limit": "Número total de obxectos a devolver.",
"apihelp-query+alltransclusions-param-dir": "Dirección na cal listar.",
@@ -438,7 +490,13 @@
"apihelp-query+allusers-param-group": "Só incluír os usuarios nos grupos dados.",
"apihelp-query+allusers-param-excludegroup": "Excluír usuarios nos grupos dados.",
"apihelp-query+allusers-param-rights": "Incluír só ós usuarios cos dereitos dados. Non se inclúen grupo implícitos nin autopromocionados como *, usuario ou autoconfirmado.",
- "apihelp-query+allusers-param-prop": "Que información incluír:\n;blockinfo:Engade información sobre o bloque actual do usuario.\n;groups:Lista de grupos nos que está o usuario. Isto usa máis recursos no servidor e pode devolver menos resultados que o límite.\n;implicitgroups:Lista todos os grupos ós que usuario pertence de forma automática.\n;rights:Lista os dereitos que ten o usuario.\n;editcount:Engade o número de edicións do usuario.\n;registration:Engade o selo de tempo do momento no que se rexistrou o usuario, se está dispoñible (pode ser branco).",
+ "apihelp-query+allusers-param-prop": "Que información incluír:",
+ "apihelp-query+allusers-paramvalue-prop-blockinfo": "Engade información sobre o bloque actual do usuario.",
+ "apihelp-query+allusers-paramvalue-prop-groups": "Lista de grupos nos que está o usuario. Isto usa máis recursos no servidor e pode devolver menos resultados que o límite.",
+ "apihelp-query+allusers-paramvalue-prop-implicitgroups": "Lista todos os grupos ós que usuario pertence de forma automática.",
+ "apihelp-query+allusers-paramvalue-prop-rights": "Lista os dereitos que ten o usuario.",
+ "apihelp-query+allusers-paramvalue-prop-editcount": "Engade o número de edicións do usuario.",
+ "apihelp-query+allusers-paramvalue-prop-registration": "Engade o selo de tempo do momento no que se rexistrou o usuario, se está dispoñible (pode ser branco).",
"apihelp-query+allusers-param-limit": "Número total de nomes de usuario a devolver.",
"apihelp-query+allusers-param-witheditsonly": "Só listar usuarios que teñan feito edicións.",
"apihelp-query+allusers-param-activeusers": "Só listar usuarios activos {{PLURAL:$1|no último día|nos $1 últimos días}}.",
@@ -460,11 +518,25 @@
"apihelp-query+blocks-param-users": "Lista de usuarios a buscar (opcional).",
"apihelp-query+blocks-param-ip": "Obter todos os bloques aplicables a esta IPs ou a este rango CIDR, incluíndo bloques de rangos.\nNon pode usarse xunto con <var>$3users</var>. Os rangos CIDR maiores que IPv4/$1 ou IPv6/$2 non se aceptan.",
"apihelp-query+blocks-param-limit": "Número máximo de bloques a listar.",
+ "apihelp-query+blocks-param-prop": "Que propiedades obter:",
+ "apihelp-query+blocks-paramvalue-prop-id": "Engade o identificador do bloqueo.",
+ "apihelp-query+blocks-paramvalue-prop-user": "Engade o nome de usario do usuario bloqueado.",
+ "apihelp-query+blocks-paramvalue-prop-userid": "Engade o identificador de usuario do usuario bloqueado.",
+ "apihelp-query+blocks-paramvalue-prop-by": "Engade o nome de usuario do usuario que fixo o bloqueo.",
+ "apihelp-query+blocks-paramvalue-prop-byid": "Engade o identificador do usuario que fixo o bloqueo.",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "Engade o selo de tempo de cando se realizou o bloqueo.",
+ "apihelp-query+blocks-paramvalue-prop-expiry": "Engade o selo de tempo de cando remata o bloqueo.",
+ "apihelp-query+blocks-paramvalue-prop-reason": "Engade a razón dada para o bloqueo.",
+ "apihelp-query+blocks-paramvalue-prop-range": "Engade o rango de direccións IP afectadas polo bloqueo.",
+ "apihelp-query+blocks-paramvalue-prop-flags": "Etiqueta o bloqueo con (autoblock, anononly, etc.).",
"apihelp-query+blocks-param-show": "Só mostrar elementos correspondentes a eses criterios.\nPor exemplo, para ver só bloques indefinidos en direccións IP, ponga <kbd>$1show=ip|!temp</kbd>.",
"apihelp-query+blocks-example-simple": "Listar bloques.",
"apihelp-query+blocks-example-users": "Lista de bloques de usuarios <kbd>Alice</kbd> e <kbd>Bob</kbd>.",
"apihelp-query+categories-description": "Listar todas as categorías ás que pertencen as páxinas.",
- "apihelp-query+categories-param-prop": "Que propiedades adicionais obter para cada categoría:\n;sortkey:Engade a clave de ordenación (cadea hexadecimal) e o prefixo da clave de ordenación (parte lexible) da categoría.\n;timestamp:Engade o selo de tempo de cando se engadíu a categoría.\n;hidden:Pon unha marca nas categorías que están ocultas con _&#95;HIDDENCAT_&#95;.",
+ "apihelp-query+categories-param-prop": "Que propiedades adicionais obter para cada categoría:",
+ "apihelp-query+categories-paramvalue-prop-sortkey": "Engade a clave de ordenación (cadea hexadecimal) e o prefixo da clave de ordenación (parte lexible) da categoría.",
+ "apihelp-query+categories-paramvalue-prop-timestamp": "Engade o selo de tempo de cando se engadíu a categoría.",
+ "apihelp-query+categories-paramvalue-prop-hidden": "Pon unha marca nas categorías que están ocultas con <code>_&#95;HIDDENCAT_&#95;</code>.",
"apihelp-query+categories-param-show": "Tipo de categorías a amosar.",
"apihelp-query+categories-param-limit": "Cantas categorías devolver.",
"apihelp-query+categories-param-categories": "Listar só esas categorías. Útil para verificar se unha páxina concreta está nunha categoría determinada.",
@@ -476,7 +548,13 @@
"apihelp-query+categorymembers-description": "Listar tódalas páxinas nunha categoría determinada.",
"apihelp-query+categorymembers-param-title": "Que categoría enumerar (obrigatorio). Debe incluír o prefixo <kbd>{{ns:category}}:</kbd>. Non pode usarse xunto con <var>$1pageid</var>.",
"apihelp-query+categorymembers-param-pageid": "ID de páxina da categoría a enumerar. Non se pode usar xunto con <var>$1title</var>.",
- "apihelp-query+categorymembers-param-prop": "Que información incluír:\n;ids:Engade o ID da páxina.\n;title:Engade o título e o ID do espazo de nomes da páxina.\n;sortkey:Engade a clave de ordenación usada para ordenala na categoría (cadea hexadecimal).\n;sortkeyprefix:Engade o prefixo da clave de ordenación usado para ordenala na categoría (parte lexible da clave de ordenación).\n;type:Engade o tipo no que foi categorizado a páxina (páxina, subcategoría ou ficheiro)\n;timestamp:Engade o selo de tempo no que foi incluída a páxina.",
+ "apihelp-query+categorymembers-param-prop": "Que información incluír:",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "Engade o ID da páxina.",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "Engade o título e o ID do espazo de nomes da páxina.",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkey": "Engade a clave de ordenación usada para ordenala na categoría (cadea hexadecimal).",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "Engade o prefixo da clave de ordenación usado para ordenala na categoría (parte lexible da clave de ordenación).",
+ "apihelp-query+categorymembers-paramvalue-prop-type": "Engade o tipo no que foi categorizado a páxina (páxina, subcategoría ou ficheiro)",
+ "apihelp-query+categorymembers-paramvalue-prop-timestamp": "Engade o selo de tempo no que foi incluída a páxina.",
"apihelp-query+categorymembers-param-namespace": "Só incluír páxinas nestes espazos de nomes. Decátese de que poden usarse <kbd>$1type=subcat</kbd> ou <kbd>$1type=file</kbd> no canto de <kbd>$1namespace=14</kbd> ou <kbd>6</kbd>.",
"apihelp-query+categorymembers-param-type": "Que tipo de membros da categoría incluír. Ignorado cando está activo <kbd>$1sort=timestamp</kbd>.",
"apihelp-query+categorymembers-param-limit": "Máximo número de páxinas a retornar.",
@@ -484,12 +562,12 @@
"apihelp-query+categorymembers-param-dir": "En que dirección ordenar.",
"apihelp-query+categorymembers-param-start": "Selo de tempo para comezar o listado. Só pode usarse con <kbd>$1sort=timestamp</kbd>.",
"apihelp-query+categorymembers-param-end": "Selo de tempo co que rematar o listado. Só pode usarse con <kbd>$1sort=timestamp</kbd>.",
- "apihelp-query+categorymembers-param-starthexsortkey": "Chave de ordenación coa que comezar o listado, como se indique en <kbd>$1prop=sortkey</kbd>. Pode usarse só con <kbd>$1sort=sortkey</kbd>.",
- "apihelp-query+categorymembers-param-endhexsortkey": "Chave de ordenación coa que rematar o listado, como se indique en <kbd>$1prop=sortkey</kbd>. Pode usarse só con <kbd>$1sort=sortkey</kbd>.",
- "apihelp-query+categorymembers-param-startsortkeyprefix": "Prefixo da chave de ordenación coa que comezar o listado. Pode usarse só con <kbd>$1sort=sortkey</kbd>. Ignórase <var>$1starthexsortkey</var>.",
- "apihelp-query+categorymembers-param-endsortkeyprefix": "Prefixo da chave de ordenación ANTES de rematar o listado (e non a, se existe este valor entón non será incluído!). Pode usarse só con <kbd>$1sort=sortkey</kbd>. Ignórase $1endhexsortkey.",
- "apihelp-query+categorymembers-param-startsortkey": "Usar $1starthexsortkey no canto.",
- "apihelp-query+categorymembers-param-endsortkey": "Usar $1endhexsortkey no canto.",
+ "apihelp-query+categorymembers-param-starthexsortkey": "Clave de ordenación coa que comezar a lista, como se indique en <kbd>$1prop=sortkey</kbd>. Pode usarse só con <kbd>$1sort=sortkey</kbd>.",
+ "apihelp-query+categorymembers-param-endhexsortkey": "Clave de ordenación na que rematar a lista, como se indique en <kbd>$1prop=sortkey</kbd>. Pode usarse só con <kbd>$1sort=sortkey</kbd>.",
+ "apihelp-query+categorymembers-param-startsortkeyprefix": "Prefixo da clave de ordenación co que comezar a lista. Pode usarse só con <kbd>$1sort=sortkey</kbd>. Sobrescríbese <var>$1starthexsortkey</var>.",
+ "apihelp-query+categorymembers-param-endsortkeyprefix": "Prefixo da clave de ordenación no que rematar a lista <strong>antes</strong> (e non <strong>en</strong>; se existe este valor entón non será incluído!). Pode usarse só con $1sort=sortkey. Sobrescríbese $1endhexsortkey.",
+ "apihelp-query+categorymembers-param-startsortkey": "Usar $1starthexsortkey no seu lugar.",
+ "apihelp-query+categorymembers-param-endsortkey": "Usar $1endhexsortkey no seu lugar.",
"apihelp-query+categorymembers-example-simple": "Obter as dez primeiras páxinas de <kbd>Category:Physics</kbd>.",
"apihelp-query+categorymembers-example-generator": "Obter a información das primeiras dez páxinas de <kbd>Category:Physics</kbd>.",
"apihelp-query+contributors-description": "Obter a lista de contribuidores conectados e o número de contribuidores anónimos dunha páxina.",
@@ -505,8 +583,6 @@
"apihelp-query+deletedrevisions-param-tag": "Só listar revisións marcadas con esta etiqueta.",
"apihelp-query+deletedrevisions-param-user": "Só listar revisións deste usuario.",
"apihelp-query+deletedrevisions-param-excludeuser": "Non listar revisións deste usuario.",
- "apihelp-query+deletedrevisions-param-limit": "Máximo número de revisións a listar.",
- "apihelp-query+deletedrevisions-param-prop": "Que propiedades obter:\n;revid:Engade o ID da modificación borrada.\n;parentid:Engade o ID da modificación da modificación anterior da páxina.\n;user:Engade o usuario que fixo a modificación.\n;userid:Engade o ID do usuario que fixo a modificación.\n;comment:Engade o comentario da modificación.\n;parsedcomment:Engade o comentario analizado da modificación.\n;minor:Engade unha marca se a modificación é menor.\n;len:Engade a lonxitude (bytes) da modificación.\n;sha1:Engade a función SHA-1 (base 16) da modificación.\n;content:Engade o contido da modificación.\n;tags:Marcas da modificación.",
"apihelp-query+deletedrevisions-example-titles": "Listar as revisións borradas das páxinas <kbd>Main Page</kbd> e <kbd>Talk:Main Page</kbd>, con contido.",
"apihelp-query+deletedrevisions-example-revids": "Listar a información para a revisión borrada <kbd>123456</kbd>.",
"apihelp-query+deletedrevs-description": "Lista as modificación borradas.\n\nOpera según tres modos:\n#Lista as modificacións borradas dos títulos indicados, ordenados por selo de tempo.\n#Lista as contribucións borradas do usuario indicado, ordenadas por selo de tempo (sen indicar títulos).\n#Lista todas as modificacións borradas no espazo de nomes indicado, ordenadas por título e selo de tempo (sen indicar títulos, sen fixar $1user).\n\nCertos parámetros só se aplican a algúns modos e son ignorados noutros.",
@@ -522,6 +598,7 @@
"apihelp-query+deletedrevs-param-excludeuser": "Non listar revisións deste usuario.",
"apihelp-query+deletedrevs-param-namespace": "Só listar páxinas neste espazo de nomes.",
"apihelp-query+deletedrevs-param-limit": "Máximo número de revisións a listar.",
+ "apihelp-query+deletedrevs-param-prop": "Que propiedades devolver:\n;revid:Engade o identificador de modificación da modificación borrada.\n;parentid:Engade o identificador de modificación da versión anterior da páxina.\n;user:Engade o usuario que fixo esa modificación.\n;userid:Engade o identificador de usuario que fixo esa modificación.\n;comment:Engade o comentario da modificación.\n;parsedcomment:Engade o comentario analizado da modificación.\n;minor:Indica se a modificación é menor.\n;len:Engade a lonxitude (bytes) da modificación.\n;sha1:Engade o SHA-1 (base 16) da modificación.\n;content:Engade o contido da modificación.\n;token:<span class=\"apihelp-deprecated\">Obsoleto.</span> Devolve o identificador da modificación.\n;tags:Etiquetas da modificación.",
"apihelp-query+deletedrevs-example-mode1": "Listar as últimas revisións borradas das páxinas <kbd>Main Page</kbd> e <kbd>Talk:Main Page</kbd>, con contido (modo 1).",
"apihelp-query+deletedrevs-example-mode2": "Listar as últimas 50 contribucións borradas de <kbd>Bob</kbd> (modo 2).",
"apihelp-query+deletedrevs-example-mode3-main": "Listar as primeiras 50 revisións borradas no espazo de nomes principal (modo 3)",
@@ -549,7 +626,10 @@
"apihelp-query+extlinks-param-expandurl": "Expandir as URLs relativas a un protocolo co protocolo canónico.",
"apihelp-query+extlinks-example-simple": "Obter unha de ligazóns externas á <kbd>Páxina Principal<kbd>.",
"apihelp-query+exturlusage-description": "Enumerar páxinas que conteñen unha dirección URL dada.",
- "apihelp-query+exturlusage-param-prop": "Que información incluír:\n;ids:Engade o ID da páxina.\n;title:Engade o título e o ID do espazo de nomes da páxina.\n;url:Engade a URL usada na páxina.",
+ "apihelp-query+exturlusage-param-prop": "Que información incluír:",
+ "apihelp-query+exturlusage-paramvalue-prop-ids": "Engade o ID da páxina.",
+ "apihelp-query+exturlusage-paramvalue-prop-title": "Engade o título e o ID do espazo de nomes da páxina.",
+ "apihelp-query+exturlusage-paramvalue-prop-url": "Engade a URL usada na páxina.",
"apihelp-query+exturlusage-param-protocol": "Protocolo da URL. Se está baleiro e está activo <var>$1query</var>, o protocolo é <kbd>http</kbd>. Deixar esa variable e a <var>$1query</var> baleiras para listar todas as ligazóns externas.",
"apihelp-query+exturlusage-param-query": "Buscar unha cadea sen protocolo. Ver [[Special:LinkSearch]]. Deixar baleira para listar todas as ligazóns externas.",
"apihelp-query+exturlusage-param-namespace": "Espazo de nomes a enumerar.",
@@ -564,12 +644,28 @@
"apihelp-query+filearchive-param-dir": "Dirección na cal listar.",
"apihelp-query+filearchive-param-sha1": "Función hash SHA1 da imaxe. Invalida $1sha1base36.",
"apihelp-query+filearchive-param-sha1base36": "Función hash SHA1 da imaxe en base 36 (usado en MediaWiki).",
+ "apihelp-query+filearchive-param-prop": "Que información de imaxe devolver:",
+ "apihelp-query+filearchive-paramvalue-prop-sha1": "Engade a función hash SHA-1 da imaxe.",
+ "apihelp-query+filearchive-paramvalue-prop-timestamp": "Engade o selo de tempo da versión subida.",
+ "apihelp-query+filearchive-paramvalue-prop-user": "Engade o usuario que subiu a versión da imaxe.",
+ "apihelp-query+filearchive-paramvalue-prop-size": "Engade o tamaño da imaxe en bytes e a altura, anchura e contador de páxina (se é aplicable).",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "Alias para o tamaño.",
+ "apihelp-query+filearchive-paramvalue-prop-description": "Engade a descrición da versión da imaxe.",
+ "apihelp-query+filearchive-paramvalue-prop-parseddescription": "Analiza a descrición na versión.",
+ "apihelp-query+filearchive-paramvalue-prop-mime": "Engade o tipo MIME da imaxe.",
+ "apihelp-query+filearchive-paramvalue-prop-mediatype": "Engade o tipo multimedia da imaxe.",
+ "apihelp-query+filearchive-paramvalue-prop-metadata": "Lista os metadatos Exif da versión da imaxe.",
+ "apihelp-query+filearchive-paramvalue-prop-bitdepth": "Engade a profundidade de bit da versión.",
+ "apihelp-query+filearchive-paramvalue-prop-archivename": "Engade o nome do ficheiro da versión do ficheiro para as versións que non son a última.",
"apihelp-query+filearchive-example-simple": "Mostrar unha lista de tódolos fichieiros eliminados.",
"apihelp-query+filerepoinfo-description": "Devolver a meta información sobre os repositorios de imaxes configurados na wiki.",
"apihelp-query+filerepoinfo-param-prop": "Que propiedades do repositorio mostrar (pode haber máis dispoñible nalgunhas wikis):\n;apiurl:URL ó API do repositorio - útil para obter información das imaxes no host.\n;name:A clave do repositorio - usada p. ex. nas variables de retorno de <var>[[mw:Manual:$wgForeignFileRepos|$wgForeignFileRepos]]</var> e [[Special:ApiHelp/query+imageinfo|imageinfo]]\n;displayname:O nome lexible do wiki repositorio.\n;rooturl:URL raíz dos camiños de imaxe.\n;local:Se o repositorio é o repositorio local ou non.",
"apihelp-query+filerepoinfo-example-simple": "Obter infomación sobre os repositorios de ficheiros",
"apihelp-query+fileusage-description": "Atopar tódalas páxinas que usan os ficheiros dados.",
- "apihelp-query+fileusage-param-prop": "Que propiedades obter:\n;pageid:ID de cada páxina.\n;título:Título de cada páxina.\n;redirect:Marca de se a páxina é unha redirección.",
+ "apihelp-query+fileusage-param-prop": "Que propiedades obter:",
+ "apihelp-query+fileusage-paramvalue-prop-pageid": "ID de cada páxina.",
+ "apihelp-query+fileusage-paramvalue-prop-title": "Título de cada páxina.",
+ "apihelp-query+fileusage-paramvalue-prop-redirect": "Marca de se a páxina é unha redirección.",
"apihelp-query+fileusage-param-namespace": "Só incluír páxinas nestes espazos de nomes.",
"apihelp-query+fileusage-param-limit": "Cantos mostrar.",
"apihelp-query+fileusage-param-show": "Mostrar só elementos que cumpren estes criterios:\n;redirect:Só mostra redireccións.\n;!redirect:Só mostra as que non son redireccións.",
@@ -605,6 +701,7 @@
"apihelp-query+imageinfo-param-extmetadatalanguage": "Que lingua buscar en extmetadata. Isto afecta tanto á tradución a buscar, se hai varias dispoñibles, como a como se formatean cousas como os números e outros valores.",
"apihelp-query+imageinfo-param-extmetadatamultilang": "Se as traducións para a propiedade extmetadata están dispoñibles, búscaas todas.",
"apihelp-query+imageinfo-param-extmetadatafilter": "Se está especificado e non baleiro, só se devolverán esas claves para $1prop=extmetadata.",
+ "apihelp-query+imageinfo-param-urlparam": "Unha cadea de parámetro específico no analizador. Por exemplo, os PDFs poden usar <kbd>page15-100px</kbd>. Debe usarse <var>$1urlwidth</var> que debe ser coherente con <var>$1urlparam</var>.",
"apihelp-query+imageinfo-param-localonly": "Só buscar ficheiros no repositorio local.",
"apihelp-query+imageinfo-example-simple": "Busca a información sobre a versión actual de [[:File:Albert Einstein Head.jpg]].",
"apihelp-query+imageinfo-example-dated": "Busca información sobre as versións de [[:File:Test.jpg]] posteriores a 2008.",
@@ -644,13 +741,16 @@
"apihelp-query+iwbacklinks-param-prefix": "Prefixo para a interwiki.",
"apihelp-query+iwbacklinks-param-title": "Ligazón interwiki a buscar. Debe usarse con <var>$1blprefix</var>.",
"apihelp-query+iwbacklinks-param-limit": "Número total de páxinas a devolver.",
- "apihelp-query+iwbacklinks-param-prop": "Que propiedades obter:\n;iwprefix:Engade o prefixo da interwiki.\n;iwtitle:Engade o título da interwiki.",
+ "apihelp-query+iwbacklinks-param-prop": "Que propiedades obter:",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Engade o prefixo da interwiki.",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Engade o título da interwiki.",
"apihelp-query+iwbacklinks-param-dir": "Dirección na cal listar.",
"apihelp-query+iwbacklinks-example-simple": "Obter as páxinas ligadas a [[wikibooks:Test]]",
"apihelp-query+iwbacklinks-example-generator": "Obter información sobre as páxinas que ligan a [[wikibooks:Test]].",
"apihelp-query+iwlinks-description": "Devolve todas as ligazóns interwiki ás páxinas indicadas.",
"apihelp-query+iwlinks-param-url": "Se obter a URL completa (non pode usarse con $1prop).",
- "apihelp-query+iwlinks-param-prop": "Que propiedades adicionais obter para cada ligazón interwiki:\n;url:Engade a URL completa.",
+ "apihelp-query+iwlinks-param-prop": "Que propiedades adicionais obter para cada ligazón interwiki:",
+ "apihelp-query+iwlinks-paramvalue-prop-url": "Engade a URL completa.",
"apihelp-query+iwlinks-param-limit": "Cantas ligazóns interwiki devolver.",
"apihelp-query+iwlinks-param-prefix": "Só devolver ligazóns interwiki con este prefixo.",
"apihelp-query+iwlinks-param-title": "Ligazón interwiki a buscar. Debe usarse con <var>$1prefix</var>.",
@@ -660,14 +760,19 @@
"apihelp-query+langbacklinks-param-lang": "Lingua para a ligazón de lingua.",
"apihelp-query+langbacklinks-param-title": "Ligazón de lingua a buscar. Debe usarse con $1lang.",
"apihelp-query+langbacklinks-param-limit": "Número total de páxinas a devolver.",
- "apihelp-query+langbacklinks-param-prop": "Que propiedades obter:\n;lllang:Engade o código de lingua á ligazón de páxina.\n;lltitle:Engade o título da ligazón de lingua.",
+ "apihelp-query+langbacklinks-param-prop": "Que propiedades obter:",
+ "apihelp-query+langbacklinks-paramvalue-prop-lllang": "Engade o código de lingua á ligazón de páxina.",
+ "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Engade o título da ligazón de lingua.",
"apihelp-query+langbacklinks-param-dir": "Dirección na cal listar.",
"apihelp-query+langbacklinks-example-simple": "Obter as páxinas ligadas a [[:fr:Test]].",
"apihelp-query+langbacklinks-example-generator": "Obter información sobre as páxinas que ligan a [[:fr:Test]].",
"apihelp-query+langlinks-description": "Devolve todas as ligazóns interwiki ás páxinas indicadas.",
"apihelp-query+langlinks-param-limit": "Cantas ligazóns de lingua devolver.",
"apihelp-query+langlinks-param-url": "Se obter a URL completa (non pode usarse con <var>$1prop</var>).",
- "apihelp-query+langlinks-param-prop": "Que propiedades adicionais obter para cada ligazón interlingüística:\n;url:Engade a URL completa.\n;langname:Engade o nome localizado da lingua (o mellor intento). Use <var>$1inlanguagecode</var> para controlar a lingua.\n;autonym:Engade o nome nativo da lingua.",
+ "apihelp-query+langlinks-param-prop": "Que propiedades adicionais obter para cada ligazón interlingüística:",
+ "apihelp-query+langlinks-paramvalue-prop-url": "Engade a URL completa.",
+ "apihelp-query+langlinks-paramvalue-prop-langname": "Engade o nome localizado da lingua (o mellor intento). Use <var>$1inlanguagecode</var> para controlar a lingua.",
+ "apihelp-query+langlinks-paramvalue-prop-autonym": "Engade o nome nativo da lingua.",
"apihelp-query+langlinks-param-lang": "Devolver só ligazóns de lingua con este código de lingua.",
"apihelp-query+langlinks-param-title": "Ligazón a buscar. Debe usarse con <var>$1lang</var>.",
"apihelp-query+langlinks-param-dir": "Dirección na cal listar.",
@@ -682,15 +787,29 @@
"apihelp-query+links-example-generator": "Obter información sobre as ligazóns de páxina da <kbd>Main Page</kbd>.",
"apihelp-query+links-example-namespaces": "Obter as ligazóns á páxina <kbd>Main Page</kbd> nos espazos de nome {{ns:user}} e {{ns:template}}.",
"apihelp-query+linkshere-description": "Atopar todas as páxinas que ligan coas páxinas dadas.",
- "apihelp-query+linkshere-param-prop": "Que propiedades obter:\n;pageid:ID de cada páxina.\n;título:Título de cada páxina.\n;redirect:Marca de se a páxina é unha redirección.",
+ "apihelp-query+linkshere-param-prop": "Que propiedades obter:",
+ "apihelp-query+linkshere-paramvalue-prop-pageid": "ID de cada páxina.",
+ "apihelp-query+linkshere-paramvalue-prop-title": "Título de cada páxina.",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "Marca de se a páxina é unha redirección.",
"apihelp-query+linkshere-param-namespace": "Só incluír páxinas nestes espazos de nomes.",
"apihelp-query+linkshere-param-limit": "Cantos mostrar.",
"apihelp-query+linkshere-param-show": "Mostrar só elementos que cumpren estes criterios:\n;redirect:Só mostra redireccións.\n;!redirect:Só mostra as que non son redireccións.",
"apihelp-query+linkshere-example-simple": "Obter unha lista que ligan á [[Main Page]]",
"apihelp-query+linkshere-example-generator": "Obter a información das páxinas que ligan á [[Main Page]].",
"apihelp-query+logevents-description": "Obter os eventos dos rexistros.",
+ "apihelp-query+logevents-param-prop": "Que propiedades obter:",
+ "apihelp-query+logevents-paramvalue-prop-ids": "Engade o identificador do evento.",
+ "apihelp-query+logevents-paramvalue-prop-title": "Engade o título da páxina para o evento.",
+ "apihelp-query+logevents-paramvalue-prop-type": "Engade o tipo de evento.",
+ "apihelp-query+logevents-paramvalue-prop-user": "Engade o usuario responsable do evento.",
+ "apihelp-query+logevents-paramvalue-prop-userid": "Engade o identificador do usuario responsable do evento.",
+ "apihelp-query+logevents-paramvalue-prop-timestamp": "Engade o selo de tempo do evento.",
+ "apihelp-query+logevents-paramvalue-prop-comment": "Engade o comentario do evento.",
+ "apihelp-query+logevents-paramvalue-prop-parsedcomment": "Engade o comentario analizado do evento.",
+ "apihelp-query+logevents-paramvalue-prop-details": "Lista detalles adicionais do evento.",
+ "apihelp-query+logevents-paramvalue-prop-tags": "Lista as etiquetas do evento.",
"apihelp-query+logevents-param-type": "Filtrar as entradas do rexistro para mostrar só as deste tipo.",
- "apihelp-query+logevents-param-action": "Filtrar accións no rexistro para mostrar só esta acción. Ignora <var>$1type</var>. Accións comodín como <kbd>action/*</kbd> permiten especificar calquera cadea para o asterisco.",
+ "apihelp-query+logevents-param-action": "Filtrar accións no rexistro para mostrar só esta acción. Ignora <var>$1type</var>. Na lista de posibles valores, valores coa máscara asterisco como <kbd>action/*</kbd> poden ter diferentes cadeas despois da barra (/).",
"apihelp-query+logevents-param-start": "Selo de tempo no que comezar a enumeración.",
"apihelp-query+logevents-param-end": "Selo de tempo para rematar a enumeración.",
"apihelp-query+logevents-param-user": "Filtrar entradas ás feitas polo usuario indicado.",
@@ -705,14 +824,17 @@
"apihelp-query+pagepropnames-example-simple": "Obter os dez primeiros nomes de propiedade.",
"apihelp-query+pageprops-description": "Obter varias propiedades definidas no contido da páxina.",
"apihelp-query+pageprops-param-prop": "Listar só esas propiedades. Útil para verificar se unha páxina concreta usa unha propiedade de páxina determinada.",
- "apihelp-query+pageprops-example-simple": "Obter as propiedades para <kbd>Category:Foo</kbd>.",
+ "apihelp-query+pageprops-example-simple": "Obter as propiedades para as páxinas <kbd>Main Page</kbd> e <kbd>MediaWiki</kbd>",
"apihelp-query+pageswithprop-description": "Mostrar a lista de páxinas que empregan unha propiedade determinada.",
"apihelp-query+pageswithprop-param-propname": "Propiedade de páxina pola que enumerar as páxinas.",
- "apihelp-query+pageswithprop-param-prop": "Que información incluír:\n;ids:Engade o ID da páxina.\n;title:Engade o título e o ID do espazo de nomes da páxina.\n;value:Engade o valor da propiedade da páxina.",
+ "apihelp-query+pageswithprop-param-prop": "Que información incluír:",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "Engade o ID da páxina.",
+ "apihelp-query+pageswithprop-paramvalue-prop-title": "Engade o título e o ID do espazo de nomes da páxina.",
+ "apihelp-query+pageswithprop-paramvalue-prop-value": "Engade o valor da propiedade da páxina.",
"apihelp-query+pageswithprop-param-limit": "Máximo número de páxinas a retornar.",
"apihelp-query+pageswithprop-param-dir": "En que dirección ordenar.",
"apihelp-query+pageswithprop-example-simple": "Lista as dez primeiras páxinas que usan <code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code>.",
- "apihelp-query+pageswithprop-example-generator": "Obter a infomación de páxina das dez primeiras páxinas que usan <code>_&#95;NOTOC_&#95;</code>.",
+ "apihelp-query+pageswithprop-example-generator": "Obter información adicional das dez primeiras páxinas que usan <code>_&#95;NOTOC_&#95;</code>.",
"apihelp-query+prefixsearch-description": "Facer unha busca de prefixo nos títulos das páxinas.",
"apihelp-query+prefixsearch-param-search": "Buscar texto.",
"apihelp-query+prefixsearch-param-namespace": "Espazo de nomes no que buscar.",
@@ -725,16 +847,25 @@
"apihelp-query+protectedtitles-param-limit": "Número total de páxinas a devolver.",
"apihelp-query+protectedtitles-param-start": "Comezar a listar neste selo de tempo de protección.",
"apihelp-query+protectedtitles-param-end": "Rematar de listar neste selo de tempo de protección.",
- "apihelp-query+protectedtitles-param-prop": "Que propiedades obter:\n;timestamp:Engade o selo de tempo de cando se fixo a protección.\n;user:Engade o usuario que fixo a protección.\n;userid:Engade o ID do usuario que fixo a protección.\n;comment:Engade o comentario da protección.\n;parsedcomment:Engade o comentario analizado da protección.\n;expiry:Engade o selo de tempo no que rematará a protección\n;level:Engade o nivel de protección.",
+ "apihelp-query+protectedtitles-param-prop": "Que propiedades obter:",
+ "apihelp-query+protectedtitles-paramvalue-prop-timestamp": "Engade o selo de tempo de cando se fixo a protección.",
+ "apihelp-query+protectedtitles-paramvalue-prop-user": "Engade o usuario que fixo a protección.",
+ "apihelp-query+protectedtitles-paramvalue-prop-userid": "Engade o ID do usuario que fixo a protección.",
+ "apihelp-query+protectedtitles-paramvalue-prop-comment": "Engade o comentario da protección.",
+ "apihelp-query+protectedtitles-paramvalue-prop-parsedcomment": "Engade o comentario analizado da protección.",
+ "apihelp-query+protectedtitles-paramvalue-prop-expiry": "Engade o selo de tempo no que rematará a protección",
+ "apihelp-query+protectedtitles-paramvalue-prop-level": "Engade o nivel de protección.",
"apihelp-query+protectedtitles-example-simple": "Listar títulos protexidos",
"apihelp-query+protectedtitles-example-generator": "Atopar ligazóns ós títulos protexidos no espazo de nomes principal",
"apihelp-query+querypage-description": "Obtén unha lista proporcionada por unha páxina especial basada en QueryPage.",
"apihelp-query+querypage-param-page": "Nome da páxina especial. Teña en conta que diferencia entre maiúsculas e minúsculas.",
"apihelp-query+querypage-param-limit": "Número de resultados a visualizar.",
"apihelp-query+querypage-example-ancientpages": "Resultados devoltos de [[Special:Ancientpages]].",
+ "apihelp-query+random-description": "Obter un conxunto de páxinas aleatorias.\n\nAs páxinas están listadas nunha secuencia fixa, só o punto de comezo é aleatorio. Isto significa que se, por exemplo, a <samp>Main Page</samp> é a primeira páxina aleatoria da lista, a <samp>Lista de monos ficticios</samp> será <em>sempre</em> a segunda, <samp>Lista de xente en selos de Vanuatu</samp> será a terceira, etc.",
"apihelp-query+random-param-namespace": "Devolver páxinas só neste espazo de nomes.",
"apihelp-query+random-param-limit": "Limitar cantas páxinas aleatorias se van devolver.",
- "apihelp-query+random-param-redirect": "Cargar unha redirección aleatoria no canto dunha páxina aleatoria.",
+ "apihelp-query+random-param-redirect": "No canto use <kbd>$1filterredir=redirects</kbd>.",
+ "apihelp-query+random-param-filterredir": "Como filtrar para redireccións.",
"apihelp-query+random-example-simple": "Obter dúas páxinas aleatorias do espazo de nomes principal.",
"apihelp-query+random-example-generator": "Obter a información da páxina de dúas páxinas aleatorias do espazo de nomes principal.",
"apihelp-query+recentchanges-description": "Enumerar cambios recentes.",
@@ -744,6 +875,21 @@
"apihelp-query+recentchanges-param-user": "Só listar cambios deste usuario.",
"apihelp-query+recentchanges-param-excludeuser": "Non listar cambios deste usuario.",
"apihelp-query+recentchanges-param-tag": "Só listar cambios marcados con esta etiqueta.",
+ "apihelp-query+recentchanges-param-prop": "Inclúe información adicional:",
+ "apihelp-query+recentchanges-paramvalue-prop-user": "Engade o usuario responsable da modificación e marca se é unha dirección IP.",
+ "apihelp-query+recentchanges-paramvalue-prop-userid": "Engade o identificador do usuario responsable da edición.",
+ "apihelp-query+recentchanges-paramvalue-prop-comment": "Engade o comentario da edición.",
+ "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "Engade o comentario analizado da edición.",
+ "apihelp-query+recentchanges-paramvalue-prop-flags": "Engade os indicadores da edición.",
+ "apihelp-query+recentchanges-paramvalue-prop-timestamp": "Engade o selo de tempo da edición.",
+ "apihelp-query+recentchanges-paramvalue-prop-title": "Engade o título da páxina da edición.",
+ "apihelp-query+recentchanges-paramvalue-prop-ids": "Engade o identificador da páxina, o identificador dos cambios recentes e o identificador da versión nova e da vella.",
+ "apihelp-query+recentchanges-paramvalue-prop-sizes": "Engade a lonxitude nova e vella da páxina en bytes.",
+ "apihelp-query+recentchanges-paramvalue-prop-redirect": "Pon unha marca se a páxina é unha redirección.",
+ "apihelp-query+recentchanges-paramvalue-prop-patrolled": "Marca as edicións vixiables como vixiadas ou non vixiadas.",
+ "apihelp-query+recentchanges-paramvalue-prop-loginfo": "Engade información do rexistro (identificador de rexistro, tipo de rexistro, etc) nas entradas do rexistro.",
+ "apihelp-query+recentchanges-paramvalue-prop-tags": "Lista as etiquetas da entrada.",
+ "apihelp-query+recentchanges-paramvalue-prop-sha1": "Engade o control de contido para as entradas asociadas a unha revisión.",
"apihelp-query+recentchanges-param-token": "Usar <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> no canto diso.",
"apihelp-query+recentchanges-param-show": "Só mostrar elementos que cumpran esos criterios. Por exemplo, para ver só edicións menores feitas por usuarios conectados, activar $1show=minor|!anon.",
"apihelp-query+recentchanges-param-limit": "Número total de páxinas a devolver.",
@@ -752,7 +898,10 @@
"apihelp-query+recentchanges-example-simple": "Listar cambios recentes.",
"apihelp-query+recentchanges-example-generator": "Obter a información de páxina sobre cambios recentes sen vixiancia.",
"apihelp-query+redirects-description": "Devolve todas as redireccións das páxinas indicadas.",
- "apihelp-query+redirects-param-prop": "Que propiedades recuperar:\n;pageid:ID de páxina de cada redirección.\n;title:Título de cada redirección.\n;fragment:Fragmento de cada redirección, se hai algún.",
+ "apihelp-query+redirects-param-prop": "Que propiedades recuperar:",
+ "apihelp-query+redirects-paramvalue-prop-pageid": "ID de páxina de cada redirección.",
+ "apihelp-query+redirects-paramvalue-prop-title": "Título de cada redirección.",
+ "apihelp-query+redirects-paramvalue-prop-fragment": "Fragmento de cada redirección, se hai algún.",
"apihelp-query+redirects-param-namespace": "Só incluir páxinas nestes espacios de nomes.",
"apihelp-query+redirects-param-limit": "Cantos redireccións devolver.",
"apihelp-query+redirects-param-show": "Só mostrar elementos que cumpran estos criterios:\n;fragment:Só mostrar redireccións que teñan un fragmento.\n;!fragment:Só mostrar redireccións que non teñan un fragmento.",
@@ -774,19 +923,47 @@
"apihelp-query+revisions-example-first5-after": "Mostrar as cinco primeiras revisións da <kbd>Páxina Principal</kbd> feitas despois de 2006-05-01.",
"apihelp-query+revisions-example-first5-not-localhost": "Mostrar as cinco primeiras revisións da <kbd>Páxina Principal</kbd> que non foron feitas polo usuario anónimo <kbd>127.0.0.1</kbd>.",
"apihelp-query+revisions-example-first5-user": "Mostrar as cinco primeiras revisión da <kbd>Páxina Principal</kbd> feitas polo usuario <kbd>MediaWiki default</kbd>.",
+ "apihelp-query+revisions+base-param-prop": "Que propiedades mostrar para cada modificación:",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "O identificador da modificación.",
+ "apihelp-query+revisions+base-paramvalue-prop-flags": "Marcas de modificación (menor).",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "O selo de tempo da modificación.",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "Usuario que fixo a revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-userid": "Identificador de usuario do creador da modificación.",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "Lonxitude (en bytes) da revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "SHA-1 (base 16) da modificación.",
+ "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "Identificador do modelo de contido da modificación.",
+ "apihelp-query+revisions+base-paramvalue-prop-comment": "Comentario do usuario para a modificación.",
+ "apihelp-query+revisions+base-paramvalue-prop-parsedcomment": "Comentario analizado do usuario para a modificación.",
+ "apihelp-query+revisions+base-paramvalue-prop-content": "Texto da revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-tags": "Etiquetas para a revisión.",
+ "apihelp-query+revisions+base-paramvalue-prop-parsetree": "Árbore de análise XML do contido da modificación (precisa o modelo de contido <code>$1</code>).",
"apihelp-query+revisions+base-param-limit": "Limitar cantas revisións se van devolver.",
"apihelp-query+revisions+base-param-expandtemplates": "Expandir os modelos no contido da revisión (require $1prop=content).",
- "apihelp-query+revisions+base-param-generatexml": "Xenerar a árbore de análise XML para o contido da revisión (require $1prop=content).",
+ "apihelp-query+revisions+base-param-generatexml": "Xenerar a árbore de análise XML para o contido da revisión (require $1prop=content; substituído por <kbd>$1prop=parsetree</kbd>).",
"apihelp-query+revisions+base-param-parse": "Analizar o contido da revisión (require $1prop=content). Por razóns de rendemento, se se usa esta opción, $1limit cámbiase a 1.",
"apihelp-query+revisions+base-param-section": "Recuperar unicamente o contido deste número de sección.",
"apihelp-query+revisions+base-param-diffto": "ID de revisión a comparar con cada revisión. Use <kbd>prev</kbd>, <kbd>next</kbd> e <kbd>cur</kbd> para a versión precedente, seguinte e actual respectivamente.",
"apihelp-query+revisions+base-param-difftotext": "Texto co que comparar cada revisión. Só compara un número limitado de revisións. Ignora <var>$1diffto</var>. Se <var>$1section</var> ten valor, só se comparará co texto esa sección.",
"apihelp-query+revisions+base-param-contentformat": "Formato de serialización usado por <var>$1difftotext</var> e esperado para a saída do contido.",
"apihelp-query+search-description": "Facer unha busca por texto completo.",
- "apihelp-query+search-param-search": "Buscar tódolos títulos de páxina (ou contido) que teñan este valor.",
+ "apihelp-query+search-param-search": "Buscar os títulos de páxina ou contido que coincidan con este valor. Pode usar a cadea de busca para invocar funcións especiais de busca, dependendo do motor de busca que teña a wiki.",
"apihelp-query+search-param-namespace": "Buscar só nestes espazos de nomes.",
"apihelp-query+search-param-what": "Que tipo de busca lanzar.",
"apihelp-query+search-param-info": "Que metadatos devolver.",
+ "apihelp-query+search-param-prop": "Que propiedades devolver:",
+ "apihelp-query+search-paramvalue-prop-size": "Engade o tamaño da páxina en bytes.",
+ "apihelp-query+search-paramvalue-prop-wordcount": "Engade o número de palabras da páxina.",
+ "apihelp-query+search-paramvalue-prop-timestamp": "Engade o selo de tempo da última vez que foi editada a páxina.",
+ "apihelp-query+search-paramvalue-prop-snippet": "Engade o fragmento analizado da páxina.",
+ "apihelp-query+search-paramvalue-prop-titlesnippet": "Engade un fragmento analizado do título da páxina.",
+ "apihelp-query+search-paramvalue-prop-redirectsnippet": "Engade un fragmento analizado do título da redirección.",
+ "apihelp-query+search-paramvalue-prop-redirecttitle": "Engade o título da redirección asociada.",
+ "apihelp-query+search-paramvalue-prop-sectionsnippet": "Engade un fragmento analizado do título de sección asociado.",
+ "apihelp-query+search-paramvalue-prop-sectiontitle": "Engade o título da sección asociada.",
+ "apihelp-query+search-paramvalue-prop-categorysnippet": "Engade un fragmento analizado da categoría asociada.",
+ "apihelp-query+search-paramvalue-prop-isfilematch": "Engade unha marca indicando se o resultado da busca é un ficheiro.",
+ "apihelp-query+search-paramvalue-prop-score": "<span class=\"apihelp-deprecated\">Obsoleto e ignorado.</span>",
+ "apihelp-query+search-paramvalue-prop-hasrelated": "<span class=\"apihelp-deprecated\">Obsoleto e ignorado.</span>",
"apihelp-query+search-param-limit": "Número total de páxinas a devolver.",
"apihelp-query+search-param-interwiki": "Incluir na busca resultados de interwikis, se é posible.",
"apihelp-query+search-param-backend": "Que servidor de busca usar, se non se indica usa o que hai por defecto.",
@@ -794,6 +971,29 @@
"apihelp-query+search-example-text": "Buscar texto por <kbd>significado</kbd>.",
"apihelp-query+search-example-generator": "Obter información da páxina sobre as páxinas devoltas por unha busca por <kbd>significado</kbd>.",
"apihelp-query+siteinfo-description": "Devolver información xeral sobre o sitio.",
+ "apihelp-query+siteinfo-param-prop": "Que información obter:",
+ "apihelp-query+siteinfo-paramvalue-prop-general": "Información xeral do sistema.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespaces": "Lista dos espazos de nomes rexistrados e os seus nomes canónicos.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespacealiases": "Lista de alias de espazos de nomes rexistrados .",
+ "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "Lista de alias de páxinas especiais.",
+ "apihelp-query+siteinfo-paramvalue-prop-magicwords": "Lista de palabras máxicas e os seus alias.",
+ "apihelp-query+siteinfo-paramvalue-prop-statistics": "Devolve as estatísticas do sitio.",
+ "apihelp-query+siteinfo-paramvalue-prop-interwikimap": "Devolve o mapa interwiki (opcionalmente filtrado, opcionalmente localizado usando <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-dbrepllag": "Devolve o servidor de base de datos con maior retardo de replicación.",
+ "apihelp-query+siteinfo-paramvalue-prop-usergroups": "Devolve os grupos de usuarios e os permisos que teñen asociados.",
+ "apihelp-query+siteinfo-paramvalue-prop-libraries": "Devolve as bibliotecas de funcións software instaladas na wiki.",
+ "apihelp-query+siteinfo-paramvalue-prop-extensions": "Devolve as extensións instaladas na wiki.",
+ "apihelp-query+siteinfo-paramvalue-prop-fileextensions": "Devolve a lista de extenxións de ficheiro permitidas para subir ficheiros.",
+ "apihelp-query+siteinfo-paramvalue-prop-rightsinfo": "Devolve a información dos dereitos (licenza) da wiki se está dispoñible.",
+ "apihelp-query+siteinfo-paramvalue-prop-restrictions": "Devolve información dos tipos de restricións (protección) dispoñibles.",
+ "apihelp-query+siteinfo-paramvalue-prop-languages": "Devolve unha lista dos idiomas que soporta Mediawiki (opcionalmente pode localizarse usando <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-skins": "Devolve unha lista de todas as aparencias dispoñibles (opcionalmente pode localizarse usando <var>$1inlanguagecode</var>, noutro caso no idioma do contido).",
+ "apihelp-query+siteinfo-paramvalue-prop-extensiontags": "Devolve unha lista de etiquetas de extensión de analizador.",
+ "apihelp-query+siteinfo-paramvalue-prop-functionhooks": "Devolve unha lista de ganchos de función de analizador.",
+ "apihelp-query+siteinfo-paramvalue-prop-showhooks": "Devolve unha lista de todos os ganchos subscritos (contido de <var>[[mw:Manual:$wgHooks|$wgHooks]]</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-variables": "Devolve unha lista de identificadores de variable.",
+ "apihelp-query+siteinfo-paramvalue-prop-protocols": "Devolve unha lista de protocolos que están permitidos nas ligazóns externas.",
+ "apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Devolve os valores por defecto das preferencias de usuario.",
"apihelp-query+siteinfo-param-filteriw": "Só devolver entradas locais ou só non locais da correspondencia interwiki.",
"apihelp-query+siteinfo-param-showalldb": "Listar todos os servidores de base de datos, non só o que teña máis retardo.",
"apihelp-query+siteinfo-param-numberingroup": "Listar o número de usuarios nos grupos de usuarios.",
@@ -808,6 +1008,14 @@
"apihelp-query+stashimageinfo-example-params": "Devolve as miniaturas de dous ficheiros almacenados.",
"apihelp-query+tags-description": "Lista de marcas de cambios.",
"apihelp-query+tags-param-limit": "Máximo número de etiquetas a listar.",
+ "apihelp-query+tags-param-prop": "Que propiedades recuperar:",
+ "apihelp-query+tags-paramvalue-prop-name": "Engade o nome da etiqueta.",
+ "apihelp-query+tags-paramvalue-prop-displayname": "Engade a mensaxe do sistema para a etiqueta.",
+ "apihelp-query+tags-paramvalue-prop-description": "Engade a descrición da etiqueta.",
+ "apihelp-query+tags-paramvalue-prop-hitcount": "Engade o número de modificacións e de entradas do rexistro que teñen esta etiqueta.",
+ "apihelp-query+tags-paramvalue-prop-defined": "Indica se a etiqueta está definida.",
+ "apihelp-query+tags-paramvalue-prop-source": "Obtén as fontes da etiqueta, que poden incluír <samp>extension</samp> para etiquetas definidas en extensión e <samp>manual</samp> para etiquetas que poden ser aplicadas manualmente polos usuarios.",
+ "apihelp-query+tags-paramvalue-prop-active": "Se a etiqueta aínda está a ser usada.",
"apihelp-query+tags-example-simple": "Listar as marcas dispoñibles",
"apihelp-query+templates-description": "Devolve todas as páxinas incluídas na páxina indicada.",
"apihelp-query+templates-param-namespace": "Mostrar modelos só neste espazo de nomes.",
@@ -822,7 +1030,10 @@
"apihelp-query+tokens-example-simple": "Recuperar un identificador csrf (por defecto).",
"apihelp-query+tokens-example-types": "Recuperar un identificador vixiancia e un de patrulla.",
"apihelp-query+transcludedin-description": "Atopar todas as páxinas que inclúen ás páxinas indicadas.",
- "apihelp-query+transcludedin-param-prop": "Que propiedades obter:\n;pageid:ID de páxina de cada páxina.\n;title:Título de cada páxina.\n;redirect:Marca si a páxina é unha redirección.",
+ "apihelp-query+transcludedin-param-prop": "Que propiedades obter:",
+ "apihelp-query+transcludedin-paramvalue-prop-pageid": "ID de páxina de cada páxina.",
+ "apihelp-query+transcludedin-paramvalue-prop-title": "Título de cada páxina.",
+ "apihelp-query+transcludedin-paramvalue-prop-redirect": "Marca si a páxina é unha redirección.",
"apihelp-query+transcludedin-param-namespace": "Só incluir páxinas nestes espacios de nomes.",
"apihelp-query+transcludedin-param-limit": "Cantos mostrar.",
"apihelp-query+transcludedin-param-show": "Mostrar só elementos que cumpren estes criterios:\n;redirect:Só mostra redireccións.\n;!redirect:Só mostra as que non son redireccións.",
@@ -835,16 +1046,51 @@
"apihelp-query+usercontribs-param-user": "Usuarios para os que recuperar as contribucións.",
"apihelp-query+usercontribs-param-userprefix": "Recuperar as contribucións de todos os usuarios cuxo nome comece por este valor. Ignora $1user.",
"apihelp-query+usercontribs-param-namespace": "Só listar contribucións nestes espazos de nomes.",
+ "apihelp-query+usercontribs-param-prop": "Engade información adicional:",
+ "apihelp-query+usercontribs-paramvalue-prop-ids": "Engade os identificadores de páxina e modificación.",
+ "apihelp-query+usercontribs-paramvalue-prop-title": "Engade o título e o identificador do espazo de nomes da páxina.",
+ "apihelp-query+usercontribs-paramvalue-prop-timestamp": "Engade o selo de tempo da modificación.",
+ "apihelp-query+usercontribs-paramvalue-prop-comment": "Engade o comentario da modificación.",
+ "apihelp-query+usercontribs-paramvalue-prop-parsedcomment": "Engade o comentario analizado da modificación.",
+ "apihelp-query+usercontribs-paramvalue-prop-size": "Engade o novo tamaño da modificación.",
+ "apihelp-query+usercontribs-paramvalue-prop-sizediff": "Engade o delta do tamaño da modificación comparada coa anterior.",
+ "apihelp-query+usercontribs-paramvalue-prop-flags": "Engade os indicadores da modificación.",
+ "apihelp-query+usercontribs-paramvalue-prop-patrolled": "Marca as modificacións vixiadas.",
+ "apihelp-query+usercontribs-paramvalue-prop-tags": "Lista as etiquetas da modificación.",
"apihelp-query+usercontribs-param-show": "Só mostrar elementos que cumpran estos criterios, p.ex. só edicións menores: <kbd>$2show=!minor</kbd>.\n\nSe está fixado <kbd>$2show=patrolled</kbd> ou <kbd>$2show=!patrolled</kbd>, as modificacións máis antigas que <var>[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|segundo|segundos}}) non se mostrarán.",
"apihelp-query+usercontribs-param-tag": "Só listar revisións marcadas con esta etiqueta.",
"apihelp-query+usercontribs-param-toponly": "Listar só cambios que son a última revisión.",
"apihelp-query+usercontribs-example-user": "Mostrar as contribucións do usuario <kbd>Exemplo</kbd>.",
"apihelp-query+usercontribs-example-ipprefix": "Mostrar contribucións de tódalas direccións IP que comezan por <kbd>192.0.2.</kbd>.",
"apihelp-query+userinfo-description": "Obter información sobre o usuario actual.",
+ "apihelp-query+userinfo-param-prop": "Que pezas de información incluír:",
+ "apihelp-query+userinfo-paramvalue-prop-blockinfo": "Marca se o usuario actual está bloqueado, por que, e por que razón.",
+ "apihelp-query+userinfo-paramvalue-prop-hasmsg": "Engade unha etiqueta <samp>messages</samp> (mensaxe) se o usuario actual ten mensaxes pendentes.",
+ "apihelp-query+userinfo-paramvalue-prop-groups": "Lista todos os grupos ós que pertence o usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-implicitgroups": "Lista todos so grupos dos que o usuario actual é membro automaticamente.",
+ "apihelp-query+userinfo-paramvalue-prop-rights": "Lista todos os dereitos que ten o usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-changeablegroups": "Lista os grupos ós que o usuario pode engadir ou eliminar a outros usuarios.",
+ "apihelp-query+userinfo-paramvalue-prop-options": "Lista todas as preferencias que ten seleccionadas o usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-preferencestoken": "<span class=\"apihelp-deprecated\">Obsoleto.</span>Obtén o identificador para cambiar as preferencias do usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-editcount": "Engade o contador de edicións do usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-ratelimits": "Lista todos o límites de rango aplicados ó usuario actual.",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "Engade o nome real do usuario.",
+ "apihelp-query+userinfo-paramvalue-prop-email": "Engade a dirección de correo electrónico do usuario e a data de autenticación desa dirección.",
+ "apihelp-query+userinfo-paramvalue-prop-acceptlang": "Reenvía a cabeceira <code>Accept-Language</code> enviada polo cliente nun formato estruturado.",
+ "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Engade a data de rexistro do usuario.",
+ "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Engade o número de páxinas sen ler da lista de vixiancia do usuario (máximo $1; devolve <samp>$2</samp> se son máis).",
"apihelp-query+userinfo-example-simple": "Obter información sobre o usuario actual.",
"apihelp-query+userinfo-example-data": "Obter información adicional sobre o usuario actual.",
"apihelp-query+users-description": "Obter información sobre unha lista de usuarios.",
- "apihelp-query+users-param-prop": "Que información incluír:\n;blockinfo:Etiquetas se o usuario está bloqueado, por quen, e por que razón.\n;groups:Lista todos os grupos ós que pertence cada usuario.\n;implicitgroups:Lista os grupos dos que un usuario é membro de forma automatica.\n;rights:Lista todos os dereitos que ten cada usuario.\n;editcount:Engade o contador de edicións do usuario.\n;registration:Engade o selo de tempo do rexistro do usuario.\n;emailable:Marca se o usuario pode e quere recibir correos usando [[Special:Emailuser]].\n;gender:Marca o xénero do usuario. Devolve \"home\", \"muller\" ou \"descoñecido\".",
+ "apihelp-query+users-param-prop": "Que información incluír:",
+ "apihelp-query+users-paramvalue-prop-blockinfo": "Etiquetas se o usuario está bloqueado, por quen, e por que razón.",
+ "apihelp-query+users-paramvalue-prop-groups": "Lista todos os grupos ós que pertence cada usuario.",
+ "apihelp-query+users-paramvalue-prop-implicitgroups": "Lista os grupos dos que un usuario é membro de forma automatica.",
+ "apihelp-query+users-paramvalue-prop-rights": "Lista todos os dereitos que ten cada usuario.",
+ "apihelp-query+users-paramvalue-prop-editcount": "Engade o contador de edicións do usuario.",
+ "apihelp-query+users-paramvalue-prop-registration": "Engade o selo de tempo do rexistro do usuario.",
+ "apihelp-query+users-paramvalue-prop-emailable": "Marca se o usuario pode e quere recibir correos usando [[Special:Emailuser]].",
+ "apihelp-query+users-paramvalue-prop-gender": "Marca o xénero do usuario. Devolve \"home\", \"muller\" ou \"descoñecido\".",
"apihelp-query+users-param-users": "Lista de usuarios para os que obter información.",
"apihelp-query+users-param-token": "Usar <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> no canto diso.",
"apihelp-query+users-example-simple": "Mostar información para o usuario <kbd>Exemplo</kbd>.",
@@ -856,6 +1102,19 @@
"apihelp-query+watchlist-param-user": "Só listar cambios deste usuario.",
"apihelp-query+watchlist-param-excludeuser": "Non listar cambios deste usuario.",
"apihelp-query+watchlist-param-limit": "Cantos resultados totais mostrar por petición.",
+ "apihelp-query+watchlist-param-prop": "Que propiedades adicionais obter:",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "Engade os identificadores das revisións e os identificadores das páxinas.",
+ "apihelp-query+watchlist-paramvalue-prop-title": "Engade o título da páxina.",
+ "apihelp-query+watchlist-paramvalue-prop-flags": "Engade etiquetas para a edición.",
+ "apihelp-query+watchlist-paramvalue-prop-user": "Engade o usuario que fixo a edición.",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "Engade o identificador do usuario que fixo a edición.",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "Engade o comentario da edición.",
+ "apihelp-query+watchlist-paramvalue-prop-parsedcomment": "Engade o comentario analizado da edición.",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "Engade o selo de tempo da edición.",
+ "apihelp-query+watchlist-paramvalue-prop-patrol": "Marca edicións que están vixiadas.",
+ "apihelp-query+watchlist-paramvalue-prop-sizes": "Engade o tamaño antigo e novo da páxina.",
+ "apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "Engade o selo de tempo da última vez en que o usuario foi avisado da modificación.",
+ "apihelp-query+watchlist-paramvalue-prop-loginfo": "Engade información do rexistro cando sexa axeitado.",
"apihelp-query+watchlist-param-show": "Só mostrar elementos que cumpran esos criterios. Por exemplo, para ver só edicións menores feitas por usuarios conectados, activar $1show=minor|!anon.",
"apihelp-query+watchlist-param-type": "Que tipos de cambios mostrar:\n;edit:Modificacións normais de páxina.\n;external:Modificacións externas.\n;new:Creación de páxinas.\n;log:Entradas no rexistro.",
"apihelp-query+watchlist-param-owner": "Usado con $1token para acceder á lista de páxinas de vixiancia doutro usuario.",
@@ -869,10 +1128,13 @@
"apihelp-query+watchlistraw-description": "Obter todas as páxinas da lista de vixiancia do usuario actual.",
"apihelp-query+watchlistraw-param-namespace": "Só listar páxinas nestes espazos de nomes.",
"apihelp-query+watchlistraw-param-limit": "Cantos resultados totais mostrar por petición.",
- "apihelp-query+watchlistraw-param-prop": "Que propiedades adicionais obter:\n;changed:Engade o selo de tempo da última notificación ó usuario dunha modificación.",
+ "apihelp-query+watchlistraw-param-prop": "Que propiedades adicionais obter:",
+ "apihelp-query+watchlistraw-paramvalue-prop-changed": "Engade o selo de tempo da última notificación ó usuario dunha modificación.",
"apihelp-query+watchlistraw-param-show": "Só listar os elementos que cumplen estos criterios.",
"apihelp-query+watchlistraw-param-owner": "Usado con $1token para acceder á lista de páxinas de vixiancia doutro usuario.",
"apihelp-query+watchlistraw-param-token": "Identificador de seguridade (dispoñible nas [[Special:Preferences#mw-prefsection-watchlist|preferencias]] de usuario) para permitir o acceso a outros á súa páxina de vixiancia.",
+ "apihelp-query+watchlistraw-param-fromtitle": "Título (co prefixo de espazo de nomes) dende o que comezar a enumerar.",
+ "apihelp-query+watchlistraw-param-totitle": "Título (co prefixo de espazo de nomes) no que rematar de enumerar.",
"apihelp-query+watchlistraw-example-simple": "Listar páxinas na lista de vixiancia do usuario actual.",
"apihelp-query+watchlistraw-example-generator": "Buscar a información de páxina das páxinas da lista de vixiancia do usuario actual.",
"apihelp-revisiondelete-description": "Borrar e restaurar revisións.",
@@ -896,7 +1158,7 @@
"apihelp-rollback-example-summary": "Desfacer as últimas edicións á páxina <kbd>Main Page</kbd> polo usuario da dirección IP <kbd>192.0.2.5</kbd> co resumo de edición <kbd>Revertindo vandalismo</kbd>, marcar esas edicións e a reversión como edicións de bot.",
"apihelp-rsd-description": "Exportar un esquema RSD (Really Simple Discovery, Descubrimento Moi Simple).",
"apihelp-rsd-example-simple": "Exportar o esquema RSD.",
- "apihelp-setnotificationtimestamp-description": "Actualiza o selo de tempo de notificación das páxinas vixiadas.\n\nIsto afecta ó resalte das páxinas modificadas na lista de vixiancia e historial, e o envío de correo cando a preferencia \"Mandarme un correo cando cambie unha páxina da miña lista de vixiancia\" está activa.",
+ "apihelp-setnotificationtimestamp-description": "Actualizar a data e hora da notificación das páxinas vixiadas.\n\nIsto afecta ao realce das páxinas modificadas na lista de vixiancia e no historial, e ao envío de correos cando a preferencia \"{{int:tog-enotifwatchlistpages}}\" está activada.",
"apihelp-setnotificationtimestamp-param-entirewatchlist": "Traballar en tódalas páxinas vixiadas.",
"apihelp-setnotificationtimestamp-param-timestamp": "Selo de tempo ó que fixar a notificación.",
"apihelp-setnotificationtimestamp-param-torevid": "Modificación á que fixar o selo de tempo de modificación (só unha páxina).",
@@ -905,6 +1167,15 @@
"apihelp-setnotificationtimestamp-example-page": "Restaurar o estado de notificación para a <kbd>Páxina Principal</kbd>.",
"apihelp-setnotificationtimestamp-example-pagetimestamp": "Fixar o selo de tempo de notificación para a <kbd>Main page</kbd> de forma que todas as edicións dende o 1 se xaneiro de 2012 queden sen revisar.",
"apihelp-setnotificationtimestamp-example-allpages": "Restaurar o estado de notificación para as páxinas no espazo de nomes de <kbd>{{ns:user}}</kbd>.",
+ "apihelp-tag-description": "Engadir ou eliminar etiquetas de cambio de revisións individuais ou entradas de rexistro.",
+ "apihelp-tag-param-rcid": "Identificadores de un ou máis cambios recentes nos que engadir ou eliminar a etiqueta.",
+ "apihelp-tag-param-revid": "Identificadores de unha ou máis revisións nas que engadir ou eliminar a etiqueta.",
+ "apihelp-tag-param-logid": "Identificadores de unha ou máis entradas do rexistro nas que engadir ou eliminar a etiqueta.",
+ "apihelp-tag-param-add": "Etiquetas a engadir. Só poden engadirse etiquetas definidas manualmente.",
+ "apihelp-tag-param-remove": "Etiquetas a eliminar. Só se poden eliminar as etiquetas definidas manualmente ou que non teñen ningunha definición.",
+ "apihelp-tag-param-reason": "Razón para o cambio.",
+ "apihelp-tag-example-rev": "Engadir a etiqueta <kbd>vandalismo</kbd> á revisión con identificador 123 sen indicar un motivo",
+ "apihelp-tag-example-log": "Eliminar a etiqueta <kbd>publicidade</kbd> da entrada do rexistro con identificador 123 co motivo <kbd>aplicada incorrectamente</kbd>",
"apihelp-tokens-description": "Obter os identificadores para accións de modificación de datos.\n\nEste módulo está obsoleto e foi reemprazado por [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
"apihelp-tokens-param-type": "Tipos de identificadores a consultar.",
"apihelp-tokens-example-edit": "Recuperar un identificador de modificación (por defecto).",
@@ -923,6 +1194,7 @@
"apihelp-undelete-param-watchlist": "Engadir ou eliminar a páxina da lista de vixiancia do usuario actual sen condicións, use as preferencias ou non cambie a vixiancia.",
"apihelp-undelete-example-page": "Restaurar a <kbd>Páxina Principal</kbd>.",
"apihelp-undelete-example-revisions": "Restaurar dúas revisións de <kbd>[[Main Page]]</kbd>.",
+ "apihelp-upload-description": "Subir un ficheiro, ou obter o estado de subas pedentes.\n\nHai varios métodos dispoñibles:\n*Subir o contido do ficheiro directamente, usando o parámetro <var>$1file</var>.\n*Subir o ficheiro por partes, usando os parámetros <var>$1filesize</var>, <var>$1chunk</var>, e <var>$1offset</var>.\n*Mandar ó servidor MediaWiki que colla un ficheiro dunha URL, usando o parámetro <var>$1url</var>.\n*Completar unha suba anterior que fallou a causa dos avisos, usando o parámetro <var>$1filekey</var>. \nTeña en conta que o HTTP POST debe facerse como suba de ficheiro (p.ex. usando <code>multipart/form-data</code>)cando se envie o <var>$1file</var>.",
"apihelp-upload-param-filename": "Nome de ficheiro obxectivo.",
"apihelp-upload-param-comment": "Subir comentario. Tamén usado como texto da páxina inicial para ficheiros novos se non se especifica <var>$1text</var>.",
"apihelp-upload-param-text": "Texto da páxina inicial para novos ficheiros.",
@@ -958,23 +1230,22 @@
"apihelp-watch-example-watch": "Vixiar a páxina <kbd>Páxina Principal</kbd>.",
"apihelp-watch-example-unwatch": "Deixar de vixiar a páxina <kbd>Páxina Principal</kbd>.",
"apihelp-watch-example-generator": "Vixiar as primeiras páxinas no espazo de nomes principal",
- "apihelp-format-example-generic": "Formatar o resultado da consulta no formato $1.",
+ "apihelp-format-example-generic": "Devolver o resultado da consulta no formato $1.",
"apihelp-dbg-description": "Datos de saída en formato <code>var_export()</code> de PHP.",
"apihelp-dbgfm-description": "Datos de saída en formato <code>var_export()</code> de PHP(impresión en HTML).",
- "apihelp-dump-description": "Datos de saída en formato PHP <code>var_dump()</code>.",
- "apihelp-dumpfm-description": "Datos de saída en formato <code>var_dump()</code> de PHP(impresión en HTML).",
"apihelp-json-description": "Datos de saída en formato JSON.",
"apihelp-json-param-callback": "Se está especificado, inclúe a saída na chamada da función indicada. Para maior seguridade, todos os datos específicos do usuario serán restrinxidos.",
- "apihelp-json-param-utf8": "Se está especificado, codifica a maioría (pero non todos) dos caracteres ASCII como UTF-8 no canto de reemprazalos con secuencias de escape hexadecimais.",
+ "apihelp-json-param-utf8": "Se está especificado, codifica a maioría (pero non todos) dos caracteres ASCII como UTF-8 no canto de reemprazalos con secuencias de escape hexadecimais. Por defecto cando <var>formatversion</var> non é <kbd>1</kbd>.",
+ "apihelp-json-param-ascii": "Se está indicado, codifica todos os caracteres que non sexan ASCII usando secuencias de escape hexadecimais. Por defecto cando <var>formatversion</var> é <kbd>1</kbd>.",
+ "apihelp-json-param-formatversion": "Formato de saída:\n;1:Formato compatible con versións anteriores(booleanos estilo XML,claves <samp>*</samp> para nodos, etc.).\n;2:Formato moderno experimental. Os detalles poden cambiar!\n;latest:Usa o último formato (actualmente kbd>2</kbd>), pode cambiar sen aviso previo.",
"apihelp-jsonfm-description": "Datos de saída en formato JSON(impresión en HTML).",
"apihelp-none-description": "Ningunha saída.",
"apihelp-php-description": "Datos de saída en formato serializado de PHP.",
+ "apihelp-php-param-formatversion": "Formato de saída:\n;1:Formato compatible con versións anteriores(booleanos estilo XML,claves <samp>*</samp> para nodos, etc.).\n;2:Formato moderno experimental. Os detalles poden cambiar!\n;latest:Usa o último formato (actualmente kbd>2</kbd>), pode cambiar sen aviso previo.",
"apihelp-phpfm-description": "Datos de saída en formato serializado de PHP(impresión en HTML).",
"apihelp-rawfm-description": "Datos de saída cos elementos de depuración en formato JSON(impresión en HTML).",
"apihelp-txt-description": "Datos de saída en formato PHP <code>print_r()</code>.",
"apihelp-txtfm-description": "Datos de saída en formato <code>print_r()</code> de PHP(impresión en HTML).",
- "apihelp-wddx-description": "Datos de saída en formato WDDX.",
- "apihelp-wddxfm-description": "Datos de saída en formato WDDX(impresión en HTML).",
"apihelp-xml-description": "Datos de saída en formato XML.",
"apihelp-xml-param-xslt": "Se está indicado, engade o nome da páxina como unha folla de estilo XSL. O valor debe ser un título no espazo de nomes {{ns:mediawiki}} rematando con <code>.xsl</code>.",
"apihelp-xml-param-includexmlnamespace": "Se está indicado, engade un espazo de nomes XML.",
@@ -982,6 +1253,8 @@
"apihelp-yaml-description": "Datos de saída en formato YAML.",
"apihelp-yamlfm-description": "Datos de saída en formato YAML(impresión en HTML).",
"api-format-title": "Resultado de API de MediaWiki",
+ "api-format-prettyprint-header": "Esta é a representación HTML do formato $1. HTML é bó para depurar, pero non é axeitado para usar nunha aplicación.\n\nEspecifique o parámetro <var>format</var> para cambiar o formato de saída. Para ver a representación non-HTML do formato $1, fixe <kbd>format=$2</kbd>.\n\n\nRevise a [[mw:API|documentación completa]], ou a [[Special:ApiHelp/main|axuda da API]] para obter máis información.",
+ "api-format-prettyprint-header-only-html": "Esta é unha representación HTML empregada para a depuración de erros, e non é axeitada para o uso de aplicacións.\n\nVexa a [[mw:API|documentación completa]], ou a [[Special:ApiHelp/main|axuda da API]] para máis información.",
"api-orm-param-props": "Campos a consultar.",
"api-orm-param-limit": "Número máximo de filas a mostrar.",
"api-pageset-param-titles": "Lista de títulos nos que traballar.",
@@ -1000,10 +1273,22 @@
"api-help-flag-writerights": "Este módulo precisa permisos de escritura.",
"api-help-flag-mustbeposted": "Este módulo só acepta peticións POST.",
"api-help-flag-generator": "Este módulo pode usarse como xenerador.",
+ "api-help-source": "Fonte: $1",
+ "api-help-source-unknown": "Fonte: <span class=\"apihelp-unknown\">descoñecida</span>",
+ "api-help-license": "Licenza: [[$1|$2]]",
+ "api-help-license-noname": "Licenza: [[$1|Ver ligazón]]",
+ "api-help-license-unknown": "Licenza: <span class=\"apihelp-unknown\">descoñecida</span>",
"api-help-parameters": "{{PLURAL:$1|Parámetro|Parámetros}}:",
"api-help-param-deprecated": "Obsoleto.",
"api-help-param-required": "Este parámetro é obrigatorio.",
- "api-help-param-list": "{{PLURAL:$1|1=Un valor|2=Valores (separados con <kbd>{{!}}</kbd>)}}: $2",
+ "api-help-datatypes-header": "Tipos de datos",
+ "api-help-datatypes": "Algúns tipos de parámetros nas solicitudes de API necesitan máis explicación:\n;boolean\n:Os parámetros booleanos traballan como caixas de verificación HTML: se o parámetro se especifica, independentemente do seu valor, considérase verdadeiro. Para un valor falso, omíta o parámetro completo.\n;timestamp\n:Os selos de tempo poden especificarse en varios formatos. Recoméndase o ISO 8601 coa data e a hora. Todas as horas están en UTC, a inclusión da zona horaria é ignorada.\n:* ISO 8601 con data e hora, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (signos de puntuación e <kbd>Z</kbd> son opcionais)\n:* ISO 8601 data e hora (omítense) fraccións de segundo, <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> (guións, dous puntos e, <kbd>Z</kbd> son opcionais)\n:* Formato MediaWiki, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Formato numérico xenérico, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (opcional na zona horaria <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd>, o <kbd>-<var>##</var></kbd> omítese)\n:* Formato EXIF, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:*Formato RFC 2822 (a zona horaria pódese omitir), <kbd><var>Mon</var>, <var>15</var> <var>Xan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Formato RFC 850 (a zona horaria pódese omitir), <kbd><var>luns</var>, <var>15</var>-<var>xaneiro</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Formato C ctime, <kbd><var>luns</var> <var>xaneiro</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>de 2001</var></kbd>\n:* Segundos desde 1970-01-01T00:00:00Z como de 1 a 13, díxitos enteiros (excluíndo o <kbd>0</kbd>)\n:* O texto <kbd>now</kbd> (agora)",
+ "api-help-param-type-limit": "Tipo: enteiro ou <kbd>max</kbd>",
+ "api-help-param-type-integer": "Tipo: {{PLURAL:$1|1=enteiro|2=lista de enteiros}}",
+ "api-help-param-type-boolean": "Tipo: booleano ([[Special:ApiHelp/main#main/datatypes|detalles]])",
+ "api-help-param-type-timestamp": "Tipo: {{PLURAL:$1|1=selo de tempo|2=lista de selos de tempo}} ([[Special:ApiHelp/main#main/datatypes|formatos permitidos]])",
+ "api-help-param-type-user": "Tipo: {{PLURAL:$1|1=nome de usuario|2=lista de nomes de usuarios}}",
+ "api-help-param-list": "{{PLURAL:$1|1=Un valor dos seguintes valores|2=Valores (separados con <kbd>{{!}}</kbd>)}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Debe ser baleiro|Pode ser baleiro, ou $2}}",
"api-help-param-limit": "Non se permiten máis de $1.",
"api-help-param-limit2": "Non se permiten máis de $1 ($2 para bots).",
@@ -1026,5 +1311,6 @@
"api-help-permissions": "{{PLURAL:$1|Permiso|Permisos}}:",
"api-help-permissions-granted-to": "{{PLURAL:$1|Concedida a|Concedidas a}}: $2",
"api-help-right-apihighlimits": "Usar os valores superiores das consultas da API (consultas lentas: $1; consultas rápidas: $2). Os límites para as consultas lentas tamén se aplican ós parámetros multivaluados.",
- "api-credits-header": "Créditos"
+ "api-credits-header": "Créditos",
+ "api-credits": "Desenvolvedores da API:\n* Roan Kattouw (desenvolvedor principal, set. 2007-2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (creador e desenvolvedor principal, set. 2006-sep. 2007)\n* Brad Jorsch (desenvolvedor principal, 2013-actualidade)\n\nEnvía comentarios, suxerencias e preguntas a mediawiki-api@lists.wikimedia.org\nou informa dun erro en https://phabricator.wikimedia.org/."
}
diff --git a/includes/api/i18n/he.json b/includes/api/i18n/he.json
index fcc7f7bd..5cd1d944 100644
--- a/includes/api/i18n/he.json
+++ b/includes/api/i18n/he.json
@@ -6,15 +6,46 @@
"Inkbug",
"Danny-w",
"YaronSh",
- "ערן"
+ "ערן",
+ "LaG roiL",
+ "Elyashiv",
+ "Umherirrender"
]
},
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|תיעוד]]\n* [[mw:API:FAQ|שו\"ת]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api רשימת דיוור]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce הודעות על API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R באגים ובקשות]\n</div>\n<strong>מצב:</strong> כל האפשרויות שמוצגות בדף הזה אמורות לעבוד, אבל ה־API עדיין בפיתוח פעיל, ויכול להשתנות בכל זמן. עשו מינוי ל [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ רשימת הדיוור mediawiki-api-announce] להודעות על עדכונים.\n\n<strong>בקשות שגויות:</strong> כשבקשות שגויות נשלחות ל־API, תישלח כותרת HTTP עם המפתח \"MediaWiki-API-Error\" ואז גם הערך של הכותרת וגם קוד השגיאה יוגדרו לאותו ערך. למידע נוסף ר' [[mw:API:Errors_and_warnings|API: שגיאות ואזהרות]].",
"apihelp-main-param-action": "איזו פעולה לבצע.",
- "apihelp-main-param-format": "התבנית של הפלט.",
- "apihelp-main-param-curtimestamp": "הכללת חותמת הזמן הנוכחית בתוצאה.",
+ "apihelp-main-param-format": "תסדיר הפלט.",
+ "apihelp-main-param-maxlag": "שיהוי מרבי יכול לשמש כשמדיה־ויקי מותקנת בצביר עם מסד נתונים משוכפל. כדי לחסוך בפעולות שגורמות יותר שיהוי בשכפול אתר, הפרמטר הזה יכול לגרום ללקוח להמתין עד ששיהוי השכפול יורד מתחת לערך שצוין. במקרה של שיהוי מוגזם, קוד השגיאה <samp>maxlag</samp> מוחזר עם הודעה כמו <samp>Waiting for $host: $lag seconds lagged</samp>.<br />ר' [[mw:Manual:Maxlag_parameter|מדריך למשתמש: פרמטר maxlag]] למידע נוסף.",
+ "apihelp-main-param-smaxage": "הגדרת כותרת בקרת מטמון HTTP‏ <code>s-maxage</code> למספר כזה של שניות.",
+ "apihelp-main-param-maxage": "הגדרת כותרת בקרת מטמון HTTP‏ <code>max-age</code> למספר כזה של שניות.",
+ "apihelp-main-param-assert": "לוודא שהמשתמש נכנס אם זה מוגדר ל־<kbd>user</kbd>, או שיש לו הרשאת בוט אם זה <kbd>bot</kbd>.",
+ "apihelp-main-param-requestid": "כל ערך שיינתן כאן ייכלל בתשובה. אפשר להשתמש בזה כדי להבדיל בין בקשות.",
+ "apihelp-main-param-servedby": "לכלול את שם המארח ששירת את הבקשה בתוצאות.",
+ "apihelp-main-param-curtimestamp": "הכללת חותם־הזמן הנוכחי בתוצאה.",
+ "apihelp-main-param-origin": "בעת גישה ל־API עם בקשת AJAX חוצה מתחמים (CORS), יש להציב כאן את המתחם שהבקשה יוצאת ממנו. זה היה להיות כלול בכל בקשה מקדימה, ולכן הוא חייב להיות חלק מה־URI של הבקשה (לא גוף ה־POST). זה חייב להיות תואם במדויק לאחד המקורות בכותרת <code>Origin</code>, כך שזה צריך להיות מוגדר למשהו כמו <kbd>https://en.wikipedia.org</kbd> או <kbd>https://meta.wikimedia.org</kbd>. אם הפרמטר הזה אינו תואם לכותרת <code>Origin</code>, תוחזר תשובת 403. אם הפרמטר הזה תורם לכותרת <code>Origin</code> והמקור נמצא ברשימה הלבנה, תוגדר כותרת <code>Access-Control-Allow-Origin</code>.",
+ "apihelp-main-param-uselang": "באיזו שפה להשתמש לתרגומי הודעות. אפשר לקבל רשימת קודים מ־<kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> עם <kbd>siprop=languages</kbd> או לציין <kbd>user</kbd> כדי להשתמש בהעדפת השפה של המשתמש הנוכחי, או להגדיר את <kbd>content</kbd> להשתמש בקוד השפה של הוויקי הזה.",
"apihelp-block-description": "חסימת משתמש.",
"apihelp-block-param-user": "שם משתמש, כתובת IP, או טווח IP שהנך רוצה לחסום.",
+ "apihelp-block-param-expiry": "זמן תפוגה. יכול להיות יחסי (למשל <kbd>5 months</kbd> או <kbd>2 weeks</kbd>) או מוחלט (למשל <kbd>2014-09-18T12:34:56Z</kbd>). אם זה מוגדר ל־<kbd>infinite</kbd>‏, <kbd>indefinite</kbd>, או <kbd>never</kbd>, החסימה לא תפוג לעולם.",
"apihelp-block-param-reason": "סיבה לחסימה.",
+ "apihelp-block-param-anononly": "לחסום משתמשים אלמוניים בלבד (דהיינו, השבתת עריכות אלמוניות מכתובת ה־IP הזאת)",
+ "apihelp-block-param-nocreate": "מניעת יצירת חשבונות",
+ "apihelp-block-param-autoblock": "חסימה אוטומטית גם של כתובת ה־IP האחרונה שהשתמש בה ושל כל כתובת IP שינסה להשתמש בה בעתיד.",
+ "apihelp-block-param-noemail": "למנוע ממשתמש לשלוח דואר אלקטרוני דרך הוויקי. (דורש את ההרשאה <code>blockemail</code>).",
+ "apihelp-block-param-hidename": "הסרת השם מיומן החסימות. (דורש את ההרשאה <code>hideuser</code>.)",
+ "apihelp-block-param-allowusertalk": "לאפשר למשתמש לערוך את דף השיחה שלו או שלה (תלוי ב־<var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
+ "apihelp-block-param-reblock": "אם המשתמש כבר חסום, לדרוס את החסימה הנוכחית.",
+ "apihelp-block-param-watchuser": "לעקוב אחרי דף המשתמש ודף השיחה של המשתמש או של כתובת ה־IP.",
+ "apihelp-block-example-ip-simple": "חסימת כתובת ה־IP‏ <kbd>192.0.2.5</kbd> לשלושה ימים עם הסיבה <kbd>First strike</kbd>.",
+ "apihelp-block-example-user-complex": "חסימת המשתמש <kbd>Vandal</kbd> ללא הגבלת זמן עם הסיבה <kbd>Vandalism</kbd>, ומניעת יצירת חשבובות חדשים ושליחת דוא\"ל.",
+ "apihelp-checktoken-description": "בדיקת התקינות של האסימון מ־<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
+ "apihelp-checktoken-param-type": "סוג האסימון שבבדיקה.",
+ "apihelp-checktoken-param-token": "איזה אסימון לבדוק.",
+ "apihelp-checktoken-param-maxtokenage": "הגיל המרבי המותר של האסימון, בשניות.",
+ "apihelp-checktoken-example-simple": "בדיקת התקינות של אסימון <kbd>csrf</kbd>.",
+ "apihelp-clearhasmsg-description": "מנקה את דגל <code>hasmsg</code> עבור המשתמש הנוכחי.",
+ "apihelp-clearhasmsg-example-1": "לנקות את דגל <code>hasmsg</code> עבור המשתמש הנוכחי.",
+ "apihelp-compare-description": "קבלת ההבדל בין 2 דפים.\n\nיש להעביר מספר גרסה, כותרת דף או מזהה דף גם ל־\"from\" וגם ל־\"to\".",
"apihelp-compare-param-fromtitle": "כותרת ראשונה להשוואה.",
"apihelp-compare-param-fromid": "מס׳ זיהוי של העמוד הראשון להשוואה.",
"apihelp-compare-param-fromrev": "גרסה ראשונה להשוואה.",
@@ -39,19 +70,86 @@
"apihelp-delete-param-pageid": "מס׳ הזיהוי של העמוד למחיקה. לא ניתן להשתמש בשילוב עם <var>$1title</var>.",
"apihelp-delete-param-reason": "סיבת המחיקה. אם לא הוגדרה, תתווסף סיבה שנוצרה אוטומטית.",
"apihelp-delete-param-watch": "הוספת העמוד לרשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-delete-param-watchlist": "הוספה או הסרה של הדף ללא תנאי מרשימת המעקב של המשתמש הנוכחי, להשתמש בהעדפות או לא לשנות את המעקב.",
"apihelp-delete-param-unwatch": "הסרת הדף מרשימת המעקב של של המשתמש הנוכחי.",
- "apihelp-delete-example-simple": "מחיקת הדף הראשי",
+ "apihelp-delete-param-oldimage": "שם התמונה הישנה למחיקה כפי שסופק ל־[[Special:ApiHelp/query+imageinfo|action=query&prop=imageinfo&iiprop=archivename]].",
+ "apihelp-delete-example-simple": "מחיקת <kbd>Main Page</kbd>.",
+ "apihelp-delete-example-reason": "מחיקת <kbd>Main Page</kbd>. סיבה: <kbd>Preparing for move</kbd>.",
+ "apihelp-disabled-description": "היחידה הזאת כובתה.",
+ "apihelp-edit-description": "יצירה ועריכה של דפים.",
+ "apihelp-edit-param-title": "שם הדף לעריכה. לא לשימוש עם <var>$1pageid</var>.",
+ "apihelp-edit-param-pageid": "מזהה הדף לעריכה. לא לשימוש עם <var>$1title</var>.",
+ "apihelp-edit-param-section": "מספר הפסקה <kbd>0</kbd> לפסקה העליונה, <kbd>new</kbd> לפסקה חדשה.",
+ "apihelp-edit-param-sectiontitle": "הכותרת לפסקה החדשה.",
"apihelp-edit-param-text": "תוכן הדף.",
+ "apihelp-edit-param-summary": "תקציר עריכה. גם גותרת פסקה כש־$1section=new ו־$1sectiontitle אינו מוגדר.",
+ "apihelp-edit-param-tags": "אילו תגי שינוי להחיל על הגרסה.",
"apihelp-edit-param-minor": "עריכה משנית.",
+ "apihelp-edit-param-notminor": "שינוי לא משני.",
+ "apihelp-edit-param-bot": "סימון עריכה זו כבוט.",
+ "apihelp-edit-param-basetimestamp": "חותם־זמן של גרסת הבסיס, משמש לזיהוי התנגשויות עריכה. אפשר לקבל אותו באמצעות [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
+ "apihelp-edit-param-starttimestamp": "חותם־הזמן של תחילת תהליך העריכה, משמש לזיהוי התנגשויות. אפשר לקבל ערך מתאים באמצעות <var>[[Special:ApiHelp/main|curtimestamp]]</var> בעת תחילת תהליך העריכה (למשל בזמן טעינת תוכן הדף לעריכה).",
+ "apihelp-edit-param-recreate": "לעקוב את כל הטעויות על כך שהדף נמחק בינתיים.",
+ "apihelp-edit-param-createonly": "לא לערוך את הדף אם הוא כבר קיים.",
+ "apihelp-edit-param-nocreate": "לזרוק שגיאה אם הדף אינו קיים.",
+ "apihelp-edit-param-watch": "הוספת העמוד לרשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-edit-param-unwatch": "הסרת הדף מרשימת המעקב של של המשתמש הנוכחי.",
+ "apihelp-edit-param-watchlist": "להוסיף את הדף לרשימת המעקב של המשתמש הנוכחי או להסיר אותו משם, להשתמש בהעדפות, או לא לשנות את מצב המעקב.",
+ "apihelp-edit-param-md5": "גיבוב MD5 של הפרמטר $1text או צירוף של הפטמטרים $1prependtext ו־$1appendtext. אם זה מוגדר, העריכה לא תיעשה אלא אם כן הגיבוב נכון.",
+ "apihelp-edit-param-prependtext": "הוספת הטקסט הזה לתחילת הדף. דורס את $1text.",
+ "apihelp-edit-param-appendtext": "הוספת הטקסט הזה לסוף הדף. דורס את $1text.\n\nיש להשתמש ב־$1section=new כדי להוסיף פסקה חדשה, ולא בפרמטר הזה.",
+ "apihelp-edit-param-undo": "לבטל את הגרסה הזאת. דורס את $1text‏, $1prependtext ו־$1appendtext.",
+ "apihelp-edit-param-undoafter": "ביטול כל הגרסאות מ־$1undo עד כאן. אם זה לא מוגדר, לבטל רק גרסה אחת.",
+ "apihelp-edit-param-redirect": "לפתור הפניות אוטומטית.",
+ "apihelp-edit-param-contentformat": "תסדיר להסדרת תוכן שמשמש את טקסט הקלט.",
+ "apihelp-edit-param-contentmodel": "מודל התוכן של התוכן החדש.",
+ "apihelp-edit-param-token": "האסימון תמיד צריך להישלח בתור הפרמטר האחרון, או לפחות אחרי הפרמטר $1text parameter.",
"apihelp-edit-example-edit": "עריכת דף",
+ "apihelp-edit-example-prepend": "הוספת <kbd>_&#95;NOTOC_&#95;</kbd> לתחילת העמוד.",
+ "apihelp-edit-example-undo": "ביטול גרסאות מ־13579 עד 13585 עם תקציר אוטומטי.",
"apihelp-emailuser-description": "שליחת דוא\"ל למשתמש.",
+ "apihelp-emailuser-param-target": "לאיזה משתמש לשלוח דוא\"ל.",
+ "apihelp-emailuser-param-subject": "כותרת נושא.",
+ "apihelp-emailuser-param-text": "גוף הדואר.",
+ "apihelp-emailuser-param-ccme": "שליחת עותק של הדואר הזה אליי.",
+ "apihelp-emailuser-example-email": "שליחת דוא\"ל למשתמש <kbd>WikiSysop</kbd> עם הטקסט <kbd>Content</kbd>.",
+ "apihelp-expandtemplates-description": "הרחבת כל התבניות בקוד הוויקי.",
"apihelp-expandtemplates-param-title": "כותרת הדף.",
+ "apihelp-expandtemplates-param-text": "איזה קוד ויקי להמיר.",
+ "apihelp-expandtemplates-param-revid": "מזהה גרסה, עבור <nowiki>{{REVISIONID}}</nowiki> ומשתנים דומים.",
+ "apihelp-expandtemplates-param-prop": "אילו חלקי מידע לקבל.\n\nיש לשים לכך שאם לא נבחרו ערכים, התוצאה תכיל את קוד הוויקי, אבל הפלט יהיה בתסדיר מיושן.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "קוד הוויקי המורחב.",
+ "apihelp-expandtemplates-paramvalue-prop-categories": "קטגוריות כלשהן שקיימות בקלט ואינן מיוצגות בפלט הוויקיטקסט.",
+ "apihelp-expandtemplates-paramvalue-prop-properties": "מאפייני דף המוגדרים במילות קסם מורחבות בקוד ויקי.",
+ "apihelp-expandtemplates-paramvalue-prop-volatile": "האם הפלט הוא נדיף ואין להשתמש בו במקום אחר בעמוד.",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "הזמן המרבי שאחריו המטמונים של התוצאה צריכים לפוג.",
+ "apihelp-expandtemplates-paramvalue-prop-modules": "כל יחידות ה־ResourceLoader שפונקציות מפענח ביקשו לוסיף לפלט. יש לבקש את <kbd>jsconfigvars</kbd> או את <kbd>encodedjsconfigvars</kbd> יחד עם <kbd>modules</kbd>.",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "נותן משתני הגדרות של JavaScript שייחודיים לדף הזה.",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "נותן משתני הגדרות של JavaScript שייחודיים לדף הזה בתור מחרוזת JSON.",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "עץ פענוח XML של הקלט.",
+ "apihelp-expandtemplates-param-includecomments": "האם לכלול הערות HTML בפלט.",
+ "apihelp-expandtemplates-param-generatexml": "יצירת עץ פענוח XML (מוחלף ב־$1prop=parsetree).",
+ "apihelp-expandtemplates-example-simple": "להרחיב את קוד הוויקי <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
+ "apihelp-feedcontributions-description": "החזרת הזנת תרומות משתמש.",
+ "apihelp-feedcontributions-param-feedformat": "תסדיר ההזנה.",
+ "apihelp-feedcontributions-param-user": "לקבל תרומות של אילו משמשים.",
+ "apihelp-feedcontributions-param-namespace": "לפי איזה מרחב שם לסנן את התרומות.",
"apihelp-feedcontributions-param-year": "החל משנה (ולפני כן).",
"apihelp-feedcontributions-param-month": "החל מחודש (ולפני כן).",
"apihelp-feedcontributions-param-tagfilter": "סינון תרומות בעלות התגיות הבאות.",
"apihelp-feedcontributions-param-deletedonly": "הצגת תרומות שנמחקו בלבד.",
"apihelp-feedcontributions-param-toponly": "הצגת עריכות שהן הגרסה העדכנית ביותר בלבד.",
+ "apihelp-feedcontributions-param-newonly": "להציג רק עריכות שהן יצירות דפים.",
+ "apihelp-feedcontributions-param-showsizediff": "להציג את ההבדל בגודל בין גרסאות.",
"apihelp-feedcontributions-example-simple": "החזרת תרומות עבור המשתמש <kbd>Example</kbd>.",
+ "apihelp-feedrecentchanges-description": "להחזיר הזנת שינויים אחרונים.",
+ "apihelp-feedrecentchanges-param-feedformat": "תסדיר ההזנה.",
+ "apihelp-feedrecentchanges-param-namespace": "לאיזה מרחב שם להגביל את התוצאות.",
+ "apihelp-feedrecentchanges-param-invert": "כל מרחבי השם למעט זה שנבחר.",
+ "apihelp-feedrecentchanges-param-associated": "לכלול מרחב שם משויך (שיחה או ראשי).",
+ "apihelp-feedrecentchanges-param-days": "לכמה ימים להגביל את התוצאות.",
+ "apihelp-feedrecentchanges-param-limit": "המספר המרבי של התוצאות להחזיר.",
+ "apihelp-feedrecentchanges-param-from": "להציג תוצאות מאז.",
"apihelp-feedrecentchanges-param-hideminor": "הסתרת שינוים משניים.",
"apihelp-feedrecentchanges-param-hidebots": "הסתרת שינויים שנעשו על ידי בוטים.",
"apihelp-feedrecentchanges-param-hideanons": "הסתרת שינויים שנעשו על ידי אנונימים.",
@@ -60,12 +158,46 @@
"apihelp-feedrecentchanges-param-hidemyself": "הסתרת שינוים שנעשו על ידי המשתמש הנוכחי.",
"apihelp-feedrecentchanges-param-tagfilter": "סינון לפי תגית.",
"apihelp-feedrecentchanges-param-target": "הצגת שינויים שנעשו בדפים המקושרים לדף זה בלבד.",
+ "apihelp-feedrecentchanges-param-showlinkedto": "להציג את השינויים בדפים שמקושרים לדף שנבחר במקום זה.",
"apihelp-feedrecentchanges-example-simple": "הצגת שינויים אחרונים.",
"apihelp-feedrecentchanges-example-30days": "הצגת שינויים אחרונים עבור 30 ימים.",
+ "apihelp-feedwatchlist-description": "החזרת הזנת רשימת מעקב.",
+ "apihelp-feedwatchlist-param-feedformat": "תסדיר ההזנה.",
+ "apihelp-feedwatchlist-param-hours": "רשימת דפים ששונו בתוך מספר כזה של שעות מעכשיו.",
+ "apihelp-feedwatchlist-param-linktosections": "לקשר ישר לפסקאות ששונו אם אפשר.",
+ "apihelp-feedwatchlist-example-default": "הצגת הזנת רשימת מעקב.",
+ "apihelp-feedwatchlist-example-all6hrs": "להציג את כל השינויים בדפים שבמעקב ב־6 השעות האחרונות.",
+ "apihelp-filerevert-description": "לשחזר את הקובץ לגרסה ישנה יותר.",
+ "apihelp-filerevert-param-filename": "שם קובץ היעד, ללא התחילית File:.",
+ "apihelp-filerevert-param-comment": "הערת העלאה.",
+ "apihelp-filerevert-param-archivename": "שם הארכיון של הגרסה שאליה ישוחזר הקובץ.",
+ "apihelp-filerevert-example-revert": "לשחזר את <kbd>Wiki.png</kbd> לגרסה מ־<kbd>2011-03-05T15:27:40Z</kbd>.",
"apihelp-help-description": "הצגת עזרה עבור היחידות שצוינו.",
+ "apihelp-help-param-modules": "עזרה של אילו יחידות להציג (ערכים של הפרמטרים <var>action</var> ו־<var>format</var>, או <kbd>main</kbd>). אפשר להגדיר תת־יחידות עם <kbd>+</kbd>.",
+ "apihelp-help-param-submodules": "לכלול עזרה לתת־יחידות ליחידה שצוינה.",
+ "apihelp-help-param-recursivesubmodules": "לכלול עזרה לתת־יחידות באופן רקורסיבי.",
"apihelp-help-param-helpformat": "תסדיר פלט העזרה.",
+ "apihelp-help-param-wrap": "לעטוף את הפלט במבנה תשובת API תקני.",
"apihelp-help-param-toc": "לכלול תוכן עניינים בפלט HTML.",
+ "apihelp-help-example-main": "עזרה ליחידה הראשית.",
+ "apihelp-help-example-recursive": "כל העזרה בדף אחד.",
+ "apihelp-help-example-help": "עזרה ליחידת העזרה עצמה.",
+ "apihelp-help-example-query": "עזרה לשתי תת־יחידות של שאילתה.",
+ "apihelp-imagerotate-description": "סיבוב של תמונה אחת או יותר.",
+ "apihelp-imagerotate-param-rotation": "בכמה מעלות לסובב בכיוון השעון.",
+ "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-description": "לייבא דף מוויקי אחר או מקובץ XML.\n\nיש לשים לב לכך שפעולת HTTP POST צריכה להיעשות בתור העלאת קובץ (כלומר, עם multipart/form-data) בזמן שליחת קובץ לפרמטר <var>xml</var>.",
+ "apihelp-import-param-summary": "תקציר יבוא.",
"apihelp-import-param-xml": "קובץ XML שהועלה.",
+ "apihelp-import-param-interwikisource": "ליבוא בין אתרי ויקי: מאיזה ויקי לייבא.",
+ "apihelp-import-param-interwikipage": "ליבוא בין אתרי ויקי: איזה דף לייבא.",
+ "apihelp-import-param-fullhistory": "ליבוא בין אתרי ויקי: לייבר את ההיסטוריה המלאה, לא רק את הגרסה הנוכחית.",
+ "apihelp-import-param-templates": "ליבוא בין אתרי ויקי: לייבא גם את כל התבניות המוכללות.",
+ "apihelp-import-param-namespace": "לייבא למרחב השם הזה. לא ניתן להשתמש בזה יחד עם <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "לייבא בתור תת־משנה של הדף הזה. לא ניתן להשתמש בזה יחד עם <var>$1namespace</var>.",
+ "apihelp-import-example-import": "לייבא את [[meta:Help:ParserFunctions]] למרחב השם 100 עם היסטוריה מלאה.",
+ "apihelp-login-description": "להיכנס ולקבל עוגיות אימות.\n\nבמקרה של כניסה מוצלחת, העוגיות הדרושות תיכללנה בכותרות תשובות של HTTP. במקרה של כניסה לא מוצלחת, הניסיונות הבאים עשויים להיות חנוקים כדי להגביל תקיפות ניחוש ססמה אוטומטי.",
"apihelp-login-param-name": "שם משתמש.",
"apihelp-login-param-password": "ססמה.",
"apihelp-login-param-domain": "שם מתחם (רשות).",
@@ -75,84 +207,1089 @@
"apihelp-logout-description": "יציאה וניקוי של נתוני הפעילות.",
"apihelp-logout-example-logout": "הוצאת המשתמש הנוכחי.",
"apihelp-managetags-description": "ביצוע פעולות ניהוליות הקשורות בשינוי תגיות.",
+ "apihelp-managetags-param-operation": "איזו פעולה לבצע:\n;create:יצירת תג שינוי חדש לשימוש ידני.\n;delete:הסרת תג שינוי ממסד הנתונים, כולל הסרת התג מכל הגרסאות, עיולי שינויים אחרונים ועיולי יומן שהוא משמש בהן.\n;activate:הפעלת תג שינוי, ואפשור למשתמש להחיל אותו ידנית.\n;deactivate:כיבוי תג שינוי, ומניעה ממשתמשים להחיל אותו ידנית.",
+ "apihelp-managetags-param-tag": "תג ליצירה, מחיקה, הפעלה או כיבוי. ליצירת תג, התג לא צריך להיות קיים. למחיקת תג, התג צריך להיות קיים. להפעלת תג, התג צריך להתקיים ולא להיות בשימוש של הרחבה. לכיבוי תג, התג צריך להיות קיים ומוגדר ידנית.",
+ "apihelp-managetags-param-reason": "סיבה אופציונלית ליצירה, מחיקה, הפעלה או כיבוי של תג.",
+ "apihelp-managetags-param-ignorewarnings": "האם להתעלם מכל האזהרות שמופיעות תוך כדי הפעולה.",
+ "apihelp-managetags-example-create": "יצירת תג בשם <kbd>spam</kbd> עם הסיבה <kbd>For use in edit patrolling</kbd>",
+ "apihelp-managetags-example-delete": "מחיקת התג <kbd>vandlaism</kbd> עם הסיבה <kbd>Misspelt</kbd>",
+ "apihelp-managetags-example-activate": "הפעלת התג <kbd>spam</kbd> עם הסיבה <kbd>For use in edit patrolling</kbd>",
+ "apihelp-managetags-example-deactivate": "כיבוי התג <kbd>spam</kbd> עם הסיבה <kbd>No longer required</kbd>",
"apihelp-move-description": "העברת עמוד.",
+ "apihelp-move-param-from": "שם הדף ששמו ישונה. לא יכול לשמש יחד עם <var>$1fromid</var>.",
+ "apihelp-move-param-fromid": "מזהה הדף של הדף שצריך לשנות את שמו. לא יכול לשמש עם <var>$1from</var>.",
+ "apihelp-move-param-to": "לאיזו כותרת לשנות את שם הדף.",
+ "apihelp-move-param-reason": "הסיבה לשינוי השם.",
+ "apihelp-move-param-movetalk": "שינוי שם דף השיחה, אם הוא קיים.",
+ "apihelp-move-param-movesubpages": "שינוי השמות של דפי־המשנה, אם זה שייך.",
+ "apihelp-move-param-noredirect": "לא ליצור הפניה.",
+ "apihelp-move-param-watch": "הוספת הדף וההפניה לרשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-move-param-unwatch": "הסרת הדף וההפניה מרשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-move-param-watchlist": "הוספה או הסרה של הדף ללא תנאי מרשימת המעקב של המשתמש הנוכחי, להשתמש בהעדפות או לא לשנות את המעקב.",
+ "apihelp-move-param-ignorewarnings": "להתעלם מכל האזהרות.",
+ "apihelp-move-example-move": "העברת <kbd>Badtitle</kbd> ל־<kbd>Goodtitle</kbd> בלי להשאיר הפניה.",
+ "apihelp-opensearch-description": "חיפוש בוויקי בפרוטוקול OpenSearch.",
"apihelp-opensearch-param-search": "מחרוזת לחיפוש.",
+ "apihelp-opensearch-param-limit": "המספר המרבי של התוצאות שתוחזרנה.",
"apihelp-opensearch-param-namespace": "שמות מתחם לחיפוש.",
+ "apihelp-opensearch-param-suggest": "לא לעשות דבר אם <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> הוא false.",
+ "apihelp-opensearch-param-redirects": "איך לטפל בהפניות:\n;return:להחזיר את ההפניה עצמה.\n;resolve:להחזיר את דף היעד. יכול להחזיר פחות מ־$1limit תוצאות.\nמסיבות היסטוריות, בררת המחדל היא \"return\" עבור $1format=json ו־\"resolve\" עבור תסדירים אחרים.",
"apihelp-opensearch-param-format": "תסדיר הפלט.",
+ "apihelp-opensearch-param-warningsaserror": "אם אזהרות מוּעלות עם <kbd>format=json</kbd>, להחזיר שגיאת API במקום להתעלם מהן.",
+ "apihelp-opensearch-example-te": "חיפוש דפים שמתחילים ב־<kbd>Te</kbd>.",
+ "apihelp-options-description": "שינוי העדפות של המשתמש הנוכחי.\n\nרק אפשרויות שמוגדרות בליבה או באחת מההרחבות המותקנות, או אפשרויות עם מפתחות עם התחילית \"<code dir=\"ltr\">userjs-</code>\" (שמיועדות לשימוש תסריטי משתמשים) יכולות להיות מוגדרות.",
+ "apihelp-options-param-reset": "אתחול ההעדפות לבררות המחדל של האתר.",
+ "apihelp-options-param-resetkinds": "רשימת סוגי אפשרויות לאתחל כאשר מוגדרת האפשרות <var>$1reset</var>.",
+ "apihelp-options-param-change": "רשימת שינויים, בתסדיר name=value (למשל skin=vector). הערך אינו יכול להכיל תווי מקל (|). אם לא ניתן ערך, אפילו לא סימן שווה, למשל optionname|otheroption|...‎, האפשרות תאופס לערך בררת המחדל שלה.",
+ "apihelp-options-param-optionname": "שם האפשרות שצריך להגדיר לערך שניתן ב־<var>$1optionvalue</var>.",
+ "apihelp-options-param-optionvalue": "ערך האפשרות שצוין ב־<var>$1optionname</var>, יכול להכיל תווי מקל.",
+ "apihelp-options-example-reset": "אתחול כל ההעדפות.",
+ "apihelp-options-example-change": "לשנות את ההעדפות <kbd>skin</kbd> ו־<kbd>hideminor</kbd>.",
+ "apihelp-options-example-complex": "לאתחל את כל ההעדפות ואז להגדיר את <kbd>skin</kbd> ואת <kbd>nickname</kbd>.",
+ "apihelp-paraminfo-description": "קבלת מידע על יחידות של API.",
+ "apihelp-paraminfo-param-modules": "רשימה של שמות יחידות (ערכים של הפרמטרים <var>action</var> ו־<var>format</var>, או <kbd>main</kbd>). אפשר להגדיר תת־יחידות עם <kbd>+</kbd>.",
+ "apihelp-paraminfo-param-helpformat": "תסדיר מחרוזות העזרה.",
+ "apihelp-paraminfo-param-querymodules": "רשימת שמות יחידות query (ערך של הפרמטר <var>prop</var>‏, <var>meta</var> או <var>list</var>). יש להשתמש ב־<kbd>$1modules=query+foo</kbd> במקום <kbd>$1querymodules=foo</kbd>.",
+ "apihelp-paraminfo-param-mainmodule": "קבלת מידע עם היחידה הראשית (העליונה). יש להשתמש ב־<kbd>$1modules=main</kbd> במקום זה.",
+ "apihelp-paraminfo-param-pagesetmodule": "קבלת מידע גם על יחידת pageset (שמספק את titles=‎ וידידיו).",
+ "apihelp-paraminfo-param-formatmodules": "רשימת שמות תסדירים (ערכים של הפרמטר <var>format</var>). יש להשתמש ב־<var>$1modules</var> במקום זה.",
+ "apihelp-paraminfo-example-1": "הצגת מידע עבור <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>‏, <kbd>[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>‏, <kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd>‏, ו־<kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd>.",
+ "apihelp-parse-description": "מפענח את התוכן ומחזיר פלט מפענח.\n\nר' את יחידת ה־prop השיונות של <kbd>[[Special:ApiHelp/query|action=query]]</kbd> כדי לקבל מידע על הגרסה הנוכחית של הדף.\n\nיש מספר דרכים לציין טקסט לפענוח:\n# ציון דף או גרסה באמצעות <var>$1page</var>‏, <var>$1pageid</var>, או <var>$1oldid</var>.\n# ציון התוכן במפורש, באמצעות <var>$1text</var>‏, <var>$1title</var>, ו־<var>$1contentmodel</var>.\n# ציון רק של התקציר לפענוח. ל־<var>$1prop</var> צריך לתת ערך ריק.",
+ "apihelp-parse-param-title": "שם הדף שהטקסט שייך אליו. אם זה מושמט, יש לציין את <var>$1contentmodel</var>, ו־[[API]] ישמש ככותרת.",
+ "apihelp-parse-param-text": "הטקסט לפענוח. יש להשתמש ב־<var>$1title</var> או ב־<var>$1contentmodel</var>.",
+ "apihelp-parse-param-summary": "התקציר שצריך לפענח.",
+ "apihelp-parse-param-page": "פענוח תוכן הדף הזה. לא יכול לשמש יחד עם <var>$1text</var> ו־<var>$1title</var>.",
+ "apihelp-parse-param-pageid": "לפענח את התוכן של הדף הזה. דורס את <var>$1page</var>.",
+ "apihelp-parse-param-redirects": "אם <var>$1page</var> או <var>$1pageid</var> מוגדרים להפניה, לפתור אותה.",
+ "apihelp-parse-param-oldid": "לפענח את התוכן של הגרסה הזאת. דורס את <var>$1page</var> ואת <var>$1pageid</var>.",
+ "apihelp-parse-param-prop": "אילו פריטי מידע לקבל:",
+ "apihelp-parse-paramvalue-prop-text": "נותן טקסט מפוענח של קוד הוויקי.",
+ "apihelp-parse-paramvalue-prop-langlinks": "נותן קישורי שפה בקוד הוויקי המפוענח.",
+ "apihelp-parse-paramvalue-prop-categories": "נותן קטגוריות בקוד ויקי מפוענח.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "נותן את גרסת ה־HTML של הקטגוריות.",
+ "apihelp-parse-paramvalue-prop-links": "נותן קישורים פנימיים בקוד הוויקי המפוענח.",
+ "apihelp-parse-paramvalue-prop-templates": "נותן תבניות בקוד הוויקי המפוענח.",
+ "apihelp-parse-paramvalue-prop-images": "נותן תמונות בקוד הוויקי המפוענח.",
+ "apihelp-parse-paramvalue-prop-externallinks": "מתן קישורים חיצוניים בקוד הוויקי המפוענח.",
+ "apihelp-parse-paramvalue-prop-sections": "מתן הפסקאות בקוד הוויקי המפוענח.",
+ "apihelp-parse-paramvalue-prop-revid": "הוספת מזהה הגרסה של הדף המפוענח.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "הוספת הכותרת של קוד הוויקי המפוענח.",
+ "apihelp-parse-paramvalue-prop-headitems": "נותן פריטים לשים ב־<code>&lt;head&gt;</code> של הדף.",
+ "apihelp-parse-paramvalue-prop-headhtml": "נותן את ה־<code>&lt;head&gt;</code> המפוענח של הדף.",
+ "apihelp-parse-paramvalue-prop-modules": "מצן יחידות ResourceLoader שמשמשות בדף. יש לבקש את <kbd>jsconfigvars</kbd> או את <kbd>encodedjsconfigvars</kbd> יחד עם <kbd>modules</kbd>.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "נותן משתני הגדרות של JavaScript שייחודיים לדף הזה.",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "נותן משתני הגדרות של JavaScript שייחודיים לדף הזה בתור מחרוזת JSON.",
+ "apihelp-parse-paramvalue-prop-indicators": "נותן את ה־HTML של מחווני מצב דף שמשמשים בדף.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "מתן קישורי בינוויקי בקוד הוויקי המפוענח.",
+ "apihelp-parse-paramvalue-prop-wikitext": "מתן קוד הוויקי המקורי שפוענח.",
+ "apihelp-parse-paramvalue-prop-properties": "נותן מאפיינים שונים שמוגדרים בקוד הוויקי המפוענח.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "נותן דו\"ח הגבלות בדרך מובנית. לא נותן שום נתונים כאשר מוגדר <var>$1disablelimitreport</var>.",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "נותן את גרסת ה־HTML של דו\"ח ההגבלות. לא נותן שום נתונים כאשר מוגדר <var>$1disablelimitreport</var>.",
+ "apihelp-parse-paramvalue-prop-parsetree": "עץ פענוח XML של תוכן הגרסה (דורש מודל תוכן <code>$1</code>)",
+ "apihelp-parse-param-pst": "לעשות התמרה לפני שמירה על הקלט לפני פענוחו. תקין רק בשימוש עם טקסט.",
+ "apihelp-parse-param-onlypst": "לעשות התמרה לפני שמירה (pre-save transform‏, PST) על הקלט, אבל לא לפענח אותו. מחזיר את אותו קוד הוויקי אחרי החלת PST. תקף רק בשימוש עם <var>$1text</var>.",
+ "apihelp-parse-param-effectivelanglinks": "כולל קישור שפה שמספקות הרחבות (לשימוש עם <kbd>$1prop=langlinks</kbd>).",
+ "apihelp-parse-param-section": "לאחזר את התוכן של הפסקה עם המספר הזה, או, אם זה <kbd>new</kbd>, ליצור פסקה חדשה.\n\n<kbd>new</kbd> יכובד רק בעת ציון <var>text</var>.",
+ "apihelp-parse-param-sectiontitle": "כותרת פסקה חדשה כאשר <var>section</var> הוא <kbd>new</kbd>.\n\nבניגוד לעריכת דף, זה לא מתגבה ל־<var>summary</var> כשזה מושמט אם ריק.",
+ "apihelp-parse-param-disablelimitreport": "להשמיט את דו\"ח הקדם־מעבד (\"NewPP limit report\") מפלט המפענח.",
+ "apihelp-parse-param-disablepp": "יש להשתמש ב־<var>$1disablelimitreport</var> במקום.",
+ "apihelp-parse-param-disableeditsection": "להשמיט את קישורי עריכת הפסקאות מפלט המפענח.",
+ "apihelp-parse-param-disabletidy": "לא להריץ ניקוי HTML (למשל tidy) על פלט המפענח.",
+ "apihelp-parse-param-generatexml": "יצירת עץ פענוח של XML (נדרש מודל תוכן <code>$1</code>; מוחלף ב־<kbd>$2prop=parsetree</kbd>).",
+ "apihelp-parse-param-preview": "לפענח במצב תצוגה מקדימה.",
+ "apihelp-parse-param-sectionpreview": "לפענח במצב תצוגה מקדימה של פסקה (מדליק גם את מצב תצוגה מקדימה).",
+ "apihelp-parse-param-disabletoc": "להשמיט את תוכן העניינים בפלט.",
+ "apihelp-parse-param-contentformat": "תסדיר הסדרת תוכן שישמש לטקסט הקלט. תקף רק עם $1text.",
+ "apihelp-parse-param-contentmodel": "מודל התוכן של טקסט הקלט. אם זה מושמט, יש לציין את $1title והערך ההתחלתי יהיה המודל של הכותרת שצוינה. תקין רק כאשר משמש עם $1text.",
+ "apihelp-parse-example-page": "לפענח דף.",
+ "apihelp-parse-example-text": "לפענח קוד ויקי.",
+ "apihelp-parse-example-texttitle": "לפענח קוד, עם ציון כותרת דף.",
+ "apihelp-parse-example-summary": "לפענח תקציר.",
+ "apihelp-patrol-description": "לנטר דף או גרסה.",
+ "apihelp-patrol-param-rcid": "מזהה שינויים אחרונים לניטור.",
+ "apihelp-patrol-param-revid": "מזהה גרסה לניטור.",
+ "apihelp-patrol-example-rcid": "לנטר עיול משינויים אחרונים.",
+ "apihelp-patrol-example-revid": "לנטר גרסה.",
+ "apihelp-protect-description": "לשנות את רמת ההגנה של דף.",
+ "apihelp-protect-param-title": "כותרת הדף להגנה או הסרת הגנה. לא ניתן להשתמש בזה יחד עם $1pageid.",
+ "apihelp-protect-param-pageid": "מזהה הדף להגנה או הסרת הגנה. לא ניתן להשתמש בזה יחד עם $1title.",
+ "apihelp-protect-param-protections": "רשימת רמות הכנה, בתסדיר <kbd>action=level</kbd> (למשל <kbd>edit=sysop</kbd>).",
+ "apihelp-protect-param-expiry": "חותמי־זמן של תפוגה. אם הוגדר רק חותם־זמן אחד, הוא ישמש לכל ההגנות. יש להשתמש ב־<kbd>infinite</kbd>‏, <kbd>indefinite</kbd>‏, <kbd>infinity</kbd>, או <kbd>never</kbd> להגנה שלא פגה לעולם.",
+ "apihelp-protect-param-reason": "סיבה להגנה או הסרת הגנה.",
+ "apihelp-protect-param-cascade": "הפעלת הגנה מדורגת (כלומר, להגן על דפים שמוכללים בדף הזה ועל תמונות שמשמות בו). אין לזה השפעה אם אף אחת מרמות ההגנה שניתנו אינה תומכת בדירוג.",
+ "apihelp-protect-param-watch": "אם זה מוגדר, הוספת הדף שהגנה נוספת אליו או מוסרת ממנו לרשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-protect-param-watchlist": "הוספה או הסרה של הדף ללא תנאי מרשימת המעקב של המשתמש הנוכחי, להשתמש בהעדפות או לא לשנות את המעקב.",
"apihelp-protect-example-protect": "הגנה על דף.",
+ "apihelp-protect-example-unprotect": "להסיר את ההגנה מהדף על־ידי הגדרת מגבלות על <kbd>all</kbd>.",
+ "apihelp-protect-example-unprotect2": "הסרת הגנה מדף על־ידי הגדרה של אפס הגבלות.",
+ "apihelp-purge-description": "ניקוי המטמון לכותרות שניתנו.\n\nדורש בקשת POST אם המשתמש לא נכנס לחשבון.",
+ "apihelp-purge-param-forcelinkupdate": "עדכון טבלאות הקישורים.",
+ "apihelp-purge-param-forcerecursivelinkupdate": "עדכון טבלת הקישורים ועדכון טבלאות הקישורים עבור כל דף שמשתמש בדף הזה בתור תבנית.",
+ "apihelp-purge-example-simple": "ניקוי המטמון של הדפים <kbd>Main Page</kbd> ו־<kbd>API</kbd>.",
+ "apihelp-purge-example-generator": "ניקוי 10 הדפים הראשונים במרחב הראשי.",
+ "apihelp-query-description": "אחזור נתונים ממדיה־ויקי ועליה.\n\nכל שינויי הנתונים יצטרכו תחילה להשתמש ב־query כדי לקבל אסימון למניעת שימוש לרעה מאתרים זדוניים.",
+ "apihelp-query-param-prop": "אילו מאפיינים לקבל על הדפים בשאילתה.",
"apihelp-query-param-list": "אילו רשימות לקבל.",
- "apihelp-query+allcategories-description": "מניין של כל הקטגוריות.",
- "apihelp-query+allcategories-param-from": "הקטגוריה ממנה להתחיל למנות.",
+ "apihelp-query-param-meta": "אילו מטא־נתונים לקבל.",
+ "apihelp-query-param-indexpageids": "לכלול פסקת pageids נוספת עם רשימת כל מזהי הדף שהוחזרו.",
+ "apihelp-query-param-export": "יצוא הגרסאות הנוכחיות של כל הדפים הנתונים המחוללים.",
+ "apihelp-query-param-exportnowrap": "להחזיר את ה־XML של היצוא בלי לעטוף אותו בתוצאת XML (אותו תסדיר כמו [[Special:Export]]). אפשר להשתמש בזה רק עם $1export.",
+ "apihelp-query-param-iwurl": "האם לקבל את ה־URL המלא אם הכותרת היא קישור בינוויקי.",
+ "apihelp-query-param-rawcontinue": "להחזיר נתוני <samp>query-continue</samp> גולמיים להמשך.",
+ "apihelp-query-example-revisions": "אחזור [[Special:ApiHelp/query+siteinfo|site info]] ו־[[Special:ApiHelp/query+revisions|revisions]] של <kbd>Main Page</kbd>.",
+ "apihelp-query-example-allpages": "אחזור גרסאת של דפים שמתחילים ב־<kbd>API/</kbd>.",
+ "apihelp-query+allcategories-description": "למנות את כל הקטגוריות.",
+ "apihelp-query+allcategories-param-from": "מאיזו קטגוריה להתחיל למנות.",
+ "apihelp-query+allcategories-param-to": "באיזו קטגוריה להפסיק למנות.",
+ "apihelp-query+allcategories-param-prefix": "חיפוש כל כותרות הקטגוריות שמתחילות בערך הזה.",
+ "apihelp-query+allcategories-param-dir": "באיזה כיוון למיין.",
+ "apihelp-query+allcategories-param-min": "להחזיר רק קטגוריות עם מספר כזה לפחות של חברים.",
+ "apihelp-query+allcategories-param-max": "להחזיר רק קטגוריות עם מספר כזה לכל היותר של חברים.",
+ "apihelp-query+allcategories-param-limit": "כמה קטגוריות להחזיר.",
+ "apihelp-query+allcategories-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+allcategories-paramvalue-prop-size": "הוספת מספר הדפים בקטגוריה.",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "מתייג קטגוריות מוסתרות עם <code>_&#95;HIDDENCAT_&#95;</code>.",
+ "apihelp-query+allcategories-example-size": "רשימת קטגוריות עם מידע על מספר הדפים בכל אחת מהן.",
+ "apihelp-query+allcategories-example-generator": "אחזור מידע על דף הקטגוריה עצמו עבור קטגוריות שמתחילות ב־<kbd>List</kbd>.",
+ "apihelp-query+alldeletedrevisions-description": "רשימת כל הגרסאות המחוקות על־ידי משתמש או במרחב.",
+ "apihelp-query+alldeletedrevisions-paraminfo-useronly": "יכול לשמש רק <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "לא יכול לשמש עם <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-param-start": "מאיזה חותם־זמן להתחיל למנות.",
+ "apihelp-query+alldeletedrevisions-param-end": "באיזה חותם־זמן להפסיק למנות.",
+ "apihelp-query+alldeletedrevisions-param-from": "להתחיל את הרשימה בשם הזה.",
+ "apihelp-query+alldeletedrevisions-param-to": "להפסיק את הרשימה בכותרת הזאת.",
+ "apihelp-query+alldeletedrevisions-param-prefix": "חיפוש כל שמות הדפים שמתחילים בערך הזה.",
+ "apihelp-query+alldeletedrevisions-param-tag": "לרשום רק גרסאות עם התג הזה.",
+ "apihelp-query+alldeletedrevisions-param-user": "לרשום רק גרסאות מאת המשתמש הזה.",
+ "apihelp-query+alldeletedrevisions-param-excludeuser": "לא לרשום גרסאות מאת המשתמש הזה.",
+ "apihelp-query+alldeletedrevisions-param-namespace": "לרשום רק דפים במרחב השם הזה.",
+ "apihelp-query+alldeletedrevisions-param-miser-user-namespace": "<strong>לתשומת לבך:</strong> בשל [[mw:Manual:$wgMiserMode|מצב חיסכון]], שימוש ב־<var>$1user</var> וב־<var>$1namespace</var> ביחד עלול להניב החזרה של פחות מ־<var>$1limit</var> תוצאות לפני המשך; במצבים קיצוניים יכולות להיות מוחזרות אפס תוצאות.",
+ "apihelp-query+alldeletedrevisions-param-generatetitles": "בעת שימוש בתור מחולל, לחולל כותרת במקום מזהי גרסה.",
+ "apihelp-query+alldeletedrevisions-example-user": "לרשום את 50 התרומות המחוקות האחרונות של משתמש <kbd>Example<kbd>.",
+ "apihelp-query+alldeletedrevisions-example-ns-main": "רשימת 50 הגרסאות המחוקות הראשונות במרחב הראשי.",
+ "apihelp-query+allfileusages-description": "לרשום את כל שימושי הקובץ, כולל בלתי־קיימים.",
+ "apihelp-query+allfileusages-param-from": "מאיזה שם קובץ להתחיל למנות.",
+ "apihelp-query+allfileusages-param-to": "שם הקובץ שהמנייה תסתיים בו.",
+ "apihelp-query+allfileusages-param-prefix": "חיפוש כל שמות הקבצים שמתחילים עם הערך הזה.",
+ "apihelp-query+allfileusages-param-unique": "להציג רק שמות קבצים ייחודיים. לא יכול לשמש עם $1prop=ids.\nבעת שימוש בתור מחולל, נותן דפי יעד במקום דפי מקור.",
+ "apihelp-query+allfileusages-param-prop": "אילו חלקי מידע לכלול:",
+ "apihelp-query+allfileusages-paramvalue-prop-ids": "הוספת מזהי הדף של הדפים המשתמשים (לא יכול לשמש עם $1unique).",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "הוספת שם הקובץ.",
+ "apihelp-query+allfileusages-param-limit": "כמה פריטים להחזיר בסך הכול.",
+ "apihelp-query+allfileusages-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+allfileusages-example-B": "רשימת שמות קבצים, כולל חסרים, עם מזהי הדפים שהם מופיעים בהם, החל מ־<kbd>B</kbd>.",
+ "apihelp-query+allfileusages-example-unique": "רשימת שמות קבצים ייחודיים.",
+ "apihelp-query+allfileusages-example-unique-generator": "קבלת כל שמות הקבצים, כולל חסרים.",
+ "apihelp-query+allfileusages-example-generator": "קבלת דפים שמכילים את הקבצים.",
+ "apihelp-query+allimages-description": "למנות את כל התמונות לפי הסדר.",
+ "apihelp-query+allimages-param-sort": "לפי איזה מאפיין למיין.",
+ "apihelp-query+allimages-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+allimages-param-from": "מאיזה שם תמונה להתחיל למנות. יכול לשמש רק עם $1sort=name.",
+ "apihelp-query+allimages-param-to": "כותרת תמונה שבה תסתיים המניי. יכול לשמש רק עם $1sort=name.",
+ "apihelp-query+allimages-param-start": "מאיזה חותם־זמן להתחיל למנות. יכול לשמש רק עם $1sort=timestamp.",
+ "apihelp-query+allimages-param-end": "באיזה חותם זמן להפסיק לרשום. אפשר להשתמש בזה רק עם $1sort=timestamp.",
+ "apihelp-query+allimages-param-prefix": "חיפוש כל שמות התמונות שמתחילים בערך הזה. יכול לשמש רק עם $1sort=name.",
+ "apihelp-query+allimages-param-minsize": "להגביל לתמונות עם מספר כזה של בתים לפחות.",
+ "apihelp-query+allimages-param-maxsize": "להגביל לתמונות עם מספר כזה לכל היותר של בתים.",
"apihelp-query+allimages-param-sha1": "גיבוב SHA1 של תמונה. דריסת $1sha1base36.",
"apihelp-query+allimages-param-sha1base36": "גיבוב SHA1 של התמונה בבסיס 36 (הבסיס בו נעשה שימוש במדיה־ויקי).",
+ "apihelp-query+allimages-param-user": "להחזיר רק קבצים שהועלו על־ידי המשתמש הזה. יכול לשמש רק עם $1sort=timestamp. לא יכול לשמש יחד עם $1filterbots.",
+ "apihelp-query+allimages-param-filterbots": "איך לסנן קבצים שמעלים בוטים. יכול לשמש רק עם $1sort=timestamp. לא יכול לשמש יחד עם $1user.",
+ "apihelp-query+allimages-param-mime": "אילו סוגי MIME לחבפש, למשל <kbd>image/jpeg</kbd>.",
"apihelp-query+allimages-param-limit": "כמה תמונות להחזיר בסך הכול.",
"apihelp-query+allimages-example-B": "הצגת רשימה של קבצים שמתחילים באות <kbd>B</kbd>.",
+ "apihelp-query+allimages-example-recent": "הצגת רשימת קבצים שהועלו לאחרונה, דומה ל־[[Special:NewFiles]].",
+ "apihelp-query+allimages-example-mimetypes": "להציג רשימה של קבצות שסוג ה־MIME שלהם הוא <kbd>image/png</kbd> או <kbd>image/png</kbd>.",
"apihelp-query+allimages-example-generator": "הצגת מידע על 4 קבצים המתחילים באות <kbd>T</kbd>.",
+ "apihelp-query+alllinks-description": "למנות את כל הקישורים שמצביעים למרחב שם נתון.",
+ "apihelp-query+alllinks-param-from": "מאיזה שם קישור להתחיל למנות.",
+ "apihelp-query+alllinks-param-to": "כותרת הקישור שהמנייה תסתיים בו.",
+ "apihelp-query+alllinks-param-prefix": "חיפוש כל הכותרות המקושרות שמתחילות בערך הזה.",
+ "apihelp-query+alllinks-param-unique": "להציג רק שמות מקושרים ייחודיים. לא יכול לשמש עם <kbd>$1prop=ids</kbd>.\nבעת שימוש בתור מחולל, נותן דפי יעד במקום דפי מקור.",
+ "apihelp-query+alllinks-param-prop": "אילו חלקי מידע לכלול:",
+ "apihelp-query+alllinks-paramvalue-prop-ids": "הוספת מזהי הדף של הדף המקשר (לא יכול לשמש עם <var>$1unique</var>).",
+ "apihelp-query+alllinks-paramvalue-prop-title": "הוספת שם הקישור.",
+ "apihelp-query+alllinks-param-namespace": "איזה מרחב שם למנות.",
+ "apihelp-query+alllinks-param-limit": "כמה פריטים להחזיר בסך הכול.",
+ "apihelp-query+alllinks-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+alllinks-example-B": "רשימת כותרות מקושרות, כולל חסרות, עם מזהי הדפים שהן מופיעות בהם, החל מ־<kbd>B</kbd>.",
+ "apihelp-query+alllinks-example-unique": "רשימת כותרות מקושרים ייחודיות.",
+ "apihelp-query+alllinks-example-unique-generator": "קבלת כל הכותרות המקושרות, וסימון החסרות.",
+ "apihelp-query+alllinks-example-generator": "קבלת דפים שמכילים את הקישורים.",
+ "apihelp-query+allmessages-description": "החזרת הודעות מהאתר הזה.",
+ "apihelp-query+allmessages-param-messages": "אילו הודעות לפלוט. כתיבת <kbd>*</kbd> (בררת מחדל) תפלוט את כל ההודעות.",
"apihelp-query+allmessages-param-prop": "אלו מאפיינים לקבל.",
+ "apihelp-query+allmessages-param-enableparser": "יש להגדיר כדי להפעיל את המפענח, יעשה קדם־עיבוד לקוד ויקי של ההודעה (יחליף מילות קסם, יטפל בתבניות, וכו').",
+ "apihelp-query+allmessages-param-nocontent": "אם זה מוגדר, לא לכלול את תוכן ההודעות בפלט.",
+ "apihelp-query+allmessages-param-includelocal": "לכלול גם הודעות מקומיות, כלומר הודעות שאינן קיימות בתכנה, אבל כן קיימות בתור דף מדיה־ויקי.\nזה רושם את כל דפי MediaWiki: כך שזה ירשום גם דפים שאינם באמת הודעות, כגון [[MediaWiki:Common.js|Common.js]].",
+ "apihelp-query+allmessages-param-args": "ארגומנטים שיוחלפו לתוך ההודעה.",
+ "apihelp-query+allmessages-param-filter": "החזרה רק של הודעות עם שמות שמכילים את המחרוזת הזאת.",
+ "apihelp-query+allmessages-param-customised": "להחזיר רק הודעות במצב ההתאמה הזה.",
+ "apihelp-query+allmessages-param-lang": "החזרת הודעת בשפה הזאת.",
+ "apihelp-query+allmessages-param-from": "החזרת הודעת החל מההודעה הזאת.",
+ "apihelp-query+allmessages-param-to": "החזרת הודעות עד ההודעה הזאת.",
+ "apihelp-query+allmessages-param-title": "שם דף לשימוש בתור הֶקשר בעת ענוח הודעה (עבור האפשרות $1enableparser).",
+ "apihelp-query+allmessages-param-prefix": "החזרת הודעת עם התחילית הזאת.",
+ "apihelp-query+allmessages-example-ipb": "להציג הודעות שמתחילות ב־<kbd dir=\"ltr\">ipb-</kbd>.",
+ "apihelp-query+allmessages-example-de": "להציג את ההודעות <kbd>august</kbd> ו־<kbd>mainpage</kbd> בגרמנית.",
+ "apihelp-query+allpages-description": "למנות את כל הדפים לפי הסדר במרחב שם נתון.",
+ "apihelp-query+allpages-param-from": "מאיזה שם דף להתחיל למנות.",
+ "apihelp-query+allpages-param-to": "כותרת הדף שהמנייה תסתיים בו.",
+ "apihelp-query+allpages-param-prefix": "חיפוש כל שמות הדפים שמתחילים בערך הזה.",
+ "apihelp-query+allpages-param-namespace": "איזה מרחב שם למנות.",
+ "apihelp-query+allpages-param-filterredir": "אילו דפים לרשום.",
+ "apihelp-query+allpages-param-minsize": "להגביל לדפים עם מספר כזה לפחות של בתים.",
+ "apihelp-query+allpages-param-maxsize": "להגביל לדפים שיש בהם לכל היותר מספר כזה של בתים.",
+ "apihelp-query+allpages-param-prtype": "להגביל רק לדפים מוגנים.",
+ "apihelp-query+allpages-param-prlevel": "לסנו הגנות לפי רמת ההגנה (חייב לשמש עם $1prtype= parameter).",
+ "apihelp-query+allpages-param-prfiltercascade": "לסנן הגנות לפי דירוגיות (לא תקף כאשר $1prtype אינו מוגדר).",
"apihelp-query+allpages-param-limit": "כמה דפים להחזיר בסך הכול.",
+ "apihelp-query+allpages-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+allpages-param-filterlanglinks": "סינון על סמך קיום קישורים לשוניים בדף. יש לשים לב לכך שזה אולי לא יתייחס לקישורים לשוניים שנוספו על־ידי הרחבות.",
+ "apihelp-query+allpages-param-prexpiry": "לפי איזו תפוגת הגנה לסנן את הדף הזה:\n;indefinite:לקבל רק דפים מוגנית לצמיתות.\n;definite:לקבל רק דפים עם תפוגת הגנה מוגדרת.\n;all:לקבל דפים עם תפוגת הגנה כלשהי.",
+ "apihelp-query+allpages-example-B": "להציג רשימה של דפים במתחילים באות <kbd>B</kbd>.",
+ "apihelp-query+allpages-example-generator": "להציג מידע על 4 דפים שמתחילים באות <kbd>T</kbd>.",
+ "apihelp-query+allpages-example-generator-revisions": "להציג את תוכן של 2 הדפים הראשונים שמתחילים ב־<kbd>Re</kbd> ושאינם דפי הפניה.",
+ "apihelp-query+allredirects-description": "רשימה של כל ההפניות למרחב שם.",
+ "apihelp-query+allredirects-param-from": "מאיזו כותרת הפניה להתחיל את מנייה.",
+ "apihelp-query+allredirects-param-to": "כותרת ההפניה שהמנייה תיפסק בה.",
+ "apihelp-query+allredirects-param-prefix": "חיפוש על דפי היעד שמתחילים בערך הזה.",
+ "apihelp-query+allredirects-param-unique": "להציג רק דפים ייחודיים. לא יכול לשמש עם $1prop=ids|fragment|interwiki.\nבעת שימוש בתור מחולל, נותן דפי יעד במקום דפי מקור.",
+ "apihelp-query+allredirects-param-prop": "אילו חלקי מידע לכלול:",
+ "apihelp-query+allredirects-paramvalue-prop-ids": "הוספת מזהה הדף של הדף המפנה (לא יכול לשמש עם <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-title": "הוספת כותרת ההפניה.",
+ "apihelp-query+allredirects-paramvalue-prop-fragment": "הוספת המובאה מההפניה, אם יש (לא יכול לשמש עם <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-interwiki": "הוספת תחילית הבינוויקי מההפניה, אם יש (לא יכול לשמש עם <var>$1unique</var>).",
+ "apihelp-query+allredirects-param-namespace": "איזה מרחב שם למנות.",
"apihelp-query+allredirects-param-limit": "כמה פריטים להחזיר בסך הכול.",
+ "apihelp-query+allredirects-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+allredirects-example-B": "רשימת דפי יעד, כולל חסרים, עם מזהי הדפים שהם מופיעים בהם, החל מ־<kbd>B</kbd>.",
+ "apihelp-query+allredirects-example-unique": "רשימת דפי יעד ייחודיים.",
+ "apihelp-query+allredirects-example-unique-generator": "קבלת על דפי היעד, תוך כדי סימון החסרים.",
+ "apihelp-query+allredirects-example-generator": "קבלת דפים שמכילים את ההפניות.",
+ "apihelp-query+alltransclusions-description": "רשימת כל ההכללות (דפים שמוטבעים באמצעות &#123;&#123;x&#125;&#125;), כולל כאלה שאינם קיימים.",
+ "apihelp-query+alltransclusions-param-from": "מאיזו כותרת ההכללה להתחיל למנות.",
+ "apihelp-query+alltransclusions-param-to": "כותרת ההכללה שהמנייה תיפסק בה.",
+ "apihelp-query+alltransclusions-param-prefix": "חיפוש כל הכותרות המוכללות שמתחילות הערך הזה.",
+ "apihelp-query+alltransclusions-param-unique": "להציג רק שמות מוכללים ייחודיים. לא יכול לשמש עם $1prop=ids.\nבעת שימוש בתור מחולל, נותן דפי יעד במקום דפי מקור.",
+ "apihelp-query+alltransclusions-param-prop": "אילו חלקי מידע לכלול:",
+ "apihelp-query+alltransclusions-paramvalue-prop-ids": "הוספת מזהי הדף של הדפים המכלילים (לא יכול לשמש עם $1unique).",
+ "apihelp-query+alltransclusions-paramvalue-prop-title": "הוספת כותרת ההכללה.",
+ "apihelp-query+alltransclusions-param-namespace": "איזה מרחב שם למנות.",
+ "apihelp-query+alltransclusions-param-limit": "כמה פריטים להחזיר בסך הכול.",
+ "apihelp-query+alltransclusions-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+alltransclusions-example-B": "רשימת כותרות מוכללות, כולל חסרות, עם מזהי הדפים שהן מופיעות בהם, החל מ־<kbd>B</kbd>.",
+ "apihelp-query+alltransclusions-example-unique": "רשימת כותרת מוכללות ייחודיות.",
+ "apihelp-query+alltransclusions-example-unique-generator": "קבלת כל כל הכותרות המוכללות, תוך כדי סימון החסרות.",
+ "apihelp-query+alltransclusions-example-generator": "קבלת דפים שמכילים את ההכללות.",
+ "apihelp-query+allusers-description": "למנות את כל המשתמשים הרשומים.",
+ "apihelp-query+allusers-param-from": "מאיזה שם משתמש להתחיל למנות.",
+ "apihelp-query+allusers-param-to": "באיזה שם משתמש להפסיק למנות.",
+ "apihelp-query+allusers-param-prefix": "חיפוש כל המשתמשים שמתחילים בערך הזה.",
+ "apihelp-query+allusers-param-dir": "באיזה כיוון למיין.",
+ "apihelp-query+allusers-param-group": "לכלול רק משתמשים בקבוצות הנתונות.",
+ "apihelp-query+allusers-param-excludegroup": "לא לכלול משתמשים בקבוצות הנתונות.",
+ "apihelp-query+allusers-param-rights": "לכלול רק משתמשים עם ההרשאות הנתונות. לא כולל הרשאות שניתנו בקבוצות משתמעות או אוטומטיות כגון *, user או autoconfirmed.",
+ "apihelp-query+allusers-param-prop": "אילו פרטי מידע לכלול:",
+ "apihelp-query+allusers-paramvalue-prop-blockinfo": "הוספת מידע עם החסימה הנוכחית של משתמש.",
+ "apihelp-query+allusers-paramvalue-prop-groups": "הוספת קבוצות שמשתמש חבר בהן. זה משתמש ביותר משאבי דפדפן ויכול להחזיר פחות תוצאות מהמגבלה.",
+ "apihelp-query+allusers-paramvalue-prop-implicitgroups": "לרשום את כל הקבוצות שהמשתמש חבר בהן אוטומטית.",
+ "apihelp-query+allusers-paramvalue-prop-rights": "רשימת הההרשאות שיש למשתמש.",
+ "apihelp-query+allusers-paramvalue-prop-editcount": "הוספת מניין העריכות של המשתמש .",
+ "apihelp-query+allusers-paramvalue-prop-registration": "הוספת חותם־הזמן של זמן הרישום של המשתמש (יכול להיות ריק).",
+ "apihelp-query+allusers-param-limit": "כמה שמות משתמש בסך הכול לשנות.",
+ "apihelp-query+allusers-param-witheditsonly": "לרשום רק משתמשים שעשו עריכות.",
+ "apihelp-query+allusers-param-activeusers": "לרשום רק משתמשים שהיו פעילים {{PLURAL:$1|ביום האחרון|ביומיים האחרונים|ב־$1 הימים האחרונים}}.",
+ "apihelp-query+allusers-example-Y": "לרשום משתמשים שמתחילים ב־<kbd>Y</kbd>.",
+ "apihelp-query+backlinks-description": "מציאת כל הדפים שמקשרים לדף הנתון.",
+ "apihelp-query+backlinks-param-title": "איזו כותרת לחפש. לא ניתן להשתמש בזה יחד עם <var>$1pageid</var>.",
+ "apihelp-query+backlinks-param-pageid": "מזהה דף לחיפוש. לא ניתן להשתמש בזה יחד עם <var>$1title</var>.",
+ "apihelp-query+backlinks-param-namespace": "איזה מרחב שם למנות.",
+ "apihelp-query+backlinks-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+backlinks-param-filterredir": "איך לסנן הפניות. אם זה מוגדר ל־<kbd>nonredirects</kbd> כש־<var>$1redirect</var> מופעל, זה חל רק על הרמה השנייה.",
+ "apihelp-query+backlinks-param-limit": "כמה דפים להחזיר בסך הכול. אם <var>$1redirect</var> מופעל, ההגבלה חלה על כל רמה בנפרד (כלומר יכולות להיות מוחזרות עד <span dir=\"ltr\">2 * <var>$1limit</var></span> תוצאות).",
+ "apihelp-query+backlinks-param-redirect": "אם הדף המקשר הוא הפניה, למצוא גם את כל הדפים שמקשרים לאותה ההפניה. ההגבלה המרבית מוקטנת בחצי.",
+ "apihelp-query+backlinks-example-simple": "הצגת קישורים ל־<kbd>Main Page</kbd>.",
+ "apihelp-query+backlinks-example-generator": "קבל מידע על דפים שמקשרים ל־<kbd>Main page<kbd>.",
+ "apihelp-query+blocks-description": "לרשום את כל המשתמשים וכתובות ה־IP שנחסמו.",
+ "apihelp-query+blocks-param-start": "מאיזה חותם‏־זמן להתחיל למנות.",
+ "apihelp-query+blocks-param-end": "באיזה חותם זמן להפסיק למנות.",
+ "apihelp-query+blocks-param-ids": "רשימת מזהי חסימות לרשום (לא חובה).",
+ "apihelp-query+blocks-param-users": "רשימת משתמשים לחיפוש (לא חובה).",
+ "apihelp-query+blocks-param-ip": "קבלת כל החסימות שחלות על טווח ה־IP או ה־CIDR הזה, כולל חסימות טווח.\nלא יכול לשמש יחד עם <var>$3users</var>. טווחי CIDR רחבים מ־IPv4/$1 או IPv6/$2 אינם מתקבלים.",
+ "apihelp-query+blocks-param-limit": "המספר המרבי של חסימות לרשום.",
+ "apihelp-query+blocks-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+blocks-paramvalue-prop-id": "הוספת מזהה החסימה.",
+ "apihelp-query+blocks-paramvalue-prop-user": "הוספת שם המשתמש שנחסם.",
+ "apihelp-query+blocks-paramvalue-prop-userid": "הוספת המזהה של המשמש שנחסם.",
+ "apihelp-query+blocks-paramvalue-prop-by": "הוספת שם המשתמש שחסם.",
+ "apihelp-query+blocks-paramvalue-prop-byid": "הוספת מזהה המשתמש שחסם.",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "הוספת חותם־הזמן של החסימה.",
+ "apihelp-query+blocks-paramvalue-prop-expiry": "הוספת חותם־הזמן של תפוגת החסימה.",
+ "apihelp-query+blocks-paramvalue-prop-reason": "הוספת הסיבה שניתנה לחסימה.",
+ "apihelp-query+blocks-paramvalue-prop-range": "הוספת טווח כתובות ה־IP שהחסימה משפיעה עליהן.",
+ "apihelp-query+blocks-paramvalue-prop-flags": "מתייג את ההחרמה (autoblock‏, anononly, וכו'.).",
+ "apihelp-query+blocks-param-show": "להציג רק פריטים שמתאימים לאמות המידה האלו.\nלמשל, כדי לראות רק חסימות ללא לצמיתות על כתובות IP יש להגדיר <kbd>$1show=ip|!temp</kbd>.",
+ "apihelp-query+blocks-example-simple": "רשימת חסימות.",
+ "apihelp-query+blocks-example-users": "רשימת חסימות של המשתמשים <kbd>Alice</kbd> ו־<kbd>Bob</kbd>.",
+ "apihelp-query+categories-description": "לרשום את כל הקטגוריות שהדף שייך אליהן.",
+ "apihelp-query+categories-param-prop": "אילו מאפיינים נוספים לקבל עבור כל קטגוריה:",
+ "apihelp-query+categories-paramvalue-prop-sortkey": "הוספת מפתח מיון (מחרוזת הקסדצימלית) ותחילית מפתח מיון (החלק הקריא) עבור קטגוריה.",
+ "apihelp-query+categories-paramvalue-prop-timestamp": "הוספת חותם־הזמן של יצירת הקטגוריה.",
+ "apihelp-query+categories-paramvalue-prop-hidden": "תיוג קטגוריות שהוסתרו באמצעות <code>_&#95;HIDDENCAT_&#95;</code>.",
+ "apihelp-query+categories-param-show": "איזה סוג של קטגוריות להציג.",
"apihelp-query+categories-param-limit": "כמה קטגוריות להחזיר.",
+ "apihelp-query+categories-param-categories": "לרשום רק את הקטגוריות האלו. שימושי לבדיקה עם דף מסוים נמצא בקטגוריה מסוימת.",
+ "apihelp-query+categories-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+categories-example-simple": "קבלת רשימת קטגוריות שהם <kbd>Albert Einstein</kbd> שייך אליהן.",
+ "apihelp-query+categories-example-generator": "קבלת מידע על כל הקטגוריות שמשמשות בדף <kbd>Albert Einstein</kbd>.",
+ "apihelp-query+categoryinfo-description": "החזרת מידע על הקטגוריות הנתונות.",
+ "apihelp-query+categoryinfo-example-simple": "קבחצ מידע על <kbd>Category:Foo</kbd> ועל <kbd>Category:Bar</kbd>.",
+ "apihelp-query+categorymembers-description": "רשימת כל הדפים בקטגוריה נתונה.",
+ "apihelp-query+categorymembers-param-title": "איזו קטגוריה למנות (נדרש). חייב לכלול את התחילית <kbd>{{ns:category}}:</kbd>. לא יכול לשמש יחד עם <var>$1pageid</var>.",
+ "apihelp-query+categorymembers-param-pageid": "מזהה הדף של הקטגוריה שצריך למנות. לא יכול לשמש יחד עם <var>$1title</var>.",
+ "apihelp-query+categorymembers-param-prop": "אילו חלקי מידע לכלול:",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "הוספת מזהה הדף.",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "הוספת השם ומזהה מרחב השם של הדף.",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkey": "הוספת מפתח המיון שמשמש למיון בקטגוריה (מחרזות הקסדצימלית).",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "הוספת מפתח המיון שמשמש למיון בקטגוריה (מחרוזת הקסדצימלית).",
+ "apihelp-query+categorymembers-paramvalue-prop-type": "הוספת הסוג שהדף מוין אליו (דף, תת־קטגוריה, או קובץ).",
+ "apihelp-query+categorymembers-paramvalue-prop-timestamp": "הוספת חותם־הזמן שבו הדף נכלל.",
+ "apihelp-query+categorymembers-param-namespace": "לכלול רק דפים במרחבי השם האלה. יש לשים לב לכך ש־<kbd>$1type=subcat</kbd> או <kbd>$1type=file</kbd> יכולים לשמש במקום <kbd>$1namespace=14</kbd> או <kbd>6</kbd>.",
+ "apihelp-query+categorymembers-param-type": "איזה סוג של חברי קטגוריה לכלול. לא תקף כאשר מוגדר <kbd>$1sort=timestamp</kbd>.",
+ "apihelp-query+categorymembers-param-limit": "מספר הדפים המרבי שיוחזר.",
+ "apihelp-query+categorymembers-param-sort": "לפי איזה מאפיין למיין.",
+ "apihelp-query+categorymembers-param-dir": "באיזה כיוון למיין.",
+ "apihelp-query+categorymembers-param-start": "מאיזה חותם־זמן להתחיל לרשום. יכול לשמש רק עם <kbd>$1sort=timestamp</kbd>.",
+ "apihelp-query+categorymembers-param-end": "באיזה חותם־זמן לסיים לרשום. יכול לשמש רק עם <kbd>$1sort=timestamp</kbd>.",
+ "apihelp-query+categorymembers-param-starthexsortkey": "מפתח מיון להתחיל לרשום ממנו, כפי שמוחזר על־ידי <kbd>$1prop=sortkey</kbd. יכול לשמש רק עם <kbd>$1sort=sortkey</kbd>.",
+ "apihelp-query+categorymembers-param-endhexsortkey": "מפתח מיון לסיים לרשום ממנו, כפי שמוחזר על־ידי <kbd>$1prop=sortkey</kbd>. יכול לשמש רק עם <kbd>$1sort=sortkey</kbd>.",
+ "apihelp-query+categorymembers-param-startsortkeyprefix": "תחילית מפתח מיון להתחיל לרשום ממנה. יכול לשמש רק עם <kbd>$1sort=sortkey</kbd>. דורס את <var>$1starthexsortkey</var>.",
+ "apihelp-query+categorymembers-param-endsortkeyprefix": "תחילית מפתח מיון שהרשימה תסתיים <strong>לפניה</strong> (לא <strong>בה</strong>, אם הערך הזה מוגדר, הוא לא ייכלל!). יכול לשמש רק עם $1sort=sortkey. דורס את $1endhexsortkey.",
"apihelp-query+categorymembers-param-startsortkey": "כדאי להשתמש ב־$1starthexsortkey במקום.",
"apihelp-query+categorymembers-param-endsortkey": "כדאי להשתמש ב־$1endhexsortkey במקום.",
"apihelp-query+categorymembers-example-simple": "קבלת עשרת העמודים הראשונים שתחת <kbd>קטגוריה:פיזיקה</kbd>.",
+ "apihelp-query+categorymembers-example-generator": "קבל מידע על הדף עבור 10 הדפים הראשונים ב־<kbd>Category:Physics</kbd>.",
+ "apihelp-query+contributors-description": "קבלת רשימה של תורמים שנכנסו לחשבון ומניין של תורמים אלמוניים לדף.",
+ "apihelp-query+contributors-param-group": "לכלול רק משתמשים בקבוצות הנתונות. לא כולל קבוצות משתמעות או אוטומטיות כגון *, user או autoconfirmed.",
+ "apihelp-query+contributors-param-excludegroup": "לא לכלול משתמשים בקבוצות הנתונות. לא כולל קבוצות משתמעות או אוטומטיות כגון *, user או autoconfirmed.",
+ "apihelp-query+contributors-param-rights": "לכלול רק משתמשים עם ההרשאות הנתונות. לא כולל הרשאות שניתנו בקבוצות משתמעות או אוטומטיות כגון *, user או autoconfirmed.",
+ "apihelp-query+contributors-param-excluderights": "לא לכלול משתמשים עם ההרשאות הנתונות. לא כולל הרשאות שניתנו בקבוצות משתמעות או אוטומטיות כגון *, user או autoconfirmed.",
"apihelp-query+contributors-param-limit": "כמה תורמים להחזיר.",
"apihelp-query+contributors-example-simple": "הצגת תורמים לדף <kbd>עמוד ראשי</kbd>.",
+ "apihelp-query+deletedrevisions-description": "קבלת מידע על גרסה מחוקה.\n\nיכול לשמש במספר דרכים:\n# קבלת גרסאות מחוקות עבור ערכת דפים, על־ידי הגדרת שמות או מזהי דף. ממוין לפי שם וחותם־זמן.\n# קבלת מידע על ערכת גרסאות מחוקות באמצעות הגדרת המזהים שלהם עם revid־ים. ממוין לפי מזהה גרסה.",
+ "apihelp-query+deletedrevisions-param-start": "מאיזה חותם־זמן להתחיל למנות. לא תקף בעיבוד רשימת מזהי גרסה.",
+ "apihelp-query+deletedrevisions-param-end": "באיזה חותם־זמן להפסיק למנות. לא תקף בעת עיבוד רשימת מזהי גרסה.",
+ "apihelp-query+deletedrevisions-param-tag": "לרשום רק גרסאות עם התג הזה.",
+ "apihelp-query+deletedrevisions-param-user": "לרשום רק גרסאות מאת המשתמש הזה.",
+ "apihelp-query+deletedrevisions-param-excludeuser": "לא לרשום גרסאות מאת המשתמש הזה.",
+ "apihelp-query+deletedrevisions-example-titles": "רשימת גרסאות מחוקות של הדפים <kbd>Main Page</kbd> ו־<kbd>Talk:Main Page</kbd>, עם תוכן.",
+ "apihelp-query+deletedrevisions-example-revids": "קבלת מידע לגרסה המחוקה <kbd>123456</kbd>.",
+ "apihelp-query+deletedrevs-description": "רשימת גרסאות מחוקות.\n\nפועל בשלושה אופנים:\n# רשימת גרסאות מחוקות לשמות שניתנו, ממוינות לפי חותם־זמן.\n# רשימת תרומות מחוקות של המשתמש שניתן, ממוינות לפי חותם־זמן (בלי לציין שמות).\n# רשימת כל הגרסאות המחוקות במרחב השם שניתן, ממוינות לפי שם וחותם־זמן (בלי לציין שמות, בלי להגדיר $1user).\n\nפרמטרים מסוימים חלים רק על חלק מהאופנים ולא תקפים באחרים.",
"apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|מצב|מצבים}}: $2",
+ "apihelp-query+deletedrevs-param-start": "באיזה חותם־זמן להתחיל למנות.",
+ "apihelp-query+deletedrevs-param-end": "באיזה חותם־זמן להפסיק למנות.",
+ "apihelp-query+deletedrevs-param-from": "להתחיל את הרשימה בשם הזה.",
+ "apihelp-query+deletedrevs-param-to": "להפסיק את הרשימה בכותרת הזאת.",
+ "apihelp-query+deletedrevs-param-prefix": "חיפוש כל שמות הדפים שמתחילים בערך הזה.",
+ "apihelp-query+deletedrevs-param-unique": "לרשום רק גרסה אחת עבור כל דף.",
+ "apihelp-query+deletedrevs-param-tag": "לרשום רק גרסאות עם התג הזה.",
+ "apihelp-query+deletedrevs-param-user": "לרשום רק גרסאות מאת המשתמש הזה.",
+ "apihelp-query+deletedrevs-param-excludeuser": "לא לרשום גרסאות מאת המשתמש הזה.",
+ "apihelp-query+deletedrevs-param-namespace": "לרשום רק דפים במרחב השם הזה.",
+ "apihelp-query+deletedrevs-param-limit": "המספר המרבי של הגרסאות שיירשם.",
+ "apihelp-query+deletedrevs-param-prop": "אילו מאפיינים לקבל:\n;revid:הוספת מזהה הגרסה של הגרסה המחוקה.\n;parentid:הוספת מזהה הגרסה של הגרסה הקודמת של הדף.\n;user:הוספת המשתמש שעשה את הגרסה.\n;userid:הוספת מזהה המשתמש שעשה את הגרסה.\n;comment:הוספת ההערה על הגרסה.\n;parsedcomment:הוספת ההערה המפוענחת על הגרסה.\n;minor:מתייג אם הגרסה משנית.\n;len:מוסיף את האורך (בבתים) של הגרסה.\n;sha1:הוספת ה־SHA-1 (בסיס 16) של הגרסה.\n;content:הוספת התוכן של הגרסה.\n;token:<span class=\"apihelp-deprecated\">מיושן.</span> נותן אסימון עריכה.\n;tags:תגים עבור הגרסה.",
+ "apihelp-query+deletedrevs-example-mode1": "רשימת כל הגרסאות המחוקות של הדפים <kbd>Main Page</kbd> ו־<kbd>Talk:Main Page</kbd>, עם תוכן (mode 1).",
+ "apihelp-query+deletedrevs-example-mode2": "רשימת 50 העריכות המחוקות האחרונות של <kbd>Bob</kbd>‏ (mode 2).",
+ "apihelp-query+deletedrevs-example-mode3-main": "רשימת 50 הגרסאות המחוקות הראשונות במרחב הראשי (mode 3).",
+ "apihelp-query+deletedrevs-example-mode3-talk": "רשימת 50 הדפים המחוקים הראשונים במרחב השם {{ns:talk}}‏ (mode 3).",
+ "apihelp-query+disabled-description": "יחידת ה־query הזאת כובתה.",
+ "apihelp-query+duplicatefiles-description": "רשימת כל הקבצים שהם כפולים של קבצים נתונים לפי ערכי הגיבוב.",
"apihelp-query+duplicatefiles-param-limit": "כמה קבצים כפולים להחזיר.",
+ "apihelp-query+duplicatefiles-param-dir": "באיזה כיוון לרשום.",
"apihelp-query+duplicatefiles-param-localonly": "חיפוש אחר קבצים במאגר המקומי בלבד.",
"apihelp-query+duplicatefiles-example-simple": "חיפוש אחר כפילויות של [[:קובץ:Albert Einstein Head.jpg]].",
"apihelp-query+duplicatefiles-example-generated": "חיפוש אחר כפילויות בין כל הקבצים.",
+ "apihelp-query+embeddedin-description": "חיפוש כל הדפים שמטמיעים (מכלילים) את הכותרת הנתונה.",
+ "apihelp-query+embeddedin-param-title": "איזו כותרת לחפש. לא ניתן להשתמש בזה יחד עם $1pageid.",
+ "apihelp-query+embeddedin-param-pageid": "מזהה דף לחיפוש. לא יכול לשמש יחד עם $1title.",
+ "apihelp-query+embeddedin-param-namespace": "איזה מרחב שם למנות.",
+ "apihelp-query+embeddedin-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+embeddedin-param-filterredir": "איך לסנן עבור הפניות.",
+ "apihelp-query+embeddedin-param-limit": "כמה דפים להחזיר בסך הכול.",
+ "apihelp-query+embeddedin-example-simple": "הצגת דפים שמכלילים את <kbd>Template:Stub</kbd>.",
+ "apihelp-query+embeddedin-example-generator": "קבלת מידע על דפים שמכלילים את <kbd>Template:Stub</kbd>.",
+ "apihelp-query+extlinks-description": "החזרת כל ה־URL־ים החיצוניים (לא בינוויקי) מהדפים הנתונים.",
"apihelp-query+extlinks-param-limit": "כמה קישורים להחזיר.",
+ "apihelp-query+extlinks-param-protocol": "הפרוטוקול של ה־URL. אם זה ריק, ו־<var>$1query</var> מוגדר, הפרוטוקול הוא <kbd>http</kbd>. יש להשאיר את זה ואת <var>$1query</var> ריק כדי לרשום את כל הקישורים החיצוניים.",
+ "apihelp-query+extlinks-param-query": "מחרוזת חיפוש ללא פרוטוקול. שימושי לבדיקה האם דף מסוים מכיל url חיצוני מסוים.",
+ "apihelp-query+extlinks-param-expandurl": "הרחבת URL־ים בעלי פרוטוקול יחסי בפרוטוקול קנוני.",
+ "apihelp-query+extlinks-example-simple": "קבלת רשימת קישורים חיצוניים ב־<kbd>Main Page<kbd>.",
+ "apihelp-query+exturlusage-description": "למנות דפים שמכילים URL נתון.",
+ "apihelp-query+exturlusage-param-prop": "אילו חלקי מידע לכלול:",
+ "apihelp-query+exturlusage-paramvalue-prop-ids": "הוספת מזהה הדף.",
+ "apihelp-query+exturlusage-paramvalue-prop-title": "הוספת השם ומזהה מרחב השם של הדף.",
+ "apihelp-query+exturlusage-paramvalue-prop-url": "הוספת ה־URL שמשמש בדף.",
+ "apihelp-query+exturlusage-param-protocol": "הפרוטוקול של ה־URL. אם זה ריק, ו־<var>$1query</var> מוגדר, הפרוטוקול הוא <kbd>http</kbd>. יש להשאיר את זה ואת <var>$1query</var> ריק כדי לרשום את כל הקישורים החיצוניים.",
+ "apihelp-query+exturlusage-param-query": "מחרוזת חיפוש ללא פרוטוקל. ר' [[Special:LinkSearch]]. יש להשאיר את זה ריק כדי לרשום את כל הקישורים החיצוניים.",
+ "apihelp-query+exturlusage-param-namespace": "איזה מרחב שם למנות.",
+ "apihelp-query+exturlusage-param-limit": "כמה דפים להחזיר.",
+ "apihelp-query+exturlusage-param-expandurl": "הרחבת URL־ים בעלי פרוטוקול יחסי בפרוטוקול קנוני.",
+ "apihelp-query+exturlusage-example-simple": "הצגת דפים שמקשרים ל־<kbd>http://www.mediawiki.org</kbd>.",
+ "apihelp-query+filearchive-description": "למנות את כל הקבצים המחוקים לפי הסדר.",
+ "apihelp-query+filearchive-param-from": "מאיזו כותרת תמונה להתחיל למנות.",
+ "apihelp-query+filearchive-param-to": "באיזו כותרת תמונה להפסיק למנות.",
+ "apihelp-query+filearchive-param-prefix": "חיפוש כל שמות התמונות שמתחילים בערך הזה.",
+ "apihelp-query+filearchive-param-limit": "כמה תמונות להחזיר בסך הכול.",
+ "apihelp-query+filearchive-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+filearchive-param-sha1": "גיבוב SHA1 של תמונה. דורס את $1sha1base36.",
+ "apihelp-query+filearchive-param-sha1base36": "גיבוב SHA1 של תמונה בבסיס 36 (משמש במדיה־ויקי).",
+ "apihelp-query+filearchive-param-prop": "איזה מידע על תמונה לקבל:",
+ "apihelp-query+filearchive-paramvalue-prop-sha1": "הוספת גיבוב SHA-1 עבור התמונה.",
+ "apihelp-query+filearchive-paramvalue-prop-timestamp": "הוספת חותם־זמן לגרסה המועלית.",
+ "apihelp-query+filearchive-paramvalue-prop-user": "הוספת המשתמש שהעלה על גרסת התמונה.",
+ "apihelp-query+filearchive-paramvalue-prop-size": "הוספת הגודל של התמונה בבתים והגובה, הרוחב ומניין הדפים (אם מתאים).",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "כינוי ל־size.",
+ "apihelp-query+filearchive-paramvalue-prop-description": "הוספת תיאור לגרסת התמונה.",
+ "apihelp-query+filearchive-paramvalue-prop-parseddescription": "פענוח התיאור של הגרסה.",
+ "apihelp-query+filearchive-paramvalue-prop-mime": "הוספת ה־MIME של התמונה.",
+ "apihelp-query+filearchive-paramvalue-prop-mediatype": "הוספת סוג המדיה של התמונה.",
+ "apihelp-query+filearchive-paramvalue-prop-metadata": "רשימת מטא־נתוני Exif עבור גרסת הקובץ.",
+ "apihelp-query+filearchive-paramvalue-prop-bitdepth": "הוספת עומק הביטים של הגרסה.",
+ "apihelp-query+filearchive-paramvalue-prop-archivename": "הוספת שם הקובץ של גרסה מאורכבת עבור גרסאות שאינן האחרונה.",
+ "apihelp-query+filearchive-example-simple": "הצגת רשימת כל הקבצים המחוקים.",
+ "apihelp-query+filerepoinfo-description": "החזרת מידע מטא על מאגרי תמונות שמוגדרים בוויקי.",
+ "apihelp-query+filerepoinfo-param-prop": "אילו מאפייני מאגר לקבל (יכולים להיות יותר מזה באתרי ויקי אחדים):\n;apiurl:URL ל־API של המאגר – מועיל לקבלת מידע על התמונה מהמארח.\n;name:המפתח של המאגר – משמש למשל בערכים המוחזרים מ־<var>[[mw:Manual:$wgForeignFileRepos|$wgForeignFileRepos]]</var> ומ־[[Special:ApiHelp/query+imageinfo|imageinfo]].\n;displayname:שם קריא של אתר הוויקי של המאגר.\n;rooturl:URL שורש לנתיבי תמונות.\n;local:האם המאגר הוא מקומי או לא.",
+ "apihelp-query+filerepoinfo-example-simple": "קבלת מידע על מאגרי קבצים.",
+ "apihelp-query+fileusage-description": "מציאת כל הדפים שמשתמשים בקבצים הנתונים.",
+ "apihelp-query+fileusage-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+fileusage-paramvalue-prop-pageid": "מזהה הדף של כל דף.",
+ "apihelp-query+fileusage-paramvalue-prop-title": "השם של כל דף.",
+ "apihelp-query+fileusage-paramvalue-prop-redirect": "דגל אם הדף הוא הפניה.",
+ "apihelp-query+fileusage-param-namespace": "לכלול רק דפים במרחבי השם האלה.",
+ "apihelp-query+fileusage-param-limit": "כמה להחזיר.",
+ "apihelp-query+fileusage-param-show": "לחפש רק פריטים שמתאימים לאמות המידה הבאות:\n;redirect:להציג רק הפניות.\n;!redirect:לא להציג הפניות.",
+ "apihelp-query+fileusage-example-simple": "קבלת רשימת דפים שמשתמשים ב־[[:File:Example.jpg]].",
+ "apihelp-query+fileusage-example-generator": "קבלת מידע על דפים שמשתמשים ב־[[:File:Example.jpg]].",
+ "apihelp-query+imageinfo-description": "החזרת מידע על קובץ והיסטורייה העלאה.",
+ "apihelp-query+imageinfo-param-prop": "איזה מידע על הקובץ לקבל:",
+ "apihelp-query+imageinfo-paramvalue-prop-timestamp": "הוספת חותם־זמן לגרסה שהועלתה.",
+ "apihelp-query+imageinfo-paramvalue-prop-user": "הוספה המשתמש שהעלה כל גרסה של קובץ.",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "הוספת מזהה המשתמש שהעלה כל גרסה של קובץ.",
"apihelp-query+imageinfo-paramvalue-prop-comment": "תגובה על הגרסה.",
+ "apihelp-query+imageinfo-paramvalue-prop-parsedcomment": "פענוח ההערה על גרסה.",
+ "apihelp-query+imageinfo-paramvalue-prop-canonicaltitle": "הוספת הכותרת הקנונית של הקובץ.",
+ "apihelp-query+imageinfo-paramvalue-prop-url": "מתן URL לקובץ ולדף התיאור.",
+ "apihelp-query+imageinfo-paramvalue-prop-size": "הוספת הגודל של הקובץ בבתים והגובה, הרוחב ומניין הדפים (אם זה מתאים).",
+ "apihelp-query+imageinfo-paramvalue-prop-dimensions": "כינוי ל־size.",
+ "apihelp-query+imageinfo-paramvalue-prop-sha1": "הוספת גיבוב SHA-1 עבור הקובץ.",
+ "apihelp-query+imageinfo-paramvalue-prop-mime": "הוספת סוג ה־MIME של הקובץ.",
+ "apihelp-query+imageinfo-paramvalue-prop-thumbmime": "הוספת סוג ה־MIME של התמונה הממוזערת (נדרש url והפרמטר $1urlwidth).",
+ "apihelp-query+imageinfo-paramvalue-prop-mediatype": "הוספת סוג המדיה של הקובץ.",
+ "apihelp-query+imageinfo-paramvalue-prop-metadata": "טעינת מטא־נתונים של Exif עבור גרסת הקובץ.",
+ "apihelp-query+imageinfo-paramvalue-prop-commonmetadata": "רשימת מטא־נתונים כלליים על תסדיר הקובץ עבור גרסת הקובץ.",
+ "apihelp-query+imageinfo-paramvalue-prop-extmetadata": "רשימת מטא־נתונים מעוצבים משולבים ממספר מקורות. התוצאה מעוצבת ב־HTML.",
+ "apihelp-query+imageinfo-paramvalue-prop-archivename": "הוספת שם הקובץ של גרסת הארכיון עבור הגרסאות שאינן האחרונה.",
+ "apihelp-query+imageinfo-paramvalue-prop-bitdepth": "הוספת עומק הביטים של הגרסה.",
+ "apihelp-query+imageinfo-paramvalue-prop-uploadwarning": "משמש את Special:Upload כדי לקבל מידע על קובץ קיים. לא נועד לשימוש מחוץ לליבת MediaWiki.",
+ "apihelp-query+imageinfo-param-limit": "כמה גרסאות של קובץ לכל קובץ.",
+ "apihelp-query+imageinfo-param-start": "מאיז חותם־זמן להתחיל רשימה.",
+ "apihelp-query+imageinfo-param-end": "באיזה חותם־זמן לסיים את הרשימה.",
+ "apihelp-query+imageinfo-param-urlwidth": "אם מוגדר $2prop=url, יוחזר URL לתמונה שגודלה הותאם לרוחב הזה.\nמסיבות של ביצועים, אם האפשרות הזאת משמשת, לא יוחזרו יותר מ־$1 תמונות.",
+ "apihelp-query+imageinfo-param-urlheight": "דומה ל־$1urlwidth.",
+ "apihelp-query+imageinfo-param-metadataversion": "גרסת המטא־נתונים לשימוש. אם מוגדר <kbd>latest</kbd>, להשתמש בגרסה החדשה ביותר. בררת המחדל היא <kbd>1</kbd> לצורך תאימות אחורה.",
+ "apihelp-query+imageinfo-param-extmetadatalanguage": "באיזו שפה לאחזר את המטא־נתונים. זה משפיע על אילו תרגומים לאחזר, האם יש כמה, וגם איך דברים כמו מספרים וערכים שונים מעוצבים.",
+ "apihelp-query+imageinfo-param-extmetadatamultilang": "אם תרגומים של המאפיין extmetadata זמינים, לאחזר את כולם.",
+ "apihelp-query+imageinfo-param-extmetadatafilter": "אם זה מוגדר ולא ריק, רק המפתחות האלה יוחזרו עבור $1prop=extmetadata.",
+ "apihelp-query+imageinfo-param-urlparam": "מחרוזת פרמטר ייחודית למטפל. למשל, PDF־ים יכולים להשתמש ב־<kbd>page15-100px</kbd>.‏ <var>$1urlwidth</var> צריך לשמש ולהיות עקבי עם <var>$1urlparam</var>.",
"apihelp-query+imageinfo-param-localonly": "חיפוש אחר קבצים במאגר המקומי בלבד.",
- "apihelp-query+imageinfo-example-simple": "קבלת פרטים על הגרסה הנוכחית של [[:קובץ:Albert Einstein Head.jpg]].",
+ "apihelp-query+imageinfo-example-simple": "קבלת מידע על הגרסה הנוכחית של [[:File:Albert Einstein Head.jpg]].",
+ "apihelp-query+imageinfo-example-dated": "אחזור מידע על גרסאות של [[:File:Test.jpg]] מ־2008 ואחרי‏־כן.",
+ "apihelp-query+images-description": "להחזיר את כל הקבצים שמכילים הדפים הנתונים.",
"apihelp-query+images-param-limit": "כמה קבצים להחזיר.",
+ "apihelp-query+images-param-images": "לרשום רק את הקבצים האלה. שימוש לבדיקת האם לדף מסוים יש קובץ מסוים.",
+ "apihelp-query+images-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+images-example-simple": "קבלת רשימת קבצים שמשמשים ב־[[Main Page]].",
+ "apihelp-query+images-example-generator": "קבלת מידע על כל הקבצים שמשמשים ב־[[Main Page]].",
+ "apihelp-query+imageusage-description": "מציאת כל הדפים שמתמשים בשם התמונה הנתונה.",
+ "apihelp-query+imageusage-param-title": "איזו כותרת לחפש. לא ניתן להשתמש בזה יחד עם $1pageid.",
+ "apihelp-query+imageusage-param-pageid": "מזהה דף לחיפוש. לא יכול לשמש יחד עם $1title.",
+ "apihelp-query+imageusage-param-namespace": "איזה מרחב שם למנות.",
+ "apihelp-query+imageusage-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+imageusage-param-filterredir": "איך לסנן הפניות. אם זה מוגדר ל־nonredirects כש־$1redirect מופעל, זה חל רק על הרמה השנייה.",
+ "apihelp-query+imageusage-param-limit": "כמה דפים להחזיר בסך הכול. אם <var>$1redirect</var> מופעל, ההגבלה חלה על כל רמה בנפרד (כלומר יכולות להיות מוחזרות עד <span dir=\"ltr\">2 * <var>$1limit</var></span> תוצאות).",
+ "apihelp-query+imageusage-param-redirect": "אם הדף המקשר הוא הפניה, למצוא גם את כל הדפים שמקשרים לאותה ההפניה. ההגבלה המרבית מוקטנת בחצי.",
+ "apihelp-query+imageusage-example-simple": "הצגת דפים שמשתמשים ב־[[:File:Albert Einstein Head.jpg]].",
+ "apihelp-query+imageusage-example-generator": "קבלת פרטים על דפים שמשתמשים ב־[[:File:Albert Einstein Head.jpg]].",
+ "apihelp-query+info-description": "קבלת מידע בסיסי על הדף.",
+ "apihelp-query+info-param-prop": "אילו מאפיינים נוספים לקבל:",
+ "apihelp-query+info-paramvalue-prop-protection": "לרשום את רמת ההגנה של כל דף.",
+ "apihelp-query+info-paramvalue-prop-talkid": "מזהה הדף של דף השיחה עבור כל דף שאינו דף שיחה.",
+ "apihelp-query+info-paramvalue-prop-watched": "לרשום את מצב המעקב של כל דף.",
"apihelp-query+info-paramvalue-prop-watchers": "מספר העוקבים, אם קיבלת הרשאה.",
+ "apihelp-query+info-paramvalue-prop-notificationtimestamp": "חותם־זמן של הודעת רשימת מעקב של כל דף.",
+ "apihelp-query+info-paramvalue-prop-subjectid": "מזהה הדף של הדף העיקרי של כל דף שיחה.",
+ "apihelp-query+info-paramvalue-prop-url": "נותן URL מלא, URL לעריכה ו־URL קנוני לכל דף.",
"apihelp-query+info-paramvalue-prop-readable": "האם המשתמש יכול להציג דף זה.",
+ "apihelp-query+info-paramvalue-prop-preload": "נותן את הטקסט שמוחזר על־ידי EditFormPreloadText.",
+ "apihelp-query+info-paramvalue-prop-displaytitle": "נותן את האופן שבה שם הדף באמת מוצג.",
+ "apihelp-query+info-param-testactions": "בדיקה האם המשתמש הנוכחי יכול לבצע פעולות מסוימות על הדף.",
+ "apihelp-query+info-param-token": "להשתמש ב־[[Special:ApiHelp/query+tokens|action=query&meta=tokens]] במקום.",
+ "apihelp-query+info-example-simple": "קבלת מידע על הדף <kbd>Main Page</kbd>",
+ "apihelp-query+info-example-protection": "קבלת מידע כללי ומידע על הגנה של הדף <kbd>Main Page</kbd>.",
+ "apihelp-query+iwbacklinks-description": "מציאות כל הדפים שמקשרים לקישור הבינוויקי הנתון.\n\nיכול לשמש למציאת כל הקישורים עם התחילית, או כל הקישורים לכותרת (עם תחילית נתונה). אי־שימוש בשום פרמטר אומר \"כל קישורי בינוויקי\".",
+ "apihelp-query+iwbacklinks-param-prefix": "תחילית לבינוויקי.",
+ "apihelp-query+iwbacklinks-param-title": "איזה קישור בינוויקי לחפש. צריך להשתמש בזה יחד עם <var>$1blprefix</var>.",
+ "apihelp-query+iwbacklinks-param-limit": "כמה דפים להחזיר בסך הכול.",
+ "apihelp-query+iwbacklinks-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "הוספת התחילית של הבינוויקי.",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "הוספת הכותרת של הבינוויקי.",
+ "apihelp-query+iwbacklinks-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+iwbacklinks-example-simple": "קבלת דפים שמקשרים ל־[[wikibooks:Test]].",
+ "apihelp-query+iwbacklinks-example-generator": "קבלת מידע על דפים שמקשרים ל־[[wikibooks:Test]].",
+ "apihelp-query+iwlinks-description": "החזרת כל קישורי הבינוויקי מהדפים הנתונים.",
+ "apihelp-query+iwlinks-param-url": "האם לקבל את ה־URL המלא (לא יכול לשמש עם $1prop).",
+ "apihelp-query+iwlinks-param-prop": "אילו מאפיינים נוספים לקבל עבור כל קישור בין־לשוני:",
+ "apihelp-query+iwlinks-paramvalue-prop-url": "הוספת ה־URL המלא.",
+ "apihelp-query+iwlinks-param-limit": "כמה קישורי בינוויקי להחזיר.",
+ "apihelp-query+iwlinks-param-prefix": "להחזיר רק קישורי בינוויקי עם התחילית הזאת.",
+ "apihelp-query+iwlinks-param-title": "איזה קישור בינוויקי לחפש. צריך להשתמש בזה יחד עם <var>$1prefix</var>.",
+ "apihelp-query+iwlinks-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+iwlinks-example-simple": "קבלת קישורי בינוויקי מהדף <kbd>Main Page</kbd>.",
+ "apihelp-query+langbacklinks-description": "מציאת כל הדפים שמקשרים לקישור השפה הנתון.\n\nיכול לשמש למציאת כל הקישורים עם קוד שפה, או כל הקישורים לכותרת (עם שפה נתונה). אי־שימוש בשום פרמטר פירושו \"כל קישורי שפה\".\n\nנא לשים לב לכך שזה עשוי לא להתייחס לקישורי שפה שמוסיפות הרחבות.",
+ "apihelp-query+langbacklinks-param-lang": "שפה עבור קישור שפה.",
+ "apihelp-query+langbacklinks-param-title": "איזה קישור שפה לחפש. חייב לשמש עם $1lang.",
+ "apihelp-query+langbacklinks-param-limit": "כמה דפים להחזיר בסך הכול.",
+ "apihelp-query+langbacklinks-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+langbacklinks-paramvalue-prop-lllang": "הוספת קוד השפה של קישור השפה.",
+ "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "הוספת הכותרת של קישור השפה.",
+ "apihelp-query+langbacklinks-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+langbacklinks-example-simple": "קבלת דפים שמקשרים ל־[[:fr:Test]].",
+ "apihelp-query+langbacklinks-example-generator": "קבלת מידע על דפים שמקשרים ל־[[:fr:Test]].",
+ "apihelp-query+langlinks-description": "החזרת כל הקישורים הבין־לשוניים מהדפים הנתונים.",
+ "apihelp-query+langlinks-param-limit": "כמה קישורי שפה להחזיר.",
+ "apihelp-query+langlinks-param-url": "האם לקבל את ה־URL המלא (לא יכול לשמש עם <var>$1prop</var>).",
+ "apihelp-query+langlinks-param-prop": "אילו מאפיינים נוספים לקבל עבור כל קישור בין־לשוני:",
+ "apihelp-query+langlinks-paramvalue-prop-url": "הוספת ה־URL המלא.",
+ "apihelp-query+langlinks-paramvalue-prop-langname": "הוספת שם השפה המתורגם (עם המאמץ הטוב ביותר). יש להשתמש ב־<var>$1inlanguagecode</var> כדי לשלוט בשפה.",
+ "apihelp-query+langlinks-paramvalue-prop-autonym": "הוספת השם הילידי של השפה.",
+ "apihelp-query+langlinks-param-lang": "להחזיר רק קישורי שפה עם קוד השפה הזה.",
"apihelp-query+langlinks-param-title": "קישור לחיפוש. חובה להשתמש עם <var>$1lang</var>.",
+ "apihelp-query+langlinks-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+langlinks-param-inlanguagecode": "קוד שפה ששמות שפות מתורגמות.",
+ "apihelp-query+langlinks-example-simple": "קבלת קישורים בין־לשוניים מהדף <kbd>Main Page</kbd>.",
"apihelp-query+links-description": "החזרת כל הקישורים מהדפים שצוינו.",
+ "apihelp-query+links-param-namespace": "להציג קישורים רק במרחבי השם האלה.",
+ "apihelp-query+links-param-limit": "כמה קישורים להחזיר.",
+ "apihelp-query+links-param-titles": "לרשום רק קישורים לכותרות האלו. שימושי לבדיקה האם דף מסוים מקשר לכותרת מסוימת.",
+ "apihelp-query+links-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+links-example-simple": "קבלת קישורים מהדף <kbd>Main Page</kbd>",
+ "apihelp-query+links-example-generator": "קבלת מידע על דפי הקישור בדף <kbd>Main Page</kbd>.",
+ "apihelp-query+links-example-namespaces": "קבלת קישורים מהדף <kbd>Main Page</kbd> במרחבי השם {{ns:user}} ו־{{ns:template}}.",
+ "apihelp-query+linkshere-description": "מציאת כל הדפים שמקשרים לדפים הנתונים.",
+ "apihelp-query+linkshere-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+linkshere-paramvalue-prop-pageid": "מזהה הדף של כל דף.",
+ "apihelp-query+linkshere-paramvalue-prop-title": "השם של כל דף.",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "דגל אם הדף הוא הפניה.",
+ "apihelp-query+linkshere-param-namespace": "לכלול רק דפים במרחבי השם האלה.",
"apihelp-query+linkshere-param-limit": "כמה להחזיר.",
"apihelp-query+linkshere-param-show": "הצגת פריטים שתואמים את הדרישות הללו בלבד:\n;redirect:הצגת הפניות בלבד.\n;!redirect:הצגת קישורים שאינם הפניות בלבד.",
+ "apihelp-query+linkshere-example-simple": "קבלת רשימת דפים שמקשרים ל־[[Main Page]].",
+ "apihelp-query+linkshere-example-generator": "קבל מידע על דפים שמקשרים ל־[[Main Page]].",
"apihelp-query+logevents-description": "קבלת אירועים מהרישומים.",
+ "apihelp-query+logevents-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+logevents-paramvalue-prop-ids": "הוספת המזהה של אירוע היומן.",
+ "apihelp-query+logevents-paramvalue-prop-title": "הוספת שם הדף של אירוע היומן.",
+ "apihelp-query+logevents-paramvalue-prop-type": "הוספת הסוג של אירוע היומן.",
+ "apihelp-query+logevents-paramvalue-prop-user": "הוספת המשתמש האחראי על אירוע היומן.",
+ "apihelp-query+logevents-paramvalue-prop-userid": "הוספת מזהה המשתמש האחראי על אירוע היומן.",
+ "apihelp-query+logevents-paramvalue-prop-timestamp": "הוספת חותם־הזמן עבור האירוע.",
+ "apihelp-query+logevents-paramvalue-prop-comment": "הוספת ההערה של האירוע.",
+ "apihelp-query+logevents-paramvalue-prop-parsedcomment": "הוספת ההערה המפוענחת של האירוע.",
+ "apihelp-query+logevents-paramvalue-prop-details": "הוספת פרטים נוספים על האירוע.",
+ "apihelp-query+logevents-paramvalue-prop-tags": "רשימת התגים של האירוע.",
+ "apihelp-query+logevents-param-type": "סינון עיולי יומן רק לסוג הזה.",
+ "apihelp-query+logevents-param-action": "סינון פעולות יומן רק לפעולה הזאת. דורס את <var>$1type</var>. ברשימת הערכים האפשריים, ערכים עם תו־כל כוכבית כגון <kbd>action/*</kbd> יכולים להיות מחרוזות שונות אחרי הקו הנטוי (/).",
+ "apihelp-query+logevents-param-start": "מאיזה חותם־זמן להתחיל למנות.",
+ "apihelp-query+logevents-param-end": "באיזה חותם זמן להפסיק לרשום.",
+ "apihelp-query+logevents-param-user": "לסנן את העיולים שעשה המשתמש הנתון.",
+ "apihelp-query+logevents-param-title": "סינון עיולים רק לכאלה שמתייחסים לדף.",
+ "apihelp-query+logevents-param-namespace": "סינון עיולים רק לכאלה במרחב השם הנתון.",
+ "apihelp-query+logevents-param-prefix": "סינון עיולים לכאלה שמתחילים עם התחילית הזאת.",
+ "apihelp-query+logevents-param-tag": "לרשום רק אירועים שמתויגם בתג הזה.",
+ "apihelp-query+logevents-param-limit": "כמה עיולי אירועים להחזיר בסך הכול.",
+ "apihelp-query+logevents-example-simple": "רשימת אירועי יומן אחרונים.",
+ "apihelp-query+pagepropnames-description": "רשימת כל שמות המאפיינים שמשמשים בוויקי.",
+ "apihelp-query+pagepropnames-param-limit": "המספר המרבי של השמות להחזיר.",
+ "apihelp-query+pagepropnames-example-simple": "לתת את 10 שמות המאפיינים הראשונים.",
+ "apihelp-query+pageprops-description": "קבלת מאפיינים שונים בתוכן הדף.",
+ "apihelp-query+pageprops-param-prop": "לרשום רק את המאפיינים האלה. שימושי לבדיקה האם דף מסוים משתמש במאפיין דף מסוים.",
+ "apihelp-query+pageprops-example-simple": "קבלת מאפיינים עבור הדפים <kbd>Main Page</kbd> ו־<kbd>MediaWiki</kbd>.",
+ "apihelp-query+pageswithprop-description": "לרשום את כל הדפים שמשתמשים במאפיין דף נתון.",
+ "apihelp-query+pageswithprop-param-propname": "מאפיין דף שעבורו למנות דפים.",
+ "apihelp-query+pageswithprop-param-prop": "אילו חלקי מידע לכלול:",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "הוספת מזהה הדף.",
+ "apihelp-query+pageswithprop-paramvalue-prop-title": "הוספת השם ומזהה מרחב השם של הדף.",
+ "apihelp-query+pageswithprop-paramvalue-prop-value": "הוספת הערך של מאפיין הדף.",
+ "apihelp-query+pageswithprop-param-limit": "מספר הדפים המרבי שיוחזר.",
"apihelp-query+pageswithprop-param-dir": "באיזה כיוון לסדר.",
"apihelp-query+pageswithprop-example-simple": "הצגת עשרת הדפים הראשונים שעושים שימוש ב־<code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code>.",
- "apihelp-query+pageswithprop-example-generator": "קבלת פרטיהם של עשרת הדפים הראשונים המשתמשים ב־<code>_&#95;NOTOC_&#95;</code>.",
+ "apihelp-query+pageswithprop-example-generator": "קבלת מידע נוסף על עשרת הדפים הראשונים המשתמשים ב־<code>_&#95;NOTOC_&#95;</code>.",
+ "apihelp-query+prefixsearch-description": "ביצוע חיפוש תחילית של כותרות דפים.",
"apihelp-query+prefixsearch-param-search": "מחרוזת לחיפוש.",
+ "apihelp-query+prefixsearch-param-namespace": "שמות מתחם לחיפוש.",
"apihelp-query+prefixsearch-param-limit": "מספר התוצאות המרבי להחזרה.",
"apihelp-query+prefixsearch-param-offset": "מספר תוצאות לדילוג.",
+ "apihelp-query+prefixsearch-example-simple": "חיפוש שםות דפים שמתחילים ב־<kbd>meaning</kbd>.",
+ "apihelp-query+protectedtitles-description": "לרשום את כל הכותרות שמוגנות מפני יצירה.",
+ "apihelp-query+protectedtitles-param-namespace": "לרשום רק כותרות במרחבי השם האלה.",
+ "apihelp-query+protectedtitles-param-level": "לרשום רק שמות עם רמת ההגנה הזאת.",
+ "apihelp-query+protectedtitles-param-limit": "כמה דפים להחזיר בסך הכול.",
+ "apihelp-query+protectedtitles-param-start": "להתחיל לרשום בחותם־זמן ההגנה הזה.",
+ "apihelp-query+protectedtitles-param-end": "באיזה חותם־זמן הגנה לסיים את הרשימה.",
+ "apihelp-query+protectedtitles-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+protectedtitles-paramvalue-prop-timestamp": "הוספת חותם־הזמן של הוספת ההגנה.",
+ "apihelp-query+protectedtitles-paramvalue-prop-user": "הוספת המשתמש שהוסיף את ההגנה.",
+ "apihelp-query+protectedtitles-paramvalue-prop-userid": "הוספת מזהה המשתמש שהוסיף את ההגנה.",
+ "apihelp-query+protectedtitles-paramvalue-prop-comment": "הוספת ההערה עבור ההגנה.",
+ "apihelp-query+protectedtitles-paramvalue-prop-parsedcomment": "הוספת ההערה המפוענחת עבור ההגנה.",
+ "apihelp-query+protectedtitles-paramvalue-prop-expiry": "הוספת חותם־הזמן של הסרת ההגנה.",
+ "apihelp-query+protectedtitles-paramvalue-prop-level": "הוספת רמת ההגנה.",
+ "apihelp-query+protectedtitles-example-simple": "רשימת כותרות מוגנות.",
+ "apihelp-query+protectedtitles-example-generator": "חיפוש קישורים לכותרות מוגנות במרחב הראשי.",
+ "apihelp-query+querypage-description": "קבלת רשימה שמסופקת על־ידי דף מיוחד מבוסס־QueryPage.",
+ "apihelp-query+querypage-param-page": "שם הדף המיוחד. לתשומת לבך, זה תלוי־רישיות.",
"apihelp-query+querypage-param-limit": "מספר תוצאות להחזרה.",
- "apihelp-query+recentchanges-description": "מניית השינויים האחרונים.",
+ "apihelp-query+querypage-example-ancientpages": "מחזיר תוצאות מ־[[Special:Ancientpages]].",
+ "apihelp-query+random-description": "קבלת ערכת דפים אקראיים.\n\nהדפים רשומים בסדר קבוע, ורק נקודת ההתחלה אקראית. זה אומר שאם, למשל, <samp>Main Page</samp> הוא הדף האקראי הראשון הרשימה, <samp>List of fictional monkeys</samp> יהיה <em>תמיד</em> השני, <samp>List of people on stamps of Vanuatu</samp> שלישי, וכו'.",
+ "apihelp-query+random-param-namespace": "מחזיר דפים רק במרחבי השם האלה.",
+ "apihelp-query+random-param-limit": "להגביל את מספר הדפים האקראיים שיוחזרו.",
+ "apihelp-query+random-param-redirect": "נא להשתמש ב־<kbd>$1filterredir=redirects</kbd> במקום.",
+ "apihelp-query+random-param-filterredir": "איך לסנן הפניות.",
+ "apihelp-query+random-example-simple": "להחזיר שני דפים אקראיים מהמרחב הראשי.",
+ "apihelp-query+random-example-generator": "החזרת מידע על הדף על שני דפים אקראיים מהמרחב הראשי.",
+ "apihelp-query+recentchanges-description": "למנות שינויים אחרונים.",
+ "apihelp-query+recentchanges-param-start": "מאיזה חותם־זמן להתחיל למנות.",
+ "apihelp-query+recentchanges-param-end": "באיזה חותם זמן להפסיק לרשום.",
+ "apihelp-query+recentchanges-param-namespace": "לסנן את השינויים רק למרחבי השם האלה.",
+ "apihelp-query+recentchanges-param-user": "לרשום רק שינויים של המשתמש הזה.",
+ "apihelp-query+recentchanges-param-excludeuser": "Don't list changes by this user",
+ "apihelp-query+recentchanges-param-tag": "לרשום רק שינויים שמתויגים עם התג הזה.",
+ "apihelp-query+recentchanges-param-prop": "לכלול פריטי מידע נוספים:",
+ "apihelp-query+recentchanges-paramvalue-prop-user": "הוספת המשתמש האחראי על העריכה ותיוג אם זאת כתובת IP.",
+ "apihelp-query+recentchanges-paramvalue-prop-userid": "הוספת המשתמש האחראי על העריכה.",
+ "apihelp-query+recentchanges-paramvalue-prop-comment": "הוספת ההערה על העריכה.",
+ "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "הוספת ההערה המפוענחת על העריכה.",
+ "apihelp-query+recentchanges-paramvalue-prop-flags": "הוספת דגלים לעריכה.",
+ "apihelp-query+recentchanges-paramvalue-prop-timestamp": "הוספת חותם־זמן של העריכה.",
+ "apihelp-query+recentchanges-paramvalue-prop-title": "הוספת שם הדף של העריכה.",
+ "apihelp-query+recentchanges-paramvalue-prop-ids": "הוספת מזהה הדף, מזהה שינויים אחרונים, והמזהה הגרסה החדשה והישנה.",
+ "apihelp-query+recentchanges-paramvalue-prop-sizes": "הוספת אורך הדף החדש והישן בבתים.",
+ "apihelp-query+recentchanges-paramvalue-prop-redirect": "מתייג שהדף הוא הפניה.",
+ "apihelp-query+recentchanges-paramvalue-prop-patrolled": "מתייג עריכה בת־בדיקה בתור בדוקה או בלתי־בדוקה.",
+ "apihelp-query+recentchanges-paramvalue-prop-loginfo": "הוספת מידע יומן (זהה יומן, סוג יומן וכו') לעיולי יומן.",
+ "apihelp-query+recentchanges-paramvalue-prop-tags": "רשימת תגים עבור העיול.",
+ "apihelp-query+recentchanges-paramvalue-prop-sha1": "הוספת סיכום־ביקורת תוכן לעיולים שמשויכים לגרסה.",
+ "apihelp-query+recentchanges-param-token": "יש להשתמש ב־<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> במקום.",
+ "apihelp-query+recentchanges-param-show": "הצגה רק של פריטים שמתאימים לאמות המידה האלו. למשל, כדי לראות רק עריכות משניות שעשו משתמשים שנכנסו לחשבון, יש להגדיר $1show=minor|!anon.",
"apihelp-query+recentchanges-param-limit": "כמה שינויים להחזיר בסך הכול.",
"apihelp-query+recentchanges-param-type": "אילו סוגים של שינויים להציג.",
+ "apihelp-query+recentchanges-param-toponly": "לרשום רק שינויים שהם הגרסה האחרונה.",
"apihelp-query+recentchanges-example-simple": "הצגת השינויים האחרונים.",
+ "apihelp-query+recentchanges-example-generator": "קבלת מידע על הדף על שינויים אחרונים שלא נבדקו.",
+ "apihelp-query+redirects-description": "מחזיר את כל ההפניות לדפים הנתונים.",
+ "apihelp-query+redirects-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+redirects-paramvalue-prop-pageid": "מזהה הדף של כל הפניה.",
+ "apihelp-query+redirects-paramvalue-prop-title": "השם של כל הפניה.",
+ "apihelp-query+redirects-paramvalue-prop-fragment": "מובאה מכל הפניה, אם יש.",
+ "apihelp-query+redirects-param-namespace": "לכלול רק דפים במרחבי השם האלה.",
"apihelp-query+redirects-param-limit": "כמה הפניות להחזיר.",
+ "apihelp-query+redirects-param-show": "לחפש רק פריטים שמתאימים לאמות המידה הבאות:\n;fragment:להציג רק הפניות עם מקטע.\n;!fragment:להציג רק הפניות ללא מקטע.",
+ "apihelp-query+redirects-example-simple": "קבלת רשימת הפניות ל־[[Main Page]]",
+ "apihelp-query+redirects-example-generator": "קבלת מידע על כל ההפניות ל־[[Main Page]].",
+ "apihelp-query+revisions-description": "קבלת מידע על גרסה.\n\nיכול לשמש במספר דרכים:\n# קבלת נתונים על ערכת דפים (גרסה אחרונה), באמצעות כותרות או מזהי דף.\n# קבלת גרסאות עבור דף נתון אחד, באמצעות שימוש בכותרות או במזהי דף עם start‏, end או limit.\n# קבלת נתונים על ערכת גרסאות באמצעות הגדרת המזהים שלהם עם revid־ים.",
+ "apihelp-query+revisions-paraminfo-singlepageonly": "יכול לשמש רק עם דף בודד (mode #2).",
+ "apihelp-query+revisions-param-startid": "מאיזה מזהה גרסה להתחיל למנות.",
+ "apihelp-query+revisions-param-endid": "באיזה מזהה גרסה להפסיק את מניית הגרסאות.",
+ "apihelp-query+revisions-param-start": "מאיזה חותם־זמן של גרסה להתחיל למנות.",
+ "apihelp-query+revisions-param-end": "למנות עד חותם־הזמן הזה.",
+ "apihelp-query+revisions-param-user": "לכלול רק גרסאות מאת משתמש.",
+ "apihelp-query+revisions-param-excludeuser": "לא לכלול שינויים מאת משתמש.",
+ "apihelp-query+revisions-param-tag": "לרשום רק גרסאות עם התג הזה.",
+ "apihelp-query+revisions-param-token": "אילו אסימונים לקבל עבור כל גרסה.",
+ "apihelp-query+revisions-example-content": "קבל נתונים על תוכן עבור הגרסאות האחרונות של הכותרות <kbd>API</kbd> ו־<kbd>Main Page</kbd>.",
+ "apihelp-query+revisions-example-last5": "קבלת 5 הגרסאות האחרונות של <kbd>Main Page</kbd>.",
+ "apihelp-query+revisions-example-first5": "קבלת 5 הגרסאות הראשונות של <kbd>Main Page</kbd>.",
+ "apihelp-query+revisions-example-first5-after": "קבלת 5 הגרסאות הראשונות של <kbd>Main Page</kbd> שנעשו אחרי 2006-05-01.",
+ "apihelp-query+revisions-example-first5-not-localhost": "קבלת 5 הגרבאות הראשונות של <kbd>Main Page</kbd> שלא נעשו על־ידי המשתמש האלמוני <kbd>127.0.0.1</kbd>.",
+ "apihelp-query+revisions-example-first5-user": "קבלת 5 הגרסאות הראשונות של <kbd>Main Page</kbd> שנעשו על־ידי המשתמש <kbd>MediaWiki default</kbd>.",
+ "apihelp-query+revisions+base-param-prop": "אילו מאפיינים לקבל עבור כל גרסה:",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "מזהה הגרסה.",
+ "apihelp-query+revisions+base-paramvalue-prop-flags": "דגלי גרסה (משני).",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "חותם־הזמן של הגרסה.",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "המתמש שעשה את הגרסה",
+ "apihelp-query+revisions+base-paramvalue-prop-userid": "מזהה המשתמש של יוצר הגרסה.",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "אורך (בבתים) של הגרסה.",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "SHA-1 (בבסיס 16) של הגרסה.",
+ "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "מזהה מודל התוכן של הגרסה.",
+ "apihelp-query+revisions+base-paramvalue-prop-comment": "הערה מאת המשתמש על הגרסה.",
+ "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": "עץ פענוח XML של תוכן הגרסה (דורש מודל תוכן <code>$1</code>).",
"apihelp-query+revisions+base-param-limit": "הגבלת מספר הגרסאות שיוחזרו.",
+ "apihelp-query+revisions+base-param-expandtemplates": "להרחיב תבניות בתוכן הגרסה (דורש $1prop=content).",
+ "apihelp-query+revisions+base-param-generatexml": "יצירת עץ פענוח XML עבור תוכן הגרסה (דורש את $1prop=content; מוחלף ב־<kbd>$1prop=parsetree</kbd>).",
+ "apihelp-query+revisions+base-param-parse": "פענוח תוכן הגרסה (דורש $1prop=content). מסיבות של ביצועים, אם האפשרות הזאת משמשת, $1limit נכפה לערך 1.",
+ "apihelp-query+revisions+base-param-section": "לאחזר רק את התוכן של הפִסקה עם המספר הזה.",
+ "apihelp-query+revisions+base-param-diffto": "מזהה הגרסה שאליו תושווה כל גרסה. יש להשתמש ב־<kbd>prev</kbd>‏, <kbd>next</kbd> ו־<kbd>cur</kbd> עבור הגרסה הקודמת, הבא והנוכחית, בהתאמה.",
+ "apihelp-query+revisions+base-param-difftotext": "הטקסט שאליו תושווה כל גרסה. מבצע השוואה רק של מספר מוגבל של גרסאות. דורס את <var>$1diffto</var>. אם מוגדר <var>$1section</var>, רק הפסקה הזאת תושווה אל מול הטקסט הזה.",
+ "apihelp-query+revisions+base-param-contentformat": "תסדיר ההסדרה שמשמש את <var>$1difftotext</var> וצפוי לפלט של תוכן.",
+ "apihelp-query+search-description": "ביצוע חיפוש בכל הטקסט.",
+ "apihelp-query+search-param-search": "חיפוש שמות דפים או תוכן שמתאים לערך הזה. אפשר להשתמש בחיפוש מחרוזת כדי לקרוא לאפשרויות חיפוש מתקדמות, בהתאם למה שממומש בשרת החיפוש של הוויקי.",
+ "apihelp-query+search-param-namespace": "חיפוש רק במרחבי השם האלה.",
+ "apihelp-query+search-param-what": "איזה סוג חיפוש לבצע.",
+ "apihelp-query+search-param-info": "אילו מטא־נתונים להחזיר.",
+ "apihelp-query+search-param-prop": "אילו מאפיינים להחזיר:",
+ "apihelp-query+search-paramvalue-prop-size": "הוספת גודל הדף בבתים.",
+ "apihelp-query+search-paramvalue-prop-wordcount": "הוספת מניין המילים של הדף.",
+ "apihelp-query+search-paramvalue-prop-timestamp": "הוספת חותם־הזמן של העריכה האחרונה של הדף.",
+ "apihelp-query+search-paramvalue-prop-snippet": "הוספת קטע קצר מפוענח מהדף.",
+ "apihelp-query+search-paramvalue-prop-titlesnippet": "הוספת קטע קצר מפוענח משם הדף.",
+ "apihelp-query+search-paramvalue-prop-redirectsnippet": "הוספת קטע קצר מפוענח משם ההפניה.",
+ "apihelp-query+search-paramvalue-prop-redirecttitle": "הוספת שם ההפניה התואמת.",
+ "apihelp-query+search-paramvalue-prop-sectionsnippet": "הוספת קטע קצר מפוענח של שם הפסקה התואמת.",
+ "apihelp-query+search-paramvalue-prop-sectiontitle": "הוספת שם הפסקה התואמת.",
+ "apihelp-query+search-paramvalue-prop-categorysnippet": "הוספת קטע קצר מפוענח של הקטגוריה התואמת.",
+ "apihelp-query+search-paramvalue-prop-isfilematch": "הוספת בוליאני שמציין אם החיפוש תאם לתוכן של קובץ.",
+ "apihelp-query+search-paramvalue-prop-score": "<span class=\"apihelp-deprecated\">מיושן וחסר־השפעה.</span>",
+ "apihelp-query+search-paramvalue-prop-hasrelated": "<span class=\"apihelp-deprecated\">מיושן וחסר־השפעה.</span>",
+ "apihelp-query+search-param-limit": "כמה דפים להחזיר בסך הכול.",
+ "apihelp-query+search-param-interwiki": "לכלול תוצאות בינוויקי בחיפוש, אם זמין.",
+ "apihelp-query+search-param-backend": "באיזה שרת חיפוש להשתמש אם לא בבררת המחדל.",
+ "apihelp-query+search-param-enablerewrites": "הפעלת שכתוב שאילתות פנימי. שרתי חיפוש אחדים יכולים לשכתב את השאילתה לצורה שלדעתם נותנת תוצאות טובות יותר, למשל תיקון שגיאות כתיב.",
+ "apihelp-query+search-example-simple": "חיפוש <kbd>meaning</kbd>.",
+ "apihelp-query+search-example-text": "חיפוש טקסטים עבור <kbd>meaning</kbd>.",
+ "apihelp-query+search-example-generator": "קבלת מידע על הדף עבור שמוחזרים מחיפוש אחרי <kbd>meaning</kbd>.",
+ "apihelp-query+siteinfo-description": "החזרת מידע כללי על האתר.",
+ "apihelp-query+siteinfo-param-prop": "איזה מיד לקבל:",
+ "apihelp-query+siteinfo-paramvalue-prop-general": "מידע מערכת כללי.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespaces": "רשימת מרחבי שם רשומים והשמות הקנוניים שלהם.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespacealiases": "רשימת כינויי מרחבי שם רשומים.",
+ "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "רשימת כינויים דפים מיוחדים.",
+ "apihelp-query+siteinfo-paramvalue-prop-magicwords": "רשימות מילות קסם וכינוייהן.",
+ "apihelp-query+siteinfo-paramvalue-prop-statistics": "החזרזת סטטיסטיקות אתר.",
+ "apihelp-query+siteinfo-paramvalue-prop-interwikimap": "החזרת מפת בינוויקי (אפשר שתהיה מסוננת, אפשר שתהיה מותאמת מקומית באמצעות <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-dbrepllag": "החזרת שרת מסד־נתונים עם שיהוי השכפול הגבוה ביותר.",
+ "apihelp-query+siteinfo-paramvalue-prop-usergroups": "החזרת קבוצות משתמשים וההרשאות המשויכות.",
+ "apihelp-query+siteinfo-paramvalue-prop-libraries": "החזרת הספריות המותקנות בוויקי.",
+ "apihelp-query+siteinfo-paramvalue-prop-extensions": "החזרת ההרחבות המותקנות בוויקי.",
+ "apihelp-query+siteinfo-paramvalue-prop-fileextensions": "החזרת רשימת סיומות קבצים שאפשר להעלות.",
+ "apihelp-query+siteinfo-paramvalue-prop-rightsinfo": "החזרת הזכויות (הרישיון) של הוויקי, אם זמין.",
+ "apihelp-query+siteinfo-paramvalue-prop-restrictions": "החזרת מידע על ההגבלות (ההגנות) הזמינות.",
+ "apihelp-query+siteinfo-paramvalue-prop-languages": "החזרת השפות שמדיה־ויקי תומכת בהן (זה יכול להיות מותאם מקומים עם <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-skins": "החזרת רשימת כל העיצובים הזמינים (זה יכול להיות מותאם מקומית באמצעות <var>$1inlanguagecode</var>, אחרת זה יהיה בשפת התוכן).",
+ "apihelp-query+siteinfo-paramvalue-prop-extensiontags": "החזרת רשימת תגי הרחבת מפענח.",
+ "apihelp-query+siteinfo-paramvalue-prop-functionhooks": "החזרת hook־ים של הרחבות מפענח.",
+ "apihelp-query+siteinfo-paramvalue-prop-showhooks": "החזרת כל ה־hook־ים המנויים (תוכן של <var>[[mw:Manual:$wgHooks|$wgHooks]]</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-variables": "החזרת מזהי משתנים.",
+ "apihelp-query+siteinfo-paramvalue-prop-protocols": "החזרת רשימת הפרוטוקולים המותרים בקישורים חיצוניים.",
+ "apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "החזרת הערכים ההתחלתיים של העדפות משתמש.",
+ "apihelp-query+siteinfo-param-filteriw": "החזרה רק של עיולים מקומיים או רק של עיולים לא מקומיים ממפת הבינוויקי.",
+ "apihelp-query+siteinfo-param-showalldb": "רשימת כל שרתי מסד הנתונים, לא רק אלה שהכי מתעכבים.",
+ "apihelp-query+siteinfo-param-numberingroup": "רשימת מספרי משתמשים בקבוצות משתמשים.",
+ "apihelp-query+siteinfo-param-inlanguagecode": "קוד שפה ששמות שפות מתורגמות (מאמץ טוב ביותר) ושמות עיצובים.",
+ "apihelp-query+siteinfo-example-simple": "איזור מידע על האתר.",
+ "apihelp-query+siteinfo-example-interwiki": "אחזור תחיליות בינוויקי מקומיות.",
+ "apihelp-query+siteinfo-example-replag": "בדיקת שיהוי השכפול הנוכחי.",
+ "apihelp-query+stashimageinfo-description": "החזרת מידע על הקובץ עבור הקבצים המוסלקים.",
+ "apihelp-query+stashimageinfo-param-filekey": "מפתח שמזהה העלאה קודמת שהונחה בצד באופן זמני.",
+ "apihelp-query+stashimageinfo-param-sessionkey": "כינוי ל־$1filekey, לתאימות אחורה.",
+ "apihelp-query+stashimageinfo-example-simple": "החזרת מידע על קובץ מוסלק.",
+ "apihelp-query+stashimageinfo-example-params": "החזרת תמונות ממוזערות עבור שני קבצים מוסלקים.",
+ "apihelp-query+tags-description": "רשימת תגי שינוי.",
+ "apihelp-query+tags-param-limit": "המספר המרבי של תגים לרשום.",
+ "apihelp-query+tags-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+tags-paramvalue-prop-name": "הוספת שם התג.",
+ "apihelp-query+tags-paramvalue-prop-displayname": "הוספת הודעת המערכת עבור התג.",
+ "apihelp-query+tags-paramvalue-prop-description": "הוספת תיאור התג.",
+ "apihelp-query+tags-paramvalue-prop-hitcount": "הוספת מספר הגרסאות ועיולי היומן עם התג הזה.",
+ "apihelp-query+tags-paramvalue-prop-defined": "ציון האם התג מוגדר.",
+ "apihelp-query+tags-paramvalue-prop-source": "קבלת מקורות התג, שיכולים להיות <samp>extension</samp> עבור תגים שמגדירות הרחבות ו־<samp>manual</samp> עבור תגים שמשתמשים יכולים להחיל ידנית.",
+ "apihelp-query+tags-paramvalue-prop-active": "האם התג עדיין מוּחל.",
+ "apihelp-query+tags-example-simple": "רשימת תגים זמינים.",
+ "apihelp-query+templates-description": "החזרת כל הדפים המוכללים בדפים הנתונים.",
+ "apihelp-query+templates-param-namespace": "הצגת תבניות רק במרחב השם הזה.",
+ "apihelp-query+templates-param-limit": "כמה תבניות להחזיר.",
+ "apihelp-query+templates-param-templates": "לרשום רק את התבניות האלו. שימושי לבדיקה האם דף מסוים משתמש בתבנית מסוימת.",
+ "apihelp-query+templates-param-dir": "באיזה כיוון לרשום.",
+ "apihelp-query+templates-example-simple": "קבלת התבניות המשמשות בדף <kbd>Main Page</kbd>.",
+ "apihelp-query+templates-example-generator": "קבלת מידע על דפי התבנית שמשמשים ב־<kbd>Main Page</kbd>.",
+ "apihelp-query+templates-example-namespaces": "קבלת מידע במרחבי השם {{ns:user}} ו־{{ns:template}} שמוכללים בדף <kbd>Main Page</kbd>.",
+ "apihelp-query+tokens-description": "קבלת אסימונים לפעולות שמשנות נתונים.",
+ "apihelp-query+tokens-param-type": "סוגי האסימונים לבקש.",
+ "apihelp-query+tokens-example-simple": "אחזור אסימון csrf (בררת המחדל).",
"apihelp-query+tokens-example-types": "אחזור אסימון של רשימת המעקב ואסימון של ניטור",
+ "apihelp-query+transcludedin-description": "מציאת כל הדפים שמכלילים את הדפים הנתונים.",
+ "apihelp-query+transcludedin-param-prop": "אילו מאפיינים לקבל:",
+ "apihelp-query+transcludedin-paramvalue-prop-pageid": "מזהה הדף של כל דף.",
+ "apihelp-query+transcludedin-paramvalue-prop-title": "השם של כל דף.",
+ "apihelp-query+transcludedin-paramvalue-prop-redirect": "דגל אם הדף הוא הפניה.",
+ "apihelp-query+transcludedin-param-namespace": "לכלול רק דפים במרחבי השם האלה.",
+ "apihelp-query+transcludedin-param-limit": "כמה להחזיר.",
+ "apihelp-query+transcludedin-param-show": "לחפש רק פריטים שמתאימים לאמות המידה הבאות:\n;redirect:להציג רק הפניות.\n;!redirect:לא להציג הפניות.",
+ "apihelp-query+transcludedin-example-simple": "קבלת רשימה של דפים שמכלילים את <kbd>Main Page</kbd>.",
+ "apihelp-query+transcludedin-example-generator": "קבלת מידע על הדפים שמכלילים את <kbd>Main Page</kbd>.",
+ "apihelp-query+usercontribs-description": "קבלת כל העריכות של המשתמש.",
+ "apihelp-query+usercontribs-param-limit": "המספר המרבי של התרומות להחזיר.",
+ "apihelp-query+usercontribs-param-start": "באיזה חותם־הזמן להתחיל.",
+ "apihelp-query+usercontribs-param-end": "באיזה חותם־הזמן לסיים",
+ "apihelp-query+usercontribs-param-user": "עבור אילו משתמשים לאחזר תרומות.",
+ "apihelp-query+usercontribs-param-userprefix": "אחזור תרומות עבור כל המשתמשים שהשמות שלהם מתחילים בערך הזה. דורס את $1user.",
+ "apihelp-query+usercontribs-param-namespace": "לרשום רק תרומות במרחבי השם האלה.",
+ "apihelp-query+usercontribs-param-prop": "לכלול פריטי מידע נוספים:",
+ "apihelp-query+usercontribs-paramvalue-prop-ids": "הוספת מזהה הדף ומזהה הגרסה.",
+ "apihelp-query+usercontribs-paramvalue-prop-title": "הוספת השם ומזהה מרחב השם של הדף.",
+ "apihelp-query+usercontribs-paramvalue-prop-timestamp": "הוספת חותם־הזמן של העריכה.",
+ "apihelp-query+usercontribs-paramvalue-prop-comment": "הוספת ההערה על העריכה.",
+ "apihelp-query+usercontribs-paramvalue-prop-parsedcomment": "הוספת ההערה המפוענחת של העריכה.",
+ "apihelp-query+usercontribs-paramvalue-prop-size": "הוספת הגודל החדש של העריכה.",
+ "apihelp-query+usercontribs-paramvalue-prop-sizediff": "הוספת ההפרש של העריכה אל מול ההורה שלה.",
+ "apihelp-query+usercontribs-paramvalue-prop-flags": "הוספת הדגלים של העריכה.",
+ "apihelp-query+usercontribs-paramvalue-prop-patrolled": "מתייג עריכות בדוקות.",
+ "apihelp-query+usercontribs-paramvalue-prop-tags": "רשימת תגים עבור עריכות.",
+ "apihelp-query+usercontribs-param-show": "הצגה רק של פריטים שמתאימים לאמות המידה האלה, למשל רק עריכות לא־משניות.\n\nאם מוגדר <kbd>$2show=patrolled</kbd> או <kbd>$2show=!patrolled</kbd>, גרסאות ישנות מ־<var dir=\"ltr\">[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var>‏ ({{PLURAL:$1|שנייה אחת|$1 שניות}}) לא תוצגנה.",
+ "apihelp-query+usercontribs-param-tag": "לרשום רק גרסאות עם התג הזה.",
+ "apihelp-query+usercontribs-param-toponly": "לרשום רק שינויים שהם הגרסה האחרונה.",
+ "apihelp-query+usercontribs-example-user": "הצגת התרומות של המשתמש <kbd>Example</kbd>.",
+ "apihelp-query+usercontribs-example-ipprefix": "הצגת תרומות מכל כתובות ה־IP שמתחילות ב־<kbd dir=\"ltr\">192.0.2.</kbd>.",
+ "apihelp-query+userinfo-description": "קבלת מידע על המשתמש הנוכחי.",
+ "apihelp-query+userinfo-param-prop": "אילו חלקי מידע לכלול:",
+ "apihelp-query+userinfo-paramvalue-prop-blockinfo": "מתייג אם המשתמש הנוכחי נחסם, על־ידי מי ומאיזו סיבה.",
+ "apihelp-query+userinfo-paramvalue-prop-hasmsg": "הוספת התג <samp>messages</samp> אם למשתמש הנוכחי יש הודעות ממתינות.",
+ "apihelp-query+userinfo-paramvalue-prop-groups": "רשימת כל הקבוצות שהמשתמש שייך אליהן.",
+ "apihelp-query+userinfo-paramvalue-prop-implicitgroups": "רשימת כל הקבוצות שהמשתמש שייך אליהן באופן אוטומטי.",
+ "apihelp-query+userinfo-paramvalue-prop-rights": "רשימת כל ההרשאות שיש למשתמש הזה.",
+ "apihelp-query+userinfo-paramvalue-prop-changeablegroups": "רשימת הקבוצות שהמשתמש הנוכחי יכול להוסיף אליהן ולגרוע מהן.",
+ "apihelp-query+userinfo-paramvalue-prop-options": "רשימת כל ההעדפות שהמשתמש הנוכחי הגדיר.",
+ "apihelp-query+userinfo-paramvalue-prop-preferencestoken": "<span class=\"apihelp-deprecated\">מיושן.</span> קבלת אסימון לשינוי ההעדפות של המשתמש הנוכחי.",
+ "apihelp-query+userinfo-paramvalue-prop-editcount": "הוספת מניין העריכות של המשתמש הנוכחי.",
+ "apihelp-query+userinfo-paramvalue-prop-ratelimits": "רשימת כל מגבלות הקצב שחלות על המשתמש הנוכחי.",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "הוספת השם האמתי של המשתמש.",
+ "apihelp-query+userinfo-paramvalue-prop-email": "הוספת כתובת הדוא\"ל ותאריך אימות כתובת הדוא\"ל.",
+ "apihelp-query+userinfo-paramvalue-prop-acceptlang": "מדפיס את כותרת <code>Accept-Language</code> ששלח הלקוח בתסדיר מובנה.",
+ "apihelp-query+userinfo-paramvalue-prop-registrationdate": "הוספת תאריך הרישום של המשתמש.",
+ "apihelp-query+userinfo-paramvalue-prop-unreadcount": "הוספת מניין הדפים שלא נקראו ברשימת המעקב של המשתמש (לכל היותר $1; מחזיר <samp>$2</samp> אם יש יותר).",
+ "apihelp-query+userinfo-example-simple": "קבלת מידע על המשתמש הנוכחי.",
+ "apihelp-query+userinfo-example-data": "קבלת מידע נוסף על המשתמש הנוכחי.",
+ "apihelp-query+users-description": "קבלת מידע על רשימת משתמשים.",
+ "apihelp-query+users-param-prop": "אילו חלקי מידע לקבל:",
+ "apihelp-query+users-paramvalue-prop-blockinfo": "מתייג אם המשתמש חסום, על־ידי מי, ומאיזו סיבה.",
+ "apihelp-query+users-paramvalue-prop-groups": "רשימת כל הקבוצות שהמשתמש שייך אליהן.",
+ "apihelp-query+users-paramvalue-prop-implicitgroups": "רשימת כל הקבוצות שהמשתמש חבר בהן אוטומטית.",
+ "apihelp-query+users-paramvalue-prop-rights": "רשימת כל ההרשאות שיש למשתמש.",
+ "apihelp-query+users-paramvalue-prop-editcount": "הוספת מניין העריכות של המשתמש.",
+ "apihelp-query+users-paramvalue-prop-registration": "הוספת חותם־הזמן של רישום המשתמש.",
+ "apihelp-query+users-paramvalue-prop-emailable": "מתייג אם המשתמש יכול ורוצה לקבל דואר אלקטרוני דרך [[Special:Emailuser]].",
+ "apihelp-query+users-paramvalue-prop-gender": "מתייג את המגדר של המשתמש. מחזיר \"male\"‏, \"female\" או \"unknown\".",
+ "apihelp-query+users-param-users": "רשימת משתמשים שעליהם צריך לקבל מידע.",
+ "apihelp-query+users-param-token": "יש להשתמש ב־<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> במקום.",
+ "apihelp-query+users-example-simple": "החזרת מידע עבור המשתמש <kbd>Example</kbd>.",
+ "apihelp-query+watchlist-description": "קבלת שינויים אחרונים לדפים ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-query+watchlist-param-allrev": "לכלול גרסאות מרובות של אותו הדף בתוך מסגרת הזמן הנתונה.",
+ "apihelp-query+watchlist-param-start": "מאיזה חותם־זמן להתחיל למנות.",
+ "apihelp-query+watchlist-param-end": "באיזה חותם זמן להפסיק לרשום.",
+ "apihelp-query+watchlist-param-namespace": "סינון שינויים רק למרחבי השם שניתנו.",
+ "apihelp-query+watchlist-param-user": "לרשום רק שינויים של המשתמש הזה.",
+ "apihelp-query+watchlist-param-excludeuser": "Don't list changes by this user",
+ "apihelp-query+watchlist-param-limit": "כמה תוצאות סך הכול להחזיר בכל בקשה.",
+ "apihelp-query+watchlist-param-prop": "אילו מאפיינים נוספים לקבל:",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "הוספת מזהי גסה ומזהי דף.",
+ "apihelp-query+watchlist-paramvalue-prop-title": "הוספת שם הדף.",
+ "apihelp-query+watchlist-paramvalue-prop-flags": "הוספת דגלים לעריכה.",
+ "apihelp-query+watchlist-paramvalue-prop-user": "הוספת המשתמש שעשה את העריכה.",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "הוספת מזהה המשתמש של מי שעשה את העריכה.",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "הוספת ההערה של העריכה.",
+ "apihelp-query+watchlist-paramvalue-prop-parsedcomment": "הוספת ההערכה המפוענחת של העריכה.",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "הוספת חותם־זמן של העריכה.",
+ "apihelp-query+watchlist-paramvalue-prop-patrol": "תיוג עריכות שנבדקו.",
+ "apihelp-query+watchlist-paramvalue-prop-sizes": "הוספת האורך החדש והישן של הדף.",
+ "apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "הוספת חותם־זמן של ההודעה האחרונה למשתמש על העריכה.",
+ "apihelp-query+watchlist-paramvalue-prop-loginfo": "הוספת מידע מהיומן איפה שמתאים.",
+ "apihelp-query+watchlist-param-show": "הצגה רק של פריטים שמתאימים לאמות המידה האלו. למשל, כדי לראות רק עריכות משניות שעשו משתמשים שנכנסו לחשבון, יש להגדיר $1show=minor|!anon.",
+ "apihelp-query+watchlist-param-type": "אולי סוגי שינויים להציג:\n;edit:עריכות דף רגילות.\n;external:שינויים חיצוניים.\n;new:יצירות דף.\n;log:עיולי יומן.",
+ "apihelp-query+watchlist-param-owner": "משמש יחד עם $1token לגישה לרשימת מעקב של משתמש אחר.",
+ "apihelp-query+watchlist-param-token": "אסימון אבטחה (זמין ב־[[Special:Preferences#mw-prefsection-watchlist|העדפות]]) שמאפשר לגשת לרשימת מעקב של משתמש אחר.",
+ "apihelp-query+watchlist-example-simple": "לרשום את הגרסה האחרונה עבור דפים שהשתנו לאחרונה ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-query+watchlist-example-props": "אחזור מידע נוסף על הגרסה האחרונה עבור דפים שהשתנו לאחרונה ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-query+watchlist-example-allrev": "אחזור מידע על כל השינויים האחרונים לדפים ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-query+watchlist-example-generator": "אחזור מידע על הדף עבור דפים שהשתנו לאחרונה ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-query+watchlist-example-generator-rev": "אחזור מידע על הגרסה עבור דפים שהשתנו לאחרונה ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-query+watchlist-example-wlowner": "לרשום את הגרסה האחרונה עבור דפים שהשתנו לאחרונה ברשימת המעקב של משתמש <kbd>Example</kbd>.",
+ "apihelp-query+watchlistraw-description": "קבלת כל הדפים ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-query+watchlistraw-param-namespace": "לרשום רק דפים במרחב השם הנתון.",
+ "apihelp-query+watchlistraw-param-limit": "כמה תוצאות סך הכול להחזיר בכל בקשה.",
+ "apihelp-query+watchlistraw-param-prop": "אילו מאפיינים נוספים לקבל:",
+ "apihelp-query+watchlistraw-paramvalue-prop-changed": "הוספת חותם־הזמן של ההודעה האחרונה למשתמש על העריכה.",
+ "apihelp-query+watchlistraw-param-show": "לרשום רק פריטים שעונים על אמות המידה האלו.",
+ "apihelp-query+watchlistraw-param-owner": "משמש יחד עם $1token לגישה לרשימת מעקב של משתמש אחר.",
+ "apihelp-query+watchlistraw-param-token": "אסימון אבטחה (זמין ב־[[Special:Preferences#mw-prefsection-watchlist|העדפות]]) שמאפשר לגשת לרשימת מעקב של משתמש אחר.",
+ "apihelp-query+watchlistraw-param-fromtitle": "מאיזו כותרת (עם תחילית מרחב שם) להתחיל למנות.",
+ "apihelp-query+watchlistraw-param-totitle": "באיזו כותרת (עם תחילית מרחב שם) להפסיק למנות.",
+ "apihelp-query+watchlistraw-example-simple": "לרשום דפים ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-query+watchlistraw-example-generator": "אחזור מידע על הדפים עבור דפים ברשימת המעקב של המשתמש הנוכחי.",
+ "apihelp-revisiondelete-description": "מחיקה ושחזור ממחיקה של גרסאות.",
+ "apihelp-revisiondelete-param-type": "סוג מחיקת הגרסה שמתבצע.",
+ "apihelp-revisiondelete-param-target": "שם הדף למחיקת גרסה, אם זה נחוץ לסוג.",
+ "apihelp-revisiondelete-param-ids": "מזהים של הגרסה שתימחק.",
+ "apihelp-revisiondelete-param-hide": "מה להסתיר עבור כל גרסה.",
+ "apihelp-revisiondelete-param-show": "הסתרה של מה לבטל עבור כל גרסה.",
+ "apihelp-revisiondelete-param-suppress": "האם להעלים נתונים ממפעילים ומאחרים.",
+ "apihelp-revisiondelete-param-reason": "סיבה למחיקה או לשחזור ממחיקה.",
+ "apihelp-revisiondelete-example-revision": "הסתרת התוכן של הגרסה <kbd>12345</kbd> בדף <kbd>Main Page</kbd>.",
+ "apihelp-revisiondelete-example-log": "הסתרת כל הנתוהים על עיול היומן <kbd>67890</kbd> עם הסיבה <kbd>BLP violation</kbd>.",
+ "apihelp-rollback-description": "ביטול העריכה האחרונה לדף.\n\nאם המשמש האחרון שערך את הדף עשה מספר עריכות זו אחר זו, הן תשוחזרנה.",
+ "apihelp-rollback-param-title": "שם הדף לשחזור. לא יכול לשמש יחד עם <var>$1pageid</var>.",
+ "apihelp-rollback-param-pageid": "מזהה הדף לשחזור. לא יכול לשמש יחד עם <var>$1title</var>.",
+ "apihelp-rollback-param-user": "שם המשתמשים שהעריכות שלו תשוחזרנה.",
+ "apihelp-rollback-param-summary": "תקציר עריכה מותאם. אם ריק, ישמש תקציר לפי בררת מחדל.",
+ "apihelp-rollback-param-markbot": "לסמן את העריכות ששוחזרו ואת השחזור בתור עריכות בוט.",
+ "apihelp-rollback-param-watchlist": "הוספה או הסרה של הדף ללא תנאי מרשימת המעקב של המשתמש הנוכחי, להשתמש בהעדפות או לא לשנות את המעקב.",
+ "apihelp-rollback-example-simple": "שחזור העריכות האחרונות לדף <kbd>Main Page</kbd> על־ידי המשתמש <kbd>Example</kbd>.",
+ "apihelp-rollback-example-summary": "שחזור העריכות האחרונות לדף <kbd>Main Page</kbd> מאת משתמש ה־IP‏ <kbd>192.0.2.5</kbd> עם התקציר <kbd>Reverting vandalism</kbd> וסימון של העריכות האלה ושל השחזור בתור עריכות בוט.",
+ "apihelp-rsd-description": "יצוא סכמת RSD‏ (Really Simple Discovery).",
+ "apihelp-rsd-example-simple": "יצוא סכמת ה־RSD.",
+ "apihelp-setnotificationtimestamp-description": "עדכון חותם־הזמן של ההודעה עבור דפים במעקב.\n\nזה משפיע על הדגשת הדפים שהשתנו ברשימת המעקב ובהיסטוריה, ושליחת דואר אלקטרוני כאשר ההעדפה \"{{int:tog-enotifwatchlistpages}}\" מופעלת.",
+ "apihelp-setnotificationtimestamp-param-entirewatchlist": "לעבוד על כל הדפים שבמעקב.",
+ "apihelp-setnotificationtimestamp-param-timestamp": "חותם־הזמן להגדרת חותם־זמן של הודעה.",
+ "apihelp-setnotificationtimestamp-param-torevid": "לאיזו גרסה להגדיר את חותם הזמן (רק דף אחד).",
+ "apihelp-setnotificationtimestamp-param-newerthanrevid": "הגרסה שחותם־הזמן של ההודעה יוגדר בתור חדש ממנה (רק דף אחד).",
+ "apihelp-setnotificationtimestamp-example-all": "אתחול מצב ההודעה עבור כל רשימת המעקב.",
+ "apihelp-setnotificationtimestamp-example-page": "אתחול מצב ההודעה עבור <kbd>Main Page</kbd>.",
+ "apihelp-setnotificationtimestamp-example-pagetimestamp": "הגדרת חותם־הזמן להודעה ל־<kbd>Main page</kbd> כך שכל העריכות מאז 1 בינואר 2012 מוגדרות בתור כאלה שלא נצפו.",
+ "apihelp-setnotificationtimestamp-example-allpages": "אתחול מצב ההודעה עבור דפים במרחב השם <kbd>{{ns:user}}</kbd>.",
+ "apihelp-tag-description": "הוספת או הסרה של תגים מגרסאות בודדות או עיולי יומן בודדים.",
+ "apihelp-tag-param-rcid": "מזהה שינוי אחרון אחד או יותר שתג יתווסף אליו או יוסר ממנו.",
+ "apihelp-tag-param-revid": "מזהה גרסה אחד או יותר שתג יתווסף אליה או יוסר ממנה.",
+ "apihelp-tag-param-logid": "מזהה עיול יומן אחד או יותר שתג יתווסף אליו או יוסר ממנו.",
+ "apihelp-tag-param-add": "התגים להוספה. אפשר להוסיף רק תגים קיימים.",
+ "apihelp-tag-param-remove": "תגים להסרה. רק תגים שהוגדרו ידנית או שאינם מוגדרים כלל יכולים להיות מוסרים.",
+ "apihelp-tag-param-reason": "סיבה לשינוי.",
+ "apihelp-tag-example-rev": "הוספת התג <kbd>vandalism</kbd> לגרסה עם המזהה 123 בלי לציין סיבה",
+ "apihelp-tag-example-log": "הסרת התג <kbd>spam</kbd> מעיול עם המזהה 123 עם הסיבה <kbd>Wrongly applied</kbd>",
+ "apihelp-tokens-description": "קבלת אסימונים לפעולות שמשנות נתונים.\n\nהיחידה הזאת הוכרזה בתור מיושנת לטובת [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
+ "apihelp-tokens-param-type": "סוגי האסימונים לבקש.",
+ "apihelp-tokens-example-edit": "אחזור אסימון עריכה (בררת המחדל).",
+ "apihelp-tokens-example-emailmove": "אחזור אסימון דוא\"ל ואסימון העברה.",
+ "apihelp-unblock-description": "שחרור משתמש מחסימה.",
+ "apihelp-unblock-param-id": "מזהה החסימה לשחרור (מתקבל דרך <kbd>list=blocks</kbd>). לא יכול לשמש יחד עם <var>$1user</var>.",
+ "apihelp-unblock-param-user": "שם משתמש, כתובת IP או טווח IP לחסימה. לא יכול לשמש יחד עם <var>$1id</var>",
+ "apihelp-unblock-param-reason": "סיבה להסרת חסימה.",
+ "apihelp-unblock-example-id": "לשחרר את החסימה עם מזהה #<kbd>105</kbd>.",
+ "apihelp-unblock-example-user": "לשחרר את החסימה של המשתמש <kbd>Bob</kbd> עם הסיבה <kbd>Sorry Bob</kbd>.",
+ "apihelp-undelete-description": "שחזור גרסאות של דף מחוק.\n\nאפשר לאחזר רשימת גרסאות מחוקות (כולל חותמי־זמן) דרך [[Special:ApiHelp/query+deletedrevs|list=deletedrevs]], ואפשר לאחזר רשימת מזהי קבצים מחוקים דרך [[Special:ApiHelp/query+filearchive|list=filearchive]].",
+ "apihelp-undelete-param-title": "שם הדף לשחזור ממחיקה.",
+ "apihelp-undelete-param-reason": "סיבה לשחזור.",
+ "apihelp-undelete-param-timestamps": "חותמי־זמן של הגרסה לשחזור. אם גם <var>$1timestamps</var> וגם <var>$1fileids</var> ריקים, הכול ישוחזר.",
+ "apihelp-undelete-param-fileids": "מזהי גרסאות הקובץ לשחזור. אם גם <var>$1timestamps</var> וגם <var>$1fileids</var> ריקים, הכול ישוחזר.",
+ "apihelp-undelete-param-watchlist": "הוספה או הסרה של הדף ללא תנאי מרשימת המעקב של המשתמש הנוכחי, להשתמש בהעדפות או לא לשנות את המעקב.",
+ "apihelp-undelete-example-page": "שחזור ממחיקה של הדף <kbd>Main Page</kbd>.",
+ "apihelp-undelete-example-revisions": "שחזור שתי גרסאות של הדף <kbd>Main Page</kbd>.",
+ "apihelp-upload-description": "העלאת קובץ, או קבלת מצב ההעלאות הממתינות.\n\nיש מספר שיטות:\n* להעלות את הקובץ ישירות, באמצעות הפרמטר <var>$1file</var>.\n* להעלות את הקובץ בחלקים, באמצעות הפרמטרים <var>$1filesize</var>‏, <var>$1chunk</var> ו־<var>$1offset</var>.\n* לגרום לשרת מדיה־ויקי לאחזר את הקובץ מ־URL באמצעות הפרמטר <var>$1url</var>.\n* להשלים העלאה קודמת שנכשלה בשל אזהרות באמצעות הפרמטר <var>$1filekey</var>.\nלתשומך לבך, יש לעשות את HTTP POST בתור העלאת קובץ (כלומר באמצעות <code>multipart/form-data</code>) בעת שליחת ה־<var>$1file</var>.",
+ "apihelp-upload-param-filename": "שם קובץ היעד.",
+ "apihelp-upload-param-comment": "הערת העלאה. משמש גם בתור טקסט הדף ההתחלתי עבור קבצים חדשים אם <var>$1text</var> אינו מצוין.",
+ "apihelp-upload-param-text": "טקסט הדף ההתחלתי לקבצים חדשים.",
+ "apihelp-upload-param-watch": "לעקוב אחרי הדף.",
+ "apihelp-upload-param-watchlist": "הוספה או הסרה של הדף ללא תנאי מרשימת המעקב של המשתמש הנוכחי, להשתמש בהעדפות או לא לשנות את המעקב.",
+ "apihelp-upload-param-ignorewarnings": "להתעלם מכל האזהרות.",
+ "apihelp-upload-param-file": "תוכן הקובץ.",
+ "apihelp-upload-param-url": "URL לאחזור הקובץ.",
+ "apihelp-upload-param-filekey": "מפתח שמזהה העלאה קודמת שהונחה בצד באופן זמני.",
+ "apihelp-upload-param-sessionkey": "אותו דבר כמו $1filekey, מושאר לצור תאימות אחורה.",
+ "apihelp-upload-param-stash": "אם זה מוגדר, השרת יסליק את הקובץ זמנית במקום להוסיף אותו למאגר.",
+ "apihelp-upload-param-filesize": "גודל הקובץ של כל ההעלאה.",
+ "apihelp-upload-param-offset": "היסט החתיכה בבתים.",
+ "apihelp-upload-param-chunk": "תוכן החתיכה.",
+ "apihelp-upload-param-async": "להפוך פעולות קבצים גדולות לאסינכרוניות כשאפשר.",
+ "apihelp-upload-param-asyncdownload": "להפוך אחזור URL לאסינכרוני.",
+ "apihelp-upload-param-leavemessage": "אם משמש asyncdownload, להשאיר הודעה על דף שיחת משתמש אם זה מסתיים.",
+ "apihelp-upload-param-statuskey": "לאחזר את מצב העלאת הקובץ עבור מפתח הקובץ הזה (העלאה באמצעות URL).",
+ "apihelp-upload-param-checkstatus": "לאחזר רק מצב העלאה עבור מפתח הקובץ שניתן.",
+ "apihelp-upload-example-url": "להעלות מ־URL.",
+ "apihelp-upload-example-filekey": "להשלים העלאה שנכשלה בשל אזהרות.",
+ "apihelp-userrights-description": "שינוי חברות בקבוצות של המשתמש.",
+ "apihelp-userrights-param-user": "שם משתמש.",
+ "apihelp-userrights-param-userid": "מזהה משתמש.",
+ "apihelp-userrights-param-add": "הוספת המשתמש לקבוצות האלו.",
+ "apihelp-userrights-param-remove": "הסרת משתמש מהקבוצות האלו.",
+ "apihelp-userrights-param-reason": "סיבה לשינוי.",
+ "apihelp-userrights-example-user": "הוספת המשתמש <kbd>FooBot</kbd> לקבוצה <kbd>bot</kbd> והסרתו מהקבוצות <kbd>sysop</kbd> ו־<kbd>bureaucrat</kbd>.",
+ "apihelp-userrights-example-userid": "הוספת המשתמש עם המזהה <kbd>123</kbd> לקבוצה <kbd>bot</kbd> והסרתו מהקבוצות <kbd>sysop</kbd> ו־<kbd>bureaucrat</kbd>.",
+ "apihelp-watch-description": "להוסיף דפים לרשימת המעקב של המשתמש הנוכחי או הסרתם ממנה.",
+ "apihelp-watch-param-title": "הדף להוסיף לרשימת המעקב או להסיר ממנה. יש להשתמש במקום זאת ב־<var>$1titles</var>.",
+ "apihelp-watch-param-unwatch": "אם זה מוגדר, הדף יהיה לא במעקב במקום להיות במעקב.",
+ "apihelp-watch-example-watch": "לעקוב אחרי הדף <kbd>Main Page</kbd>.",
+ "apihelp-watch-example-unwatch": "להפסיק את המעקב אחרי הדף <kbd>Main Page</kbd>.",
+ "apihelp-watch-example-generator": "לעקוב אחרי הדפים הראשונים במרחב הראשי.",
+ "apihelp-format-example-generic": "להחזיר את תוצאות השאילתה בתסדיר $1.",
+ "apihelp-dbg-description": "לפלוט נתונים בתסדיר <code dir=\"ltr\">var_export()</code> של PHP.",
+ "apihelp-dbgfm-description": "לפלוט את הנתונים בתסדיר <code dir=\"ltr\">var_export()</code> של PHP (עם הדפסה יפה ב־HTML).",
+ "apihelp-json-description": "לפלוט נתונים בתסדיר JSON.",
+ "apihelp-json-param-callback": "אם זה צוין, עוטף את הפלט לתוך קריאת פונקציה נתונה. למען הבטיחות, כל הנתונים הייחודיים למשתמש יוגבלו.",
+ "apihelp-json-param-utf8": "אם זה צוין, רוב התווים שאינם ASCII (אבל לא כולם) יקודדו בתור UTF-8 במקום להתחלף בסדרות חילוף הקסדצימליות. זאת בררת המחדל אם הערך של <var>formatversion</var> הוא לא <kbd>1</kbd>.",
+ "apihelp-json-param-ascii": "אם זה צוין, לקודד את כל מה שאינו ASCII בסדרות חילוף הקסדצימליות. זאת בררת המחדל כש־<var>formatversion</var> היא <kbd>1</kbd>.",
+ "apihelp-json-param-formatversion": "תסדיר הפלט:\n;1:תסדיר עם תאימות אחורה (ערכים בוליאניים בסגנון XML, מפתחות <samp>*</samp> לצומתי תוכן, וכו').\n;2:תסדיר מודרני ניסיוני. הפרטים יכולים להשתנות!\n;latest:להשתמש בתסדיר החדש ביותר (כרגע <kbd>2</kbd>), יכול להשתנות ללא התראה.",
+ "apihelp-jsonfm-description": "לפלוט נתונים בתסדיר JSON (עם הדפסה יפה ב־HTML).",
+ "apihelp-none-description": "לא לפלוט שום דבר.",
+ "apihelp-php-description": "לפלוט נתונים בתסדיר PHP מוסדר.",
+ "apihelp-php-param-formatversion": "תסדיר הפלט:\n;1:תסדיר עם תאימות אחורה (ערכים בוליאניים בסגנון XML, מפתחות <samp>*</samp> לצומתי תוכן, וכו').\n;2:תסדיר מודרני ניסיוני. הפרטים יכולים להשתנות!\n;latest:להשתמש בתסדיר החדש ביותר (כרגע <kbd>2</kbd>), יכול להשתנות ללא התראה.",
+ "apihelp-phpfm-description": "לפלוט נתונים בתסדיר PHP מוסדר (עם הדפסה יפה ב־HTML).",
+ "apihelp-rawfm-description": "לפלוט את הנתונים עם אלמנטים לניפוי שגיאות בתסדיר JSON (עם הדפסה יפה ב־HTML).",
+ "apihelp-txt-description": "לפלוט נתונים בתסדיר <code dir=\"ltr\">print_r()</code> של PHP.",
+ "apihelp-txtfm-description": "לפלוט את הנתונים בתסדיר <code dir=\"ltr\">print_r()</code> של PHP (עם הדפסה יפה ב־HTML).",
+ "apihelp-xml-description": "לפלוט נתונים בתסדיר XML.",
"apihelp-xml-param-xslt": "אם צוין, יש להוסיף את שם הדף כגיליון עיצוב XSL. על הערך להיות כותרת ב {{ns:mediawiki}} במרחב שם המשתמש, המסתיים ב- <code>.xsl</code>.",
+ "apihelp-xml-param-includexmlnamespace": "אם זה צוין, מוסיף מרחב שם של XML.",
+ "apihelp-xmlfm-description": "לפלוט נתונים בתסדיר XML (עם הדפסה יפה ב־HTML).",
+ "apihelp-yaml-description": "לפלוט את הנתונים בתסדיר YAML.",
+ "apihelp-yamlfm-description": "לפלוט נתונים בתסדיר YAML (עם הדפסה יפה ב־HTML).",
"api-format-title": "תוצאה של API של מדיה־ויקי",
- "api-format-prettyprint-header": "זהו ייצוג ב־HTML של תסדיר $1. תסדיר HTML טוב לתיקון שגיאות, אבל אינו מתאים ליישומים.\n\nיש לציין את הפרמטר format כדי לשנות את תסדיר הפלט. כדי לראות ייצוג של תסדיר $1 לא ב־HTML יש לרשום format=$2.\n\nר' את [https://www.mediawiki.org/wiki/API התיעוד המלא], או את [[Special:ApiHelp/main|העזרה של API]] למידע נוסף.",
+ "api-format-prettyprint-header": "זהו ייצוג ב־HTML של תסדיר $1. תסדיר HTML טוב לתיקון שגיאות, אבל אינו מתאים ליישומים.\n\nיש לציין את הפרמטר <var>format</var> כדי לשנות את תסדיר הפלט. כדי לראות ייצוג של תסדיר $1 לא ב־HTML יש לרשום <kbd>format=$2</kbd>.\n\nר' את [[mw:API|התיעוד המלא]], או את [[Special:ApiHelp/main|העזרה של API]] למידע נוסף.",
+ "api-format-prettyprint-header-only-html": "זה ייצוג HTML שמיועד לניפוי שגיאות ואינו מתאים לשימוש ביישומים.\n\nר' את [[mw:API|התיעוד המלא]] או את [[Special:ApiHelp/main|העזרה של API]] למידע נוסף.",
"api-orm-param-props": "באילו שדות לעשות שאילתה.",
"api-orm-param-limit": "מספר מרבי של שורות להחזיר.",
"api-pageset-param-titles": "רשימת כותרות.",
- "api-pageset-param-pageids": "רשימת מזהי דף לעובד עליהם.",
+ "api-pageset-param-pageids": "רשימת מזהי דף לעבוד עליהם.",
"api-pageset-param-revids": "רשימת מזהי גרסה לעבוד עליהם.",
- "api-pageset-param-generator": "קבלת רשימת דפים לעבוד עליהם על־ידי הרצת יחידת שאילתה שצוינה.\n\n'''לתשומת לבך:''' לשמות בפרמטר generator צריכה להיות התחילית \"g\", ר' דוגמאות.",
- "api-pageset-param-redirects-generator": "פתרון אוטומטי של הפניות ב־$1titles, ב־$1pageids, וב־$1revids, ודפים שמחזיר $1generator.",
- "api-pageset-param-redirects-nogenerator": "פתרון אוטומטי של הפניות ב־$1titles, ב־$1pageids וב־$1revids.",
- "api-pageset-param-converttitles": "המרת כותרות לסוגי כתב אחרים אם זה נחוץ. זה עובד רק אם שפת הכותרת של הוויקי תומכת בהמרת סוגי כתב. השפות שתמכות בהמרת סוגי כתב הן $1.",
+ "api-pageset-param-generator": "קבלת רשימת דפים לעבוד עליהם על־ידי הרצת יחידת ה־query שצוינה.\n\n<strong>לתשומת לבך:</strong> לשמות בפרמטר generator צריכה להיות התחילית \"g\", ר' דוגמאות.",
+ "api-pageset-param-redirects-generator": "פתרון אוטומטי של הפניות ב־<var>$1titles</var>, ב־<var>$1pageids</var>, וב־<var>$1revids</var>, ובדפים שמחזיר <var>$1generator</var>.",
+ "api-pageset-param-redirects-nogenerator": "פתרון אוטומטי של הפניות ב־<var>$1titles</var>, ב־<var>$1pageids</var> וב־<var>$1pageids</var>.",
+ "api-pageset-param-converttitles": "המרת כותרות לסוגי כתב אחרים אם זה נחוץ. זה עובד רק אם שפת הכותרת של הוויקי תומכת בהמרת סוגי כתב. השפות שתומכות בהמרת סוגי כתב הן $1.",
"api-help-title": "עזרה של MediaWiki API",
"api-help-lead": "זהו דף תיעוד של API שנוצר באופן אוטומטי.\n\nתיעוד ודוגמאות: https://www.mediawiki.org/wiki/API",
"api-help-main-header": "יחידה ראשית",
"api-help-flag-deprecated": "יחידה זו אינה מומלצת לשימוש.",
- "api-help-flag-internal": "<strong>יחידה זו היא פנימית או לא יציבה.</strong>\nהפעולה שלה עשויה להשתנות ללא הודעה מוקדמת.",
+ "api-help-flag-internal": "<strong>היחידה הזאת היא פנימית או בלתי־יציבה.</strong> הפעולה שלה יכולה להשתנות ללא הודעה מוקדמת.",
"api-help-flag-readrights": "יחידה זו דורשת הרשאות קריאה.",
- "api-help-flag-writerights": "יחידה זו דורשת הרשאות כתיבה.",
+ "api-help-flag-writerights": "היחידה הזאת דורשת הרשאות כתיבה.",
"api-help-flag-mustbeposted": "יחידה זו מקבלת רק בקשות POST.",
- "api-help-flag-generator": "היחידה הזאת יכולה להיות מחולל.",
+ "api-help-flag-generator": "אפשר להשתמש ביחידה הזאת בתור מחולל.",
+ "api-help-source": "מקור: $1",
+ "api-help-source-unknown": "מקור: <span class=\"apihelp-unknown\">לא ידוע</span>",
+ "api-help-license": "רישיון: <span dir=\"auto\">[[$1|$2]]</span>",
+ "api-help-license-noname": "רישיון: [[$1|ראו קישור]]",
+ "api-help-license-unknown": "רישיון: <span class=\"apihelp-unknown\">לא ידוע</span>",
"api-help-parameters": "{{PLURAL:$1|פרמטר|פרמטרים}}:",
"api-help-param-deprecated": "מיושן.",
"api-help-param-required": "פרמטר זה נדרש.",
- "api-help-param-list": "{{PLURAL:$1|1=ערך אחד|2=ערכים (מופרדים באמצעות \"{{!}}\")}}: $2",
+ "api-help-datatypes-header": "סוגי נתונים",
+ "api-help-datatypes": "חלק מסוגי הפרמטרים בבקשות API דורשים הסבר נוסף:\n;בוליאני (boolean)\n:פרמטרים בוליאניים עובדים כמו תיבות סימון של HTML: אם הפרמטר צוין, בלי קשר לערך שלו, הוא אמת (true). בשביל ערך שקר (false), יש להשמיט את הפרמטר לגמרי.\n;חותם־זמן (timestamp)\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 dir=\"ltr\">+<var>##</var></kbd>, או <kbd dir=\"ltr\">-<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:* תסדיר C ctime‏, <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>",
+ "api-help-param-type-limit": "סוג: מספר שלם או <kbd>max</kbd>",
+ "api-help-param-type-integer": "סוג: {{PLURAL:$1|1=מספר שלם|2=רשימת מספרים שלמים}}",
+ "api-help-param-type-boolean": "סוג: בוליאני ([[Special:ApiHelp/main#main/datatypes|פרטים]])",
+ "api-help-param-type-timestamp": "סוג: {{PLURAL:$1|חותם־זמן|רשימת חותמי־זמן}} ([[Special:ApiHelp/main#main/datatypes|תסדירים מורשים]])",
+ "api-help-param-type-user": "סוג: {{PLURAL:$1|1=שם משתמש|2=רשימת שמות משתמשים}}",
+ "api-help-param-list": "{{PLURAL:$1|1=אחד מהערכים הבאים|2=ערכים (מופרדים באמצעות \"<kbd>{{!}}</kbd>\")}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=חייב להיות ריק|יכול להיות ריק או $2}}",
"api-help-param-limit": "מספר הפרמטרים לא יכול להיות גדול מ־$1.",
"api-help-param-limit2": "המספר המרבי המותר הוא $1 (עבור בוטים – $2).",
@@ -164,11 +1301,11 @@
"api-help-param-multi-max": "מספר הערכים המרבי הוא {{PLURAL:$1|$1}} (עבור בוטים – {{PLURAL:$2|$2}}).",
"api-help-param-default": "ברירת מחדל: $1",
"api-help-param-default-empty": "ברירת מחדל: <span class=\"apihelp-empty\">(ריק)</span>",
- "api-help-param-token": "אסימון \"$1\" אוחזר מ־[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]",
+ "api-help-param-token": "אסימון \"$1\" שאוחזר מ־[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]",
"api-help-param-token-webui": "לשם תאימות, גם האסימון שמשמש בממשק דפדפן מתקבל.",
- "api-help-param-disabled-in-miser-mode": "כבוי בשל [https://www.mediawiki.org/wiki/Manual:$wgMiserMode מצב חיסכון].",
- "api-help-param-limited-in-miser-mode": "'''לתשומת לבך:''' בשל [https://www.mediawiki.org/wiki/Manual:$wgMiserMode מצב חיסכון], שימוש בזה יכול להוביל לפחות מ־\"$1limit\" תוצאות לפני המשך; במצבים קיצוניים ייתכן שיחזרו אפס תוצאות.",
- "api-help-param-direction": "באיזה כיוון למספר:\n;newer:לרשום את הישנים ביותר בהתחלה. לתשומת לבך: $1start חייב להיות לפני $1end.\n;older:לרשום את החדשים ביותר בהתחלה (בררת מחדל). לתשומת לבך: $1start חייב להיות אחרי $1end.",
+ "api-help-param-disabled-in-miser-mode": "כבוי בשל [[mw:Manual:$wgMiserMode|מצב חיסכון]].",
+ "api-help-param-limited-in-miser-mode": "<strong>לתשומת לבך:</strong> בשל [[mw:Manual:$wgMiserMode|מצב חיסכון]], שימוש בזה יכול להוביל לפחות מ־<var>$1limit</var> תוצאות לפני המשך; במצבים קיצוניים ייתכן שיחזרו אפס תוצאות.",
+ "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-examples": "{{PLURAL:$1|דוגמה|דוגמאות}}:",
@@ -176,5 +1313,5 @@
"api-help-permissions-granted-to": "{{PLURAL:$1|הוענק ל|הוענקו ל}}: $2",
"api-help-right-apihighlimits": "להשתמש במגבלות גבוהות יותר בשאילתות API (שאילתות אטיות: $1; שאילתות מהירות: $2). המגבלות לשאילתות אטיות חלות גם על פרמטרים מרובי־ערכים.",
"api-credits-header": "קרדיטים",
- "api-credits": "מפתחי ה־API:\n* רואן קטאו (מפתח מוביל 2007–2009)\n* ויקטור וסילייב\n* בריאן טונג מין\n* סאם ריד\n* יורי אסטרחן (יוצר, מפתח מוביל מספטמבר 2006 עד ספטמבר 2007)\n* בראד יורש (מפתח מוביל מאז 2013)\n\nאנא שלחו הערות, הצעות ושאלות לכתובת mediawiki-api@lists.wikimedia.org או כתבו דיווח באג באתר https://bugzilla.wikimedia.org."
+ "api-credits": "מפתחי ה־API:\n* רואן קטאו (מפתח מוביל 2007–2009)\n* ויקטור וסילייב\n* בריאן טונג מין\n* סאם ריד\n* יורי אסטרחן (יוצר, מפתח מוביל מספטמבר 2006 עד ספטמבר 2007)\n* בראד יורש (מפתח מוביל מאז 2013)\n\nאנא שלחו הערות, הצעות ושאלות לכתובת mediawiki-api@lists.wikimedia.org או כתבו דיווח באג באתר https://phabricator.wikimedia.org."
}
diff --git a/includes/api/i18n/ht.json b/includes/api/i18n/ht.json
new file mode 100644
index 00000000..dee39e13
--- /dev/null
+++ b/includes/api/i18n/ht.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bfpage"
+ ]
+ },
+ "apihelp-query-param-rawcontinue": "Bay tounen done anvan tout koreksyon <samp>query-continue</samp> pou kontinyasyon"
+}
diff --git a/includes/api/i18n/hu.json b/includes/api/i18n/hu.json
index 516d8c77..7e6ecc41 100644
--- a/includes/api/i18n/hu.json
+++ b/includes/api/i18n/hu.json
@@ -2,15 +2,24 @@
"@metadata": {
"authors": [
"Csega",
- "Dorgan"
+ "Dorgan",
+ "Tacsipacsi",
+ "ViDam"
]
},
+ "apihelp-main-param-action": "Milyen műveletet hajtson végre.",
+ "apihelp-main-param-format": "A kimenet formátuma.",
+ "apihelp-main-param-requestid": "Az itt megadott bármilyen érték szerepelni fog a válaszban. Több kérés megkülönböztetésére használható.",
+ "apihelp-main-param-servedby": "Tartalmazza a válasz kérést kiszolgáló gép nevét.",
+ "apihelp-main-param-curtimestamp": "Tartalmazza a válasz az aktuális időbélyeget.",
"apihelp-block-description": "Szerkesztő blokkolása",
+ "apihelp-block-param-user": "Blokkolandó felhasználónév, IP-cím vagy IP-címtartomány.",
+ "apihelp-block-param-expiry": "Lejárat ideje. Lehet relatív (pl. <kbd>5 months</kbd>, <kbd>2 weeks</kbd>) vagy abszolút (pl. <kbd>2014-09-18T12:34:56Z</kbd>). Ha <kbd>infinite</kbd>-re, <kbd>indefinite</kbd>-re vagy <kbd>never</kbd>-re állítod, a blokk soha nem fog lejárni.",
"apihelp-block-param-reason": "Blokkolás oka.",
"apihelp-block-param-nocreate": "Új regisztráció megakadályozása",
"apihelp-createaccount-param-name": "Felhasználónév.",
"apihelp-delete-description": "Lap törlése.",
- "apihelp-delete-example-simple": "Kezdőlap törlése.",
+ "apihelp-delete-example-simple": "<kbd>Kezdőlap</kbd> törlése.",
"apihelp-edit-example-edit": "Lap szerkesztése",
"apihelp-expandtemplates-param-title": "Lap címe.",
"apihelp-userrights-param-userid": "Felhasználói azonosító."
diff --git a/includes/api/i18n/ia.json b/includes/api/i18n/ia.json
index de9d65fe..5201072d 100644
--- a/includes/api/i18n/ia.json
+++ b/includes/api/i18n/ia.json
@@ -23,6 +23,9 @@
"apihelp-block-param-nocreate": "Impedir le creation de contos.",
"apihelp-block-param-autoblock": "Blocar automaticamente le adresse IP usate le plus recentemente, e omne IPs successive desde le quales ille/-a tenta facer modificationes.",
"apihelp-block-param-noemail": "Impedir que le usator invia e-mail per le wiki. (Require le derecto \"blockemail\").",
+ "apihelp-checktoken-param-type": "Typo de indicio a testar.",
+ "apihelp-checktoken-param-token": "Indicio a testar.",
+ "apihelp-createaccount-param-name": "Nomine de usator.",
"apihelp-query+revisions-example-first5-not-localhost": "Obtener le prime 5 versiones del \"Pagina principal\" que non ha essite facite per le usator anonyme \"127.0.0.1\"",
"api-credits": "Programmatores del API:\n* Roan Kattouw (programmator dirigente Sept. 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (creator, programmator dirigente Sept. 2006–Sept. 2007)\n* Brad Jorsch (programmator dirigente 2013–presente)\n\nInvia tu commentos, suggestiones e questiones a mediawiki-api@lists.wikimedia.org\no insere un reportage de bug a https://phabricator.wikimedia.org/."
}
diff --git a/includes/api/i18n/is.json b/includes/api/i18n/is.json
new file mode 100644
index 00000000..956ace83
--- /dev/null
+++ b/includes/api/i18n/is.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sveinn í Felli"
+ ]
+ },
+ "api-help-license": "Notkunarleyfi: [[$1|$2]]",
+ "api-help-license-noname": "Notkunarleyfi: [[$1|Sjá tengil]]",
+ "api-help-license-unknown": "Notkunarleyfi: <span class=\"apihelp-unknown\">óþekkt</span>"
+}
diff --git a/includes/api/i18n/it.json b/includes/api/i18n/it.json
index 68f4e40a..5c4c55e5 100644
--- a/includes/api/i18n/it.json
+++ b/includes/api/i18n/it.json
@@ -3,7 +3,11 @@
"authors": [
"Beta16",
"Nivit",
- "Toadino2"
+ "Toadino2",
+ "Gianfranco",
+ "Alexmar983",
+ "Ricordisamoa",
+ "Valepert"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentazione (in inglese)]]\n* [[mw:API:FAQ|FAQ (in inglese)]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailing list]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annunci sull'API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bug & richieste]\n</div>\n<strong>Stato:</strong> Tutte le funzioni e caratteristiche mostrate su questa pagina dovrebbero funzionare, ma l'API è ancora in fase d'attivo sviluppo, e potrebbe cambiare in qualsiasi momenento. Iscriviti alla [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce mailing list] per essere informato sugli aggiornamenti.\n\n<strong>Istruzioni sbagliate:</strong> quando vengono impartite all'API delle istruzioni sbagliate, un'intestazione HTTP verrà inviata col messaggio \"MediaWiki-API-Error\" e sia al valore dell'intestazione sia al codice d'errore verrà impostato lo stesso valore. Per maggiori informazioni leggi [[mw:API:Errors_and_warnings|API:Errori ed avvertimenti (in inglese)]].",
@@ -11,18 +15,102 @@
"apihelp-main-param-format": "Formato dell'output.",
"apihelp-main-param-assert": "Verifica che l'utente sia loggato se si è impostato <kbd>utente</kbd>, o che abbia i permessi di bot se si è impostato <kbd>bot</kbd>.",
"apihelp-main-param-requestid": "Tutti i valori forniti saranno implementati nella risposta. Potrebbero venir utilizzati per distinguere le richieste.",
+ "apihelp-main-param-servedby": "Includi nei risultati il nome dell'host che ha servito la richiesta.",
+ "apihelp-main-param-curtimestamp": "Includere il timestamp corrente nel risultato.",
"apihelp-block-description": "Blocca un utente.",
+ "apihelp-block-param-user": "Nome utente, indirizzo IP o range di IP da bloccare.",
"apihelp-block-param-reason": "Motivo del blocco.",
+ "apihelp-block-param-nocreate": "Evitare la creazione di account.",
+ "apihelp-block-param-hidename": "Nascondi il nome utente dal registro dei blocchi (Richiede i permessi di <code>hideuser</code>).",
+ "apihelp-block-param-reblock": "Se l'utente è già bloccato, sovrascrivere il blocco esistente.",
+ "apihelp-block-param-watchuser": "Segui la pagina utente e le pagine di discussione utente dell'utente o dell'indirizzo IP.",
+ "apihelp-block-example-ip-simple": "Blocca l'indirizzo IP <kbd>192.0.2.5</kbd> per tre giorni con motivazione <kbd>Primo avvertimento</kbd>.",
+ "apihelp-block-example-user-complex": "Blocca l'utente <kbd>Vandalo</kbd> a tempo indeterminato con motivazione <kbd>Vandalismo</kbd>, e impediscigli la creazione di nuovi account e l'invio di e-mail.",
+ "apihelp-checktoken-description": "Verifica la validità di un token da <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
+ "apihelp-checktoken-param-type": "Tipo di token in corso di test.",
+ "apihelp-checktoken-param-token": "Token da testare.",
+ "apihelp-checktoken-param-maxtokenage": "Massima età consentita per il token, in secondi.",
+ "apihelp-checktoken-example-simple": "Verifica la validità di un token <kbd>csrf</kbd>.",
+ "apihelp-clearhasmsg-description": "Cancella il flag <code>hasmsg</code> per l'utente corrente.",
+ "apihelp-clearhasmsg-example-1": "Cancella il flag <code>hasmsg</code> per l'utente corrente.",
+ "apihelp-compare-description": "Trova la differenza tra 2 pagine.\n\nUn numero di revisione, il titolo di una pagina, o un ID di pagina deve essere indicato sia per il \"da\" che per lo \"a\".",
+ "apihelp-compare-param-fromtitle": "Primo titolo da confrontare.",
+ "apihelp-compare-param-fromid": "Primo ID di pagina da confrontare.",
+ "apihelp-compare-param-fromrev": "Prima revisione da confrontare.",
+ "apihelp-compare-param-totitle": "Primo titolo da confrontare.",
+ "apihelp-compare-param-toid": "Secondo ID di pagina da confrontare.",
+ "apihelp-compare-param-torev": "Seconda revisione da confrontare.",
+ "apihelp-compare-example-1": "Crea un diff tra revisione 1 e revisione 2.",
+ "apihelp-createaccount-description": "Crea un nuovo account utente.",
+ "apihelp-createaccount-param-name": "Nome Utente",
+ "apihelp-createaccount-param-password": "Password (verrà ignorata se è impostato <var>$1mailpassword</var>).",
+ "apihelp-createaccount-param-domain": "Dominio per l'autenticazione esterna (opzionale).",
+ "apihelp-createaccount-param-email": "Indirizzo Email dell'utente (opzionale).",
+ "apihelp-createaccount-param-realname": "Nome reale dell'utente (opzionale).",
+ "apihelp-createaccount-param-mailpassword": "Se impostato su un qualsiasi valore, una password random (casuale) verrà inviata all'utente.",
+ "apihelp-createaccount-param-reason": "Ragione, facoltativa, della creazione dell'account da inserire nei registri.",
+ "apihelp-createaccount-param-language": "Codice di lingua da impostare come predefinita per l'utente (opzionale, di default è la lingua del contenuto).",
+ "apihelp-createaccount-example-pass": "Crea l'utente <kbd>testuser</kbd> con password <kbd>test123</kbd>.",
+ "apihelp-createaccount-example-mail": "Crea l'utente <kbd>testmailuser</kbd> e mandagli via e-mail una password generata casualmente.",
+ "apihelp-delete-description": "Cancella una pagina.",
+ "apihelp-delete-param-title": "Titolo della pagina che si desidera eliminare. Non può essere usato insieme con <var>$1pageid</var>.",
+ "apihelp-delete-param-pageid": "ID di pagina della pagina da cancellare. Non può essere usato insieme con <var>$1title</var>.",
+ "apihelp-delete-param-reason": "Motivo della cancellazione. Se non indicato, verrà usata una motivazione generata automaticamente.",
+ "apihelp-delete-param-watch": "Aggiungi la pagina agli Osservati Speciali dell'utente corrente.",
+ "apihelp-delete-param-unwatch": "Rimuovi la pagina dagli Osservati Speciali dell'utente corrente.",
+ "apihelp-delete-example-simple": "Cancella la <kbd>Pagina Principale</kbd>.",
+ "apihelp-delete-example-reason": "Cancella la <kbd>Pagina Principale</kbd> con motivazione <kbd>Preparazione allo spostamento</kbd>.",
+ "apihelp-disabled-description": "Questo modulo è stato disabilitato.",
+ "apihelp-edit-description": "Crea e modifica pagine.",
+ "apihelp-edit-param-title": "Titolo della pagina da modificare. Non può essere usato insieme con <var>$1pageid</var>.",
+ "apihelp-edit-param-pageid": "ID di pagina della pagina da modificare. Non può essere usato insieme con <var>$1title</var>.",
+ "apihelp-edit-param-sectiontitle": "Il titolo per una nuova sezione.",
+ "apihelp-edit-param-text": "Contenuto della pagina.",
+ "apihelp-edit-param-summary": "Oggetto della modifica. Anche titolo della sezione se $1sezione=new e $1sectiontitle non è impostato.",
+ "apihelp-edit-param-tags": "Cambia i tag da applicare alla revisione.",
+ "apihelp-edit-param-minor": "Modifica minore.",
+ "apihelp-edit-param-notminor": "Modifica non minore.",
+ "apihelp-edit-param-bot": "Segna questa modifica come bot.",
+ "apihelp-edit-param-createonly": "Non modificare la pagina se già esiste.",
+ "apihelp-edit-param-nocreate": "Genera un errore se la pagina non esiste.",
+ "apihelp-edit-param-watch": "Aggiungi la pagina agli Osservati Speciali dell'utente corrente.",
+ "apihelp-edit-param-unwatch": "Rimuovi la pagina dagli Osservati Speciali dell'utente corrente.",
+ "apihelp-edit-example-edit": "Modifica una pagina.",
"apihelp-emailuser-description": "Manda un'e-mail ad un utente.",
"apihelp-emailuser-param-ccme": "Mandami una copia di questa mail.",
"apihelp-expandtemplates-description": "Espandi tutti i template nel wikitesto.",
"apihelp-expandtemplates-param-title": "Titolo della pagina.",
"apihelp-expandtemplates-param-text": "Wikitesto da convertire.",
+ "apihelp-expandtemplates-param-prop": "Quale informazione ottenere.\n\nNota che se non è selezionato alcun valore, il risultato conterrà il codice wiki, ma l'output sarà in un formato obsoleto.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "Il wikitext espanso.",
+ "apihelp-expandtemplates-paramvalue-prop-volatile": "Se l'output sia volatile e non debba essere riutilizzato altrove all'interno della pagina.",
+ "apihelp-feedcontributions-param-year": "Dall'anno (e precedenti).",
+ "apihelp-feedcontributions-param-month": "Dal mese (e precedenti).",
+ "apihelp-feedcontributions-param-deletedonly": "Mostra solo i contribuiti cancellati.",
+ "apihelp-feedcontributions-param-toponly": "Mostra solo i contributi che sono le ultime versioni per la pagina.",
+ "apihelp-feedcontributions-param-newonly": "Visualizza solo le modifiche che sono creazioni di pagina.",
+ "apihelp-feedrecentchanges-param-hideminor": "Nascondi le modifiche minori.",
+ "apihelp-feedrecentchanges-param-hidebots": "Nascondi le modifiche apportate da bot.",
+ "apihelp-feedrecentchanges-param-hideanons": "Nascondi le modifiche fatte da utenti anonimi.",
+ "apihelp-feedrecentchanges-param-hideliu": "Nascondi le modifiche apportate dagli utenti registrati.",
+ "apihelp-feedrecentchanges-param-showlinkedto": "Mostra solo le modifiche alle pagine collegate a quella specificata.",
+ "apihelp-login-param-name": "Nome utente.",
+ "apihelp-login-param-password": "Password.",
+ "apihelp-move-description": "Sposta una pagina.",
+ "apihelp-move-param-ignorewarnings": "Ignora i messaggi di avvertimento del sistema.",
+ "apihelp-options-example-reset": "Reimposta tutte le preferenze.",
+ "apihelp-query+blocks-example-simple": "Elenca i blocchi.",
"apihelp-query+recentchanges-example-simple": "Elenco modifiche recenti.",
+ "apihelp-unblock-description": "Sblocca un utente",
+ "apihelp-undelete-param-title": "Titolo della pagina da ripristinare.",
"apihelp-upload-example-url": "Carica da un URL.",
+ "api-help-main-header": "Modulo principale",
+ "api-help-license": "Licenza: [[$1|$2]]",
+ "api-help-license-unknown": "Licenza: <span class=\"apihelp-unknown\">sconosciuta</span>",
"api-help-parameters": "{{PLURAL:$1|Parametro|Parametri}}:",
"api-help-param-deprecated": "Deprecato.",
"api-help-param-required": "Questo parametro è obbligatorio.",
+ "api-help-param-multi-max": "Il numero massimo di valori è {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} per i bot).",
"api-help-param-default": "Predefinito: $1",
"api-help-param-default-empty": "Predefinito: <span class=\"apihelp-empty\">(vuoto)</span>",
"api-help-param-no-description": "<span class=\"apihelp-empty\">(nessuna descrizione)</span>",
diff --git a/includes/api/i18n/ja.json b/includes/api/i18n/ja.json
index 3940469a..bb403c6f 100644
--- a/includes/api/i18n/ja.json
+++ b/includes/api/i18n/ja.json
@@ -5,13 +5,15 @@
"2nd-player",
"Los688",
"Whym",
- "Mfuji"
+ "Mfuji",
+ "Otokoume",
+ "Sujiniku"
]
},
"apihelp-main-param-action": "実行する操作です。",
"apihelp-main-param-format": "出力する形式です。",
- "apihelp-main-param-smaxage": "<code>s-maxage</code> ヘッダーにこの秒数を設定します。エラーがキャッシュされることはありません。",
- "apihelp-main-param-maxage": "<code>max-age</code> ヘッダーにこの秒数を設定します。エラーがキャッシュされることはありません。",
+ "apihelp-main-param-smaxage": "<code>s-maxage</code> HTTP キャッシュ コントロール ヘッダー に、この秒数を設定します。エラーがキャッシュされることはありません。",
+ "apihelp-main-param-maxage": "<code>max-age</code> HTTP キャッシュ コントロール ヘッダー に、この秒数を設定します。エラーがキャッシュされることはありません。",
"apihelp-main-param-assert": "<kbd>user</kbd> を設定した場合は利用者がログイン済みかどうかを、<kbd>bot</kbd> を指定した場合はボット権限があるかどうかを、それぞれ検証します。",
"apihelp-main-param-requestid": "任意の値を指定でき、その値が結果に含められます。リクエストを識別するために使用できます。",
"apihelp-main-param-servedby": "リクエストを処理したホスト名を結果に含めます。",
@@ -19,6 +21,7 @@
"apihelp-main-param-uselang": "メッセージの翻訳に使用する言語です。コードの一覧は <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> に <kbd>siprop=languages</kbd> を付けることで取得できます。<kbd>user</kbd> を指定することで現在の利用者の個人設定の言語を、<kbd>content</kbd> を指定することでこのウィキの本文の言語を使用することもできます。",
"apihelp-block-description": "利用者をブロックします。",
"apihelp-block-param-user": "ブロックする利用者名、IPアドレスまたはIPレンジ。",
+ "apihelp-block-param-expiry": "有効期限。相対的 (例: <kbd>5 months</kbd> または <kbd>2 weeks</kbd>) または絶対的 (e.g. <kbd>2014-09-18T12:34:56Z</kbd>) どちらでも構いません。<kbd>infinite</kbd>, <kbd>indefinite</kbd>, もしくは <kbd>never</kbd> と設定した場合, 無期限ブロックとなります。",
"apihelp-block-param-reason": "ブロックの理由。",
"apihelp-block-param-anononly": "匿名利用者のみブロックします(つまり、このIPアドレスからの匿名での編集を不可能にします)。",
"apihelp-block-param-nocreate": "アカウントの作成を禁止します。",
@@ -29,13 +32,22 @@
"apihelp-block-param-watchuser": "その利用者またはIPアドレスの利用者ページとトークページをウォッチします。",
"apihelp-block-example-ip-simple": "IPアドレス <kbd>192.0.2.5</kbd> を <kbd>First strike<kbd> という理由で3日ブロックする",
"apihelp-block-example-user-complex": "利用者 <kbd>Vandal</kbd> を <kbd>Vandalism</kbd> という理由で無期限ブロックし、新たなアカウント作成とメールの送信を禁止する。",
+ "apihelp-checktoken-description": "<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> のトークンの妥当性を確認します。",
"apihelp-checktoken-param-type": "調べるトークンの種類。",
"apihelp-checktoken-param-token": "調べるトークン。",
"apihelp-checktoken-example-simple": "<kbd>csrf</kbd> トークンの妥当性を調べる。",
+ "apihelp-compare-description": "2つの版間の差分を取得します。\n\n\"from\" と \"to\" の両方の版番号、ページ名、もしくはページIDを渡す必要があります。",
+ "apihelp-compare-param-fromtitle": "比較する1つ目のページ名。",
+ "apihelp-compare-param-fromid": "比較する1つ目のページID。",
+ "apihelp-compare-param-fromrev": "比較する1つ目の版。",
+ "apihelp-compare-param-totitle": "比較する2つ目のページ名。",
+ "apihelp-compare-param-toid": "比較する2つ目のページID。",
+ "apihelp-compare-param-torev": "比較する2つ目の版。",
"apihelp-compare-example-1": "版1と2の差分を生成する。",
"apihelp-createaccount-description": "新しい利用者アカウントを作成します。",
"apihelp-createaccount-param-name": "利用者名。",
"apihelp-createaccount-param-password": "パスワード (<var>$1mailpassword</var> が設定されると無視されます)。",
+ "apihelp-createaccount-param-domain": "外部認証のドメイン (省略可能)。",
"apihelp-createaccount-param-token": "最初のリクエストで得られたアカウント作成用トークンです。",
"apihelp-createaccount-param-email": "利用者の電子メールアドレス (任意)。",
"apihelp-createaccount-param-realname": "利用者の本名 (省略可能)。",
@@ -49,6 +61,7 @@
"apihelp-delete-param-reason": "削除の理由です。入力しない場合、自動的に生成された理由が使用されます。",
"apihelp-delete-param-watch": "そのページを現在の利用者のウォッチリストに追加します。",
"apihelp-delete-param-unwatch": "そのページを現在の利用者のウォッチリストから除去します。",
+ "apihelp-delete-param-oldimage": "削除する古い画像の[[Special:ApiHelp/query+imageinfo|action=query&prop=imageinfo&iiprop=archivename]] で取得できるような名前。",
"apihelp-delete-example-simple": "<kbd>Main Page</kbd> を削除する",
"apihelp-delete-example-reason": "<kbd>Preparing for move</kbd> という理由で <kbd>Main Page</kbd> を削除する",
"apihelp-disabled-description": "このモジュールは無効化されています。",
@@ -58,34 +71,71 @@
"apihelp-edit-param-section": "節番号です。先頭の節の場合は <kbd>0</kbd>、新しい節の場合は <kbd>new</kbd>を指定します。",
"apihelp-edit-param-sectiontitle": "新しい節の名前です。",
"apihelp-edit-param-text": "ページの本文。",
+ "apihelp-edit-param-tags": "この版に適用する変更タグ。",
"apihelp-edit-param-minor": "細部の編集",
+ "apihelp-edit-param-notminor": "細部の編集ではない。",
+ "apihelp-edit-param-bot": "この編集をボットとしてマークする。",
+ "apihelp-edit-param-basetimestamp": "編集前の版のタイムスタンプ。編集競合を検出するために使用されます。\n[[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]] で取得できます。",
+ "apihelp-edit-param-starttimestamp": "編集作業を開始したときのタイムスタンプ。編集競合を検出するために使用されます。適切な値は <var>[[Special:ApiHelp/main|curtimestamp]]</var> を使用して編集作業を開始するとき (たとえば、編集するページの本文を読み込んだとき) に取得できます。",
"apihelp-edit-param-createonly": "すでにそのページが存在する場合は編集を行いません。",
"apihelp-edit-param-nocreate": "そのページが存在しない場合にエラーを返します。",
"apihelp-edit-param-watch": "そのページを現在の利用者のウォッチリストに追加します。",
"apihelp-edit-param-unwatch": "そのページを現在の利用者のウォッチリストから除去します。",
+ "apihelp-edit-param-prependtext": "このテキストをページの先頭に追加します。$1text をオーバーライドします。",
+ "apihelp-edit-param-appendtext": "このテキストをページの末尾に追加する。$1textを上書きします。\n\n新しい節を追加するにはこのパラメータではなく $1section=newを使用してください。",
+ "apihelp-edit-param-undo": "この版を取り消します。$1text, $1prependtext および $1appendtext をオーバーライドします。",
+ "apihelp-edit-param-undoafter": "$1undo からこの版までのすべての版を取り消します。設定しない場合、ひとつの版のみ取り消されます。",
+ "apihelp-edit-param-redirect": "自動的にリダイレクトを解決します。",
"apihelp-edit-param-token": "このトークンは常に最後のパラメーターとして、または少なくとも $1text パラメーターより後に送信されるべきです。",
"apihelp-edit-example-edit": "ページを編集",
+ "apihelp-edit-example-prepend": "<kbd>_&#95;NOTOC_&#95;</kbd> をページの先頭に挿入する。",
+ "apihelp-edit-example-undo": "版 13579 から 13585 まで要約を自動入力して取り消す。",
"apihelp-emailuser-description": "利用者に電子メールを送信します。",
"apihelp-emailuser-param-target": "送信先の利用者名。",
+ "apihelp-emailuser-param-subject": "題名。",
"apihelp-emailuser-param-text": "電子メールの本文。",
"apihelp-emailuser-param-ccme": "電子メールの複製を自分にも送信します。",
"apihelp-emailuser-example-email": "利用者 <kbd>WikiSysop</kbd> に <kbd>Content</kbd> という本文の電子メールを送信。",
"apihelp-expandtemplates-description": "ウィキテキストに含まれるすべてのテンプレートを展開します。",
"apihelp-expandtemplates-param-title": "ページの名前です。",
"apihelp-expandtemplates-param-text": "変換するウィキテキストです。",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "展開されたウィキテキスト。",
+ "apihelp-expandtemplates-param-includecomments": "HTMLコメントを出力に含めるかどうか。",
"apihelp-expandtemplates-example-simple": "ウィキテキスト <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd> を展開する。",
+ "apihelp-feedcontributions-description": "利用者の投稿記録フィードを返します。",
+ "apihelp-feedcontributions-param-feedformat": "フィードの形式。",
+ "apihelp-feedcontributions-param-user": "投稿記録を取得する利用者。",
+ "apihelp-feedcontributions-param-namespace": "この名前空間への投稿記録に絞り込む。",
+ "apihelp-feedcontributions-param-year": "この年以前。",
+ "apihelp-feedcontributions-param-month": "この月以前。",
+ "apihelp-feedcontributions-param-tagfilter": "このタグが付与された投稿記録に絞り込む。",
"apihelp-feedcontributions-param-deletedonly": "削除された投稿記録のみ表示します。",
"apihelp-feedcontributions-param-toponly": "最新版の編集のみ表示します。",
"apihelp-feedcontributions-param-newonly": "ページ作成を伴う編集のみを表示します。",
+ "apihelp-feedcontributions-param-showsizediff": "版間のサイズの増減を表示する。",
"apihelp-feedcontributions-example-simple": "利用者 <kbd>Example</kbd> の投稿記録を取得する。",
+ "apihelp-feedrecentchanges-description": "最近の更新フィードを返します。",
+ "apihelp-feedrecentchanges-param-feedformat": "フィードの形式。",
+ "apihelp-feedrecentchanges-param-namespace": "この名前空間の結果のみに絞り込む。",
"apihelp-feedrecentchanges-param-limit": "返す結果の最大数。",
+ "apihelp-feedrecentchanges-param-from": "これ以降の編集を表示する。",
"apihelp-feedrecentchanges-param-hideminor": "細部の変更を隠す。",
"apihelp-feedrecentchanges-param-hidebots": "ボットによる変更を隠す。",
"apihelp-feedrecentchanges-param-hideanons": "未登録利用者による変更を隠す。",
"apihelp-feedrecentchanges-param-hideliu": "登録利用者による変更を隠す。",
"apihelp-feedrecentchanges-param-hidepatrolled": "巡回済みの変更を隠す。",
+ "apihelp-feedrecentchanges-param-hidemyself": "現在の利用者による編集を非表示にする。",
+ "apihelp-feedrecentchanges-param-tagfilter": "タグにより絞り込む。",
+ "apihelp-feedrecentchanges-param-target": "このページからリンクされているページの変更のみを表示する。",
"apihelp-feedrecentchanges-example-simple": "最近の更新を表示する。",
"apihelp-feedrecentchanges-example-30days": "最近30日間の変更を表示する。",
+ "apihelp-feedwatchlist-description": "ウォッチリストのフィードを返します。",
+ "apihelp-feedwatchlist-param-feedformat": "フィードの形式。",
+ "apihelp-feedwatchlist-example-default": "ウォッチリストのフィードを表示する。",
+ "apihelp-feedwatchlist-example-all6hrs": "ウォッチ中のページに対する過去6時間の更新をすべて表示する。",
+ "apihelp-filerevert-description": "ファイルを古い版に差し戻します。",
+ "apihelp-filerevert-param-filename": "対象のファイル名 (File: 接頭辞を含めない)。",
+ "apihelp-filerevert-param-comment": "アップロードのコメント。",
"apihelp-filerevert-example-revert": "<kbd>Wiki.png</kbd> を <kbd>2011-03-05T15:27:40Z</kbd> の版に差し戻す。",
"apihelp-help-description": "指定したモジュールのヘルプを表示します。",
"apihelp-help-param-modules": "ヘルプを表示するモジュールです (<var>action</var> パラメーターおよび <var>format</var> パラメーターの値、または <kbd>main</kbd>)。<kbd>+</kbd> を使用して下位モジュールを指定できます。",
@@ -97,23 +147,34 @@
"apihelp-help-example-recursive": "すべてのヘルプを1つのページに",
"apihelp-help-example-help": "ヘルプ モジュール自身のヘルプ",
"apihelp-help-example-query": "2つの下位モジュールのヘルプ",
+ "apihelp-imagerotate-description": "1つ以上の画像を回転させます。",
"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-param-summary": "ページ取り込みの要約。",
"apihelp-import-param-xml": "XMLファイルをアップロード",
- "apihelp-import-param-rootpage": "このページの下位ページとしてインポートする。",
- "apihelp-import-example-import": "[[meta:Help:Parserfunctions]] をすべての履歴とともに名前空間100 にインポートする。",
+ "apihelp-import-param-interwikisource": "ウィキ間の取り込みの場合: 取り込み元のウィキ。",
+ "apihelp-import-param-interwikipage": "ウィキ間の取り込みの場合: 取り込むページ。",
+ "apihelp-import-param-fullhistory": "ウィキ間の取り込みの場合: 現在の版のみではなく完全な履歴を取り込む。",
+ "apihelp-import-param-templates": "ウィキ間の取り込みの場合: 読み込まれているテンプレートも取り込む。",
+ "apihelp-import-param-namespace": "この名前空間に取り込む。<var>$1rootpage</var>パラメータとは同時に使用できません。",
+ "apihelp-import-param-rootpage": "このページの下位ページとして取り込む。<var>$1namespace</var> パラメータとは同時に使用できません。",
+ "apihelp-import-example-import": "[[meta:Help:ParserFunctions]] をすべての履歴とともに名前空間100に取り込む。",
"apihelp-login-param-name": "利用者名。",
"apihelp-login-param-password": "パスワード。",
+ "apihelp-login-param-domain": "ドメイン (省略可能)",
"apihelp-login-param-token": "最初のリクエストで取得したログイントークンです。",
"apihelp-login-example-gettoken": "ログイントークンを取得する。",
"apihelp-login-example-login": "ログイン",
"apihelp-logout-description": "ログアウトしてセッションデータを消去します。",
"apihelp-logout-example-logout": "現在の利用者をログアウトする。",
+ "apihelp-managetags-example-create": "<kbd>spam</kbd> という名前のタグを <kbd>For use in edit patrolling</kbd> という理由で作成する",
+ "apihelp-managetags-example-delete": "<kbd>vandlaism</kbd> タグを <kbd>Misspelt</kbd> という理由で削除する",
+ "apihelp-managetags-example-activate": "<kbd>spam</kbd> という名前のタグを <kbd>For use in edit patrolling</kbd> という理由で有効化する",
"apihelp-move-description": "ページを移動します。",
"apihelp-move-param-from": "移動するページのページ名です。<var>$1fromid</var> とは同時に使用できません。",
"apihelp-move-param-fromid": "移動するページのページIDです。<var>$1from</var> とは同時に使用できません。",
"apihelp-move-param-to": "移動後のページ名。",
- "apihelp-move-param-reason": "名称変更の理由。",
+ "apihelp-move-param-reason": "改名の理由。",
"apihelp-move-param-movetalk": "存在する場合、トークページも名前を変更します。",
"apihelp-move-param-movesubpages": "可能であれば、下位ページも名前を変更します。",
"apihelp-move-param-noredirect": "転送ページを作成しません。",
@@ -121,49 +182,328 @@
"apihelp-move-param-unwatch": "そのページと転送ページを現在の利用者のウォッチリストから除去します。",
"apihelp-move-param-ignorewarnings": "あらゆる警告を無視",
"apihelp-move-example-move": "<kbd>Badtitle</kbd> を <kbd>Goodtitle</kbd> に転送ページを残さず移動",
+ "apihelp-opensearch-description": "OpenSearch プロトコルを使用してWiki内を検索します。",
"apihelp-opensearch-param-search": "検索文字列。",
"apihelp-opensearch-param-limit": "返す結果の最大数。",
"apihelp-opensearch-param-namespace": "検索する名前空間。",
"apihelp-opensearch-param-suggest": "<var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> が false の場合、何もしません。",
+ "apihelp-opensearch-param-format": "出力する形式。",
+ "apihelp-opensearch-example-te": "<kbd>Te</kbd> から始まるページを検索する。",
+ "apihelp-options-example-reset": "すべて初期設定に戻す。",
+ "apihelp-options-example-change": "<kbd>skin</kbd> および <kbd>hideminor</kbd> の個人設定を変更する。",
+ "apihelp-options-example-complex": "すべての個人設定を初期化し、<kbd>skin</kbd> および <kbd> nickname </kbd> を設定する。",
"apihelp-paraminfo-description": "API モジュールに関する情報を取得します。",
+ "apihelp-paraminfo-param-modules": "モジュールの名前のリスト (<var>action</var> および <var>format</var> パラメーターの値, または <kbd>main</kbd>). <kbd>+</kbd> を使用して下位モジュールを指定できます。",
+ "apihelp-paraminfo-example-1": "<kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>, <kbd>[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>, <kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd>, and <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> に関する情報を表示する。",
+ "apihelp-parse-param-disablepp": "<var>$1disablelimitreport</var> を代わりに使用してください。",
+ "apihelp-parse-param-preview": "プレビューモードでのパース",
+ "apihelp-parse-example-page": "ページをパース",
+ "apihelp-parse-example-text": "ウィキテキストをパース",
"apihelp-patrol-description": "ページまたは版を巡回済みにします。",
"apihelp-patrol-param-revid": "巡回済みにする版ID。",
"apihelp-patrol-example-rcid": "最近の更新を巡回",
+ "apihelp-patrol-example-revid": "版を巡回済みにする。",
"apihelp-protect-description": "ページの保護レベルを変更します。",
- "apihelp-protect-param-title": "保護(解除)するページ名です。$1pageid とは同時に指定できません。",
- "apihelp-protect-param-pageid": "保護(解除)するページIDです。$1title とは同時に指定できません。",
+ "apihelp-protect-param-title": "保護(解除)するページ名です。$1pageid とは同時に使用できません。",
+ "apihelp-protect-param-pageid": "保護(解除)するページIDです。$1title とは同時に使用できません。",
"apihelp-protect-param-expiry": "有効期限です。タイムスタンプがひとつだけ指定された場合は、それがすべての保護に適用されます。無期限の保護を行う場合は<kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd>, または <kbd>never</kbd> を指定します。",
"apihelp-protect-param-reason": "保護(解除)の理由。",
"apihelp-protect-param-watch": "指定されると、保護(解除)するページが現在の利用者のウォッチリストに追加されます。",
"apihelp-protect-example-protect": "ページを保護する。",
- "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "<var>$3user</var> と同時に指定できません。",
+ "apihelp-purge-example-simple": "ページ <kbd>Main Page</kbd> および <kbd>API</kbd> をパージする。",
+ "apihelp-purge-example-generator": "標準名前空間にある最初の10ページをパージする。",
+ "apihelp-query+allcategories-description": "すべてのカテゴリを一覧表示します。",
+ "apihelp-query+allcategories-param-from": "列挙を開始するカテゴリ。",
+ "apihelp-query+allcategories-param-to": "列挙を終了するカテゴリ。",
+ "apihelp-query+allcategories-param-prefix": "この値で始まるタイトルのカテゴリを検索します。",
+ "apihelp-query+allcategories-param-limit": "返すカテゴリの数。",
+ "apihelp-query+allcategories-example-generator": "<kbd>List</kbd> で始まるカテゴリページに関する情報を取得する。",
+ "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "<var>$3user</var> と同時に使用できません。",
+ "apihelp-query+alldeletedrevisions-param-start": "列挙の始点となるタイムスタンプ。",
+ "apihelp-query+alldeletedrevisions-param-end": "列挙の終点となるタイムスタンプ。",
+ "apihelp-query+alldeletedrevisions-param-from": "列挙の始点となるページ名。",
+ "apihelp-query+alldeletedrevisions-param-to": "列挙の終点となるページ名。",
+ "apihelp-query+alldeletedrevisions-param-prefix": "この値で始まるすべてのページ名を検索する。",
+ "apihelp-query+alldeletedrevisions-param-tag": "このタグが付与された版のみを一覧表示する。",
"apihelp-query+alldeletedrevisions-param-user": "この利用者による版のみを一覧表示する。",
"apihelp-query+alldeletedrevisions-param-excludeuser": "この利用者による版を一覧表示しない。",
"apihelp-query+alldeletedrevisions-param-namespace": "この名前空間に含まれるページのみを一覧表示します。",
+ "apihelp-query+alldeletedrevisions-param-generatetitles": "ジェネレーターとして使用する場合、版IDではなくページ名を生成します。",
+ "apihelp-query+alldeletedrevisions-example-user": "利用者 <kbd>Example</kbd> による削除された直近の50版を一覧表示する。",
"apihelp-query+alldeletedrevisions-example-ns-main": "標準名前空間にある削除された最初の50版を一覧表示する。",
+ "apihelp-query+allfileusages-param-from": "列挙を開始するファイルのタイトル。",
+ "apihelp-query+allfileusages-param-to": "列挙を終了するファイルのタイトル。",
+ "apihelp-query+allfileusages-param-prefix": "この値で始まるすべてのファイルのタイトルを検索する。",
+ "apihelp-query+allimages-param-from": "列挙の始点となる画像タイトル。$1sort=name を指定した場合のみ使用できます。",
+ "apihelp-query+allimages-param-to": "列挙の終点となる画像タイトル。$1sort=name を指定した場合のみ使用できます。",
+ "apihelp-query+allimages-param-start": "列挙の始点となるタイムスタンプ。$1sort=timestamp を指定した場合のみ使用できます。",
+ "apihelp-query+allimages-param-end": "列挙の終点となるタイムスタンプ。$1sort=timestamp を指定した場合のみ使用できます。",
+ "apihelp-query+allimages-param-prefix": "この値で始まるすべての画像タイトルを検索する。$1sort=name を指定した場合のみ使用できます。",
+ "apihelp-query+allimages-param-user": "この利用者によりアップロードされたファイルのみを返す。$1sort=timestamp を指定した場合のみ使用できます。 $1filterbots とは同時に使用できません。",
+ "apihelp-query+allimages-param-mime": "検索対象のMIMEタイプ、たとえば <kbd>image/jpeg</kbd>。",
+ "apihelp-query+allimages-param-limit": "返す画像の総数。",
+ "apihelp-query+allimages-example-B": "<kbd>B</kbd> で始まるファイルの一覧を表示する。",
+ "apihelp-query+allimages-example-recent": "[[Special:NewFiles]] のように、最近アップロードされたファイルの一覧を表示する。",
+ "apihelp-query+allimages-example-mimetypes": "MIMEタイプが <kbd>image/png</kbd> または <kbd>image/gif</kbd> であるファイルの一覧を表示する",
+ "apihelp-query+allimages-example-generator": "<kbd>T</kbd> で始まる4つのファイルに関する情報を表示する。",
+ "apihelp-query+alllinks-description": "与えられた名前空間へのすべてのリンクを一覧表示します。",
+ "apihelp-query+alllinks-param-from": "列挙を開始するリンクのタイトル。",
+ "apihelp-query+alllinks-param-to": "列挙を終了するリンクのページ名。",
+ "apihelp-query+alllinks-param-prefix": "この値で始まるすべてのリンクされたページを検索する。",
+ "apihelp-query+alllinks-example-B": "<kbd>B</kbd> で始まるリンクされたページ (存在しないページも含む)を、リンク元のページIDとともに表示する。",
+ "apihelp-query+allmessages-param-args": "メッセージ中に展開される引数。",
+ "apihelp-query+allmessages-param-filter": "この文字列を含んだ名前のメッセージのみを返す。",
+ "apihelp-query+allmessages-param-customised": "変更された状態のメッセージのみを返す。",
+ "apihelp-query+allmessages-param-lang": "返すメッセージの言語。",
+ "apihelp-query+allmessages-param-prefix": "この接頭辞を持つメッセージを返す。",
+ "apihelp-query+allmessages-example-ipb": "<kbd>ipb-</kbd> で始まるメッセージを表示する。",
+ "apihelp-query+allmessages-example-de": "ドイツ語のメッセージ <kbd>august</kbd> および <kbd>mainpage</kbd> を表示する。",
+ "apihelp-query+allpages-param-from": "列挙を開始するページ名。",
+ "apihelp-query+allpages-param-to": "列挙を終了するページ名。",
+ "apihelp-query+allpages-param-prefix": "この値で始まるすべてのページ名を検索します。",
+ "apihelp-query+allpages-param-prtype": "保護されているページに絞り込む。",
+ "apihelp-query+allpages-param-limit": "返すページの総数。",
+ "apihelp-query+allpages-example-B": "<kbd>B</kbd> で始まるページの一覧を表示する。",
+ "apihelp-query+allpages-example-generator": "<kbd>T</kbd> で始まる4つのページに関する情報を表示する。",
+ "apihelp-query+allpages-example-generator-revisions": "<kbd>Re</kbd> で始まる最初の非リダイレクトの2ページの内容を表示する。",
+ "apihelp-query+allredirects-param-from": "列挙を開始するリダイレクトのページ名。",
+ "apihelp-query+allredirects-param-to": "列挙を終了するリダイレクトのページ名。",
+ "apihelp-query+alltransclusions-param-prefix": "この値で始まるすべてのトランスクルードされているページを検索する。",
+ "apihelp-query+allusers-description": "すべての登録利用者を一覧表示します。",
+ "apihelp-query+allusers-param-from": "列挙を開始する利用者名。",
+ "apihelp-query+allusers-param-to": "列挙を終了する利用者名。",
+ "apihelp-query+allusers-param-prefix": "この値で始まるすべての利用者を検索する。",
+ "apihelp-query+allusers-param-group": "このグループに所属する利用者のみを結果に含める。",
+ "apihelp-query+allusers-param-excludegroup": "このグループに所属する利用者を結果から除外する。",
+ "apihelp-query+allusers-param-limit": "返す利用者名の総数。",
+ "apihelp-query+allusers-param-witheditsonly": "編集履歴のある利用者のみ一覧表示する。",
+ "apihelp-query+allusers-param-activeusers": "最近 $1 {{PLURAL:$1|日間}}のアクティブな利用者のみを一覧表示する。",
+ "apihelp-query+allusers-example-Y": "<kbd>Y</kbd> で始まる利用者を一覧表示する。",
+ "apihelp-query+backlinks-description": "与えられたページにリンクしているすべてのページを検索します。",
+ "apihelp-query+backlinks-param-title": "検索するページ名。<var>$1pageid</var> とは同時に使用できません。",
+ "apihelp-query+backlinks-param-pageid": "検索するページID。<var>$1title</var>とは同時に使用できません。",
+ "apihelp-query+backlinks-example-simple": "<kbd>Main page<kbd> へのリンクを表示する。",
+ "apihelp-query+backlinks-example-generator": "<kbd>Main page<kbd> にリンクしているページの情報を取得する。",
+ "apihelp-query+blocks-description": "ブロックされた利用者とIPアドレスを一覧表示します。",
+ "apihelp-query+blocks-param-start": "列挙の始点となるタイムスタンプ。",
+ "apihelp-query+blocks-param-end": "列挙の終点となるタイムスタンプ。",
+ "apihelp-query+blocks-param-ids": "一覧表示するブロックIDのリスト (任意)。",
+ "apihelp-query+blocks-param-users": "検索対象の利用者のリスト (任意)。",
+ "apihelp-query+blocks-param-limit": "一覧表示するブロックの最大数。",
+ "apihelp-query+blocks-example-simple": "ブロックを一覧表示する。",
+ "apihelp-query+blocks-example-users": "利用者<kbd>Alice</kbd> および <kbd>Bob</kbd> のブロックを一覧表示する。",
+ "apihelp-query+categories-param-limit": "返すカテゴリの数。",
+ "apihelp-query+categories-example-simple": "ページ <kbd>Albert Einstein</kbd> が属しているカテゴリの一覧を取得する。",
+ "apihelp-query+categories-example-generator": "ページ <kbd>Albert Einstein</kbd> で使われているすべてのカテゴリに関する情報を取得する。",
+ "apihelp-query+categoryinfo-description": "与えられたカテゴリに関する情報を返します。",
+ "apihelp-query+categoryinfo-example-simple": "<kbd>Category:Foo</kbd> および <kbd>Category:Bar</kbd> に関する情報を取得する。",
+ "apihelp-query+categorymembers-description": "与えられたカテゴリ内のすべてのページを一覧表示します。",
+ "apihelp-query+categorymembers-param-title": "一覧表示するカテゴリ (必須)。<kbd>{{ns:category}}:</kbd> 接頭辞を含まなければなりません。<var>$1pageid</var> とは同時に使用できません。",
+ "apihelp-query+categorymembers-param-pageid": "一覧表示するカテゴリのページID. <var>$1title</var> とは同時に使用できません。",
+ "apihelp-query+categorymembers-param-limit": "返すページの最大数。",
+ "apihelp-query+categorymembers-param-start": "列挙の始点となるタイムスタンプ。<kbd>$1sort=timestamp</kbd>を指定した場合のみ使用できます。",
+ "apihelp-query+categorymembers-param-end": "列挙の終点となるタイムスタンプ。<kbd>$1sort=timestamp</kbd>を指定した場合のみ使用できます。",
+ "apihelp-query+categorymembers-param-startsortkeyprefix": "列挙の始点となるソートキーの接頭辞。<kbd>$1sort=sortkey</kbd>を指定した場合のみ使用できます。<var>$1starthexsortkey</var>をオーバーライドします。",
+ "apihelp-query+categorymembers-param-startsortkey": "代わりに $1starthexsortkey を使用してください。",
+ "apihelp-query+categorymembers-param-endsortkey": "代わりに $1endhexsortkey を使用してください。",
"apihelp-query+categorymembers-example-simple": "<kbd>Category:Physics</kbd> に含まれる最初の10ページを取得する。",
"apihelp-query+categorymembers-example-generator": "<kbd>Category:Physics</kbd> に含まれる最初の10ページのページ情報を取得する。",
+ "apihelp-query+contributors-description": "ページへのログインした投稿者の一覧と匿名投稿者の数を取得します。",
+ "apihelp-query+contributors-param-limit": "返す投稿者の数。",
"apihelp-query+contributors-example-simple": "<kbd>Main Page</kbd> への投稿者を表示する。",
+ "apihelp-query+deletedrevisions-param-tag": "このタグが付与された版のみ表示します。",
"apihelp-query+deletedrevisions-param-user": "この利用者による版のみを一覧表示。",
"apihelp-query+deletedrevisions-param-excludeuser": "この利用者による版を一覧表示しない。",
- "apihelp-query+deletedrevisions-param-limit": "一覧表示する版の最大数。",
"apihelp-query+deletedrevisions-example-titles": "ページ <kbd>Main Page</kbd> および <kbd>Talk:Main Page</kbd> の削除された版とその内容を一覧表示する。",
"apihelp-query+deletedrevisions-example-revids": "削除された版 <kbd>123456</kbd> に関する情報を一覧表示する。",
+ "apihelp-query+deletedrevs-param-from": "列挙の始点となるページ名。",
+ "apihelp-query+deletedrevs-param-to": "列挙の終点となるページ名。",
+ "apihelp-query+disabled-description": "このクエリ モジュールは無効化されています。",
+ "apihelp-query+embeddedin-param-title": "検索するページ名。$1pageid とは同時に使用できません。",
+ "apihelp-query+embeddedin-param-pageid": "検索するページID. $1titleとは同時に使用できません。",
+ "apihelp-query+embeddedin-example-generator": "<kbd>Template:Stub</kbd> をトランスクルードしているページに関する情報を取得する。",
+ "apihelp-query+extlinks-description": "与えられたページにあるすべての外部URL (インターウィキを除く) を返します。",
+ "apihelp-query+extlinks-param-limit": "返すリンクの数。",
+ "apihelp-query+extlinks-param-protocol": "URLのプロトコル。このパラメータが空であり、かつ<var>$1query</var> が設定されている場合, protocol は <kbd>http</kbd> となります。すべての外部リンクを一覧表示するためにはこのパラメータと <var>$1query</var> の両方を空にしてください。",
+ "apihelp-query+extlinks-example-simple": "<kbd>Main Page<kbd> の外部リンクの一覧を取得する。",
+ "apihelp-query+exturlusage-description": "与えられたURLを含むページを一覧表示します。",
+ "apihelp-query+exturlusage-example-simple": "<kbd>http://www.mediawiki.org</kbd> にリンクしているページを一覧表示する。",
+ "apihelp-query+filearchive-example-simple": "削除されたファイルの一覧を表示する。",
+ "apihelp-query+fileusage-example-simple": "[[:File:Example.jpg]] を使用しているページの一覧を取得する。",
+ "apihelp-query+fileusage-example-generator": "[[:File:Example.jpg]] を使用しているページの情報を取得する。",
+ "apihelp-query+imageinfo-param-start": "一覧表示の始点となるタイムスタンプ。",
+ "apihelp-query+imageinfo-param-end": "一覧表示の終点となるタイムスタンプ。",
+ "apihelp-query+images-description": "与えられたページに含まれるすべてのファイルを返します。",
+ "apihelp-query+images-param-limit": "返す画像の数。",
+ "apihelp-query+images-example-simple": "[[Main Page]] で使用されているファイルの一覧を取得する。",
+ "apihelp-query+images-example-generator": "[[Main Page]] で使用されているファイルに関する情報を取得する。",
+ "apihelp-query+imageusage-param-title": "検索するページ名。$1pageid とは同時に使用できません。",
+ "apihelp-query+imageusage-param-pageid": "検索するページID. $1titleとは同時に使用できません。",
+ "apihelp-query+imageusage-example-simple": "[[:File:Albert Einstein Head.jpg]] を使用しているページを表示する。",
+ "apihelp-query+imageusage-example-generator": "[[:File:Albert Einstein Head.jpg]] を使用しているページに関する情報を取得する。",
"apihelp-query+info-description": "ページの基本的な情報を取得します。",
"apihelp-query+info-paramvalue-prop-protection": "それぞれのページの保護レベルを一覧表示する。",
"apihelp-query+info-example-simple": "<kbd>Main Page</kbd> に関する情報を取得する。",
"apihelp-query+iwbacklinks-example-simple": "[[wikibooks:Test]] へリンクしているページを取得する。",
"apihelp-query+iwbacklinks-example-generator": "[[wikibooks:Test]] へリンクしているページの情報を取得する。",
+ "apihelp-query+iwlinks-param-limit": "返すウィキ間リンクの数。",
+ "apihelp-query+iwlinks-param-prefix": "この接頭辞のウィキ間リンクのみを返す。",
+ "apihelp-query+iwlinks-param-title": "検索するウィキ間リンク。<var>$1</var> と同時に使用しなければなりません。",
+ "apihelp-query+iwlinks-example-simple": "<kbd>Main Page</kbd> にあるウィキ間リンクを取得する。",
+ "apihelp-query+langbacklinks-param-lang": "言語間リンクの言語。",
+ "apihelp-query+langbacklinks-param-title": "検索する言語間リンク。$1lang と同時に使用しなければなりません。",
+ "apihelp-query+langbacklinks-param-limit": "返すページの総数。",
"apihelp-query+langbacklinks-example-simple": "[[:fr:Test]] へリンクしているページを取得する。",
"apihelp-query+langbacklinks-example-generator": "[[:fr:Test]] へリンクしているページの情報を取得する。",
- "apihelp-format-example-generic": "クエリの結果を $1 形式に整形します",
+ "apihelp-query+langlinks-param-limit": "返す言語間リンクの数。",
+ "apihelp-query+langlinks-param-url": "完全なURLを取得するかどうか (<var>$1prop</var>とは同時に使用できません).",
+ "apihelp-query+langlinks-param-lang": "この言語コードの言語間リンクのみを返す。",
+ "apihelp-query+langlinks-param-title": "検索するリンク。<var>$1lang</var>と同時に使用しなければなりません。",
+ "apihelp-query+langlinks-example-simple": "<kbd>Main Page</kbd> にある言語間リンクを取得する。",
+ "apihelp-query+links-description": "ページからのすべてのリンクを返します。",
+ "apihelp-query+links-param-namespace": "この名前空間へのリンクのみ表示する。",
+ "apihelp-query+links-param-limit": "返すリンクの数。",
+ "apihelp-query+links-example-simple": "<kbd>Main Page</kbd> からのリンクを取得する。",
+ "apihelp-query+links-example-generator": "<kbd>Main Page</kbd> からリンクされているページに関する情報を取得する。",
+ "apihelp-query+links-example-namespaces": "<kbd>Main Page</kbd> からの {{ns:user}} および {{ns:template}} 名前空間へのリンクを取得する。",
+ "apihelp-query+linkshere-example-simple": "[[Main Page]] にリンクしているページの一覧を取得する。",
+ "apihelp-query+linkshere-example-generator": "<kbd>[[Main Page]]<kbd> にリンクしているページの情報を取得する。",
+ "apihelp-query+logevents-param-start": "列挙の始点となるタイムスタンプ。",
+ "apihelp-query+logevents-param-end": "列挙の終点となるタイムスタンプ。",
+ "apihelp-query+logevents-param-user": "与えられた利用者による記録項目に絞り込む。",
+ "apihelp-query+logevents-param-title": "そのページに関連する記録項目に絞り込む。",
+ "apihelp-query+logevents-param-namespace": "与えられた名前空間内の記録項目に絞り込む。",
+ "apihelp-query+logevents-param-prefix": "この接頭辞ではじまる記録項目に絞り込む。",
+ "apihelp-query+logevents-param-tag": "このタグが付与された記録項目のみ表示する。",
+ "apihelp-query+logevents-param-limit": "返す記録項目の総数。",
+ "apihelp-query+logevents-example-simple": "最近の記録項目を一覧表示する。",
+ "apihelp-query+pagepropnames-description": "Wiki内で使用されているすべてのページプロパティ名を一覧表示します。",
+ "apihelp-query+pagepropnames-param-limit": "返す名前の最大数。",
+ "apihelp-query+pagepropnames-example-simple": "最初の10個のプロパティ名を取得する。",
+ "apihelp-query+pageprops-example-simple": "ページ <kbd>Main Page</kbd> および <kbd>MeiaWiki</kbd> のプロパティを取得する。",
+ "apihelp-query+pageswithprop-description": "与えられたページプロパティが使用されているすべてのページを一覧表示します。",
+ "apihelp-query+pageswithprop-param-limit": "返すページの最大数。",
+ "apihelp-query+pageswithprop-example-simple": "<code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code> を使用している最初の10ページを一覧表示する。",
+ "apihelp-query+pageswithprop-example-generator": "<code>_&#95;NOTOC_&#95;</code> を使用している最初の10ページについての追加情報を取得する。",
+ "apihelp-query+prefixsearch-description": "ページ名の先頭一致検索を行います。",
+ "apihelp-query+prefixsearch-param-search": "検索文字列。",
+ "apihelp-query+prefixsearch-param-namespace": "検索する名前空間。",
+ "apihelp-query+prefixsearch-param-limit": "返す結果の最大数。",
+ "apihelp-query+prefixsearch-example-simple": "<kbd>meaning</kbd> で始まるページ名を検索する。",
+ "apihelp-query+protectedtitles-description": "作成保護が掛けられているページを一覧表示します。",
+ "apihelp-query+protectedtitles-param-namespace": "この名前空間に含まれるページのみを一覧表示します。",
+ "apihelp-query+protectedtitles-param-level": "この保護レベルのページのみを一覧表示します。",
+ "apihelp-query+protectedtitles-param-limit": "返すページの総数。",
+ "apihelp-query+protectedtitles-param-start": "一覧表示の始点となる保護タイムスタンプ。",
+ "apihelp-query+protectedtitles-param-end": "一覧表示の終点となる保護タイムスタンプ。",
+ "apihelp-query+protectedtitles-example-simple": "保護されているページを一覧表示する。",
+ "apihelp-query+protectedtitles-example-generator": "標準名前空間にある保護されたページへのリンクを検索する。",
+ "apihelp-query+querypage-param-page": "特別ページの名前です。これは大文字小文字を区別することに注意。",
+ "apihelp-query+querypage-param-limit": "返す結果の数。",
+ "apihelp-query+querypage-example-ancientpages": "[[Special:Ancientpages]] の結果を返す。",
+ "apihelp-query+random-param-namespace": "この名前空間にあるページのみを返します。",
+ "apihelp-query+random-example-simple": "標準名前空間から2つのページを無作為に返す。",
+ "apihelp-query+random-example-generator": "標準名前空間から無作為に選ばれた2つのページのページ情報を返す。",
+ "apihelp-query+recentchanges-description": "最近の更新を一覧表示します。",
+ "apihelp-query+recentchanges-param-start": "列挙の始点となるタイムスタンプ。",
+ "apihelp-query+recentchanges-param-end": "列挙の終点となるタイムスタンプ。",
+ "apihelp-query+recentchanges-param-namespace": "この名前空間の変更のみに絞り込む。",
+ "apihelp-query+recentchanges-param-user": "この利用者による変更のみを一覧表示する。",
+ "apihelp-query+recentchanges-param-excludeuser": "この利用者による変更を一覧表示しない。",
+ "apihelp-query+recentchanges-param-tag": "このタグが付与された版のみ一覧表示する。",
+ "apihelp-query+recentchanges-param-limit": "返す変更の総数。",
+ "apihelp-query+recentchanges-param-toponly": "最新の版である変更のみを一覧表示する。",
+ "apihelp-query+recentchanges-example-simple": "最近の更新を一覧表示する。",
+ "apihelp-query+redirects-description": "ページへのすべての転送を返します。",
+ "apihelp-query+redirects-param-limit": "返す転送の数。",
+ "apihelp-query+redirects-example-simple": "[[Main Page]] への転送の一覧を取得する。",
+ "apihelp-query+redirects-example-generator": "[[Main Page]] へのすべての転送ページに関する情報を取得する。",
+ "apihelp-query+revisions-param-user": "この利用者による版のみを結果に含める。",
+ "apihelp-query+revisions-param-excludeuser": "この利用者による版を結果に含めない。",
+ "apihelp-query+revisions-param-tag": "このタグが付与された版のみを一覧表示する。",
+ "apihelp-query+revisions-example-content": "ページ<kbd>API</kbd> および <kbd>Main Page</kbd> の最新の版のデータと本文を取得する。",
+ "apihelp-query+revisions-example-last5": "<kbd>Main Page</kbd> の直近の5版を取得する。",
+ "apihelp-query+revisions-example-first5": "<kbd>Main Page</kbd> の最初の5版を取得する。",
+ "apihelp-query+revisions-example-first5-after": "<kbd>Main Page</kbd> の 2006-05-01 以降の最初の5版を取得する。",
+ "apihelp-query+revisions-example-first5-not-localhost": "<kbd>Main Page</kbd> の匿名利用者 <kbd>127.0.0.1</kbd> 以外による最初の5版を取得する。",
+ "apihelp-query+revisions-example-first5-user": "<kbd>Main Page</kbd> の <kbd>MediaWiki default</kbd> による最初の5版を取得する。",
+ "apihelp-query+search-description": "全文検索を行います。",
+ "apihelp-query+search-param-search": "この値を含むページ名または本文を検索します。Wikiの検索バックエンド実装に応じて、あなたは特別な検索機能を呼び出すための文字列を検索することができます。",
+ "apihelp-query+search-param-namespace": "この名前空間内のみを検索します。",
+ "apihelp-query+search-param-what": "実行する検索の種類です。",
+ "apihelp-query+search-param-limit": "返すページの総数です。",
+ "apihelp-query+search-example-simple": "<kbd>meaning</kbd> を検索する。",
+ "apihelp-query+search-example-generator": "<kbd>meaning</kbd> の検索で返されたページのページ情報を取得する。",
+ "apihelp-query+tags-description": "変更タグを一覧表示します。",
+ "apihelp-query+tags-param-limit": "一覧表示するタグの最大数。",
+ "apihelp-query+tags-example-simple": "利用可能なタグを一覧表示する。",
+ "apihelp-query+templates-description": "与えられたページでトランスクルードされているすべてのページを返します。",
+ "apihelp-query+templates-param-namespace": "この名前空間のテンプレートのみ表示する。",
+ "apihelp-query+templates-param-limit": "返すテンプレートの数。",
+ "apihelp-query+templates-example-simple": "<kbd>Main Page</kbd> で使用されているテンプレートを取得する。",
+ "apihelp-query+templates-example-generator": "<kbd>Main Page</kbd> で使用されているテンプレートに関する情報を取得する。",
+ "apihelp-query+templates-example-namespaces": "<kbd>Main Page</kbd> でトランスクルードされている {{ns:user}} および {{ns:template}} 名前空間のページを取得する。",
+ "apihelp-query+tokens-description": "データ変更操作用のトークンを取得します。",
+ "apihelp-query+tokens-param-type": "リクエストするトークンの種類。",
+ "apihelp-query+tokens-example-simple": "csrfトークンを取得する (既定)。",
+ "apihelp-query+tokens-example-types": "ウォッチトークンおよび巡回トークンを取得する。",
+ "apihelp-query+transcludedin-description": "与えられたページをトランスクルードしているすべてのページを検索します。",
+ "apihelp-query+transcludedin-example-simple": "<kbd>Main Page</kbd> をトランスクルードしているページの一覧を取得する。",
+ "apihelp-query+transcludedin-example-generator": "<kbd>Main Page</kbd> をトランスクルードしているページに関する情報を取得する。",
+ "apihelp-query+usercontribs-description": "利用者によるすべての編集を取得します。",
+ "apihelp-query+usercontribs-param-limit": "返す投稿記録の最大数。",
+ "apihelp-query+usercontribs-param-user": "投稿記録を取得する利用者。",
+ "apihelp-query+usercontribs-param-userprefix": "この値で始まる名前のすべての利用者の投稿記録を取得します。$1user をオーバーライドします。",
+ "apihelp-query+usercontribs-param-namespace": "この名前空間への投稿記録のみを一覧表示する。",
+ "apihelp-query+usercontribs-param-tag": "このタグが付与された版のみを一覧表示する。",
+ "apihelp-query+usercontribs-param-toponly": "最新の版である変更のみを一覧表示する。",
+ "apihelp-query+usercontribs-example-user": "利用者 <kbd>Example</kbd> の投稿記録を表示する。",
+ "apihelp-query+users-param-token": "代わりに <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> を使用してください。",
+ "apihelp-query+users-example-simple": "利用者 <kbd>Example</kbd> の情報を返す。",
+ "apihelp-query+watchlist-description": "現在の利用者のウォッチリストにあるページへの最近の更新を取得します。",
+ "apihelp-query+watchlist-param-start": "列挙の始点となるタイムスタンプ。",
+ "apihelp-query+watchlist-param-end": "列挙の終点となるタイムスタンプ。",
+ "apihelp-query+watchlist-param-namespace": "この名前空間の変更のみに絞り込む。",
+ "apihelp-query+watchlist-param-user": "この利用者による変更のみを一覧表示する。",
+ "apihelp-query+watchlist-param-excludeuser": "この利用者による変更を一覧表示しない。",
+ "apihelp-query+watchlistraw-description": "現在の利用者のウォッチリストにあるすべてのページを取得します。",
+ "apihelp-query+watchlistraw-param-namespace": "この名前空間に含まれるページのみを一覧表示します。",
+ "apihelp-revisiondelete-description": "版の削除および復元を行います。",
+ "apihelp-revisiondelete-param-reason": "削除または復元の理由。",
+ "apihelp-revisiondelete-example-revision": "<kbd>Main Page</kbd> の版 <kbd>12345</kbd> の本文を隠す。",
+ "apihelp-rollback-param-title": "巻き戻すページ名です。<var>$1pageid</var> とは同時に使用できません。",
+ "apihelp-rollback-param-pageid": "巻き戻すページのページIDです。<var>$1title</var> とは同時に使用できません。",
+ "apihelp-rollback-example-simple": "利用者 <kbd>Example</kbd> による <kbd>Main Page</kbd> への最後の一連の編集を巻き戻す。",
+ "apihelp-tag-param-reason": "変更の理由。",
+ "apihelp-tag-example-log": "<kbd>Wrongly applied</kbd> という理由で <kbd>spam</kbd> タグを 記録項目ID 123 から取り除く",
+ "apihelp-tokens-param-type": "リクエストするトークンの種類。",
+ "apihelp-tokens-example-edit": "編集トークンを取得する (既定)。",
+ "apihelp-unblock-description": "利用者のブロックを解除します。",
+ "apihelp-unblock-param-id": "解除するブロックのID (<kbd>list=blocks</kbd>で取得できます)。<var>$1user</var> とは同時に使用できません。",
+ "apihelp-unblock-param-user": "ブロックを解除する利用者名、IPアドレスまたはIPレンジ。<var>$1id</var>とは同時に使用できません。",
+ "apihelp-unblock-param-reason": "ブロック解除の理由。",
+ "apihelp-unblock-example-id": "ブロックID #<kbd>105</kbd> を解除する。",
+ "apihelp-unblock-example-user": "<kbd>Sorry Bob</kbd> という理由で利用者 <kbd>Bob</kbd> のブロックを解除する。",
+ "apihelp-undelete-description": "削除されたページの版を復元します。\n\n削除された版の一覧 (タイムスタンプを含む) は[[Special:ApiHelp/query+deletedrevs|list=deletedrevs]]に、また削除されたファイルのID一覧は[[Special:ApiHelp/query+filearchive|list=filearchive]]で見つけることができます。",
+ "apihelp-undelete-param-title": "復元するページ名。",
+ "apihelp-undelete-param-reason": "復元の理由。",
+ "apihelp-undelete-param-timestamps": "復元する版のタイムスタンプ。<var>$1timestamps</var> と <var>$1fileids</var> の両方が空の場合、すべての版が復元されます。",
+ "apihelp-undelete-example-page": "<kbd>Main Page</kbd> を復元する。",
+ "apihelp-undelete-example-revisions": "<kbd>Main Page</kbd> の2つの版を復元する。",
+ "apihelp-upload-param-watch": "このページをウォッチする。",
+ "apihelp-upload-param-ignorewarnings": "あらゆる警告を無視する。",
+ "apihelp-userrights-param-user": "利用者名。",
+ "apihelp-userrights-param-userid": "利用者ID。",
+ "apihelp-userrights-param-add": "利用者をこのグループに追加します。",
+ "apihelp-userrights-param-reason": "変更の理由。",
+ "apihelp-watch-example-watch": "<kbd>Main Page</kbd> をウォッチする。",
+ "apihelp-watch-example-unwatch": "<kbd>Main Page</kbd> のウォッチを解除する。",
+ "apihelp-format-example-generic": "クエリの結果を $1 形式に返します。",
"apihelp-dbg-description": "データを PHP の <code>var_export()</code> 形式で出力します。",
"apihelp-dbgfm-description": "データを PHP の <code>var_export()</code> 形式 (HTML に埋め込んだ形式) で出力します。",
- "apihelp-dump-description": "データを PHP の <code>var_dump()</code> 形式で出力します。",
- "apihelp-dumpfm-description": "データを PHP の <code>var_dump()</code> 形式 (HTML に埋め込んだ形式) で出力します。",
"apihelp-json-description": "データを JSON 形式で出力します。",
"apihelp-json-param-callback": "指定すると、指定した関数呼び出しで出力をラップします。安全のため、利用者固有のデータはすべて制限されます。",
- "apihelp-json-param-utf8": "指定すると、大部分の非 ASCII 文字 (すべてではありません) を、16 進のエスケープ シーケンスに置換する代わりに UTF-8 として符号化します。",
+ "apihelp-json-param-utf8": "指定すると、大部分の非 ASCII 文字 (すべてではありません) を、16 進のエスケープ シーケンスに置換する代わりに UTF-8 として符号化します。<var>formatversion</var> が <kbd>1</kbd> でない場合は既定です。",
"apihelp-jsonfm-description": "データを JSON 形式 (HTML に埋め込んだ形式) で出力します。",
"apihelp-none-description": "何も出力しません。",
"apihelp-php-description": "データを PHP のシリアル化した形式で出力します。",
@@ -171,10 +511,8 @@
"apihelp-rawfm-description": "データをデバッグ要素付きで JSON 形式 (HTML に埋め込んだ形式) で出力します。",
"apihelp-txt-description": "データを PHP の <code>print_r()</code> 形式で出力します。",
"apihelp-txtfm-description": "データを PHP の <code>print_r()</code> 形式 (HTML に埋め込んだ形式) で出力します。",
- "apihelp-wddx-description": "データを WDDX 形式で出力します。",
- "apihelp-wddxfm-description": "データを WDDX 形式 (HTML に埋め込んだ形式) で出力します。",
"apihelp-xml-description": "データを XML 形式で出力します。",
- "apihelp-xml-param-xslt": "指定すると、スタイルシートとして &lt;xslt&gt; を追加します。MediaWiki 名前空間の、ページ名の末尾が \".xsl\" のウィキページに対して使用すべきです。",
+ "apihelp-xml-param-xslt": "指定すると、XSLスタイルシートとして名付けられたページを追加します。値は、必ず、{{ns:mediawiki}} 名前空間の、ページ名の末尾が <code>.xsl</code> でのタイトルである必要があります。",
"apihelp-xml-param-includexmlnamespace": "指定すると、XML 名前空間を追加します。",
"apihelp-xmlfm-description": "データを XML 形式 (HTML に埋め込んだ形式) で出力します。",
"apihelp-yaml-description": "データを YAML 形式で出力します。",
@@ -193,7 +531,7 @@
"api-help-parameters": "{{PLURAL:$1|パラメーター}}:",
"api-help-param-deprecated": "廃止予定です。",
"api-help-param-required": "このパラメーターは必須です。",
- "api-help-param-list": "{{PLURAL:$1|1=値 (いずれか1つ)|2=値 (<kbd>{{!}}</kbd>で区切る)}}: $2",
+ "api-help-param-list": "{{PLURAL:$1|1=値 (次の値のいずれか1つ)|2=値 (<kbd>{{!}}</kbd>で区切る)}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=空欄にしてください|空欄にするか、または $2}}",
"api-help-param-integer-min": "{{PLURAL:$1|値}}は $2 以上にしてください。",
"api-help-param-integer-max": "{{PLURAL:$1|値}}は $3 以下にしてください。",
diff --git a/includes/api/i18n/ko.json b/includes/api/i18n/ko.json
index 540f64c8..ab018c95 100644
--- a/includes/api/i18n/ko.json
+++ b/includes/api/i18n/ko.json
@@ -3,10 +3,15 @@
"authors": [
"Kwj2772",
"Twotwo2019",
- "아라"
+ "아라",
+ "LiteHell",
+ "Ysjbserver",
+ "Alex00728",
+ "Hwangjy9",
+ "Kurousagi"
]
},
- "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page 설명문서]\n* [https://www.mediawiki.org/wiki/API:FAQ FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 메일링 리스트]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API 공지 사항] * [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 버그 및 요청] </div>\n<strong>상태:</strong> 이 페이지에 표시된 모든 기능은 정상 작동할 것이지만, API는 여전히 활발하게 개발되고 있으며, 언제든지 바뀔 수 있습니다. 업데이트 정보를 받아보려면 [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce 메일링 리스트]를 구독하십시오.\n\n<strong>잘못된 요청:</strong> API에 잘못된 요청이 전송되면 HTTP 헤더에서 \"MediaWiki-API-Error\" 키를 보내고, 헤더 값과 오류 코드가 같게 설정됩니다. 자세한 정보에 대해서는 https://www.mediawiki.org/wiki/API:Errors_and_warnings 를 참고하십시오.",
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|설명문서]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 메일링 리스트]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API 공지 사항] * [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 버그 및 요청] </div>\n<strong>상태:</strong> 이 페이지에 표시된 모든 기능은 정상 작동할 것이지만, API는 여전히 활발하게 개발되고 있으며, 언제든지 바뀔 수 있습니다. 업데이트 정보를 받아보려면 [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce 메일링 리스트]를 구독하십시오.\n\n<strong>잘못된 요청:</strong> API에 잘못된 요청이 전송되면 HTTP 헤더에서 \"MediaWiki-API-Error\" 키를 보내고, 헤더 값과 오류 코드가 같게 설정됩니다. 자세한 정보에 대해서는 [[mw:API:Errors_and_warnings|API:오류 및 경고]]를 참조하십시오.",
"apihelp-main-param-action": "수행할 동작",
"apihelp-main-param-format": "출력값의 형식.",
"apihelp-block-description": "사용자를 차단합니다.",
@@ -23,7 +28,14 @@
"apihelp-block-param-watchuser": "해당 사용자 또는 IP 주소의 사용자 문서 및 토론 문서를 주시합니다.",
"apihelp-block-example-ip-simple": "IP <kbd>192.0.2.5</kbd>에 대해 <kbd>First strike</kbd>라는 이유로 3일간 차단하기",
"apihelp-block-example-user-complex": "사용자 <kbd>Vandal</kbd>을 <kbd>Vandalism</kbd>이라는 이유로 무기한 차단하며 계정 생성 및 이메일 발송을 막기",
+ "apihelp-createaccount-description": "새 사용자 계정을 만듭니다.",
+ "apihelp-createaccount-param-name": "사용자 이름",
+ "apihelp-createaccount-param-email": "사용자 이메일 주소 (선택).",
+ "apihelp-createaccount-param-realname": "사용자 실명 (선택).",
+ "apihelp-delete-description": "문서 삭제",
+ "apihelp-delete-param-unwatch": "문서를 현재 사용자의 주시문서 목록에서 제거합니다.",
"apihelp-delete-example-simple": "<kbd>Main Page</kbd>를 삭제합니다.",
+ "apihelp-disabled-description": "이 모듈은 해제되었습니다.",
"apihelp-edit-description": "문서를 만들고 편집합니다.",
"apihelp-edit-param-sectiontitle": "새 문단을 위한 제목.",
"apihelp-edit-param-text": "문서 내용.",
@@ -31,6 +43,66 @@
"apihelp-edit-param-minor": "사소한 편집.",
"apihelp-edit-param-notminor": "사소하지 않은 편집.",
"apihelp-edit-param-bot": "이 편집을 봇으로 표시.",
+ "apihelp-edit-param-unwatch": "문서를 현재 사용자의 주시문서 목록에서 제거합니다.",
+ "apihelp-edit-example-edit": "문서 편집",
+ "apihelp-emailuser-description": "사용자에게 이메일을 보냅니다.",
+ "apihelp-emailuser-param-target": "이메일을 받을 사용자.",
+ "apihelp-expandtemplates-param-title": "문서 제목",
+ "apihelp-expandtemplates-param-text": "변환할 위키텍스트.",
+ "apihelp-feedrecentchanges-param-hideminor": "사소한 편집을 숨깁니다.",
+ "apihelp-feedrecentchanges-param-hidebots": "봇의 편집을 숨깁니다.",
+ "apihelp-feedrecentchanges-param-hideanons": "익명 사용자의 편집을 숨깁니다.",
+ "apihelp-feedrecentchanges-param-hideliu": "등록된 사용자의 편집을 숨깁니다.",
+ "apihelp-feedrecentchanges-param-hidepatrolled": "검토된 편집을 숨깁니다.",
+ "apihelp-feedrecentchanges-param-tagfilter": "태그로 분류",
+ "apihelp-feedrecentchanges-example-simple": "최근 바뀜을 봅니다.",
+ "apihelp-feedrecentchanges-example-30days": "30일간의 최근 바뀜을 봅니다.",
+ "apihelp-filerevert-description": "파일을 이전 판으로 되돌립니다.",
+ "apihelp-login-param-name": "계정 이름.",
+ "apihelp-login-param-password": "비밀번호.",
+ "apihelp-login-example-login": "로그인.",
+ "apihelp-move-description": "문서 이동하기.",
+ "apihelp-move-param-reason": "제목을 변경하는 이유",
+ "apihelp-move-param-movetalk": "토론 문서가 존재한다면, 토론 문서도 이름을 변경해주세요.",
+ "apihelp-move-param-movesubpages": "하위 문서가 있다면, 하위 문서도 이름을 변경해주세요.",
+ "apihelp-move-param-noredirect": "넘겨주기 문서 만들지 않기",
+ "apihelp-move-param-watch": "현재 사용자의 주시 문서에 이 문서와 넘겨주기 문서를 추가하기",
+ "apihelp-move-param-unwatch": "현재 사용자의 주시 문서에 이 문서와 넘겨주기 문서를 제거하기",
+ "apihelp-move-param-ignorewarnings": "모든 경고 무시하기",
+ "apihelp-opensearch-description": "OpenSearch 프로토콜을 이용하여 위키 검색하기",
+ "apihelp-opensearch-param-search": "문자열 검색",
+ "apihelp-opensearch-param-limit": "반환할 결과의 최대 수",
+ "apihelp-options-param-reset": "사이트 기본으로 설정 초기화",
+ "apihelp-options-example-reset": "모든 설정 초기화",
+ "apihelp-protect-example-protect": "문서 보호",
+ "apihelp-query+pageswithprop-param-limit": "나타낼 문서의 최대 수입니다.",
+ "apihelp-query+pageswithprop-param-dir": "정렬 순서",
+ "apihelp-query+prefixsearch-param-search": "문자열 검색",
+ "apihelp-unblock-description": "사용자를 차단 해제합니다.",
+ "api-help-title": "미디어위키 API 도움말",
+ "api-help-lead": "이 페이지는 자동으로 생성된 미디어위키 API 도움말 문서입니다.\n\n설명 문서 및 예시: https://www.mediawiki.org/wiki/API",
+ "api-help-main-header": "메인 모듈",
+ "api-help-flag-deprecated": "이 모듈은 사용되지 않습니다.",
+ "api-help-flag-readrights": "이 모듈은 read 권한을 요구합니다.",
+ "api-help-flag-writerights": "이 모듈은 write 권한을 요구합니다.",
+ "api-help-flag-mustbeposted": "이 모듈은 POST 요청만을 허용합니다.",
+ "api-help-source": "출처: $1",
+ "api-help-license": "라이선스: [[$1|$2]]",
+ "api-help-license-noname": "라이선스: [[$1|링크 참조]]",
+ "api-help-license-unknown": "라이선스: <span class=\"apihelp-unknown\">알 수 없음</span>",
+ "api-help-parameters": "{{PLURAL:$1|변수}}:",
+ "api-help-param-deprecated": "사용 중지됨.",
+ "api-help-param-required": "이 변수는 필수 입력 사항입니다.",
+ "api-help-datatypes-header": "데이터 유형",
+ "api-help-datatypes": "API 요청 내 몇몇 매개변수형에 대해 더 자세히 설명해보겠습니다:\n;boolean\n:Boolean 매개변수들은 HTML 체크박스처럼 동작합니다: 만약 매개변수가 지저오딨다면, 값에 상관없이 참의 값으로 여겨집니다. 거짓값은 매개변수 전체를 생략하여 표현해보세요.\n;timestamp\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:* 미디어위키 형식, <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:*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:* C ctime 형식, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* 1부터 13자리까지의 숫자로 표현된 1970-01-01T00:00:00Z 부터 흐른 시간(초)",
+ "api-help-param-type-integer": "유형: {{PLURAL:$1|1=정수|2=정수 목록}}",
+ "api-help-param-type-boolean": "유형: 부울 ([[Special:ApiHelp/main#main/datatypes|자세한 정보]])",
"api-help-param-list": "{{PLURAL:$1|1=하나의 값|2=값 (\"{{!}}\"로 구분)}}: $2",
- "api-help-param-default": "기본값: $1"
+ "api-help-param-default": "기본값: $1",
+ "api-help-param-default-empty": "기본값: <span class=\"apihelp-empty\">(비어 있음)</span>",
+ "api-help-param-no-description": "<span class=\"apihelp-empty\">(설명 없음)</span>",
+ "api-help-examples": "{{PLURAL:$1|예시}}:",
+ "api-help-permissions": "{{PLURAL:$1|권한}}:",
+ "api-help-permissions-granted-to": "{{PLURAL:$1|다음 그룹에 부여됨}}: $2",
+ "api-credits": "API 개발자:\n* Roan Kattouw (선임 개발자, 2007년 9월–2009년)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (초기 개발자, 선임 개발자 2006년 9월~2007년 9월)\n* Brad Jorsch (선임 개발자 2013년–현재)\n\n당신의 의견이나 제안, 질문은 mediawiki-api@lists.wikimedia.org 로 보내주시거나,\nhttps://phabricator.wikimedia.org/ 에 버그 신고를 해 주시기 바랍니다.."
}
diff --git a/includes/api/i18n/ksh.json b/includes/api/i18n/ksh.json
index cdcca375..46ef9682 100644
--- a/includes/api/i18n/ksh.json
+++ b/includes/api/i18n/ksh.json
@@ -4,62 +4,99 @@
"Purodha"
]
},
- "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page/de|Dokemäntazjohn]]\n* [[mw:API:FAQ/de|Öff jefrohch]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mäileng_Leß]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Aanköndejonge zom <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i>]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Jemäldte Fähler un Wönsch]\n</div>\n<strong>Status:</strong> Alle op heh dä Sigg aanjzeischte Ußwahle sullte donn, ävver et <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> wee jrahd noch äntwekeld un et kann sesch alle Nahslangs jädd ändere. Holl Der de [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ Mäileng_Leß med Aanköndejonge], öm automattesch övver Neujeschkeite enfommehrt ze wähde.\n\n<strong>Kapodde Aanfrohe:</strong> Wam_mer kapodde Aanfroheaan et API <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> schek, kritt mer ene <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Transfer Protocol\">HTTP</i>-Kopp ußjejovve met däm Täx „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">MediaWiki-API-Error</code>“ dren, dä mer als ene Schlößel bedraachte kann. Mih dohzoh fengk met op dä Sigg [[mw:API:Errors_and_warnings|<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i>: Fähler un Warnonge]].",
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page/de|Dokemäntazjohn]]\n* [[mw:API:FAQ/de|Öff jefrohch]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mäileng_Leß]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Aanköndejonge zom <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i>]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Jemäldte Fähler un Wönsch]\n</div>\n<strong>Status:</strong> Alle op heh dä Sigg aanjzeischte Ußwahle sullte donn, ävver et <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> weed jrahd noch äntwekeld un et kann sesch alle Nahslangs jädd ändere. Holl Der de [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ Mäileng_Leß med Aanköndejonge], öm automattesch övver Neujeschkeite enfommehrt ze wähde.\n\n<strong>Kapodde Aanfrohre:</strong> Wam_mer kapodde Aanfroheaan et API <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> schek, kritt mer ene <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Transfer Protocol\">HTTP</i>-Kopp ußjejovve met däm Täx „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">MediaWiki-API-Error</code>“ dren, dä mer als ene Schlößel bedraachte kann. Mih dohzoh fengk met op dä Sigg [[mw:API:Errors_and_warnings|<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i>: Fähler un Warnonge]].",
"apihelp-main-param-action": "Wat för en Aufjahb.",
"apihelp-main-param-format": "Et Fommaht för ußzejävve.",
- "apihelp-main-param-smaxage": "Säz <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">s-maxage</code> em Kobb obb esu vill Sekonde. Fähler wähde nit faßjehallde.",
- "apihelp-main-param-maxage": "Säz <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">max-age</code> em Kobb obb esu vill Sekonde. Fähler wähde nit faßjehallde.",
+ "apihelp-main-param-maxlag": "Der hühste zohjelohße Verzoch kann jenumme wähde, wann MehdijaWikki obb enem Dahtebangk replicated cluster enschtallehrt weed. Öm kein Opdräschd aan de Dahtebangk ze scheke, di dat noch schlemmer maache dähte, kam_mer övver heh dä Parramehter et Projramm affwahde lohße, bes dat the replication lag onger däm aanjejovve Wäät lit. Wann dä Verzoch övvermähßesch jruhs es kritt mer dä Fähler <samp lang=\"en\" xml:lang=\"en\" dir=\"ltr\">maxlag</samp> jemälldt en ene Nohreesch esu wi <samp lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Mer wahde op dä ẞööver $Maschihn un di es $Verzoch Sekonde hengerher</samp>.<br />Op dä [[mw:Manual:Maxlag_parameter|Hanndbohchsigg zom \n<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Maxlag</code>-Parramehter]] kam_mer noch mih zerdoh lässe.<!-- https://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-main-param-maxlag/ksh -->",
+ "apihelp-main-param-smaxage": "Säz <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">max-age</code> en dä Kopp_Reihj <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">HTTP cache control</code> obb esu vill Sekonde. Fähler wähde nimmohls faßjehallde.",
+ "apihelp-main-param-maxage": "Säz <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">max-age</code> en dä Kopp_Reihj <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">HTTP cache control</code> obb esu vill Sekonde. Fähler wähde nimmohls faßjehallde.",
"apihelp-main-param-assert": "Ställ sescher, dat dä Metmaacher enjelogg es (doh för jiff <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">user</kbd> en), udder ene Bot es (doh för jiff <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">bot</kbd> en).",
"apihelp-main-param-requestid": "Jehde Aanjahb vun heh weed widder med ußjejovve. Esuh kam_mer einzel Affrohre ussenein hallde.",
"apihelp-main-param-servedby": "Donn däm ẞööver, dä et jedonn hät, singe Nahme med ußjävve.",
"apihelp-main-param-curtimestamp": "Donn de aktoälle Zigg un et Dattum med ußjävve.",
+ "apihelp-main-param-uselang": "De schprohch för et Övversäzze vun Täxte un Nohreeschte. En Leß met de Köözelle kam_mer vun dä Sigg <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> holle, met <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">siprop=languages</kbd>, udder jiff <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">user</kbd> aan, öm dem aktoälle Metmaacher sing eetzde Schprohch ze krijje, udder nemm <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">content</kbd> öm heh dämm Wikki singe Ennhald sing Schprohch ze krijje.",
"apihelp-block-description": "Ene Metmaacher schpärre.",
"apihelp-block-param-user": "Däm Nahme vun däm Metmaacher, de <i lang=\"en\" xml:lang=\"en\" title=\"Internet Protocol\">IP</i>-Addräß udder dä Berätt, dä De Schpärre wells.",
+ "apihelp-block-param-expiry": "De Zigg bes zom Ußloufe. Kam_mer als en Door aanjävve, esu wi „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">5 months</kbd>“ udder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">2 weeks</kbd>“ un kam_mer als ene Zigg_Pongk aanjävve, esu wi „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">2014-09-18T12:34:56Z</kbd>“, un wam_mer „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">infinite</kbd>“, „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">indefinite</kbd>“ udder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">never</kbd>“ aanjitt, dohrt di Schpärr för iiwesch.",
"apihelp-block-param-reason": "Der Schpärrjrond.",
"apihelp-block-param-anononly": "Bloß de nahmelohse Metmaaacher spärre, alsu donn et nahmelohse Beärbeide vun dä <i lang=\"en\" xml:lang=\"en\" title=\"Internet Protocol\">IP</i>-Addräß uß verhendere.",
"apihelp-block-param-nocreate": "Et Neu-Aanmelde verbeede",
"apihelp-block-param-autoblock": "Dun automattesch de läzde <i lang=\"en\" xml:lang=\"en\">IP</i>-Adräß schpärre, di dä Metmaacher jehatt hät, un och all di <i lang=\"en\" xml:lang=\"en\">IP</i>-Adräße, vun wo dä versöhk, jet ze ändere.",
+ "apihelp-block-param-noemail": "Sorresch derför, dat dä Metmaacher \n<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i> övver et Wiki verscheck. Bruch et Rääsch „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">blockemail</code>“.",
+ "apihelp-block-param-hidename": "Donn däm Metmaacher singe Nahme em Logbohch vum Metmaacher Schpärre verschteische. Bruch et Rääsch „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">hideuser</code>“.",
+ "apihelp-block-param-allowusertalk": "Lohß dä Metmaacher sing eije Klaafsigg verändere. Dat hängk aan „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>“.",
"apihelp-block-param-reblock": "Wann dä Metmaacher als jeschpächd es, donn dat övverschrihve.",
"apihelp-block-param-watchuser": "Donn de Metmaachersigg un de Klaafsigg dohzoh op mig Oppaßleß säze.",
"apihelp-block-example-ip-simple": "Donn de <i lang=\"en\" xmL:lang=\"en\" title=\"Internet Protocol\">IP</i>-Addräß <kbd>192.0.2.5</kbd> för drei ääsch schpärre mem Jrond: <kbd>Eestschlaach</kbd>.",
+ "apihelp-block-example-user-complex": "Donn dä Metmaacher „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Vandal</kbd>“ för iiwesch schpärre, mem Jrond „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Vandalism</kbd>“, un donn_em neu Zohjäng aanzelähje un <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i> ze verscheke verbehde.",
+ "apihelp-checktoken-description": "Donn de Jölteschkeid vun enem Makkehrongsschlößel vun „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>“ pröhve.",
+ "apihelp-checktoken-param-type": "De Zoot Makkehrongsschlößel zom Pröhfe.",
+ "apihelp-checktoken-param-token": "Der Makkehrongsschlößel zom Pröhve.",
+ "apihelp-checktoken-param-maxtokenage": "Et jrühßte zojelohße Allder fun däm Makkehrongsschlößel en Sekonde.",
+ "apihelp-checktoken-example-simple": "Pröhf de Jölteschkeid vun däm Makkehrongsschlößel „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">csrf</kbd>“.",
+ "apihelp-clearhasmsg-description": "Nemmp de Makkehrong „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">hasmsg</code>“ fott vum aktoälle Metmaacher.",
+ "apihelp-clearhasmsg-example-1": "Nemm de Makkehrong „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">hasmsg</code>“ fott vum aktoälle Metmaacher.",
"apihelp-compare-description": "Donn de Ongerscheide zwesche zwai Sigge beschtemme.\n\nDo moß derför jeweils en Väsjohn, en Övverschreff för di Sigg, odder ener Sigg iehr Kännong aanjävve, för de beide Sigge.",
- "apihelp-compare-param-fromtitle": "Der Tettel vun dä eezte Sigg zom verjlihsche.",
+ "apihelp-compare-param-fromtitle": "De Övverschreff vun dä eezte Sigg zom verjlihsche.",
"apihelp-compare-param-fromid": "De Kännong vun dä eezte Sigg zom verjlihsche.",
"apihelp-compare-param-fromrev": "De Väsjohn vun dä zwaite Sigg zom verjlihsche.",
- "apihelp-compare-param-totitle": "Der Tettel vun dä zwaite Sigg zom verjlihsche.",
+ "apihelp-compare-param-totitle": "De Övverschreff vun dä zwaite Sigg zom verjlihsche.",
"apihelp-compare-param-toid": "De Kännong vun dä zwaite Sigg zom verjlihsche.",
"apihelp-compare-param-torev": "De Väsjohn vun dä zwaite Sigg zom verjlihsche.",
"apihelp-compare-example-1": "Fengk de Ongerscheide zwesche dä Väsjohne 1 un 2",
"apihelp-createaccount-description": "Ene neue Zohjang för ene Metmaacher aanlähje.",
"apihelp-createaccount-param-name": "Der Nahme för dä Metmaacher.",
"apihelp-createaccount-param-password": "Et Paßwoot (Weed ävver it jebruc un övverjange, wann <code lang=\"en\" xml:lang=\"en\"><var>$1mailpassword</var></code> jesaz es)",
+ "apihelp-createaccount-param-domain": "De Domäijn för de Zohjangsdaht vun ußerhallef beschtähtech ze krijje. Kam_mer fott_lohße.",
+ "apihelp-createaccount-param-token": "Der Makkehrongsschlößel för ene Zohjang aanzelähje, dä mer bei de eezde Aanfrohch krääje hät.",
"apihelp-createaccount-param-email": "Däm Metmaacher sing Adräß för de <i lang=\"en\" xml:lang=\"en\">e-mail</i>, kann och fott bliive.",
- "apihelp-createaccount-param-realname": "Dämm Medmaacher singe reschtejje Nahme - kann fott blihve.",
+ "apihelp-createaccount-param-realname": "Dämm Metmaacher singe reeschtejje Nahme - kann fott blihve.",
"apihelp-createaccount-param-mailpassword": "Wann heh jädd aanjejovve es, kritt dä Metmaacher e zohfällesch ußjesöhk neu Paßwood aan sing Adräß för de <i lang=\"en\" xml:lang=\"en\">e-mail</i> jescheck.",
"apihelp-createaccount-param-reason": "Ene Jrond för dä Zojang aanzelähje, dä en de Logböhscher kütt.",
"apihelp-createaccount-param-language": "Dat Schprohcheköözel, wadd als der Schtandatt för dä Metmaacher jesaz wähde sull. Kann läddesch blihve, dann es et di Schprohch vum Wikki.",
"apihelp-createaccount-example-pass": "Lääsch dä Metmaacher <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">testuser</kbd> aan, mem Paßwood <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">test123</kbd>.",
"apihelp-createaccount-example-mail": "Lääsch dä Metmaacher <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">testmailuser</kbd> aan med emem zohfällesch ußjewörfelte Paßwoot un schegg_em dat övver de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">e-mail</i>.",
"apihelp-delete-description": "Schmieß en Sigg fott.",
+ "apihelp-delete-param-title": "De Övverschreff vun dä Sigg zom fottschmiiße. Kam_mer nit zersamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</var>“ bruche.",
+ "apihelp-delete-param-pageid": "De Kännong vun dä Sigg zom fottschmiiße. Kam_mer nit zersamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1title</var>“ bruche.",
+ "apihelp-delete-param-reason": "Der Jrond för et Fottschmiiße. Wann dä nit aanjejovve es, weed ene automattesch usjräschnete Jrond jenumme.",
"apihelp-delete-param-watch": "Donn di Sigg en däm aktoälle Metmaacher sing Oppaßleß opnämme.",
+ "apihelp-delete-param-watchlist": "Donn di Sigg op däm aktoälle Metmaacher sing Oppaßleß udder nemm se druß fott, donn de Enschtällonge nämme, udder donn de Oppaßleß jaa nit verändere.",
"apihelp-delete-param-unwatch": "Schmihß di Sigg us däm aktoälle Metmaacher singe Oppaßless erus.",
- "apihelp-delete-example-simple": "Schmiiß de <kbd>Houpsigg</kbd> fott",
- "apihelp-delete-example-reason": "Schmiiß de <kbd>Houpsigg</kbd> fott mem Jrond: <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Preparing for move</kbd>.",
+ "apihelp-delete-param-oldimage": "Der Nahme vom ahle Beld zom fottschmiiße, wi hä vun [[Special:ApiHelp/query+imageinfo|action=query&prop=imageinfo&iiprop=archivename]] kütt.",
+ "apihelp-delete-example-simple": "Schmiiß de Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ fott.",
+ "apihelp-delete-example-reason": "Schmiiß de „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ fott mem Jrond: <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Preparing for move</kbd>.",
"apihelp-disabled-description": "Dat Moduhl wohd affjeschalldt.",
"apihelp-edit-description": "Sigge aanlähje un verändere.",
+ "apihelp-edit-param-title": "De Övverschreff vun dä Sigg zom Ändere. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</var>“ bruche.",
+ "apihelp-edit-param-pageid": "De Känong vun dä Sigg zom Ändere. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1title</var>“ bruche.",
+ "apihelp-edit-param-section": "De Nommer vum Affschnedd. Nemm „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">0</kbd>“ för wat vör der eezde Övverschreff schteihd. Ene neue Affscnedd määt mer met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">new</var>“.",
"apihelp-edit-param-sectiontitle": "De Övverschreff för ene neue Affschnett.",
"apihelp-edit-param-text": "Dä Sigg ehre Ennhalld.",
+ "apihelp-edit-param-summary": "Dat Fäld för „{{int:summary}}“. Och en Öveschreff för ene Affschnedd wann „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1section=new</code>“ un „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sectiontitle</code>“ nit jesaz es.",
+ "apihelp-edit-param-tags": "De Mekhonge för op heh di väsjohn aanzewännde.",
"apihelp-edit-param-minor": "En klein Änderong.",
"apihelp-edit-param-notminor": "Kein klein Änderong.",
"apihelp-edit-param-bot": "Makeer heh di Änderog als vun enem Bot jemaat.",
+ "apihelp-edit-param-basetimestamp": "Dattom un Zigg för de Ußjangs_Väsjohn, di jenumme weed, öm dubbel Beärbeijdonge bemärke ze künne. Di kam_mer övver di Sigg <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\"[[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]]</code> eruß fenge.",
+ "apihelp-edit-param-starttimestamp": "Dattom un Zigg för wann et Beärbeijde loßß jing, di jenumme weed, öm dubbel Beärbeijdonge bemärke ze künne. Di kam_mer övver di Sigg <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\"[[Special:ApiHelp/main|curtimestamp]]</code> eruß fenge em Momang, woh mem Beärbeijde bejenne deihjt.",
+ "apihelp-edit-param-recreate": "Övverjangk alle Fähler övver di Sigg, di en der Zweschezigg fott jeschneße wohd.",
"apihelp-edit-param-createonly": "Donn di Sigg nit ändere, wann se ald doh es.",
"apihelp-edit-param-nocreate": "Mäld ene Fähler, wann di Sigg nit doh es.",
"apihelp-edit-param-watch": "Donn di Sigg op dem aktälle Metmaacher sing Oppaßleß.",
"apihelp-edit-param-unwatch": "schmiiß di Sigg uß heh däm Metmaacher singe oppaßleß.",
+ "apihelp-edit-param-watchlist": "Donn en Sigg en däm aktoälle Metmaacher sing Opaßleß enndrahre udder ußdrahre udder donn däm sing Vörenschtällonge nämme udder jaa nix ändere.",
+ "apihelp-edit-param-md5": "De <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Message-Digest Algorithm 5\">MD5</i>-Prööfsomm vum Parramehter „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1text</var>“ udder de Parramehtere „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prependtext</var>“ un „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1appendtext</var>“ wähde annenannderjehange. Wann se jesaz sin, weed di Ännderong nit jeamaat, wann di Prööfsomm nit schtemmp.",
+ "apihelp-edit-param-prependtext": "Donn dä Täx aam Aanfng vun dä Sigg enndrahre. Övverjeiht „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1text</code>“.",
+ "apihelp-edit-param-appendtext": "Donn dä Täx aam Ängk vun dä Sigg aanhange. Övverjeiht „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1text</code>“.\n\nNemm „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$section=new</code>“ ömm ene neuje Affschnedd aanzehange, anschtatt vun heh dämm Parramehter.",
+ "apihelp-edit-param-undo": "Donn heh di Väsjohn widder retuhr nämme. Övverjeiht „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1text</code>“, „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prependtext </code>“ un „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1appendtext</code>“.",
+ "apihelp-edit-param-undoafter": "Donn alle Väsjohne vun „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1undo </code>“ bes zeläz heh di Väsjohn widder retuhr nämme. Wann nix ennjedrahre es, nämm blohß ein Väsjohn retuhr nämme.",
"apihelp-edit-param-redirect": "Verfollsch de Ömleidonge automattesch.",
"apihelp-edit-param-contentmodel": "Et Enhalltsmodäll för dä neue Ennhalld.",
+ "apihelp-edit-param-token": "Dä Makkehrongsschlößel suld emmer als der läzde Parramehter jeschek wähde udder winneschsdens noh däm Parramehter „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1text</var>“.",
"apihelp-edit-example-edit": "Veränder en Sigg.",
"apihelp-edit-example-prepend": "Donn <kbd>_&#95;NOTOC_&#95;</kbd> för en Sigg säze.",
+ "apihelp-edit-example-undo": "Donn alle Väsjohne vun „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">13579</code>“ bes zeläz „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">13585</code>“ widder retuhr nämme u en autmatesche Zersamfaßong derför enndrahre.",
"apihelp-emailuser-description": "Donn en <i lang=\"en\" xml:lang=\"en\">e-mail</i> aan dä Metmaacher schecke.",
"apihelp-emailuser-param-target": "D ä Metmaacher, dä di <i lang=\"en\" xml:lang=\"en\">e-mail</i> krijje sull.",
"apihelp-emailuser-param-subject": "Koppeih mem Beträff.",
@@ -68,40 +105,101 @@
"apihelp-emailuser-example-email": "Donn en <i lang=\"en\" xml:lang=\"en\">e-mail</i> aan dä Metmaacher <kbd lang=\"en\" xml:lang=\"en\">WikiSysop</kbd> schecke mem Täx <kbd>Dä Enhalld</kbd> dren.",
"apihelp-expandtemplates-description": "Deiht alle Schablohne en Wikkitäx ömsäze.",
"apihelp-expandtemplates-param-title": "De Övverschreff vun dä Sigg.",
- "apihelp-expandtemplates-param-text": "Dä Wikitäx zom ömwandelle.",
+ "apihelp-expandtemplates-param-text": "Dä Wikkitäx zom ömwandelle.",
+ "apihelp-expandtemplates-param-revid": "De Kännong vun dä Väsjohn, för \n„<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\"><nowiki>{{REVISIONID}}</nowiki></code>“ un verwandte Wääte.",
+ "apihelp-expandtemplates-param-prop": "Wat för en Aanjahbe ze holle?\n\nOpjepaß: wann jaa kei Wääte ußjewähld sinn, kütt der Wikkitäx eruß, ävver de ßjahbe kumme en enem Fommaht, wat mer nit hann welle.",
+ "apihelp-expandtemplates-paramvalue-prop-categories": "Alle Saachjroppe en dä Quällesigg, di em Wikkitäx vun de ußjejovve Sigg nit vorkumme.",
+ "apihelp-expandtemplates-paramvalue-prop-properties": "De Sigge_Eijeschaffte, di vun de Zauberwööter em Wikkitäx faßjelaat wähde.",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "De längste Zigg noh dä de zweschejescheijscherte jevonge Dahte nmmieh jöltesch sin sulle.",
+ "apihelp-expandtemplates-paramvalue-prop-modules": "Alle Moduhle vum <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Delivery system in MediaWiki for the optimized run-time loading and managing of modules\">ResourceLoader</i>, di noh de Paaserfonksjuhne en de Ußjahbe vörkumme sulle. Äntwehder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">jsconfigvars</kbd>“ udder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">encodedjsconfigvars</kbd>“ moß mer met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">modules</kbd>“ zesamme aanforrdere.",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "Jitt de Varrejahble fun de Einschtällonge vun heh Sigg, di nur för di Sigg johd sin.",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "Jitt de Varrejahble fun de Einschtällonge vun heh Sigg, di nur för di Sigg johd sin, em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"JavaScript Object Notation\">JSON</i>-Fommahd als en Reih vun Zeijsche.",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "Dä Ennjahv iere Paaser_Boum em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Extensible Markup Language\">XML</i>_Fommaht.",
"apihelp-expandtemplates-param-includecomments": "Ov Aanmärkonge em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Markup Language\">HTML</i>-Fommaht med ußjejovve wähde sulle.",
+ "apihelp-expandtemplates-param-generatexml": "Donn ene Boum vum <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Extensible Markup Language\">XML</i>-Paaser opboue. Es dorsch „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prop=parsetree</code>“ ässäz.",
+ "apihelp-expandtemplates-example-simple": "Donn dä Wikkitäx <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\"><nowiki>{{Project:Sandbox}}</nowiki></kbd> en Täx wandelle.",
+ "apihelp-feedcontributions-description": "Jidd ene Kannahl met de Beijdrähsch vun enem Metmaacher uß.",
"apihelp-feedcontributions-param-feedformat": "Däm Kannahl sing Fommaht.",
+ "apihelp-feedcontributions-param-user": "De Beijdrähsch för wat för en Metmaacher holle.",
+ "apihelp-feedcontributions-param-namespace": "Wat för ene Appachtemang för de Beijdrähsch ußjeschloße wähde sull.",
"apihelp-feedcontributions-param-year": "Vum johr un fröhjer.",
"apihelp-feedcontributions-param-month": "Vun däm Mohnd un derför",
+ "apihelp-feedcontributions-param-tagfilter": "Op wat för en Makkehronge de Beijdrähsch bschrängk wähde sulle.",
"apihelp-feedcontributions-param-deletedonly": "zeijsch blohß de fottjeschmeße Beijdrähsch.",
"apihelp-feedcontributions-param-toponly": "Zeich blohß de Änderonge, di och de neußte sin.",
"apihelp-feedcontributions-param-newonly": "Zeich blohß de Änderonge, woh Sigge neu aanjelaat woode sin.",
"apihelp-feedcontributions-param-showsizediff": "Zeijsch de Ongerscheijd en de Jrühße zwesche de Väsjohne.",
"apihelp-feedcontributions-example-simple": "Zeijsch de Änderonge vum Metmaacher <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Example</kbd>.",
+ "apihelp-feedrecentchanges-description": "Donn ene Kannahl för de neuste Änderonge ußjävve.",
"apihelp-feedrecentchanges-param-feedformat": "Däm Kannahl sing Fommaht.",
+ "apihelp-feedrecentchanges-param-namespace": "Op wat för ene Appachtemang de Beijdrähsch beschrängk wähde sulle.",
+ "apihelp-feedrecentchanges-param-invert": "Alle Appachtemangs ußer däm ußjesöhkte.",
+ "apihelp-feedrecentchanges-param-associated": "Donn et drop betroke Appachtemang — Klaafsigge udder Atikelle — med enschlehße.",
+ "apihelp-feedrecentchanges-param-days": "Wadd eruß küdd op di Dähsch enschrängke.",
"apihelp-feedrecentchanges-param-limit": "De hühßte Aanzahl vun Äjeebnesse för zeröck ze jävve",
"apihelp-feedrecentchanges-param-from": "Zeijsch de Änderonge zigg dämm.",
- "apihelp-feedrecentchanges-param-hideminor": "De kein Minni_Änderonge verschteijsche.",
+ "apihelp-feedrecentchanges-param-hideminor": "De kleine Minni_Ännderonge verschteijsche.",
+ "apihelp-feedrecentchanges-param-hidebots": "Änderonge ußschlehße, di vun Bots jemaht wohde.",
+ "apihelp-feedrecentchanges-param-hideanons": "Änderonge ußschlehße, di vun nahmelohse Metmaacher jemaht wohde.",
+ "apihelp-feedrecentchanges-param-hideliu": "Änderonge ußschlehße, di vun aanjemälldete Metmaacher jemaht wohde.",
"apihelp-feedrecentchanges-param-hidepatrolled": "Nohjelohrte Änderonge övverjonn.",
"apihelp-feedrecentchanges-param-hidemyself": "Änderonge vun heh dämm Metmaacher övverjonn.",
+ "apihelp-feedrecentchanges-param-tagfilter": "Noh Makkehronge beschängke.",
+ "apihelp-feedrecentchanges-param-target": "Zeijsch Änderonge aan Sigge, op di vun heh dä Sigg ene Lengk jeihd.",
+ "apihelp-feedrecentchanges-param-showlinkedto": "Zeijsch Änderonge aan Sigge, op di vun dä ußjesöhk Sigg ene Lengk jeihd.",
+ "apihelp-feedrecentchanges-example-simple": "Zeijsch de {{LCFIRST:{{int:recentchanges}}}}",
+ "apihelp-feedrecentchanges-example-30days": "Zeijsch de {{LCFIRST:{{int:recentchanges}}}} vun de läzde 30 Dähsch.",
+ "apihelp-feedwatchlist-description": "Donn ene Kannahl met dä Oppaßleß zerökjävve.",
"apihelp-feedwatchlist-param-feedformat": "Däm Kannahl sing Fommaht.",
+ "apihelp-feedwatchlist-param-hours": "Zeijsch de Sigge, di en de läzde su un esu vill Schtonde vun jäz aan veränder wohde sin.",
+ "apihelp-feedwatchlist-param-linktosections": "Lengk tirägg od der veränderte Affschnedd, woh müjjelesch.",
+ "apihelp-feedwatchlist-example-default": "Zeijsch ene Kannahl met dä Oppaßleß.",
+ "apihelp-feedwatchlist-example-all6hrs": "Zeijsch alle Änderonge aan Sgge obb Oppaßleßte us de läzde 6 Schtunde.",
+ "apihelp-filerevert-description": "Säz en Dattei obb en ahle Väsohn zerök.",
"apihelp-filerevert-param-filename": "De Zih_Dattei, der ohne „{{ne:file}}“ derför.",
"apihelp-filerevert-param-comment": "Aanmärkong huh lahde.",
+ "apihelp-filerevert-param-archivename": "Dä nahme vum Aschihv vun dä Väsjohn för wider drop zerök ze jon.",
+ "apihelp-filerevert-example-revert": "Donn <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Wiki.png</kbd> op di Väsohn vum <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">2011-03-05T15:27:40Z</kbd> zerök säze.",
"apihelp-help-description": "zeisch Hölp för de aanjejovve Moduhle.",
+ "apihelp-help-param-modules": "Moduhle, öm Hölp för de Wääte vun de „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">action</var>“ un „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">format</var>“ Parramehtere, udder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">main</kbd>“. aanzezeije. Mer kann Ongermoduhle met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">+</kbd>“ aanjävve.",
+ "apihelp-help-param-submodules": "Donn Hölp för de Ongermoduhle vun dämm aanjejovve Moduhl enschschlehße.",
+ "apihelp-help-param-recursivesubmodules": "Donn Hölp för de Ongermoduhle allesammp enschschlehße, esu deef, wi et jeiht.",
+ "apihelp-help-param-helpformat": "Et Fommaht vun de Ußjahbe för de Hölp.",
+ "apihelp-help-param-wrap": "Donn de Ußjahbe en dem <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> sing schtandattmähßejje Schtruktuhr vun de Antwood enschlehße.",
+ "apihelp-help-param-toc": "Donn en Enhhaldserzeijschensß en de Ußjahbe vum <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Markup Language\">HTML</i> ennschlehße.",
+ "apihelp-help-example-main": "Hölp för et Houpmoduhl.",
"apihelp-help-example-recursive": "Alle Hölp en eine Sigg.",
"apihelp-help-example-help": "Alle Hölp övver de Hölp säälver.",
- "apihelp-imagerotate-description": "Ein udder mieh Bellder driehje.",
+ "apihelp-help-example-query": "Hölp för zwei Ongermoduhle för Frohre.",
+ "apihelp-imagerotate-description": "Ein udder mih Bellder driehje.",
"apihelp-imagerotate-param-rotation": "Öm wi vill Jrahd sulle de Bellder noh de Uhr drieh wääde?",
"apihelp-imagerotate-example-simple": "Drieh de <kbd>Dattei:Beijschpell.png</kbd> öm <kbd>90</kbd> Jrahd.",
"apihelp-imagerotate-example-generator": "Drieh alle Bellder en dä <kbd>Saachjropp:Ömdriehje</kbd> öm <kbd>180</kbd> Jrahd.",
+ "apihelp-import-param-summary": "Zersammefaßong för der Empohrt.",
"apihelp-import-param-xml": "Donn en Dattei em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Extensible Markup Language\">XML</i>-Fommaht huhjahde.",
- "apihelp-import-param-rootpage": "Als Ongersiff vun heh dä Sigg empottehre-",
+ "apihelp-import-param-interwikisource": "För et Empottehre us enem andere Wikki: Dat Wikki vun woh der Empohrt kumme sull.",
+ "apihelp-import-param-interwikipage": "För et Empottehre us enem andere Wikki: De Sigg zom Empottehre.",
+ "apihelp-import-param-fullhistory": "För et Empottehre us enem andere Wikki: Donn de jannze Verjangeheid empottehre, nit blohß de aktoälle Väsjohn.",
+ "apihelp-import-param-templates": "För et Empottehre us enem andere Wikki: Donn all de nühdejje Schablohne met empottehre.",
+ "apihelp-import-param-namespace": "En heh dat Appachtemang emmpotehre. Kam_mer nit mem Parramehter „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1rootpage</var>“ zersamme bruche.",
+ "apihelp-import-param-rootpage": "Als Ongersigg vun heh dä Sigg empottehre. Km_mer nit zosamme met däm Parramehter „<varlang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1namespace</var>“ bruche.",
+ "apihelp-import-example-import": "Donn di Sigg „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[meta:Help:ParserFunctions]]</code>“ en et Appachtemang <code>100</code>empottehre, met alle älldere Väsjohne ennjeschloßße.",
"apihelp-login-param-name": "Metmaacher_Nahme.",
"apihelp-login-param-password": "Paßwoot.",
"apihelp-login-param-domain": "De Domaijn (kann fott bliehve)",
"apihelp-login-example-login": "Enlogge.",
+ "apihelp-logout-description": "Donn ußlogge un maach de Dahte övver de Sezong fott.",
"apihelp-logout-example-logout": "Donn dä aktoälle Metmaacher ußlogge.",
+ "apihelp-managetags-description": "Verwalldongsaufjahbe em Zersammehang met Makkehronge vun Änderonge donn.",
+ "apihelp-managetags-param-reason": "Ene Jrond för et Aanlähje, Fottschmiiße, Aanschallde un Ußschallde vun dä Makkehrong, dä mer ävver nit aanjävve moß.",
+ "apihelp-managetags-param-ignorewarnings": "Ov alle Warnonge övverjange wähde sulle, di bei dämm Opdracht opkumme.",
+ "apihelp-managetags-example-create": "Donn en Makkehrong aanlähje mem Nahme „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">spam</kbd>“ mem Jrond „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">For use in edit patrolling</kbd>“.",
+ "apihelp-managetags-example-delete": "Schmiiß de Makkehrong mem Nahme „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">vandlaism</kbd>“ fott mem Jrond „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Misspelt</kbd>“.",
+ "apihelp-managetags-example-activate": "Donn en Makkehrong aktevehre mem Nahme „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">spam</kbd>“ mem Jrond „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">For use in edit patrolling</kbd>“.",
+ "apihelp-managetags-example-deactivate": "Donn en Makkehrong mem Nahme „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">spam</kbd>“ nit mieh aktihv maache, mem Jrond „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">For use in edit patrolling</kbd>“.",
"apihelp-move-description": "Donn en Sigg ömbenänne",
+ "apihelp-move-param-from": "De Övverschreff vun dä Sigg zom Ömbenänne. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1fromid</var>“ bruche.",
+ "apihelp-move-param-fromid": "De ännong vun dä Sigg zom Ömbenänne. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1from</var>“ bruche.",
"apihelp-move-param-to": "De neue Övverschreff för di Sigg drop ömzebenänne.",
"apihelp-move-param-reason": "Der jrond för di Sigg ömzebenänne.",
"apihelp-move-param-movetalk": "Donn de Klaafsigg ömbenänne, wann et se jitt.",
@@ -116,18 +214,45 @@
"apihelp-opensearch-param-search": "Noh wat söhke?",
"apihelp-opensearch-param-limit": "De hühßte Aanzahl vun Äjeebnesse för zeröck ze jävve",
"apihelp-opensearch-param-namespace": "En wällschem Appachtemang söhke.",
- "apihelp-opensearch-param-redirects": "How to handle redirects:\n;return:Return the redirect itself.\n;resolve:Return the target page. May return fewer than $1limit results.\nFor historical reasons, the default is \"return\" for $1format=json and \"resolve\" for other formats.\n<!-- \nhttps://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-opensearch-param-redirects/en\n-->",
+ "apihelp-opensearch-param-suggest": "Don nix wann „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var>“ op „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">false</code>“ jesaz es.",
+ "apihelp-opensearch-param-redirects": "Wi met Ömleidonge ömjonn?\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">return</code>:Jivv de Ömleidonge sällver uß.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">resolve</code>:Jiff de Sigg uß, woh de Ömleidong hen jeiht. Dat künnt winnijer wi „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1limit</code>“ Sigge ußjävve.\nTradizonäll es dä Schtandatt „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">return</code>“ för „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1format=json</code>“ un „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">resolve</code>“ för alle anndere.",
"apihelp-opensearch-param-format": "Et Fommaht zom Ußjävve.",
+ "apihelp-opensearch-param-warningsaserror": "Wann Warnonge opkumme met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">format=json</kbd>“, dann donn ene Fähler vum <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> ußjävve anschtat se ze övverjonn.",
"apihelp-opensearch-example-te": "Fengk Sigge, di met <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Te</kbd> aanfange.",
"apihelp-options-param-reset": "Säz de Enschtällonge op dem Wikki singe Standatt.",
- "apihelp-options-example-reset": "Alle enschtälloonge retuur schtälle.",
+ "apihelp-options-param-optionname": "Dä Nahme vun ene Enschtällong, di op dä Wäät jesaz wähde sulle, dä „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1optionvalue</var>“ aanjitt.",
+ "apihelp-options-param-optionvalue": "Dä Wäät vun dä Enschtällong, di vun „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1optionname</var>“ aanjejovve weed. Kann Sänkrääschte Schresche („|“) ännthallde.",
+ "apihelp-options-example-reset": "Alle Enschtälloonge retuhr schtälle.",
+ "apihelp-options-example-change": "Donn de „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">skin</kbd>“ un „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">hideminor</kbd>“ Enschtällonge ändere.",
+ "apihelp-options-example-complex": "Donn alle Enschtällonge op der Schtandatt säze, dann säz „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">skin</kbd>“ un „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">nickname</kbd>“.",
"apihelp-paraminfo-description": "Holl Aanjahbe övver dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> ier Moduhle.",
"apihelp-paraminfo-param-helpformat": "Et Fommaht vun de Täxe för Hölp.",
- "apihelp-paraminfo-param-formatmodules": "Leß met de Nahme vun de Moduhle zom Fommatehre (Wäät vum „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">format</var>“-Parramehter). Nemm schtatt dämm „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1modules</kbd>“.",
+ "apihelp-paraminfo-param-formatmodules": "Leß met de Nahme vun de Moduhle zom Fommatehre (Wäät vum „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">format</var>“-Parramehter). Nemm schtatt dämm „<varlang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1modules</var>“.",
"apihelp-paraminfo-example-1": "Zisch Aanjahbe övver <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Special:ApiHelp/parse|action=parse]]</kbd>, <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>, <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd>, un <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd>.",
"apihelp-parse-param-summary": "De Zersammefaßong för ze pahse.",
+ "apihelp-parse-param-redirects": "Wann „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1page</var>“ udder „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</var>“ obb_en Ömleijdong jesaz es, donn dä follje.",
+ "apihelp-parse-param-prop": "Wat för en Schtöker aan Ennfommazjuhne holle:",
+ "apihelp-parse-paramvalue-prop-text": "Jitt dä jepahßde Täx vum Wikkitäx uß.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Jitt de Schprohche-Lengks em jepahßde Wikkitäx uß.",
+ "apihelp-parse-paramvalue-prop-categories": "Jitt de Saachjroppe em jepahßde Wikkitäx uß.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Jitt de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Markup Language\">HTML</i>-Fazung vun de Saachjroppe us.",
+ "apihelp-parse-paramvalue-prop-links": "Jitt de entärne Lengks em jepahßde Wikkitäx uß.",
+ "apihelp-parse-paramvalue-prop-templates": "Jitt de Schablohne em jepahßde Wikkitäx uß.",
+ "apihelp-parse-paramvalue-prop-images": "Jitt de Belder em jepahßde Wikkitäx uß.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Jitt de Lengks, di noh ußerhallev vum Wikki jonn, em jepahßde Wikkitäx uß.",
+ "apihelp-parse-paramvalue-prop-sections": "Jitt de Affschnedde em jepahßde Wikkitäx uß.",
+ "apihelp-parse-paramvalue-prop-revid": "Deiht de Kännong vun de Väsjohn vun dä jepahßde Sigg derbei.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Deiht de Övverschreff vum jepahßde Wikkitäx derbei.",
+ "apihelp-parse-paramvalue-prop-modules": "Jitt dem <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Delivery system in MediaWiki for the optimized run-time loading and managing of modules\">ResourceLoader</i> sing Moduhle uß, di en dä Sigg jebruch wähde. Äntwehder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">jsconfigvars</kbd>“ udder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">encodedjsconfigvars</kbd>“ moß mer met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">modules</kbd>“ zesamme aanforrdere.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Livvert de Varrejahble vun dä Ennschtällonge vum JavaSkrep, di äxtra för heh di Sigg enjeschtallt sin.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "Jitt de Engewikkilengks em jepahßde Wikkitäx uß.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Jitt de der ojinahl Wikkitäx us, dä jepahß woode es.",
+ "apihelp-parse-paramvalue-prop-properties": "Jitt devärse Eijeschafte uß, di em jepahßde Wikkitäx faßjelaat woode sen.",
"apihelp-parse-param-section": "Holl blohß dann der Ennhalld vun däm Affschnett met dä Nommer, udder wann „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">new</kbd>“ enjejovve es, maach ene neu Affschnett derbei.",
"apihelp-parse-param-sectiontitle": "De Övverschreff för dä neuje Afschnet, wann <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">section</var> = <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">new</kbd> es.\n\nAnders wi beim Beärbeide vun dä Sigg weed dä Parramehter nit dorsch de <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">summary</var> ußjetuusch, wann hä fottjelohße udder läddesch es.",
+ "apihelp-parse-param-disablelimitreport": "Jiff keine Bereesch vum Vüürbereijde zom Paase (der „<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">NewPP limit report</i>“) mem Paaser singe Dahte zosamme uß.",
+ "apihelp-parse-param-disableeditsection": "Donn de Lenks för Affschnedde ze änndere en de Ußjahbe vum Paaser eruß lohße.",
+ "apihelp-parse-param-disabletoc": "Donn et Ennhaldsverzeijscheneß en de Ußjahbe vottlohße.",
"apihelp-parse-example-page": "Donn en Sigg pahse.",
"apihelp-parse-example-text": "Donn Wikkitäx pahse.",
"apihelp-parse-example-texttitle": "Donn Wikkitäx pahse, un jiff derför en Övverschreff för en Sigg aan.",
@@ -141,15 +266,28 @@
"apihelp-protect-param-title": "De Övverschreff vun dä Sigg zom Schöze udder Freijävve. Kam_mer nit zesamme met\n„<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</code>“ bruche.",
"apihelp-protect-param-pageid": "De Kännong vun dä Sigg zom Schöze udder Freijävve. Kam_mer nit zesamme met\n„<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</code>“ bruche.",
"apihelp-protect-param-reason": "Der Jrond för et Schöze udder Freijävve.",
+ "apihelp-protect-param-cascade": "Donn en Schotz-Kaskahd zohlohße, alsu ene Schoz för ennjeföhschte Schablohne un upjerohfe Bellder vun dä Sigg. Deiht nix, wann keine von dä aanjejovve Zoote Schoz en Kaskahd zohlöht.",
"apihelp-protect-example-protect": "Donn en Sigg schöze.",
+ "apihelp-purge-param-forcelinkupdate": "Bräng de Tabälle met de lengks obb ene neue Schtand.",
+ "apihelp-purge-example-simple": "Donn fö de Sigge „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ un „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">API</kbd>“ de zweschejeschpeijscherte Väsjohn fottschmiiße.",
+ "apihelp-purge-example-generator": "Donn fö de eezte zehn Sigge em Schtanndadd_Appachtemang de zweschejeschpeijscherte Väsjohn fottschmiiße.",
+ "apihelp-query-param-prop": "Wat för en Eijeschaffte holle för de affjerohchte Sigge.",
"apihelp-query-param-list": "Wat för en Leßte holle.",
- "apihelp-query-param-meta": "Wat för en Matta_Dahte ze holle.",
+ "apihelp-query-param-meta": "Wat för en Metta_Dahte ze holle.",
+ "apihelp-query-param-rawcontinue": "Jivv Rühdahte „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">query-continue</var>“ för et Wigger Maache us.",
+ "apihelp-query-example-allpages": "Holl Väsjohne vun Sigge, di met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">API</kbd>“ bejenne.",
"apihelp-query+allcategories-description": "Alle Saachjroppe opzälle.",
"apihelp-query+allcategories-param-from": "De Saachjropp, vun woh aan opzälle.",
"apihelp-query+allcategories-param-to": "De Saachjropp, bes woh hen opzälle.",
+ "apihelp-query+allcategories-param-prefix": "Söhk noh Saachjroppe, woh de Övverschrevv esu aanfängk.",
"apihelp-query+allcategories-param-dir": "De Reijefollsch zum Zotehre.",
+ "apihelp-query+allcategories-param-min": "Jiff blohß Saachjroppe us, di winneschsdens esu vill Metjlehder han.",
+ "apihelp-query+allcategories-param-max": "Jiff blohß Saachjroppe us, di et mihts esu vill Metjlehder han.",
"apihelp-query+allcategories-param-limit": "Wi vell Saachjroppe ußjävve?",
- "apihelp-query+allcategories-param-prop": "Which properties to get:\n;size:Adds number of pages in the category.\n;hidden:Tags categories that are hidden with _&#95;HIDDENCAT_&#95;.\n<!-- \nhttps://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-query%2Ballcategories-param-prop/ksh\n-->",
+ "apihelp-query+allcategories-param-prop": "Wat för en Eijeschaffte holle:",
+ "apihelp-query+allcategories-paramvalue-prop-size": "Deiht de Aanzahl Sigge en dä Saachjropp derbei.",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "Makehrt de veschtoche Sachjroppe met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">_&#95;HIDDENCAT_&#95;</code>“.",
+ "apihelp-query+allcategories-example-generator": "Holl Ennfommazjuhne övver di Saaachjroppe_Sigg för Saachjroppe, di met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">List</kbd>“ bejenne.",
"apihelp-query+alldeletedrevisions-description": "Donn alle fottjeschmeße Väsjohne vun enem Metmaacher udder en enem Appachemang opleßte.",
"apihelp-query+alldeletedrevisions-paraminfo-useronly": "Kam_mer blohß met <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$3user</var> bruche.",
"apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "Kam_mer nit met <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$3user</var> bruche.",
@@ -158,42 +296,64 @@
"apihelp-query+alldeletedrevisions-param-from": "Bejenn de Leß bei heh dä Överschreff.",
"apihelp-query+alldeletedrevisions-param-to": "Hühr de Leß bei heh dä Överschreff oop.",
"apihelp-query+alldeletedrevisions-param-prefix": "Söhk noh Sigge, woh de Övverschrevv esu aanfängk.",
+ "apihelp-query+alldeletedrevisions-param-tag": "Donn blohß Väsjohne met heh dä Makkehrong opleßte.",
"apihelp-query+alldeletedrevisions-param-user": "Donn blohß Väsjohne vun heh däm Metmaacher opleßte.",
"apihelp-query+alldeletedrevisions-param-excludeuser": "Donn kein Väsjohne vun heh däm Metmaacher opleßte.",
- "apihelp-query+alldeletedrevisions-param-namespace": "Donn blohß Siegg en heh däm Appachtemang opleßte.",
- "apihelp-query+alldeletedrevisions-param-generatetitles": "Wann als ene Jenerahtor enjesaz, bräng Övverschreffte un kein Kännonge vu Väsjohne.",
+ "apihelp-query+alldeletedrevisions-param-namespace": "Donn blohß Sigge en heh däm Appachtemang opleßte.",
+ "apihelp-query+alldeletedrevisions-param-generatetitles": "Wann als ene Jenerahtor enjesaz, brängk dat Övverschreffte un kein Kännonge vun Väsjohne.",
"apihelp-query+alldeletedrevisions-example-user": "Donn de läzde fuffzisch fottjeschmeße Beijdrähsch vim Metmaacher „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Example<kbd>“ opleste.",
"apihelp-query+alldeletedrevisions-example-ns-main": "Donn de läzde fuffzisch fottjeschmeße Väsjohne em Houp-Appachemang opleste.",
"apihelp-query+allfileusages-description": "Donn alle Dattei_Oprohfe opleste, och vun Datteije, di (noch) nit doh sin.",
"apihelp-query+allfileusages-param-from": "De Övverschreff vun dä Dattei, woh de Leß medd aanfange sull.",
"apihelp-query+allfileusages-param-to": "De Övverschreff vun dä Dattei, woh de Leß medd ophühre sull.",
"apihelp-query+allfileusages-param-prefix": "Söhk noh alle Övverschreffte, di met heh däm Täx aanfange.",
- "apihelp-query+allfileusages-param-unique": "Donn blohß ongerscheidlijje Övverschreffte vun Datteije aanzeije. Kammer nit zesamme met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prop=ids<code>“ bruche.\nWann als ene Jenerahtor enjesaz, bräng Zihlsigge un kein Kwällsigge.",
- "apihelp-query+allfileusages-param-prop": "Which pieces of information to include:\n;ids:Adds the page ID of the using page (cannot be used with $1unique).\n;title:Adds the title of the file.\n<!-- \nhttps://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-query%2Ballfileusages-param-prop/ksh\n-->",
+ "apihelp-query+allfileusages-param-unique": "Donn blohß ongerscheidlijje Övverschreffte vun Datteije aanzeije. Kammer nit zesamme met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prop=ids<code>“ bruche.\nWann als ene Jenerahtor ennjesaz, brängk et Zihlsigge, un kein Kwällesigge.",
+ "apihelp-query+allfileusages-param-prop": "Wat för en Aanjahbe ennschlehße:",
+ "apihelp-query+allfileusages-paramvalue-prop-ids": "Deiht de Kännonge vun dä Sigge derbei, di dat bruche. Kam_mer nit zersamme met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1unique</code>“ bruche.",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "Deiht dä Dattei ehr Övverschreff derbei.",
"apihelp-query+allfileusages-param-limit": "Wi vill sulle överhoup aanjezeisch wähde?",
"apihelp-query+allfileusages-param-dir": "En wälsche Reijefollsch?",
"apihelp-query+allfileusages-example-B": "Donn Övverschreffte vun Datteije aanzeije, och vun Datteije, di (noch) nit doh sin, zesame met dä Kännonge vun dä Sigge, woh se vun sin, aanjevange vun <kbd>B</kbd>.",
"apihelp-query+allfileusages-example-unique": "Donn ongerscheidlejje Övverschreffte vun Datteije opleßte.",
+ "apihelp-query+allfileusages-example-unique-generator": "Hollt alle Övverschreffte vun Datteije, un makehr di (noch) nit doh sin.",
"apihelp-query+allfileusages-example-generator": "Holl Sigge, woh Datteieje dren vorkumme.",
"apihelp-query+allimages-description": "Donn alle Bellder der Reih noh opzälle.",
"apihelp-query+allimages-param-sort": "De Eijeschavv öm dernoh ze zottehre.",
"apihelp-query+allimages-param-dir": "En wälsche Reijefollsch?",
+ "apihelp-query+allimages-param-minsize": "Bejränz op Sigge met winneschßdens esu vill Bytes dren.",
+ "apihelp-query+allimages-param-maxsize": "Bejränz op Sigge met hüüschßdens esu vill Bytes dren.",
+ "apihelp-query+allimages-param-sha1": "Dam Bld sing <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"secure hash algorithm\">SHA-1</i>-Pröhvsomm. Övverjeiht „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sha1base36</code>“.",
+ "apihelp-query+allimages-param-sha1base36": "Däm Beld sing <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"secure hash algorithm\">SHA-1</i>-Pröhvsomm op dä bahses 36. Weed em Mehdiajwikki jebruch.",
+ "apihelp-query+allimages-param-user": "Jiv blohß de Datteije uß, di vun heh däm Metmaacher huh jelahde wohde sin. Kam_mer blohß met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sort=timestamp</code>“ bruche. Kam_mer nit met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1filterbots</code>“ zersamme bruche.",
+ "apihelp-query+allimages-param-filterbots": "Wi mer blohß de Datteije ußjitt, di vun Bots huh jelahde wohde sin. Kam_mer blohß met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sort=timestamp</code>“ bruche. Kam_mer nit met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1user</code>“ zersamme bruche.",
+ "apihelp-query+allimages-param-mime": "Wat för ene <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Multi-Purpose Internet Mail Extensions\">MIME</i>-Zoot ze Söhke, för e Beijschpell „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">image/jpeg</kbd>“.",
"apihelp-query+allimages-param-limit": "Wi vell Bellder ennsjesamp ußjävve.",
+ "apihelp-query+allimages-example-B": "Zeisch en Leß met Sigge un bejenn mem Bohchschtabe <kbd>B</kbd>.",
+ "apihelp-query+allimages-example-recent": "Zeijsch en Leß met de köözlesch huhjelahde Datteije, ähnlesch wi en [[Special:NewFiles]].",
+ "apihelp-query+allimages-example-mimetypes": "Zeijsch en Leß met dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Multi-Purpose Internet Mail Extensions\">MIME</i>-Zoote „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">image/png</kbd>“ udder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">image/gif</kbd>“.",
"apihelp-query+allimages-example-generator": "Zeisch Aanjahbe övver veer Bellder un bejenn mem Bohchschtabe <kbd>T</kbd>.",
"apihelp-query+alllinks-description": "Donn alle Lengk opzälle, di en e beschtemmpt Appachtemang jonn.",
"apihelp-query+alllinks-param-from": "De Övverschreff vun däm Lengk, woh de Leß medd aanfange sull.",
"apihelp-query+alllinks-param-to": "De Övverschreff vun dä Dattei, woh et Zälle ophühre sull.",
"apihelp-query+alllinks-param-prefix": "Söhk noh alle verlengk Övverschreffte, di met heh däm Täx aanfange.",
+ "apihelp-query+alllinks-param-unique": "Zeijsch blohß de ongerscheidlijje verlengk Sigge ier Övverschreffte. Kam_mer nit zesamme met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prop=ids</code>“ bruche. Wam_mer et als ene Jenerahtor bruche deiht, kritt mer Zihlsiggge anschtatt vun Quällesigge.",
+ "apihelp-query+alllinks-param-prop": "Wat för en Aanjahbe ennschlehße:",
+ "apihelp-query+alllinks-paramvalue-prop-ids": "Deiht de Kännonge vun dä Sigge met däm Lengk derbei. Kam_mer nit zersamme met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1unique</code>“ bruche.",
+ "apihelp-query+alllinks-paramvalue-prop-title": "Deiht däm lengk sing Övverschreff derbei.",
"apihelp-query+alllinks-param-namespace": "Dat Appachtemang zom opzälle.",
"apihelp-query+alllinks-param-limit": "Wi vill sulle överhoup aanjezeisch wähde?",
"apihelp-query+alllinks-param-dir": "En wälsche Reijefollsch?",
+ "apihelp-query+alllinks-example-B": "Donn Övverschreffte aanzeije, woh Lengks drop jonnn, och di (noch) nit doh sin, zesame met dä Kännonge vun dä Sigge, woh se vun sin, aanjevange vun <kbd>B</kbd>.",
"apihelp-query+alllinks-example-unique": "Leß ongerscheidlejje verlengk Övverschreffte.",
- "apihelp-query+alllinks-example-generator": "Holl Sigge, di di Lengks änthallde.",
+ "apihelp-query+alllinks-example-unique-generator": "Hollt alle Övverschreffte, woh Lengks drop jonnn un makehr di (noch) nit doh sin.",
+ "apihelp-query+alllinks-example-generator": "Holl Sigge, di Lengks änthallde.",
"apihelp-query+allmessages-description": "Donn em Wikki sing Täxte un Nohreescht ußjävve.",
+ "apihelp-query+allmessages-param-messages": "Wat för en Täxte un Nohreeschte usjävve. Der Schtandatt „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">*</kbd>“ bedügg alle Täxte un Nohreeschte.",
"apihelp-query+allmessages-param-prop": "Wat för en Eijeschaffte holle.",
+ "apihelp-query+allmessages-param-nocontent": "Wann dat ennjeschalld es, donn dä ennhalt vun de Täxte un Nohreeschte nit medd ußjävve.",
"apihelp-query+allmessages-param-args": "De Parramehtere för en dä Täx udder en di Nohreesch enzeföhje.",
"apihelp-query+allmessages-param-filter": "Jiv blohß de Täxte un Nohreesche uß, woh heh dat Täxschtöck dren änthallde es.",
- "apihelp-query+allmessages-param-customised": "Jiv bloß de Täxte un Nohreesche en heh däm Zohschtand uß.",
+ "apihelp-query+allmessages-param-customised": "Jiv bloß de Täxte un Nohreesche en heh däm jewönschte Aanpaßongs_Zohschtand uß.",
"apihelp-query+allmessages-param-lang": "Jiv de Täxte un Nohreesche en heh dä Schprohch uß.",
"apihelp-query+allmessages-param-from": "Jiv de Täxte un Nohreesche vun heh aan uß.",
"apihelp-query+allmessages-param-to": "Jiv de Täxte un Nohreesche bes heh uß.",
@@ -209,24 +369,39 @@
"apihelp-query+allpages-param-minsize": "Bejränz op Sigge met winneschßdens esu vill Bytes dren.",
"apihelp-query+allpages-param-maxsize": "Bejränz op Sigge met hüüschßdens esu vill Bytes dren.",
"apihelp-query+allpages-param-prtype": "Bejränz op jeschöz Sigge.",
- "apihelp-query+allpages-param-limit": "Wi vill Sigge zen aanzeije?",
+ "apihelp-query+allpages-param-limit": "Wi vill Sigge zem aanzeihje?",
"apihelp-query+allpages-param-dir": "En wälsche Reijefollsch?",
+ "apihelp-query+allpages-param-filterlanglinks": "Blohß Sigge met Schprohchelengks opleßte. Opjepaß: Dat künnt Schprohchelengks övverjonn, di vun Zohsazprojramme beijschtührt wohde sin.",
"apihelp-query+allpages-example-B": "Zeisch en Leß met Sigge un bejenn mem Bohchschtabe <kbd>B</kbd>.",
"apihelp-query+allpages-example-generator": "Zeisch Aanjahbe övver veer Bellder un bejenn mem Bohchschtabe <kbd>T</kbd>.",
"apihelp-query+allpages-example-generator-revisions": "Zeisch der Enhalld vu de eetsde zwai Sigg un bejenn bei <kbd>Re</kbd>.",
"apihelp-query+allredirects-description": "Alle Ömleidonge op e beschtemmp Appachtemang opleßte.",
"apihelp-query+allredirects-param-from": "De Övverschreff vun dä Ömleidong, woh de Leß medd ophühre sull.",
"apihelp-query+allredirects-param-to": "De Övverschreff vun dä Sigg, woh et Zälle ophühre sull.",
- "apihelp-query+allredirects-param-prefix": "Söhk not sigge, die esu aanfange.",
+ "apihelp-query+allredirects-param-prefix": "Söhk not Sigge, di esu aanfange.",
+ "apihelp-query+allredirects-param-unique": "Zeijsch blohß de ongerscheidlijje Zihl_Sigg. Kam_mer nit zesamme met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prop=ids|fragment|interwiki</code>“ bruche. Wam_mer et als ene Jenerahtor bruche deiht, kritt mer Zihlsiggge anschtatt vun Quällesigge.",
+ "apihelp-query+allredirects-paramvalue-prop-title": "Deiht dä Ömleijdong ehr Övverschreff derbei.",
"apihelp-query+allredirects-param-namespace": "Dat Appachtemang zom opzälle.",
"apihelp-query+allredirects-param-limit": "Wi vill sulle överhoup aanjezeisch wääde?",
"apihelp-query+allredirects-param-dir": "En wälsche Reijefollsch?",
"apihelp-query+allredirects-example-B": "Zeisch Zihlsigge, och di et (noch) nit jitt, met dä Kännonge, wo se her sin, un bejenn mem Bohchschtabe <kbd>B</kbd>.",
"apihelp-query+allredirects-example-unique": "Ongerscheidlijje Sigge opleste.",
+ "apihelp-query+allredirects-example-unique-generator": "Hollt alle Zihlsigge un makkehr di (noch) nit doh sin.",
"apihelp-query+allredirects-example-generator": "Holl de Sigge met de Ömleidonge.",
+ "apihelp-query+alltransclusions-param-from": "De Övverschreff vun dä ennjeföhschte Sigg, woh de Leß medd aanfange sull.",
+ "apihelp-query+alltransclusions-param-to": "De Övverschreff vun dä ennjeföhschte Sigg, woh et Zälle ophühre sull.",
+ "apihelp-query+alltransclusions-param-prefix": "Söhk noh alle dä ennjeföhschte Sigge ier Övverschreffte, di met heh däm Täx aanfange.",
+ "apihelp-query+alltransclusions-param-unique": "Zeijsch blohß de ongerscheidlijje ennjeföhschte Sigge ier Övverschreffte. Kam_mer nit zesamme met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prop=ids</code>“ bruche. Wam_mer et als ene Jenerahtor bruche deiht, kritt mer Zihlsiggge anschtatt vun Quällesigge.!FUZZY!!",
+ "apihelp-query+alltransclusions-param-prop": "Wat för en Aanjahbe ennschlehße:",
+ "apihelp-query+alltransclusions-paramvalue-prop-ids": "Deiht de Kännonge vun dä Sigg derbei, di dat bruch. Kam_mer nit zersamme met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1unique</code>“ bruche.",
+ "apihelp-query+alltransclusions-paramvalue-prop-title": "Deiht de Övverschreff vun dä jebruchte Sigg derbei.",
"apihelp-query+alltransclusions-param-namespace": "Dat Appachtemang zom opzälle.",
"apihelp-query+alltransclusions-param-limit": "Wi vill sulle överhoup aanjezeisch wähde?",
"apihelp-query+alltransclusions-param-dir": "En wälsche Reijefollsch?",
+ "apihelp-query+alltransclusions-example-B": "Donn Övverschreffte aanzeije, och vun Sigge, di (noch) nit doh sin, zesame met dä Kännonge vun dä Sigge, woh se vun sin, aanjevange vun <kbd>B</kbd>.",
+ "apihelp-query+alltransclusions-example-unique": "Donn de Övverschreffte vun ennjeföhschte Sigge opleßte, ävver jehde blohß eijmohl.",
+ "apihelp-query+alltransclusions-example-unique-generator": "Hollt alle Övverschreffte vun ennjeföhschte Sigge, un makehr di (noch) nit doh sin.",
+ "apihelp-query+alltransclusions-example-generator": "Holl Sigge, di Ennföhjonge änthallde.",
"apihelp-query+allusers-description": "Donn alle aanjemälldte Metmaacher opzälle.",
"apihelp-query+allusers-param-from": "Dä Metmaacher_Nahme vun woh aan opzälle.",
"apihelp-query+allusers-param-to": "Dä Metmaacher_Nahme bes woh hen opzälle.",
@@ -234,72 +409,502 @@
"apihelp-query+allusers-param-dir": "De Reijefollsch zum Zotehre.",
"apihelp-query+allusers-param-group": "Donn blohß Metmaacher uß dä aanjejovve Jroppe enschlehße.",
"apihelp-query+allusers-param-excludegroup": "Donn keine Metmaacher uß dä aanjejovve Jroppe enschlehße.",
+ "apihelp-query+allusers-param-prop": "Wat för en Aanjahbe med enzschlehße:",
+ "apihelp-query+allusers-paramvalue-prop-rights": "De Rääschde vn däm Memaacher.",
+ "apihelp-query+allusers-paramvalue-prop-editcount": "Donn de Aanzahl Änderonge derbei, di dä Metmaacher em Wikki jemaat hät.",
"apihelp-query+allusers-param-limit": "Wi vill Nahme Metmaacher sulle mer krijje?",
"apihelp-query+allusers-param-witheditsonly": "Blohß Metmahcher, di och ens jät verändert han.",
"apihelp-query+allusers-param-activeusers": "Donn blohß Metmaacher opleßte, di {{PLURAL:$1|der läzde Daach|en de läzde $1 Dääsch|keine läzde Daach}} aktihf wohre.",
"apihelp-query+allusers-example-Y": "Monn metmaacher opleßte, woh de Nahme vun met <kbd>Y</kbd> aanfange.",
"apihelp-query+backlinks-description": "Fengk alle Sigge, di op de aanjejovve Sigg lengke.",
+ "apihelp-query+backlinks-param-title": "De Övverschreff för noh ze Söhke. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</var>“ bruche.",
+ "apihelp-query+backlinks-param-pageid": "De Känong vun dä Sigg zom Söhke. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1title</var>“ bruche.",
"apihelp-query+backlinks-param-namespace": "Dat Appachtemang zom opzälle.",
"apihelp-query+backlinks-param-dir": "En wälsche Reijefollsch?",
+ "apihelp-query+backlinks-param-limit": "Wi vill Sigge ensjesamp ußjävve. Wann „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1redirect</var>“ ennjeschalld es, weed di Beschrängkong op jehden Nivoh äxtra aanjwandt, wat bedügg, dat bes op 2 * „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1limit</var> ußjejovve wähde künne.",
+ "apihelp-query+backlinks-param-redirect": "Wann de Sigg met dämm Lengk dren en Ömleijdong änthält, fengk derzoh och alle Sigge, di doh drop lengke. De Bovverjränz för de Aanzahl Sigge för opzeleßte weed hallbehrt.",
"apihelp-query+backlinks-example-simple": "Zeijsch Lengks op de Sigg <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main page<kbd>.",
+ "apihelp-query+backlinks-example-generator": "Holl Ennfommazjuhne övver Sigge, di op de Sigg „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</code>“ lengke donn.",
+ "apihelp-query+blocks-description": "Donn alle jeschpächte Metmaacher un <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße opleßte.",
"apihelp-query+blocks-param-start": "Et Dattom un de Zigg vun woh aff opjezallt wähde sull.",
"apihelp-query+blocks-param-end": "Et Dattom un de Zigg bes woh hen opjezallt wähde sull.",
+ "apihelp-query+blocks-param-ids": "Leß vun dä Kännonge vun Schpärre för dernoh ze söhke. Kann fott blihve.",
+ "apihelp-query+blocks-param-users": "Leß vun dä Metmaacher för dernoh ze söhke. Kann fott blihve.",
+ "apihelp-query+blocks-param-ip": "Holl alle Schpärre för heh di <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräß udder heh dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Classless Inter-Domain Routing\">CIDR</i>-Berätt, och Schpärre vun Berätte. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$3users</var>“ bruche. <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Classless Inter-Domain Routing\">CIDR</i>-Berätte vun mieh wi <code dir=\"ltr\">IPv4/$1</code> udder <code dir=\"ltr\">IPv6/$2</code> wähde nit aanjenumme.",
"apihelp-query+blocks-param-limit": "De hühßde Aanzahl Spärre zom opleste.",
- "apihelp-query+blocks-param-prop": "Which properties to get:\n;id:Adds the ID of the block.\n;user:Adds the username of the blocked user.\n;userid:Adds the user ID of the blocked user.\n;by:Adds the username of the blocking user.\n;byid:Adds the user ID of the blocking user.\n;timestamp:Adds the timestamp of when the block was given.\n;expiry:Adds the timestamp of when the block expires.\n;reason:Adds the reason given for the block.\n;range:Adds the range of IP addresses affected by the block.\n;flags:Tags the ban with (autoblock, anononly, etc.).\n<!-- \nhttps://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-query%2Bblocks-param-prop/ksh\n-->",
+ "apihelp-query+blocks-param-prop": "Wat för en Eijeschaffte holle:",
+ "apihelp-query+blocks-paramvalue-prop-id": "Deiht dä Spärr iehr Kännonge derbei.",
+ "apihelp-query+blocks-paramvalue-prop-user": "Deiht dä Nahme vom jeschpächte Metmaacher derbei.",
+ "apihelp-query+blocks-paramvalue-prop-userid": "Deiht de Kännong vum jeschpächte Metmaacher derbei.",
+ "apihelp-query+blocks-paramvalue-prop-by": "Deiht dä Nahme vun däm Metmaacher derbei, dä jeschpächt hät.",
+ "apihelp-query+blocks-paramvalue-prop-byid": "Deiht de Kännong vun däm Metmaacher derbei, dä jeschpächt hät.",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "Deihd et Dattum un de Uhrzigg derbei, wann jeschpächt wood.",
+ "apihelp-query+blocks-paramvalue-prop-expiry": "Deihd et Dattum un de Uhrzigg derbei, wann di Schparr eröm es.",
+ "apihelp-query+blocks-paramvalue-prop-reason": "Deiht der Jrond för di Schparr derbei.",
+ "apihelp-query+blocks-paramvalue-prop-range": "Deiht dä Berätt vun <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße för di Schparr derbei.",
+ "apihelp-query+blocks-paramvalue-prop-flags": "makkehrt di Spärr met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">autoblock</code>“, „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">anononly</code>“, un esu.",
"apihelp-query+blocks-example-simple": "Schpärre opleßte.",
"apihelp-query+blocks-example-users": "Donn de Schpärre vun dä Metmaacher <lang=\"en\" xml:lang=\"en\" dir=\"ltr\" kbd>Alice</kbd> un <lang=\"en\" xml:lang=\"en\" dir=\"ltr\" kbd>Bob</kbd> opleßte.",
"apihelp-query+categories-description": "Donn alle Saachjroppe epleßte, woh di Sigge dren sin.",
- "apihelp-query+categories-param-prop": "Which additional properties to get for each category:\n;sortkey:Adds the sortkey (hexadecimal string) and sortkey prefix (human-readable part) for the category.\n;timestamp:Adds timestamp of when the category was added.\n;hidden:Tags categories that are hidden with _&#95;HIDDENCAT_&#95;.\n<!-- \nhttps://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-query%2Bcategories-param-prop/ksh\n-->",
+ "apihelp-query+categories-param-prop": "Wat för en zohsäzlejje Eijeschaffte holle för jehde Saachjropp:",
+ "apihelp-query+categories-paramvalue-prop-sortkey": "Deiht dä Schlößel zom Zottehre vun dä Saachjropp derbei, en lange häxadezimahle Zahl, un der Schlößelvörsaz, woh ene Minsch jät med aanfange kann.",
+ "apihelp-query+categories-paramvalue-prop-timestamp": "Deihd en Dattom un en Zigg derbei, wann di Sachjrobb aanjelaat woode es.",
+ "apihelp-query+categories-paramvalue-prop-hidden": "Makehrt de veschtoche Sachjroppe met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">_&#95;HIDDENCAT_&#95;</code>“.",
"apihelp-query+categories-param-show": "Wat för en Zoot Saachjroppe zeije.",
"apihelp-query+categories-param-limit": "Wi vell Saachjroppe ußjävve?",
+ "apihelp-query+categories-param-categories": "Donn blohß heh di Saachjroppe opleßte. Dadd es johd, öm eruß ze fenge ovv en beschtemmpte Sigg en en beschtemmpte Saachjropp dren es.",
"apihelp-query+categories-param-dir": "En wälsche Reijefollsch?",
"apihelp-query+categories-example-simple": "Holl en Leß med alle Saachjroppe, woh di Sigg <kbd>Albert Einstein</kbd> dren es.",
"apihelp-query+categories-example-generator": "Holl Aanjahbe övver alle Saachjroppe, di en dä Sigg <kbd>Albert Einstein</kbd> jebruch wähde.",
"apihelp-query+categoryinfo-description": "Holl Aanjahbe övver de aanjejovve Saachjroppe.",
+ "apihelp-query+categoryinfo-example-simple": "Holl Enfomazjuhne övver „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Category:Foo</kbd>“ un „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Category:Bar</kbd>“.",
"apihelp-query+categorymembers-description": "Donn alle Sigge en ener aanjejove saachjrobb opleste.",
+ "apihelp-query+categorymembers-param-title": "Wat för en Sachjropp opzälle. Moß aanjejovve sin. Moß der Vörsaz „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">{{ns:category}}:</kbd>“ änthallde. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</var>“ bruche.",
+ "apihelp-query+categorymembers-param-pageid": "De Kännong vun dä Sigg zom opzälle. Kam_mer nit zersamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1title</var>“ bruche.",
+ "apihelp-query+categorymembers-param-prop": "Wat för en Aanjahbe med enzschlehße:",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "Deiht de Kännong vun de Sigge derbei.",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "Donn de Övverschrevv un de Kännong för et Appachtemang derbei.",
+ "apihelp-query+categorymembers-paramvalue-prop-timestamp": "Deihd et Dattum un de Uhrzigg derbei, wann di Sigg opjenumme wohd.",
"apihelp-query+categorymembers-param-limit": "De jrüüßte Zahl Sigge för ußzejävve.",
"apihelp-query+categorymembers-param-sort": "De Eijeschavv öm dernoh ze zottehre.",
"apihelp-query+categorymembers-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+categorymembers-param-starthexsortkey": "Der Zoteerschlößel för de Leß opzehühre, wi mer en met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prop=sortkey</kbd>“ kritt. Kann blohß met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sort=sortkey</kbd>“ jebruch wähde.",
+ "apihelp-query+categorymembers-param-endhexsortkey": "Der Zoteerschlößel för de Leß opzehühre, wi mer en met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1prop=sortkey</kbd>“ kritt. Kann blohß met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sort=sortkey</kbd>“ jebruch wähde.",
+ "apihelp-query+categorymembers-param-endsortkeyprefix": "Der Aanfang vun däm Zoteerschlößel för de Leß opzehühre. Opühre deiht se <strong>för</strong>, un nit <strong>met</strong> däm. Wann dä Wäät opdouch, weed hä nit med ußjejovve. Kann blohß met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sort=sortkey</code>“ jebruch wähde un överjeihd „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1endhexsortkey</code>“.",
"apihelp-query+categorymembers-param-startsortkey": "Söhk „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1starthexsortkey</code>“ schtatt dämm.",
"apihelp-query+categorymembers-param-endsortkey": "Söhk „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1endhexsortkey </code>“ schtatt dämm.",
"apihelp-query+categorymembers-example-simple": "Holl de eezde zehn Sigge de dä <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Category:Physics</kbd>.",
"apihelp-query+categorymembers-example-generator": "Holl anjahbe övver de eezde zehn Sigge de dä <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Category:Physics</kbd>.",
+ "apihelp-query+contributors-description": "Holl de Leß met de ennjelogg Schrihver un de Aanzahl nahmelohse Metschrihver aan ene Sigg.",
+ "apihelp-query+contributors-param-limit": "Wi vill Metschrihver ze livvere?",
+ "apihelp-query+contributors-example-simple": "Donn de Metschrihver aan dä Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">KMain PageBD</kbd>“ aanzeije.",
+ "apihelp-query+deletedrevisions-param-start": "Et Dattom un de Uhrzigg, von woh aan opzälle. Weed nit jebruch, wam_mer en Leß met Kännonge vun Väsjohne aam beärbeijde sin.",
+ "apihelp-query+deletedrevisions-param-end": "Et Dattom un de Uhrzigg, bes woh hen opzälle. Weed nit jebruch, wam_mer en Leß met Kännonge vun Väsjohne aam beärbeijde sin.",
+ "apihelp-query+deletedrevisions-param-tag": "Donn blohß Väsjohne met heh dä Makkehrong opleßte.",
"apihelp-query+deletedrevisions-param-user": "Donn blohß Väsjohne vun heh däm Metmaacher opleßte.",
"apihelp-query+deletedrevisions-param-excludeuser": "Donn kein Väsjohne vun heh däm Metmaacher opleßte.",
- "apihelp-query+deletedrevisions-param-limit": "De hühßde Aanzahl Väsjohne för opzeleßte.",
- "apihelp-query+deletedrevisions-param-prop": "Wat för en Eijeschaffte holle:\n;revid:Adds the revision ID of the deleted revision.\n;parentid:Adds the revision ID of the previous revision to the page.\n;user:Adds the user who made the revision.\n;userid:Adds the user ID who made the revision.\n;comment:Adds the comment of the revision.\n;parsedcomment:Adds the parsed comment of the revision.\n;minor:Tags if the revision is minor.\n;len:Adds the length (bytes) of the revision.\n;sha1:Adds the SHA-1 (base 16) of the revision.\n;content:Adds the content of the revision.\n;tags:Tags for the revision.\n<!-- \nhttps://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-query%2Bdeletedrevisions-param-prop/en\n-->",
"apihelp-query+deletedrevisions-example-revids": "Donn de Aanjahbe för de fottjeschmeße Väsjohn <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">123456</kbd> holle.",
+ "apihelp-query+deletedrevs-param-start": "Et Dattom un de Zigg vun woh aff opjezallt wähde sull.",
+ "apihelp-query+deletedrevs-param-end": "Et Dattom un de Zigg bes woh hen opjezallt wähde sull.",
+ "apihelp-query+deletedrevs-param-from": "Bejenn de Leß bei heh dä Överschreff.",
+ "apihelp-query+deletedrevs-param-to": "Hühr de Leß bei heh dä Överschreff oop.",
+ "apihelp-query+deletedrevs-param-prefix": "Söhk noh Sigge, woh de Övverschrevv esu aanfängk.",
+ "apihelp-query+deletedrevs-param-unique": "Donn blohß ein Väsjohn för jehde Sigg opleßte.",
+ "apihelp-query+deletedrevs-param-tag": "Donn blohß Väsjohne met heh dä Makkehrong opleßte.",
+ "apihelp-query+deletedrevs-param-user": "Donn blohß Väsjohne vun heh däm Metmaacher opleßte.",
+ "apihelp-query+deletedrevs-param-excludeuser": "Donn kein Väsjohne vun heh däm Metmaacher opleßte.",
+ "apihelp-query+deletedrevs-param-namespace": "Donn blohß Sigge en heh däm Appachtemang opleßte.",
+ "apihelp-query+deletedrevs-param-limit": "De hühßde Aanzahl Väsjohne för opzeleßte.",
+ "apihelp-query+deletedrevs-param-prop": "Wat för en Eijeschaffte holle:\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">revid</code>:Deiht de Kännong vun dä fottjeschmeße Väsjohn derbei.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">parentid</code>:Deiht de Kännong vun dä vörijje Väsjohn vun dä Sigg derbei.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">user</code>:Deiht dä Metmaacher derbei, dä di Väsjohn jemaat hät.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">userid</code>:Deiht de Kännong vun däm Metmaacher derbei, dä di Väsjohn jemaat hät.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">comment</code>:Deiht de koote Zesammefaßong vun dä Väsjohn derbei.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">parsedcomment</code>:Adds dä de jepaaste koote Zesammefaßong vun dä Väsjohn derbei.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">minor</code>:Tags, wann di Väsjohn en kleine Minni-Änderong wohr.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">len</code>:Deiht de Aanzahl <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Bytes</i> vun dä Väsjohn derbei.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">sha1</code>:Deiht dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"secure hash algorithm\">SHA-1 (base 16)</i> vun dä Väsjohn derbei.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">content</code>:Deiht dä Täx_Ennhalt vun dä Väsjohn derbei.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">token</code>:<span class=\"apihelp-deprecated\">Nit mih jewönsch.</span> Livvert de Makehrong vun dä Änderong.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">tags</code>:Makehronge vun dä Väsjohn.",
+ "apihelp-query+disabled-description": "Dat Moduhl för Frohre ze schtälle wohd affjeschalldt.",
+ "apihelp-query+duplicatefiles-description": "Donn alle Datteije opleßte, di desällve Prööfsomm han wi de aanjejovve Datteije.",
+ "apihelp-query+duplicatefiles-param-limit": "Wi vell datteije ußjävve.",
"apihelp-query+duplicatefiles-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+duplicatefiles-param-localonly": "Lohr blohß noh Datteije heh em Wikki.",
+ "apihelp-query+duplicatefiles-example-simple": "Lohr noh Datteije, di dubbelte vun dä Dattei „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[:File:Albert Einstein Head.jpg]]</code>“ sin.",
+ "apihelp-query+duplicatefiles-example-generated": "Lohr noh Dubbelte vun alle Datteije.",
+ "apihelp-query+embeddedin-description": "Fengk alle Sigge, di di aanjejovve Dattei enneschlehße.",
+ "apihelp-query+embeddedin-param-title": "De Övverschreff för noh ze Söhke. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</var>“ bruche.",
+ "apihelp-query+embeddedin-param-pageid": "De Känong vun dä Sigg zom noh Söhke. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1title</var>“ bruche.",
+ "apihelp-query+embeddedin-param-namespace": "Dat Appachtemang zom opzälle.",
"apihelp-query+embeddedin-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+embeddedin-param-filterredir": "Wi de Ömleijdonge ußzottehre?",
+ "apihelp-query+embeddedin-param-limit": "Wi vill Sigge ensjesammp zem ußjävve?",
+ "apihelp-query+embeddedin-example-simple": "Zeisch de Sigge, di di Schablohn „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Template:Stub</kbd>“ oprohfe.",
+ "apihelp-query+embeddedin-example-generator": "Holl Aanjahbe övve de Sigge, di di Schablohn „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Template:Stub</kbd>“ oprohfe.",
+ "apihelp-query+extlinks-description": "Jitt alle <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URLs</i> vun Lengks noh ußerhallef vum Wikki, ävver kein Engewiki_Lenks, vundä aanjejovve Sigge uß.",
+ "apihelp-query+extlinks-param-limit": "Wi vill Lengks ußjävve?",
+ "apihelp-query+extlinks-example-simple": "Holl en Leß met Lengks noh ußerhallef vum Wikki uß dä Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“.",
+ "apihelp-query+exturlusage-description": "Donn alle Sigge upzälle med däm aanjejovve<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i> dren.",
+ "apihelp-query+exturlusage-param-prop": "Wat för en Aanjahbe med enzschlehße:",
+ "apihelp-query+exturlusage-paramvalue-prop-ids": "Donn dä Sigg ier Kännong derbei.",
+ "apihelp-query+exturlusage-paramvalue-prop-title": "Donn de Övverschrevv un de Kännong för et Appachtemang derbei.",
+ "apihelp-query+exturlusage-paramvalue-prop-url": "Donn dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i> derbei, dä en dä Sigg jebruch weed.",
+ "apihelp-query+exturlusage-param-protocol": "Dat Schehma uß däm <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i>. Wann et läddesch jelohße es un „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1query</var>“ aanjejogge es, es dat Schehma „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Transfer Protocol\">http</kbd>“. Lohß beeds dat un „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">1query</var>“ läddesch, öm alle Lengks noh ußerhallef opzeleßte.",
+ "apihelp-query+exturlusage-param-namespace": "Dat appachtemang met dä Sigge zom opzälle.",
+ "apihelp-query+exturlusage-param-limit": "Wi vill Sigge zem ußjävve?",
+ "apihelp-query+filearchive-description": "Donn alle fottjeschmeße Datteije der Reih noh opzälle.",
+ "apihelp-query+filearchive-param-from": "De Övverschreff vun däm Beld, woh de Leß medd aanfange sull.",
+ "apihelp-query+filearchive-param-to": "De Övverschreff vun däm Beld, woh de Leß medd ophühre sull.",
+ "apihelp-query+filearchive-param-prefix": "Söhk noh alle Övverschreffte vun Bellder, di met heh dämm Wäät bejenne.",
+ "apihelp-query+filearchive-param-limit": "Wi vell Bellder ensjesamp zeröckjävve.",
"apihelp-query+filearchive-param-dir": "En wälsche Reijefollsch opleßte.",
+ "apihelp-query+filearchive-param-sha1": "Däm Beld singe <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"secure hash algorithm\">SHA-1</i>-Pröhvsomm. Övverjeiht „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1sha1base36</code>“.",
+ "apihelp-query+filearchive-param-sha1base36": "Däm Beld singe <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"secure hash algorithm\">SHA-1</i>-Pröhvsomm em 36-jer Zahlesüßtehm. Weed em Mehdiajwikki jebruch.",
+ "apihelp-query+filearchive-param-prop": "Wat för en Aanjahbe zom Beld holle:",
+ "apihelp-query+filearchive-paramvalue-prop-sha1": "Deiht dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"secure hash algorithm\">SHA-1 (base 16)</i> vun dä Väsjohn vn däm Beld derbei.",
+ "apihelp-query+filearchive-paramvalue-prop-timestamp": "Adds timestamp for the uploaded version.",
+ "apihelp-query+filearchive-paramvalue-prop-user": "Deiht dä Metmaacher derbei, dä di Väsjohn huhjelahde hät.",
+ "apihelp-query+filearchive-paramvalue-prop-size": "Deiht de Aanzahl <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Bytes</i> vun dä Dattei derbei, un, wann bikannt, de Hühde, de Wiggde, un de Aanzahl Sigge.",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "Et sällve, wi <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">size</code>.",
+ "apihelp-query+filearchive-paramvalue-prop-description": "Adds description för di Väsjohn vun däm Beld.",
+ "apihelp-query+filearchive-paramvalue-prop-parseddescription": "Parse the description för di Väsjohn vun däm Beld.",
+ "apihelp-query+filearchive-paramvalue-prop-mime": "Adds MIME vun däm Beld.",
+ "apihelp-query+filearchive-paramvalue-prop-mediatype": "Adds the media type vun däm Beld.",
+ "apihelp-query+filearchive-paramvalue-prop-metadata": "Deiht de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Exchangeable image file format\">EXIF</i>-Mettadahte för di Väsjohn vun däm Beld opleßte.",
+ "apihelp-query+filearchive-paramvalue-prop-bitdepth": "deiht de bit depth för di Väsjohn derbei.",
+ "apihelp-query+filearchive-paramvalue-prop-archivename": "Deiht dä Nahme vun dä Dattei vun dä Aschihf_Väsjohn för alle Väsjohne, bes op de läzde, derbei.",
+ "apihelp-query+filearchive-example-simple": "Zeijsch en leß met alle fottjeschmeße Datteije.",
+ "apihelp-query+filerepoinfo-example-simple": "Holl ennfommazjuhne övver de Reppossetohreje met Datteije.",
+ "apihelp-query+fileusage-description": "Fengk alle Sigge, di de aanjejovve Datteije bruche.",
+ "apihelp-query+fileusage-param-prop": "Wat för en Eijeschaffte holle:",
+ "apihelp-query+fileusage-paramvalue-prop-pageid": "De Kännong för jehde Sigg.",
+ "apihelp-query+fileusage-paramvalue-prop-title": "De Övverschreff för jehde Sigg.",
+ "apihelp-query+fileusage-paramvalue-prop-redirect": "Zeijsch aan, wann di Sigge en Ömleijdong es.",
+ "apihelp-query+fileusage-param-namespace": "Donn blohß Sigge en heh dä Appachtemangs metnämme.",
+ "apihelp-query+fileusage-param-limit": "Wi vill holle?",
+ "apihelp-query+fileusage-example-simple": "Holl Aanjahbe övver Sigge, di de Dattei „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[:File:Example.jpg]].</code>“ bruche.",
+ "apihelp-query+fileusage-example-generator": "Holl Aanjahbe övver Sigge, di de Dattei „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[:File:Example.jpg]].</code>“ bruche",
+ "apihelp-query+imageinfo-description": "Jidd Enfommazjuhne övver Datteije un de Verjangeheid vum Huhlahde aan.",
+ "apihelp-query+imageinfo-param-prop": "Wat för en Schtöker aan Ennfommazjuhne holle:",
+ "apihelp-query+imageinfo-paramvalue-prop-timestamp": "Deihd en dattom un en Zigg aan de huhjelahde Väsjohn.",
+ "apihelp-query+imageinfo-paramvalue-prop-user": "Deiht dä Metmaacher derbei, dä jehde Väsjohn vun dä Dattei huhjelahde hät.",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "Deiht de Kännong vun jehdem Metmaacher derbei, dä en Väsohn vun dä Dattei huh jelaahde hät.",
+ "apihelp-query+imageinfo-paramvalue-prop-comment": "Aanmärkonge bei dä Väsjohn.",
+ "apihelp-query+imageinfo-paramvalue-prop-parsedcomment": "Donn di Aanmärkonge bei dä Väsjohn paase.",
+ "apihelp-query+imageinfo-paramvalue-prop-canonicaltitle": "Deiht de kannohnesche, schtandattmähßejje, Överschreff vun dä Dattei derbei.",
+ "apihelp-query+imageinfo-paramvalue-prop-url": "Jitt dä <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i> för di Dattei un de Sigg met däh iere Äkliehrong uß.",
+ "apihelp-query+imageinfo-paramvalue-prop-size": "Deiht de Jrühße vun dä Dattei en \n<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Bytes</i>, de Hühde, de Breide, un, woh et se jitt, de Aanzahl Sigge derbei.",
+ "apihelp-query+imageinfo-paramvalue-prop-dimensions": "Et sällve, wi de Jrühße.",
+ "apihelp-query+imageinfo-paramvalue-prop-sha1": "Deiht de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"secure hash algorithm\">SHA-1</i>-Pröhvsomm för di Dattei derbei.",
+ "apihelp-query+imageinfo-paramvalue-prop-mime": "Deiht de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Multi-Purpose Internet Mail Extensions\">MIME</i>-Zoot fun dä Dattei derbei.",
+ "apihelp-query+imageinfo-paramvalue-prop-thumbmime": "Deiht de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Multi-Purpose Internet Mail Extensions\">MIME</i>-Zoot fun däm Minnibelldsche vun dä Dattei derbei. Bruch en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i> un dä Parramehter „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1urlwidth</code>“.",
+ "apihelp-query+imageinfo-paramvalue-prop-mediatype": "Deiht de Mehdijje_Zoot vun dä Dattei derbei.",
+ "apihelp-query+imageinfo-paramvalue-prop-metadata": "Deiht de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Exchangeable image file format\">EXIF</i>-Mettadahte för di Väsjohn vun dä Dattei oplesßte.",
+ "apihelp-query+imageinfo-paramvalue-prop-commonmetadata": "Deiht de Mettadahte för heh di Väsjohn vun dä Dattei oplesßte, di alld schtandattmähßesch en däm Datteifommaht änthallde sin.",
+ "apihelp-query+imageinfo-paramvalue-prop-archivename": "Deiht dä Nahme vun dä Dattei vun dä Aschihf_Väsjohn för alle Väsjohne, bes op de läzde, derbei.",
+ "apihelp-query+imageinfo-paramvalue-prop-bitdepth": "deiht de bit depth för di Väsjohn derbei.",
+ "apihelp-query+imageinfo-param-limit": "Wi vill Väsjohne för jehde Dattei ußjävve.",
+ "apihelp-query+imageinfo-param-start": "Et Dattom un de Zigg, vun woh aan opleßte.",
+ "apihelp-query+imageinfo-param-end": "Et Dattom un de Zigg, vun woh aan opleßte.",
+ "apihelp-query+imageinfo-param-urlheight": "Ähnlesch wi „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1urlwidth</code>“.",
+ "apihelp-query+imageinfo-param-localonly": "Belohr blohß de Datteije em eije Wikki singe Sammlong.",
+ "apihelp-query+imageinfo-example-simple": "Holl Enformazjuhne övver de aktoälle Väsjohn fun dä Dattei „<code lang=\"mul\" xml:lang=\"mul\" dir=\"ltr\">[[:File:Albert Einstein Head.jpg]]</code>“",
+ "apihelp-query+imageinfo-example-dated": "Holl Enformazjuhne övver de Väsjohne fun dä Dattei „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[:File:Test.jpg]]</code>“ vum Johr 2008 un schpääder.",
+ "apihelp-query+images-description": "Jidd alle Datteije uß, di en dä aanjejovve Sigge sin.",
+ "apihelp-query+images-param-limit": "Wi vill Datteije holle?",
+ "apihelp-query+images-param-images": "Donn blohß heh di Datteije opleßte. Dadd es johd, öm eruß ze fenge ovv en en beschtemmpte Sigg beschtemmpte Datteije dren sin.",
"apihelp-query+images-param-dir": "En wälsche Reijefollsch opleßte.",
+ "apihelp-query+images-example-simple": "Holl en Leß vun Datteije, di en de „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Main Page]]</code>“.",
+ "apihelp-query+images-example-generator": "Holl Ennfommazjuhne övver alle Datteije, di en de „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Main Page]]</code>“ jebruch wähde.",
+ "apihelp-query+imageusage-description": "Fengk alle Sigge, di en Beld medd ene bschtemmpte Övverschreff bruche.",
+ "apihelp-query+imageusage-param-title": "De Övverschreff för noh ze Söhke. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</var>“ bruche.",
+ "apihelp-query+imageusage-param-pageid": "De Känong vun dä Sigg zom noh Söhke. Kam_mer nit zesamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1title</var>“ bruche.",
"apihelp-query+imageusage-param-namespace": "Dat Appachtemang zom opzälle.",
"apihelp-query+imageusage-param-dir": "En wälsche Reijefollsch opleßte.",
+ "apihelp-query+imageusage-param-limit": "Wi vill Sigge ensjesamp ußjävve. Wann „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1redirect</var>“ ennjeschalld es, weed di Beschrängkong op jehden Nivoh äxtra aanjwandt, wat bedügg, dat bes op 2 * „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1limit</var> ußjejovve wähde künne.",
+ "apihelp-query+imageusage-param-redirect": "Wann de Sigg met dämm Lengk dren en Ömleijdong änthält, fengk derzoh och alle Sigge, di doh drop lengke. De Bovverjränz för de Aanzahl Sigge för opzeleßte weed hallbehrt.",
+ "apihelp-query+imageusage-example-simple": "Zeijsch Sigge, di di Dattei „<code lang=\"mul\" xml:lang=\"mul\" dir=\"ltr\">[[:File:Albert Einstein Head.jpg]]</code>“ bruche.",
+ "apihelp-query+imageusage-example-generator": "Holl Enformazjuhne övver de Sigge, di di Dattei „<code lang=\"mul\" xml:lang=\"mul\" dir=\"ltr\">[[:File:Albert Einstein Head.jpg]]</code>“ bruche.",
+ "apihelp-query+info-description": "Holl jrondlähje Ennfommazjuhne övver di Sigg.",
+ "apihelp-query+info-param-prop": "Wat för en zohsäzlejje Eijeschaffte holle:",
+ "apihelp-query+info-paramvalue-prop-protection": "Donn der Siggeschoz för jehde Sigg opleßte.",
+ "apihelp-query+info-paramvalue-prop-talkid": "De Kännong för de Klaafsigg för jehde Nit-Klaafsigg.",
+ "apihelp-query+info-paramvalue-prop-watched": "Donn der Zohschtand vum Oppaße för jehde Sigg opleßte.",
"apihelp-query+info-paramvalue-prop-watchers": "De Aanzahl Oppaßer, wann zohjelohße.",
+ "apihelp-query+info-paramvalue-prop-subjectid": "De Kännong för de övverje'odente Sigg för jehde Klaafsigg.",
+ "apihelp-query+info-paramvalue-prop-url": "Jidd en kumplätte <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i>, en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i> för et Beärbeide, un en kannohnesche <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i> för jehde Sigg uß.",
+ "apihelp-query+info-paramvalue-prop-readable": "Ov dä Metmaacher heh di Sigg lässe kann.",
+ "apihelp-query+info-paramvalue-prop-displaytitle": "Zeijsch de Maier, wi en Övverschreff vun en Sigg verhaftesch aanjezeijsch weed.",
+ "apihelp-query+iwbacklinks-param-prefix": "De Engerwikki_Vörsaz.",
+ "apihelp-query+iwbacklinks-param-title": "Der Engerwikki_Lengk för noh ze söhke. Moß met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1blprefix</var>“ zersamme jebruch wähde.",
+ "apihelp-query+iwbacklinks-param-limit": "Wi vill Sigge ensjesammp zem ußjävve?",
+ "apihelp-query+iwbacklinks-param-prop": "Wat för en Eijeschaffte holle:",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Deiht dä Engerwikki_Vörsaz derbei.",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Deiht de Engerwikki_Övverschreff derbei.",
"apihelp-query+iwbacklinks-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+iwbacklinks-example-simple": "Holl Sigge, di op „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[wikibooks:Test]]</code>“ verlengke.",
+ "apihelp-query+iwbacklinks-example-generator": "Holl Ennfommazjuhne övver Sigge, di op „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[wikibooks:Test]]</code>“ verlengke.",
+ "apihelp-query+iwlinks-description": "Jiff alle Engerwikki_Lengks vun de aanjejovve Sigge uß.",
+ "apihelp-query+iwlinks-param-limit": "Wi vill Engerwikki_Lengks zem ußjävve?",
+ "apihelp-query+iwlinks-param-prefix": "Jiff blohß de Engerwikki_Lengks uß, di dermet aanfange.",
"apihelp-query+iwlinks-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+langbacklinks-param-lang": "Schprohch för dä Schprohche_Lengk.",
+ "apihelp-query+langbacklinks-param-title": "Der Schprohche_Lengk för noh ze söhke. Moß zersamme met <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1lang</code> jebruch wähde.",
+ "apihelp-query+langbacklinks-param-limit": "Wi vill Sigge ensjesammp zem ußjävve?",
"apihelp-query+langbacklinks-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+langbacklinks-example-simple": "Holl Sigge, di op „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[:fr:Test]]</code>“ verlengke.",
+ "apihelp-query+langbacklinks-example-generator": "Holl Ennfommazjuhne övver Sigge, di op „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[:fr:Test]]</code>“ verlengke.",
+ "apihelp-query+langlinks-description": "Jiff alle Schprohche_Lengks vun de aanjejovve Sigge uß.",
+ "apihelp-query+langlinks-param-limit": "Wi vill Schprohche_Lengks holle?",
+ "apihelp-query+langlinks-param-lang": "Donn blohß de Schprohche_Lengks met däm aanjejovve Schprohche_Köözel.",
"apihelp-query+langlinks-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+links-description": "Jiff alle Lengks vun de aanjejovve Sigge uß.",
+ "apihelp-query+links-param-limit": "Wi vill Lengks ußjävve?",
+ "apihelp-query+links-param-titles": "Donn blohß e Lengks of heh di Övverschreffte opleßte. Dadd es johd, öm eruß ze fenge ovv en en beschtemmpte Sigg op ene beschtemmpte Övverschreff verlengk es.",
"apihelp-query+links-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+linkshere-description": "Fengk alle Sigge, di op de aanjejovve Sigge lengke.",
+ "apihelp-query+linkshere-param-prop": "Wat för en Eijeschaffte holle:",
+ "apihelp-query+linkshere-paramvalue-prop-pageid": "Page ID of each page.",
+ "apihelp-query+linkshere-paramvalue-prop-title": "Title of each page.",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "Flag if the page is a redirect.",
+ "apihelp-query+linkshere-param-namespace": "Donn blohß Sigge en heh dä Appachtemangs metnämme.",
+ "apihelp-query+linkshere-param-limit": "Wi vill holle?",
+ "apihelp-query+linkshere-example-simple": "Holl en Leß vun Sigge, di op de Sigg „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Main Page]]</code>“ lengke donn.",
+ "apihelp-query+linkshere-example-generator": "Holl Ennfommazjuhne övver Sigge, di op de Sigg „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Main Page]]</code>“ lengke.",
+ "apihelp-query+logevents-description": "Holl Enndrähsch us de Logböhscher.",
+ "apihelp-query+logevents-param-type": "Söhk blohß heh di Zood Enndrähsch us de Logböhscher.",
+ "apihelp-query+logevents-param-start": "Et Dattom un de Zigg vun woh aff opjezallt wähde sull.",
+ "apihelp-query+logevents-param-end": "Dattum un Uhrzigg, bes wann opzälle.",
+ "apihelp-query+logevents-param-user": "Donn de Enndrähsch beschrängke ob di vun enem bechtemmpte Metmaacher.",
+ "apihelp-query+logevents-param-title": "Donn de Enndrähsch beschrängke ob di sesch obb_en beschtemmpte Sigg beträcke.",
+ "apihelp-query+logevents-param-namespace": "Donn de Enndrähsch beschrängke obb e besschtemmp Appachtemang.",
+ "apihelp-query+logevents-param-prefix": "Donn de Enndrähsch beschrängke ob di medd enem beschtemmpte Bejenn.",
+ "apihelp-query+logevents-param-tag": "Donn blohß Väsjohne met heh dä Makkehrong opleßte.",
+ "apihelp-query+logevents-param-limit": "Wi vill Enndrähsch enjesammp ußjävve?",
+ "apihelp-query+logevents-example-simple": "Donn de neußte Enndrähsch uß de Logböhscher opleßte.",
+ "apihelp-query+pagepropnames-description": "Donn alle Nahme vun Eijeschaffte vun Sigge heh em Wikki opleßte.",
"apihelp-query+pagepropnames-param-limit": "De jrüüßte Zahl Nahme för ußzejävve.",
"apihelp-query+pagepropnames-example-simple": "Holl de eezde zehn Nahme vun Eijeschaffte.",
+ "apihelp-query+pageprops-description": "Jitt devärse Eijeschafte uß, di em Ennhald vun dä Sigg faßjelaat wohde sen.",
+ "apihelp-query+pageprops-example-simple": "Holl de Eijeschaffte för di Sigge „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ un „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">MediaWiki</kbd>“.",
+ "apihelp-query+pageswithprop-description": "Donn alle Sigge met bechtemmpte Sigge_Eijeschaff opleßte.",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "Deiht de Kännong vun de Sigge derbei.",
"apihelp-query+pageswithprop-param-limit": "De jrüüßte Zahl Sigge för ußzejävve.",
"apihelp-query+pageswithprop-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+pageswithprop-example-generator": "Holl zohsäzlejje Aanjahbe övver de eezde zehn Sigge, woh <code>_&#95;NOTOC_&#95;</code> dren vörkütt.",
+ "apihelp-query+prefixsearch-description": "Söhk nohm Aanfang vun dä Övverschreffte vun de Sigge.",
+ "apihelp-query+prefixsearch-param-search": "Noh wat söhke?",
"apihelp-query+prefixsearch-param-namespace": "En wällschem Appachtemang söhke.",
"apihelp-query+prefixsearch-param-limit": "De hühßte Aanzahl vun Äjeebnesse för zeröck ze jävve",
+ "apihelp-query+prefixsearch-param-offset": "De Aanzahl vun Äjeebnesse för ze övverjonn.",
+ "apihelp-query+prefixsearch-example-simple": "Söhk noh Övverschreffte vun Sigge, di met \n„<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">meaning</kbd>“ bejenne.",
+ "apihelp-query+protectedtitles-description": "Donn alle Överschreffte vun Sigge opleßte, di verbodde sin, aanzelähje.",
+ "apihelp-query+protectedtitles-param-namespace": "Donn blohß Sigge en heh dä Appachtemangs opleßte.",
+ "apihelp-query+protectedtitles-param-level": "Donn blohß de Övverschreffte vun Sigge met heh dämm Nivoh vum Sigge_Schoz opeleßte.",
+ "apihelp-query+protectedtitles-param-limit": "Wi vill Sigge ensjesammp zem ußjävve?",
+ "apihelp-query+protectedtitles-example-simple": "Donn jeschöz Övverschreffte opleßte.",
+ "apihelp-query+protectedtitles-example-generator": "Fengk Lengks op jeschözde Övverschreffte em Houp_Appachemang.",
+ "apihelp-query+querypage-param-page": "Dä {{int:specialpage}} iere Name. Opjepaß: De Jruhs- un Kleinschreff schpelld en Roll.",
"apihelp-query+querypage-param-limit": "De Aanzahl vun Äjeebnesse för zeröck ze jävve",
+ "apihelp-query+querypage-example-ancientpages": "Donn de Äjehbneße vun „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Special:Ancientpages]]</code>“ ußjävve.",
+ "apihelp-query+random-param-namespace": "Jiff blohß sigge en heh dä Appachtemangs uß.",
"apihelp-query+random-param-limit": "Wi vill zohfälleje Sigge sulle ußjejovve wähde?",
+ "apihelp-query+random-param-redirect": "Nemm <kbd>$1filterredir=redirects</kbd> schtatt dämm.",
+ "apihelp-query+random-example-simple": "Donn zwai zohfälleje Sigge vum Houb_Appachtemang ußjävve.",
+ "apihelp-query+random-example-generator": "Donn Ennfommazjuhne övver zwai zohfälleje Sigge vum Houb_Appachtemang ußjävve.",
+ "apihelp-query+recentchanges-description": "Donn de neußte Änderonge opleßte.",
+ "apihelp-query+recentchanges-param-start": "Et Dattom un de Zigg vun woh aff opjezallt wähde sull.",
+ "apihelp-query+recentchanges-param-end": "Dattum un Uhrzigg, bes wann opzälle.",
+ "apihelp-query+recentchanges-param-user": "Donn blohß Änderonge vun heh däm Metmaacher opleßte.",
+ "apihelp-query+recentchanges-param-excludeuser": "Donn kein Änderonge vun heh däm Metmaacher opleßte.",
+ "apihelp-query+recentchanges-param-tag": "Donn blohß Änderonge met heh dä Makkehrong opleßte.",
+ "apihelp-query+recentchanges-param-limit": "Wi vill Änderonge ensjesammp zem aanzeije?",
+ "apihelp-query+recentchanges-param-type": "Wat för en Zoot Änneronge aanzeije?",
+ "apihelp-query+recentchanges-param-toponly": "Bloß Änderonge aanzeije, woh de neußte Väsjohn beij eruß kohm.",
+ "apihelp-query+recentchanges-example-simple": "Zeijsch de {{LCFIRST:{{int:recentchanges}}}}",
+ "apihelp-query+redirects-description": "Jiff alle Ömleijdonge noh dä aanjejovve Sigge uß.",
+ "apihelp-query+redirects-param-prop": "Wat för en Eijeschaffte holle:",
+ "apihelp-query+redirects-paramvalue-prop-pageid": "De Sigge_Kännong för jehde Ömleijdong.",
+ "apihelp-query+redirects-paramvalue-prop-title": "De Övverschreff för jehde Ömleijdong.",
+ "apihelp-query+redirects-paramvalue-prop-fragment": "Der Fragmännd_Aandeijl för jehde Ömleijdong, wann eine doh es.",
+ "apihelp-query+redirects-param-namespace": "Donn blohß Sigge en heh dä Appachtemangs metnämme.",
+ "apihelp-query+redirects-param-limit": "Wi vell Ömeijdonge ußjävve?",
+ "apihelp-query+redirects-param-show": "Zeijsch blohß de Ömleijdonge:\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">fragment</code>:med enem Fragmännd_Aandeijl.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">!fragment</code>:der ohne ene Fragmännd_Aandeijl.",
+ "apihelp-query+redirects-example-simple": "Holl en Leß met Ömleijdonge, di op de Sigg „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Main Page]]</code>“ jonn.",
+ "apihelp-query+redirects-example-generator": "Holl Ennfommazjuhne övver alle Ömleijdonge op di Sigg „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[[Main Page]]</code>“.",
+ "apihelp-query+revisions-paraminfo-singlepageonly": "Kam_mer blohß med en einzel Sigg bruche (mode #2)",
+ "apihelp-query+revisions-param-startid": "De Kännong vun dä Väsjohn vun woh aff opjezallt wähde sull.",
+ "apihelp-query+revisions-param-endid": "De Kännong vun dä Väsjohn bes woh hen opjezallt wähde sull.",
+ "apihelp-query+revisions-param-start": "Et Dattom un de Zigg vun dä Väsjohn vun woh aff opjezallt wähde sull.",
+ "apihelp-query+revisions-param-end": "Et Dattom un de Zigg bes woh hen opjezallt wähde sull.",
+ "apihelp-query+revisions-param-user": "Väsjohne vun däm Metmaache ennschlehße.",
+ "apihelp-query+revisions-param-excludeuser": "Väsjohne vun däm Metmaache ußschlehße.",
+ "apihelp-query+revisions-param-tag": "Donn blohß Väsjohne met heh dä Makkehrong opleßte.",
+ "apihelp-query+revisions-param-token": "Wat för en Makkehronge för jehde Väsjohn holle.",
+ "apihelp-query+revisions-example-content": "Holl Dahte med Ennhalld för de läzde Väsjohn vun Övverschreffte \n„<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">API</kbd>“ un \n„<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“.",
+ "apihelp-query+revisions-example-last5": "Holl de läzde fönnef Väsjohne vun de „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“.",
+ "apihelp-query+revisions-example-first5": "Holl de eezde fönnef Väsjohne vun de „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“.",
+ "apihelp-query+revisions-example-first5-after": "Holl de eezde fönnef Väsjohne vun de „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“, di noh em eezde Mai em Johr 2006 änschtannde sin.",
+ "apihelp-query+revisions-example-first5-not-localhost": "Holl de ehzde Väsjohne vun de „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ di nit vun dämm nahmelohse Metmaacher „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">127.0.0.1</kbd>“ jemaht wohde.",
+ "apihelp-query+revisions-example-first5-user": "Holl de eezde fönnef Väsjohne vun de „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“, di vum Metmaacher „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">MediaWiki default</kbd>“ aanjelahd wohde.",
+ "apihelp-query+revisions+base-param-prop": "Wat för en Eijeschaffte vun dä Väsjohn holle.",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "Dw Kännong vu dä Väsjohn.",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "Dattom un Zigg vun dä Väsjohn.",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "Dä Metmaacher, dä di Väsjohn jemaat hät.",
+ "apihelp-query+revisions+base-paramvalue-prop-userid": "Däm Metmaacher sing Kännong, dä di Väsjohn aanjelaat hät.",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "Der Ömvang en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Bytes</i> vun dä Väsjohn.",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "De <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"secure hash algorithm\">SHA-1 (base 16)</i> Prööfsomm vun dä Väsjohn.",
+ "apihelp-query+revisions+base-paramvalue-prop-comment": "De Aanmärkong vum Metmaacher för di äsjohn.",
+ "apihelp-query+revisions+base-paramvalue-prop-content": "Der Täx vun dä Väsjohn.",
+ "apihelp-query+revisions+base-paramvalue-prop-tags": "Makkehronge vun dä Väsjohn.",
"apihelp-query+revisions+base-param-limit": "Wi vill Väsjohne sulle ußjejovve wähde?",
+ "apihelp-query+revisions+base-param-section": "Holl blohß der Ennhald vun däm Affschnett met heh dä Nommer.",
+ "apihelp-query+search-description": "Söhk em jannze Täx.",
+ "apihelp-query+search-param-search": "Söhk noh alle Övverschreffte vun Sigge udder Ennhallde, woh dä Wäät drop paß. Mer kann heh met besönder Aufjahbe beim Söhke schtälle, jeh nohdämm wadd_em Wikki sing Projramm för et Söhke esu alles kann.",
+ "apihelp-query+search-param-namespace": "Söhk blohß en heh dä Appachtemangs.",
+ "apihelp-query+search-param-what": "Wat för en Aat ze Söhke?",
+ "apihelp-query+search-param-info": "Wat för en Metta_Dahte ußzejävve.",
+ "apihelp-query+search-param-prop": "Wat för en Eijeschaffte holle:",
+ "apihelp-query+search-param-limit": "Wi vill Sigge ensjesamp ußjävve?",
+ "apihelp-query+search-param-interwiki": "Donn de Engerwiki Lengks met ußjävve beim Söhke, wann_er doh sin.",
+ "apihelp-query+search-example-simple": "Söhk noh „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">meaning</kbd>“.",
+ "apihelp-query+search-example-text": "Söhk en Täxte noh „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">meaning</kbd>“.",
+ "apihelp-query+search-example-generator": "Holl anjahbe övver di Sigge, di jefonge wähde beim söhke noh \n„<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">meaning</kbd>“",
+ "apihelp-query+siteinfo-description": "Jiff alljemeine Ennfommazjuhne övver heh di ẞaid_uß.",
+ "apihelp-query+siteinfo-param-filteriw": "Donn blohß de Enndrähsch för heh et Wikki udder blohß de Enndrähsch för ußerhallef en di Leß.",
+ "apihelp-query+siteinfo-param-showalldb": "Donn alle ẞööver för de Dahtebangke opleßte, nit blohß di am mihßte hengerher sin.",
"apihelp-query+siteinfo-param-numberingroup": "Donn de Aanzahl Metmaacher en de Jroppe vun Metmaacher opleßte.",
- "apihelp-query+tags-param-limit": "De hühßde Aanzahl !!FUZY tags zom opleste.",
- "apihelp-query+tags-param-prop": "Wat för en Eijschaffte holle:\n;name:Adds name of tag.\n;displayname:Adds system message for the tag.\n;description:Adds description of the tag.\n;hitcount:Adds the number of revisions and log entries that have this tag.\n;defined:Indicate whether the tag is defined.\n;source:Gets the sources of the tag, which may include <samp>extension</samp> for extension-defined tags and <samp>manual</samp> for tags that may be applied manually by users.\n;active:Whether the tag is still being applied.\n<!-- https://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Apihelp-query%2Btags-param-prop/ksh\n -->",
+ "apihelp-query+siteinfo-param-inlanguagecode": "Schprohche_Köözelle för de Namhme vun Schprohche en heh dä Schprohch — der bäßte Träffer zällt - un de Namhe vun de Bedehnbovverfläsche.",
+ "apihelp-query+siteinfo-example-simple": "Holl Ennfommazjuhe övver heh di ẞait.",
+ "apihelp-query+siteinfo-example-interwiki": "Holl en Leß met de Vörsäz för de Engerwiki_Lenks em eije Wikki.",
+ "apihelp-query+stashimageinfo-param-sessionkey": "Es et sällve wi „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1filekey</code>“ un kütt vun fröjere Väsjohne.",
+ "apihelp-query+tags-description": "Leß de Makehronge vun Änderonge.",
+ "apihelp-query+tags-param-limit": "De hühßde Zahl Makkehronge zom Opleste.",
+ "apihelp-query+tags-param-prop": "Wat för en Eijeschaffte holle:",
+ "apihelp-query+tags-paramvalue-prop-name": "Deiht dä Nahme vun dä Makkehrong derbei.",
+ "apihelp-query+tags-paramvalue-prop-displayname": "Deiht der Täx vum Wikki för de Makkehrong derbei.",
+ "apihelp-query+tags-paramvalue-prop-description": "Deiht dä Beschrievongstäx vun dä Makkehrong derbei.",
+ "apihelp-query+tags-paramvalue-prop-hitcount": "Deiht de Aanzahl vun Väsjohne un Enndrähsch em Logbohch derbei, di di Makkehrong han.",
+ "apihelp-query+tags-paramvalue-prop-defined": "Jivv aan, ov di Makkehrong övverhoup doh es.",
+ "apihelp-query+tags-paramvalue-prop-source": "Hollt de Kwälle vun de Makkehrong, dat kann ömfaße: „<samp lang=\"en\" xml:lang=\"en\" dir=\"ltr\">extension</samp>“ för Makkehronge, di vun Zohsazprojramme faßjelaat wähde, un „<samp lang=\"en\" xml:lang=\"en\" dir=\"ltr\">manual</samp>“ för Makkehronge, di vun de Metmaacher vun Hand verjovve wohde.",
+ "apihelp-query+tags-paramvalue-prop-active": "Ov de Makkehrong emmer noch aktihv es.",
+ "apihelp-query+tags-example-simple": "Leß de verföhschbahre Makkehronge op.",
+ "apihelp-query+templates-description": "Jidd alle Datteije uß, di en dä aanjejovve Sigge enjebonge sin.",
+ "apihelp-query+templates-param-namespace": "Zeijsch blohß de Schablohne en heh däm Appachtemang.",
"apihelp-query+templates-param-limit": "Wi vill Schablohne sulle ußjejovve wähde?",
+ "apihelp-query+templates-param-templates": "Donn blohß heh die Schablohne opleßte. Johd ze bruche zom Pröhve, ov en beschtemmpte Sigg en beschtemmpte Schlohn bruche deiht.",
"apihelp-query+templates-param-dir": "En wälsche Reihjefollsch opleßte.",
+ "apihelp-query+templates-example-simple": "Holl di Schablohne, di en dä Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ jebruch wähde.",
+ "apihelp-query+templates-example-generator": "Holl Ennfommazjuhneövver di Sigge met di Schablohne, di en dä Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ jebruch wähde.",
+ "apihelp-query+templates-example-namespaces": "Holl Sigge uß de {{ns:user}} un {{ns:template}} Appachtemangs, di en di Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ enjeschloße wähde.",
+ "apihelp-query+transcludedin-description": "Fengk alle Sigge, di di aanjejovve Sigge enneschlehße.",
+ "apihelp-query+transcludedin-param-namespace": "Donn blohß Sigge en heh dä Appachtemangs ennschlehße.",
+ "apihelp-query+transcludedin-param-limit": "Wi vill ußjävve.",
+ "apihelp-query+transcludedin-example-simple": "Holl en Leß met Sigge, di en dä Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ ennjeschloße wähde.",
+ "apihelp-query+transcludedin-example-generator": "Holl Ennfommazjuhne övver Sigge, di vun dä Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ ohjerohfe wähde.",
+ "apihelp-query+usercontribs-description": "Holl alle Änderonge vun enem Metmaacher.",
"apihelp-query+usercontribs-param-limit": "De hühßte Aanzahl vun Meddeilonge för zeröck ze jävve",
+ "apihelp-query+usercontribs-param-start": "Dattom un Zigg vun woh aan ußjävve.",
+ "apihelp-query+usercontribs-param-end": "Dattom un Zigg bes woh hen ußjävve.",
+ "apihelp-query+usercontribs-param-user": "De Metmaacher för di mer Beijdrähsch holle welle.",
+ "apihelp-query+usercontribs-param-userprefix": "Holl beijdrähsch för alle Metmaacher, dänne ier Nahme met heh däm Wääd aanfange. Övverschriehv „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1user</code>“.",
+ "apihelp-query+usercontribs-param-namespace": "Donn blohß Beijdrähsch en heh dä Appachtemangs opleßte.",
+ "apihelp-query+usercontribs-param-prop": "Donn zohsäzlejje Aanjahbe ennschlehße:",
+ "apihelp-query+usercontribs-param-tag": "Donn blohß Väsjohne met heh dä Makehrong opleßte.",
+ "apihelp-query+usercontribs-param-toponly": "Bloß Änderonge aanzeije, woh de neußte Väsjohn beij eruß kohm.",
+ "apihelp-query+usercontribs-example-user": "Zeijsch dem Metmaacher „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Example</kbd>“ sing Beijdrähsch.",
+ "apihelp-query+usercontribs-example-ipprefix": "Zeijsch de Beijdrähsch vun alle <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Internet Protocol\">IP</i>-Adräße, di met „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">192.0.2.</kbd>“ bejenne.",
+ "apihelp-query+userinfo-description": "Holl Aanjahbe övver dä aktoälle Metmaacher.",
+ "apihelp-query+userinfo-param-prop": "Wat för en Aanjahbe med enzschlehße:",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "Deiht däm Metmaacher singe reeschtejje Nahme derbei.",
+ "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Donn et Dattom vun dämm Metmaacher singe eetze Aanmäldong derbei.",
+ "apihelp-query+userinfo-example-simple": "Holl Aanjahbe övver dä aktoälle Metmaacher.",
+ "apihelp-query+userinfo-example-data": "Holl zohsäzlejje Aanjahbe övver dä aktoälle Metmaacher.",
+ "apihelp-query+users-description": "Holl Aanjahbe övver en Leß vun Metmaacher.",
+ "apihelp-query+users-param-users": "En Leß vun Metmaacher för Aanjahbe drövver ze holle.",
+ "apihelp-query+users-example-simple": "Holl Aanjahbe för dä Metmaacher <kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Example</kbd>.",
+ "apihelp-query+watchlist-param-start": "Et Dattom un de Zigg vun woh aff opjezallt wähde sull.",
+ "apihelp-query+watchlist-param-end": "Et Dattum un Uhrzigg, bes wann opzälle.",
+ "apihelp-query+watchlist-param-namespace": "Donn de Änderonge blohß us de aanjejovve Appachtemans nämme.",
+ "apihelp-query+watchlist-param-user": "Donn blohß Änderonge vun heh däm Metmaacher opleßte.",
+ "apihelp-query+watchlist-param-excludeuser": "Donn kein Änderonge vun heh däm Metmaacher opleßte.",
+ "apihelp-query+watchlist-param-limit": "Wi vell Äjehbneße ennsjesammp pro Oprohv ußjejovve wähde sulle.",
+ "apihelp-query+watchlist-param-prop": "Wat för en zohsäzlejje Eijeschaffte holle:",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "Donn de Kännong vun de Väsohne un de Sigge derbei,",
+ "apihelp-query+watchlist-paramvalue-prop-title": "Mähd en Övverschhreff övver di Sigg.",
+ "apihelp-query+watchlist-paramvalue-prop-user": "Deiht dä Metmaacher derbei, dä di Änderong jemaat hät.",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "Deiht de kännong vn äm Metmaacher derbei, dä di Änderong jemaat hät.",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "Deihd et Dattom un de Uhrzigg vun dä Änderong derbei.",
+ "apihelp-query+watchlist-param-type": "Wat för en Änderonge aanzeije:\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">edit</code>:Jewöhnlejje Änderonge aan Sigge.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">external</code>:Änderonge vun Ußerhallef.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">new</code>:Neu aanjelahte Sigge.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">log</code>:Enndrähsch em Logbohch.",
+ "apihelp-query+watchlistraw-description": "Donn alle Sigge uß dem aktälle Metmaacher sing Oppaßleß holle.",
+ "apihelp-query+watchlistraw-param-namespace": "Donn blohß Sigge en heh däm Appachtemang opleßte.",
+ "apihelp-query+watchlistraw-example-simple": "Donn alle Sigge uß dem aktälle Metmaacher sing Oppaßleß opleßte.",
+ "apihelp-revisiondelete-description": "Versione fottschmieße un widder zeröck holle.",
+ "apihelp-revisiondelete-param-hide": "Wat för jehde Väsjohn ze veschteijsche.",
+ "apihelp-revisiondelete-param-suppress": "Ov dat och för de Wiki-Köbesse verschtoche wähde sull, wie för jede Andere.",
+ "apihelp-rollback-param-title": "De Övverschreff vun dä Sigg för di_j_en vörrejje Väsjohn zeröckzeholle es. Kam_mer nit zersamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1pageid</var>“ bruche.",
+ "apihelp-rollback-param-pageid": "De Kännong vun dä Sigg för di_j_en vörrejje Väsjohn zeröckzeholle es. Kam_mer nit zersamme met „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1title</var>“ bruche.",
+ "apihelp-setnotificationtimestamp-param-entirewatchlist": "Donn alle Sigge beärbeide, di en Oppaßleßte dren sin.",
+ "apihelp-tag-description": "Donn Makkehronge vun einzel Väsjohne udder Enndraähsch em Logbohch fott nämme udder se verjävve.",
+ "apihelp-tag-param-rcid": "Ein udder mih Kännonge uß de neuste Ännderonge, woh di Makkehrong derbei jedonn udder fott jenumme wähde sull.",
+ "apihelp-tag-param-revid": "Ein Kännong udder mih, woh di Makkehrong derbei jedonn udder fott jenumme wähde sull.",
+ "apihelp-tag-param-logid": "Ein Kännong udder mih uß de neuste Änderonge, woh di Makkehrong derbei jedonn udder fott jenumme wähde sull.",
+ "apihelp-tag-param-add": "De Makkehrong zom Zohföhje. Bloß de vun Hand aanjelaat Makkehronge künne heh zohjeföhsch wähde.",
+ "apihelp-tag-param-remove": "Makkehronge zom fott nämme. Blohß vun Hand jesaz un kumplätt onjesaz Makkehronge künne fott jenumme wähde.",
+ "apihelp-tag-param-reason": "Dä Jrond för di Änderong.",
+ "apihelp-tag-example-rev": "Donn de Makkehrong „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">vandalism</kbd>“ vun dä Väsjohn met dä Kännong „<kbd>123</kbd>“ fott nämme, der ohne ene Jrond ze nänne.",
+ "apihelp-tag-example-log": "Donn de Makkehrong „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">spam</kbd>“ vun dämm Enndrahch met dä Kännong „<kbd>123</kbd>“ em Logbohch fott nämme un als Jrond draaach „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Wrongly applied</kbd>“ enn.",
+ "apihelp-unblock-description": "Don en Schpärr för ene Metmaacher ophävve.",
+ "apihelp-unblock-param-reason": "Der Jrond för de Schpärr opzehävve.",
+ "apihelp-undelete-param-title": "De Övverschreff vun dä Sigg zom zerök holle.",
+ "apihelp-undelete-param-reason": "Der Jrond för et Zerök holle.",
+ "apihelp-undelete-param-watchlist": "Donn di Sigg ohne Bedengonge op däm aktoälle Metmaacher sing Oppaßleß udder nemm se druß fott, donn de Enschtällonge nämme, udder donn de Oppaßleß jaa nit verändere.",
+ "apihelp-undelete-example-page": "Schmiiß de Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ fott.",
+ "apihelp-undelete-example-revisions": "Holl zwai Väsjohne vun dä Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ zerök.",
+ "apihelp-upload-description": "Donn en Dattei huh lahde, udder holl der Zohschtand vun de onfähdesch huhjelahde Datteije .\n\nEt jitt ongerscheidlejje Metohde:\n* Donn de Ennhallde vun de Datteije tiräk huhlahde, övver der Parramehter „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1file</var>“.\n* Donn de Datteije en en Aanzahl Rötsche huhlahde, övver de Parramehter „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1filesize</var>“, „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1chunk</var>“, un „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1offset</var>“.\n* Lohß der ẞööver vum Wikki en Dattei vun enem <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i> holle, övver de Parramehter „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1url</var>“.\n* Lohß en Dattei fähdesch huhlahde, di zeläz nit fähdesch wohd, un met Warnonge schtonn jeblevve es övver de Parramehter „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1filekey</var>“.\nOpjepaß: dä „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">POST</code>“-Befähl vum <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Transfer Protocol\">HTTP</i> moß als e Dattei-Huhlahde aanjeschtüßße wähde, allsu met „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">multipart/form-data</code>“, wam_mer dä Parramehter „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1file</var>“ scheck.",
+ "apihelp-upload-param-filename": "Zihl-Dateiname.",
+ "apihelp-upload-param-text": "Der aanfänglesche Täx op Sigge för neu aanjelahte Datteije.",
+ "apihelp-upload-param-watch": "Op di Sigg heh oppaßße.",
+ "apihelp-upload-param-watchlist": "Donn di Sigg op däm aktoälle Metmaacher sing Oppaßleß udder nemm se druß fott, donn de Enschtällonge nämme, udder donn de Oppaßleß jaa nit verändere.",
+ "apihelp-upload-param-ignorewarnings": "Donn alle Warnonge övverjonn.",
+ "apihelp-upload-param-file": "Dä Dattei ier Enhallde.",
+ "apihelp-upload-param-url": "Der <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i>, öm di Dattei dervun ze holle.",
+ "apihelp-upload-param-sessionkey": "Et sälve wi „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1filekey</code>“, wat mer emmer noch noch bruche kann, weil mer et fröhjer alld ens esu hatte.",
+ "apihelp-upload-param-filesize": "De Datteijrühße vum jannze Huhlahde.",
+ "apihelp-upload-param-asyncdownload": "Maach dat Holle vun ene <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i> zoh ene andere Zigg.",
+ "apihelp-upload-example-url": "Vun enem <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Uniform Ressource Locator\">URL</i> huhlahde.",
+ "apihelp-upload-example-filekey": "Don et Huhlahde fähdesch maace, wat wähje Warnonge nit johd jejange wohr.",
+ "apihelp-userrights-param-user": "Metmaacher_Nahme.",
+ "apihelp-userrights-param-userid": "Enem Metmaacher sing Kännong.",
+ "apihelp-userrights-param-add": "Donn dä Metmaacher en heh di Jroppe eren.",
+ "apihelp-userrights-param-remove": "Donn dä Metmaacher us heh dä Jroppe eruß nämme.",
+ "apihelp-userrights-param-reason": "Dä Jrond för di Änderong.",
+ "apihelp-watch-description": "Donn di Sigg en däm aktoälle Metmaacher singe Oppaßless eren udder schmihß se erus.",
+ "apihelp-watch-example-watch": "Don di Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ en de Oppaßleß.",
+ "apihelp-watch-example-unwatch": "Schmiiß di Sigg „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Main Page</kbd>“ uß dä Oppaßleß erus.",
+ "apihelp-format-example-generic": "Jiff wadd_erus kohm em Fommaht $1 us.",
+ "apihelp-json-param-ascii": "Wann aanjejovve, deiht alle nit-<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"American Standard Code for Information Interchange\">ASCII</i>-Zeijsche met hexadezimahle !escape-Sequänze koddehre. Dadd es der Schtandatt, wann „<var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">formatversion</var>“ <kbd>1</kbd> es.",
+ "apihelp-jsonfm-description": "Dahte em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"JavaScript Object Notation\">JSON</i>-Fommaht ußjävve un för schöhn en et <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Markup Language\">HTML</i> wandele.",
+ "apihelp-none-description": "Donn nix ußjävve.",
+ "apihelp-php-description": "Dahte em hengernader jeschrevve <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"PHP Hypertext Preprocessor\">PHP</i>-Fommaht ußjävve.",
+ "apihelp-xml-description": "Donn de Dahte em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Extensible Markup Language\">XML</i>-Fommahd ußjävve.",
+ "apihelp-xml-param-includexmlnamespace": "Wann aanjejovve, deihd en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Extensible Markup Language\">XML</i>-Appachtemand derbei.",
+ "apihelp-yaml-description": "Donn de Dahte em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"YAML Ain't Markup Language\">YAML</i>-Fommahd ußjävve.",
+ "apihelp-yamlfm-description": "Donn de Dahte em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"YAML Ain't Markup Language\">YAML</i>-Fommahd schöhn met <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Markup Language\">HTML</i> ußjävve.",
+ "api-format-title": "Wat et <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> ußjohv.",
+ "api-format-prettyprint-header-only-html": "Dat heh es en <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"HyperText Markup Language\">HTML</i>_Daaschtällong un för et Fähersöhke jedaach. Dadd is för Aanwändongsprojramme nit ze bruche.\n\nEn de [[mw:API|complete Dokkemäntazjohn]] un de [[Special:ApiHelp/main|API Hölp_Sigg]] kam_mer doh mih drövver lässe.",
+ "api-orm-param-props": "De Fällder zom Affrohre.",
+ "api-orm-param-limit": "De jrühßte Aanzahl vun Reihje zom zeröckjävve.",
+ "api-pageset-param-titles": "En Leß vun Övverschreffte för ze beärbeide.",
+ "api-pageset-param-pageids": "En Leß vun Kännonge vun Sigge för ze beärbeide.",
+ "api-pageset-param-revids": "En Leß vun Kännonge vun Väsjohne för ze beärbeide.",
+ "api-help-title": "Hölp för de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Application Programming Interface\">API</i> vum MehdijaWikki.",
+ "api-help-main-header": "Houp_Moduhl",
+ "api-help-flag-deprecated": "Dat Moduhl es nimmih johd jeligge.",
+ "api-help-flag-readrights": "Heh da Modhul bruch et Rääsch zum Lässe.",
+ "api-help-flag-writerights": "Heh da Modhul bruch et Rääsch zom Schriive.",
+ "api-help-flag-mustbeposted": "Heh dat Modhul nemmp blohß <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">POST</code>-Opdrähschd aan.",
+ "api-help-flag-generator": "Heh dat Modhul kam_mer als ene Jenerahtor ennsäze.",
+ "api-help-source": "Quäll: $1",
+ "api-help-source-unknown": "Quäll: <span class=\"apihelp-unknown\">onbikannt</span>",
+ "api-help-license": "Lezänz: [[$1|$2]]",
+ "api-help-license-noname": "Lezänz: [[$1|Loor noh dämm Lengk]]",
+ "api-help-license-unknown": "Lezänz: <span class=\"apihelp-unknown\">onbikannt</span>",
+ "api-help-parameters": "{{PLURAL:$1|Parramehter|Parramehtere|Parramehter}}:",
+ "api-help-param-deprecated": "Meßjevällesch.",
+ "api-help-param-required": "Heh dä Parramehter es nühdesch.",
+ "api-help-datatypes-header": "Zoote Dahte",
+ "api-help-param-type-limit": "Zoot: en jannze Zahl udder „<kbd lang=\"en\" xml:lang=\"en\" dir=\"ltr\">max</kbd>“",
+ "api-help-param-type-integer": "Zoot: {{PLURAL:$1|1=en jannze Zahl|2=en Leß met jannze Zahle}}",
+ "api-help-param-type-boolean": "Zoot: Boolsch ([[Special:ApiHelp/main#main/datatypes|Einjzelheijte]])",
+ "api-help-param-type-timestamp": "Zoot: {{PLURAL:$1|1=en Dattomm un en Zigg|2=en Leß met Aanjahbe us Dattom un Zigg}} (de [[Special:ApiHelp/main#main/datatypes|zohjelohße Fommahte]])",
+ "api-help-param-type-user": "Zoot: {{PLURAL:$1|1=ene Metmaacher_Nahme|2=en Leß met Metmaacher_Nahme}}",
+ "api-help-param-list": "{{PLURAL:$1|1=Eijne Wäät|2=Wääte met <kbd>{{!}}</kbd> derzwesche}} vun dänne heh: $2",
+ "api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Moß läddesch sin|Kann läddesch sin, udder $2}}",
+ "api-help-param-limit": "Nit mih wi $1 sin zohjelohße.",
+ "api-help-param-limit2": "Nit mih wi $1 sin zohjelohße, ävver $2 för de Bots.",
+ "api-help-param-integer-min": "{{PLURAL:$1|1=Dä Wäät darref|2=De Wääte dörrve}} nit kleijener wi $2 sin.",
+ "api-help-param-integer-max": "{{PLURAL:$1|1=Dä Wäät darref|2=De Wääte dörrve}} nit jrühßer wi $3 sin.",
+ "api-help-param-integer-minmax": "{{PLURAL:$1|1=Dä Wäät moß|2=De Wääte möße}} nit zwesche $2 un $3 lijje.",
+ "api-help-param-upload": "Moß als Datteij huhjelahde wähde met dä Eijeschaff „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">multipart/form-data</code>“.",
+ "api-help-param-multi-separate": "Donn de Wääte met <kbd>|</kbd> derzwesche tränne.",
+ "api-help-param-multi-max": "De jrühßte müjjelesche Zahl es {{PLURAL:$1|$1}}, un {{PLURAL:$2|$2}} för Botprojramme.",
"api-help-param-default": "Schtandatt: $1",
"api-help-param-default-empty": "Schtandatt: <span class=\"apihelp-empty\">(läddesch)</span>",
+ "api-help-param-disabled-in-miser-mode": "Dadd es wäje em [[mw:Manual:$wgMiserMode|miser mode]] affjeschalldt.",
"api-help-param-limited-in-miser-mode": "<strong>opjepaß:</strong> Weil der [[mw:Manual:$wgMiserMode|miser mode]] enjeschalld es, künne heh winnijer wi <var lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1limit</var> Äjehpneße ußjejejovve wähde, vör em Wigger_Mache. En Jränzfäll künne et Noll sin.",
- "api-help-param-direction": "En wälsche Reihjefollsch opleßte:\n;newer:List oldest first. Note: $1start has to be before $1end.\n;older:List newest first (default). Note: $1start has to be later than $1end.\n<!-- \nhttps://translatewiki.net/wiki/Thread:Support/About_MediaWiki:Api-help-param-direction/ksh\n-->",
+ "api-help-param-direction": "En wälsche Reihjefollsch opleßte:\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">newer</code>:De Ählsde et eez. Opjepaß: „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1start</code>“ moß fröhjer sin wi „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1end</code>“.\n;<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">older</code>:De Neuste et eez, der Schtanndatt. Opjepaß: „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1start</code>“ moß schpääder sin wi „<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">$1end</code>“.",
"api-help-param-continue": "Wann mih ze holle es, nemm dat för wigger ze maache.",
"api-help-param-no-description": "<span class=\"apihelp-empty\">(nix drövver bikannt)</span>",
"api-help-examples": "{{PLURAL:$1|Beijschpell|Beijschpelle|Beijschpell}}:",
diff --git a/includes/api/i18n/ku-latn.json b/includes/api/i18n/ku-latn.json
index a40e4c11..b625565b 100644
--- a/includes/api/i18n/ku-latn.json
+++ b/includes/api/i18n/ku-latn.json
@@ -4,6 +4,27 @@
"George Animal"
]
},
+ "apihelp-block-description": "Bikarhênerekî asteng bike.",
+ "apihelp-block-param-reason": "Sedemê bo astengkirinê.",
+ "apihelp-createaccount-param-name": "Navê bikarhêner.",
"apihelp-delete-description": "Rûpelekê jê bibe.",
- "apihelp-expandtemplates-param-title": "Sernavê rûpelê."
+ "apihelp-delete-example-simple": "<kbd>Destpêk</kbd>ê Jê bibe.",
+ "apihelp-edit-param-sectiontitle": "Sernavê bo beşeke nû.",
+ "apihelp-edit-param-text": "Naveroka rûpelê.",
+ "apihelp-edit-param-minor": "Guhertina biçûk.",
+ "apihelp-edit-param-createonly": "Heke ku rûpel hebe wê neguherîne.",
+ "apihelp-edit-example-edit": "Rûpelekê biguherîne.",
+ "apihelp-emailuser-description": "Ji bikarhêner re e-nameyekê bişîne.",
+ "apihelp-emailuser-param-target": "Bikarhênerê ku e-name jê rê bê şandin.",
+ "apihelp-expandtemplates-param-title": "Sernavê rûpelê.",
+ "apihelp-feedcontributions-param-deletedonly": "Tenê beşdariyên jêbirî nîşan bide.",
+ "apihelp-feedrecentchanges-example-simple": "Guherandinên dawî nîşan bide.",
+ "apihelp-feedrecentchanges-example-30days": "Guherandinên dawî yên 30 rojan nîşan bide",
+ "apihelp-help-example-recursive": "Hemû alîkarî di rûpelekê de.",
+ "apihelp-login-param-name": "Navê bikarhêner.",
+ "apihelp-login-param-password": "Şîfre.",
+ "apihelp-login-example-login": "Têkeve.",
+ "apihelp-move-param-reason": "Sedemê bo guherandina nav.",
+ "apihelp-move-param-ignorewarnings": "Guh nede hişyariyan.",
+ "apihelp-tag-param-reason": "Sedemê bo guherandinê."
}
diff --git a/includes/api/i18n/ky.json b/includes/api/i18n/ky.json
new file mode 100644
index 00000000..37619758
--- /dev/null
+++ b/includes/api/i18n/ky.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Janatkg"
+ ]
+ },
+ "apihelp-block-description": "Колдонуучуну бөгөттөө",
+ "apihelp-block-param-reason": "Бөгөттөө себеби.",
+ "apihelp-block-example-ip-simple": " <kbd>192.0.2.5</kbd> IP дарегин үч күнгө <kbd>First strike</kbd> себеби менен бөгөттөө.",
+ "apihelp-checktoken-param-token": "Текшерүү белгиси.",
+ "apihelp-createaccount-param-name": "Колдонуучунун аты:",
+ "apihelp-createaccount-param-email": "Колдонуучунун email дареги (милдеттүү эмес)",
+ "apihelp-createaccount-param-realname": "Колдонуучунун чыныгы аты (милдеттүү эмес)",
+ "apihelp-delete-description": "Баракты өчүрүү",
+ "apihelp-delete-example-simple": "<kbd>Башбарагын</kbd> өчүрүү.",
+ "apihelp-edit-description": "Барактарды түзүү жана оңдоо.",
+ "apihelp-edit-param-text": "Барактын мазмуну.",
+ "apihelp-edit-param-minor": "Майда оңдоо."
+}
diff --git a/includes/api/i18n/lb.json b/includes/api/i18n/lb.json
index ac2a1d34..c0fe7401 100644
--- a/includes/api/i18n/lb.json
+++ b/includes/api/i18n/lb.json
@@ -12,6 +12,7 @@
"apihelp-block-param-reblock": "Wann de Benotzer scho gespaart ass, déi aktuell Spär iwwerschreiwen.",
"apihelp-block-param-watchuser": "Dem Benotzer oder der IP-Adress hier Benotzer- an Diskussiouns-Säiten iwwerwaachen.",
"apihelp-compare-param-fromtitle": "Éischten Titel fir ze vergläichen.",
+ "apihelp-compare-param-torev": "Zweet Versioun fir ze vergläichen.",
"apihelp-createaccount-description": "En neie Benotzerkont uleeën.",
"apihelp-createaccount-param-name": "Benotzernumm.",
"apihelp-createaccount-param-email": "E-Mail-Adress vum Benotzer (fakultativ).",
@@ -21,26 +22,39 @@
"apihelp-delete-example-simple": "D'<kbd>Haaptsäit</kbd> läschen.",
"apihelp-disabled-description": "Dëse Modul gouf ausgeschalt.",
"apihelp-edit-param-sectiontitle": "Den Titel fir en neien Abschnitt.",
+ "apihelp-edit-param-text": "Säiteninhalt.",
"apihelp-edit-param-minor": "Kleng Ännerung.",
"apihelp-edit-param-bot": "Dës Ännerung als Bot-Ännerung markéieren.",
"apihelp-edit-param-watch": "D'Säit op dem aktuelle Benotzer seng Iwwerwaachungslëscht dobäisetzen.",
"apihelp-edit-example-edit": "Eng Säit änneren",
+ "apihelp-emailuser-example-email": "Dem Benotzer <kbd>WikiSysop</kbd> eng E-Mail mam Text <kbd>Inhalt</kbd> schécken.",
"apihelp-expandtemplates-param-title": "Titel vun der Säit.",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "D'Maximalzäit no där den Tëschespäicher vum Resultat net méi valabel si soll.",
+ "apihelp-feedcontributions-param-year": "Vum Joer (a virdrun).",
+ "apihelp-feedcontributions-param-month": "Vum Mount (a virdrun).",
"apihelp-feedrecentchanges-param-hideminor": "Kleng Ännerunge verstoppen.",
+ "apihelp-feedrecentchanges-param-hidebots": "Ännerunge vu Botte verstoppen.",
"apihelp-feedrecentchanges-param-hideanons": "Ännerunge vun anonyme Benotzer verstoppen.",
"apihelp-feedrecentchanges-param-hideliu": "Ännerunge vu registréierte Benotzer verstoppen.",
+ "apihelp-feedrecentchanges-param-hidemyself": "Ännerunge vum aktuelle Benotzer verstoppen.",
"apihelp-feedrecentchanges-example-simple": "Rezent Ännerunge weisen",
"apihelp-help-example-main": "Hëllef fir den Haaptmodul.",
"apihelp-help-example-recursive": "All Hëllef op enger Säit",
"apihelp-imagerotate-description": "Eent oder méi Biller dréinen.",
"apihelp-imagerotate-example-generator": "All Biller an der <kbd>Category:Flip]]<kbd> ëm <kbd>180<kbd> Grad dréinen.",
"apihelp-import-param-summary": "Resumé importéieren.",
+ "apihelp-import-param-xml": "Eropgeluedenen XML-Fichier.",
+ "apihelp-import-param-rootpage": "Als Ënnersäit vun dëser Säit importéieren. Kann net zesumme mam <var>$1namespace</var> benotzt ginn.",
"apihelp-login-param-name": "Benotzernumm.",
"apihelp-login-param-password": "Passwuert.",
"apihelp-login-example-login": "Aloggen.",
"apihelp-move-description": "Eng Säit réckelen.",
+ "apihelp-move-param-movetalk": "D'Diskussiounssäit ëmbenennen, wann et se gëtt.",
"apihelp-move-param-ignorewarnings": "All Warnungen ignoréieren.",
+ "apihelp-options-description": "Astellunge fir den aktuelle Benotzer änneren.\n\nNëmmen Optiounen aus dem Haaptdeel (core) oder aus enger vun den installéierten Erweiderunge, oder Optioune mat Schlësselen déi viragestallt si mat <code>userjs-</code> (geduecht fir mat Benotzer-Scripte benotzt ze ginn), kënnen agestallt ginn.",
+ "apihelp-options-param-optionname": "Den Numm vun der Optioun deen op de Wäert vun <var>$1optionvalue</var> gesat gi muss",
"apihelp-options-example-reset": "All Astellungen zrécksetzen",
+ "apihelp-parse-param-disablepp": "Benotzt an där Plaz <var>$1disablelimitreport</var>.",
"apihelp-patrol-example-rcid": "Eng rezent Ännerung nokucken.",
"apihelp-patrol-example-revid": "Eng Versioun nokucken.",
"apihelp-protect-example-protect": "Eng Säit spären",
@@ -48,16 +62,25 @@
"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+allusers-description": "All registréiert Benotzer opzielen.",
+ "apihelp-query+allusers-paramvalue-prop-implicitgroups": "Lëscht vun alle Gruppen an deenen de Benotzer automatesch dran ass.",
"apihelp-query+allusers-param-activeusers": "Nëmme Benotzer opzielen déi an de leschten $1 {{PLURAL:$1|Dag|Deeg}} aktiv waren.",
"apihelp-query+blocks-description": "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-example-simple": "Lëscht vun de Spären",
"apihelp-query+categories-description": "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-example-generator": "Informatioun iwwer all Kategorien, déi an der Säit <kbd>Albert Einstein</kbd> benotzt ginn, kréien.",
"apihelp-query+categorymembers-description": "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+deletedrevisions-param-excludeuser": "Versioune vun dësem Benotzer net opzielen.",
"apihelp-query+deletedrevs-param-unique": "Nëmmen eng Versioun fir all Säit weisen.",
+ "apihelp-query+embeddedin-param-filterredir": "Wéi Viruleedungen gefiltert gi sollen.",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "Alias fir Gréisst.",
"apihelp-query+filearchive-example-simple": "Eng Lëscht vun alle geläschte Fichiere weisen",
+ "apihelp-query+fileusage-paramvalue-prop-title": "Titel vun all Säit.",
"apihelp-query+imageinfo-paramvalue-prop-user": "Setzt fir all Versioun vum Fichier de Benotzer dobäi deen en eropgelueden huet.",
"apihelp-query+imageinfo-paramvalue-prop-comment": "Bemierkung iwwert d'Versioun.",
"apihelp-query+imageinfo-paramvalue-prop-dimensions": "Alias fir Gréisst.",
@@ -65,19 +88,51 @@
"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+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-paramvalue-prop-title": "Titel vun all Säit.",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "Markéiere wann d'Säit eng Viruleedung ass.",
+ "apihelp-query+pageswithprop-example-generator": "Zousätzlech Informatiounen iwwer déi 10 éischt Säite kréie mat <code>_&#95;NOTOC_&#95;</code>.",
"apihelp-query+protectedtitles-param-namespace": "Nëmmen Titelen aus dësen Nummraim opzielen.",
+ "apihelp-query+random-param-redirect": "Benotzt dofir <kbd>$1filterredir=Viruleedungen</kbd>.",
"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-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-ids": "D'Nummer vun der Versioun.",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "Den Zäitstempel vun der Versioun.",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "Benotzer deen d'Versioun gemaach huet.",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "Längt (Bytes) vun der Versioun.",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "SHA-1 (base 16) vun der Versioun.",
+ "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+transcludedin-paramvalue-prop-title": "Titel vun all Säit.",
"apihelp-query+usercontribs-description": "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+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+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+watchlistraw-param-show": "Nëmmen Elementer opzielen déi dëse Critèren entspriechen.",
"apihelp-query+watchlistraw-example-simple": "Säite vum aktuelle Benotzer senger Iwwerwaachungslëscht opzielen",
"apihelp-revisiondelete-description": "Versioune läschen a restauréieren.",
"apihelp-revisiondelete-param-reason": "Grond fir ze Läschen oder ze Restauréieren.",
"apihelp-rsd-example-simple": "Den RSD-Schema exportéieren",
+ "apihelp-tag-param-reason": "Grond fir d'Ännerung.",
"apihelp-unblock-description": "D'Spär vun engem Benotzer ophiewen.",
"apihelp-unblock-param-reason": "Grond fir d'Spär opzehiewen",
"apihelp-undelete-param-reason": "Grond fir ze restauréieren.",
@@ -88,7 +143,15 @@
"apihelp-userrights-param-userid": "Benotzer Id.",
"apihelp-userrights-param-reason": "Grond fir d'Ännerung.",
"apihelp-watch-example-watch": "D'Säit <kbd>Haaptsäit</kbd> iwwerwaachen.",
+ "api-help-source": "Quell: $1",
+ "api-help-source-unknown": "Quell: <span class=\"apihelp-unknown\">onbekannt</span>",
+ "api-help-license": "Lizenz: [[$1|$2]]",
+ "api-help-license-noname": "LiZenz: [[$1|Kuckt de Link]]",
+ "api-help-license-unknown": "Lizenz: <span class=\"apihelp-unknown\">onbekannt</span>",
"api-help-param-deprecated": "Vereelst.",
"api-help-param-required": "Dëse Parameter ass obligatoresch.",
- "api-help-examples": "{{PLURAL:$1|Beispill|Beispiler}}:"
+ "api-help-datatypes-header": "Datentypen",
+ "api-help-param-type-user": "Typ: {{PLURAL:$1|1=Benotzernumm|2=Lëscht vu Benotzernimm}}",
+ "api-help-examples": "{{PLURAL:$1|Beispill|Beispiler}}:",
+ "api-help-permissions": "{{PLURAL:$1|Autorisatioun|Autorisatiounen}}:"
}
diff --git a/includes/api/i18n/lv.json b/includes/api/i18n/lv.json
index b24e5f63..b163c227 100644
--- a/includes/api/i18n/lv.json
+++ b/includes/api/i18n/lv.json
@@ -1,8 +1,13 @@
{
"@metadata": {
"authors": [
- "Papuass"
+ "Papuass",
+ "Silraks"
]
},
+ "apihelp-block-description": "Bloķēt lietotāju",
+ "apihelp-block-param-reason": "Bloķēšanas iemesls:",
+ "apihelp-delete-description": "Dzēst lapas",
+ "apihelp-emailuser-description": "Sūtīt e-pastu lietotājam",
"apihelp-userrights-param-userid": "Lietotāja ID:"
}
diff --git a/includes/api/i18n/mk.json b/includes/api/i18n/mk.json
index 1efb45f3..80b41ed8 100644
--- a/includes/api/i18n/mk.json
+++ b/includes/api/i18n/mk.json
@@ -4,35 +4,40 @@
"Bjankuloski06"
]
},
- "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Документација]\n* [https://www.mediawiki.org/wiki/API:FAQ ЧПП]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Поштенски список]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Соопштенија за Извршникот]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Грешки и барања]\n</div>\n<strong>Статус:</strong> Сите ставки на страницава би требало да работат, но Извршникот сепак е во активна разработка, што значи дека може да се смени во секое време. Објавите за измени можете да ги дознавате ако се пријавите на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ поштенскиот список „the mediawiki-api-announce“].\n\n<strong>Погрешни барања:</strong> Кога Извршникот ќе добие погрешни барања, ќе се испрати HTTP-заглавие со клучот „MediaWiki-API-Error“ и потоа на вредностите на заглавието и шифрата на грешката што ќе се појават ќе им биде зададена истата вредност. ПОвеќе информации ќе најдете на https://www.mediawiki.org/wiki/API:Errors_and_warnings.",
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Документација]]\n* [[mw:API:FAQ|ЧПП]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Поштенски список]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Соопштенија за Извршникот]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Грешки и барања]\n</div>\n<strong>Статус:</strong> Сите ставки на страницава би требало да работат, но Извршникот сепак е во активна разработка, што значи дека може да се смени во секое време. Објавите за измени можете да ги дознавате ако се пријавите на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ поштенскиот список „the mediawiki-api-announce“].\n\n<strong>Погрешни барања:</strong> Кога Извршникот ќе добие погрешни барања, ќе се испрати HTTP-заглавие со клучот „MediaWiki-API-Error“ и потоа на вредностите на заглавието и шифрата на грешката што ќе се појават ќе им биде зададена истата вредност. ПОвеќе информации ќе најдете на [[mw:API:Errors_and_warnings|Извршник: Грешки и предупредувања]].",
"apihelp-main-param-action": "Кое дејство да се изврши.",
"apihelp-main-param-format": "Формат на изводот.",
- "apihelp-main-param-maxlag": "Максималниот заостаток може да се користи кога МедијаВики е воспоставен на грозд умножен од базата. За да спречите дополнителни заостатоци од дејства, овој параметар му наложува на клиентот да почека додека заостатокот не се намали под укажаната вредност. Во случај на преголем заостаток, системт ја дава грешката со код „maxlag“ со порака од обликот „Го чекам $host: има заостаток од $lag секунди“.<br />Погл. https://www.mediawiki.org/wiki/Manual:Maxlag_parameter за повеќе информации.",
- "apihelp-main-param-smaxage": "Задајте му олку секунди на заглавитето <code>s-maxage</code>. Грешките никогаш не се чуваат во меѓускладот.",
- "apihelp-main-param-maxage": "Задајте му олку секунди на заглавитето <code>max-age</code>. Грешките никогаш не се чуваат во меѓускладот.",
- "apihelp-main-param-assert": "Провери дали корисникот е најавен ако е зададено „user“ или дали го има корисничкото право на бот, ако е зададено „bot“.",
+ "apihelp-main-param-maxlag": "Максималниот заостаток може да се користи кога МедијаВики е воспоставен на грозд умножен од базата. За да спречите дополнителни заостатоци од дејства, овој параметар му наложува на клиентот да почека додека заостатокот не се намали под укажаната вредност. Во случај на преголем заостаток, системт ја дава грешката со код <samp>maxlag</samp> со порака од обликот <samp>Го чекам $host: има заостаток од $lag секунди</samp>.<br />Погл. [[mw:Manual:Maxlag_parameter|Прирачник: Параметар Maxlag]]",
+ "apihelp-main-param-smaxage": "Задајте му олку секунди на заглавието за контрола HTTP-меѓускладот <code>s-maxage</code>. Грешките никогаш не се чуваат во меѓускладот.",
+ "apihelp-main-param-maxage": "Задајте му олку секунди на заглавието за контрола HTTP-меѓускладот <code>s-maxage</code>. Грешките никогаш не се чуваат во меѓускладот.",
+ "apihelp-main-param-assert": "Провери дали корисникот е најавен ако е зададено <kbd>user</kbd> или дали го има корисничкото право на бот, ако е зададено <kbd>bot</kbd>.",
"apihelp-main-param-requestid": "Тука внесената вредност ќе биде вклучена во извештајот. Може да се користи за разликување на барањата.",
"apihelp-main-param-servedby": "Вклучи го домаќинското име што го услужило барањето во резултатите.",
"apihelp-main-param-curtimestamp": "Бклучи тековно време и време и датум во резултатот.",
- "apihelp-main-param-origin": "Кога му пристапувате на Пирлогот користејќи повеќедоменско AJAX-барање (CORS), задајте му го на ова изворниот домен. Ова мора да се вклучи во секое подготвително барање и затоа мора да биде дел од URI на барањето (не главната содржина во POST). Ова мора точно да се совпаѓа со еден од изворниците на заглавието Origin:, така што мора да е зададен на нешто како http://en.wikipedia.org or https://meta.wikimedia.org. Ако овој параметар не се совпаѓа со заглавието Origin:, ќе се појави одговор 403. Ако се совпаѓа, а изворникот е на бел список (на допуштени), тогаш ќе се зададе ззаглавието Контрола на пристап-Изворник.",
- "apihelp-main-param-uselang": "Јазик за преведување на пораките. Список на јазични кодови ќе најдете на [[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]] со siprop=languages или укажете „user“ за да го користите тековно зададениот јазик корисникот, или пак укажете „content“ за да го користите јазикот на содржината на ова вики.",
+ "apihelp-main-param-origin": "Кога му пристапувате на Пирлогот користејќи повеќедоменско AJAX-барање (CORS), задајте му го на ова изворниот домен. Ова мора да се вклучи во секое подготвително барање и затоа мора да биде дел од URI на барањето (не главната содржина во POST). Ова мора точно да се совпаѓа со еден од изворниците на заглавието Origin:, така што мора да е зададен на нешто како <kbd>https://mk.wikipedia.org</kbd> or <kbd>https://meta.wikimedia.org</kbd>. Ако овој параметар не се совпаѓа со заглавието <code>Origin</code>:, ќе се појави одговор 403. Ако се совпаѓа, а изворникот е на бел список (на допуштени), тогаш ќе се зададе заглавието <code>Access-Control-Allow-Origin</code>.",
+ "apihelp-main-param-uselang": "Јазик за преведување на пораките. Список на јазични кодови ќе најдете на <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> со <kbd>siprop=languages</kbd> или укажете <kbd>user</kbd> за да го користите тековно зададениот јазик корисникот, или пак укажете <kbd>content</kbd> за да го користите јазикот на содржината на ова вики.",
"apihelp-block-description": "Блокирај корисник.",
"apihelp-block-param-user": "Корисничко име, IP-адреса или IP-опсег ако сакате да блокирате.",
- "apihelp-block-param-expiry": "Време на истек. Може да биде релативно (на пр. „5 месеци“ или „2 недели“) или пак апсолутно (на пр. „2014-09-18T12:34:56Z“). Ако го зададете „бесконечно“, „неодредено“ или „никогаш“, блокот ќе трае засекогаш.",
+ "apihelp-block-param-expiry": "Време на истек. Може да биде релативно (на пр. <kbd>5 months</kbd> или „2 недели“) или пак апсолутно (на пр. <kbd>2014-09-18T12:34:56Z</kbd>). Ако го зададете <kbd>infinite</kbd>, <kbd>indefinite</kbd> или <kbd>never</kbd>, блокот ќе трае засекогаш.",
"apihelp-block-param-reason": "Причина за блокирање.",
"apihelp-block-param-anononly": "Блокирај само анонимни корисници (т.е. оневозможи анонимно уредување од оваа IP-адреса).",
"apihelp-block-param-nocreate": "Оневозможи создавање кориснички сметки.",
"apihelp-block-param-autoblock": "Автоматски блокирај ја последно употребената IP-адреса и сите понатамошни IP-адреси од кои лицето ќе се обиде да се најави.",
- "apihelp-block-param-noemail": "Оневозможи му на корисникот да испаќа е-пошта преку викито. (Го бара правото „блокирање е-пошта“).",
- "apihelp-block-param-hidename": "Скриј го корисничкото име од дневникот на блокирања. (Го бара правото „скривање корисник“)",
+ "apihelp-block-param-noemail": "Оневозможи му на корисникот да испаќа е-пошта преку викито. (Го бара правото code>blockemail</code>).",
+ "apihelp-block-param-hidename": "Скриј го корисничкото име од дневникот на блокирања. (Го бара правото <code>hideuser</code>)",
"apihelp-block-param-allowusertalk": "Овозможи му на корисникот да си ја уредува сопствената страница за разговор (зависи од <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
"apihelp-block-param-reblock": "Ако корисникот е веќе блокиран, наметни врз постоечкиот блок.",
"apihelp-block-param-watchuser": "Набљудувај ја корисничката страница и страницата за разговор на овој корисник или IP-адреса",
- "apihelp-block-example-ip-simple": "Блокирај ја IP-адресата 192.0.2.5 три дена со причината „Прва опомена“",
- "apihelp-block-example-user-complex": "Блокирај го корисникот Вандал (Vandal) бесконечно со причината „Вандализам“ и оневозможи создавање на нови сметки и праќање е-пошта",
+ "apihelp-block-example-ip-simple": "Блокирај ја IP-адресата <kbd>192.0.2.5</kbd> три дена со причината <kbd>Прва опомена</kbd>.",
+ "apihelp-block-example-user-complex": "Блокирај го корисникот <kbd>Vandal</kbd> (Вандал) бесконечно со причината <kbd>Vandal</kbd> (Вандализам) и оневозможи создавање на нови сметки и праќање е-пошта.",
+ "apihelp-checktoken-description": "Проверка на полноважноста на шифрата од <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
+ "apihelp-checktoken-param-type": "Тип на шифра што се испробува.",
+ "apihelp-checktoken-param-token": "Шифра што се испробува.",
+ "apihelp-checktoken-param-maxtokenage": "Најголема допуштена старост на шифрата, во секунди.",
+ "apihelp-checktoken-example-simple": "Испробај ја полноважноста на <kbd>csrf</kbd>-шифрата.",
"apihelp-clearhasmsg-description": "Ја отстранува ознаката „<code>hasmsg</code>“ од тековниот корисник.",
"apihelp-clearhasmsg-example-1": "Отстрани ја ознаката „<code>hasmsg</code>“ од тековниот корисник",
- "apihelp-compare-description": "Добивање на разлика помеѓу две страници.\n\nМора да се добие број на преработката, наслов на странивата или пак нејзина назнака. Важи и за „од“ и за „на“.",
+ "apihelp-compare-description": "Добивање на разлика помеѓу две страници.\n\nМора да се даде бројот на преработката, насловот на страницата или пак нејзина назнака за „од“ и за „на“.",
"apihelp-compare-param-fromtitle": "Прв наслов за споредба.",
"apihelp-compare-param-fromid": "Прва назнака на страница за споредба.",
"apihelp-compare-param-fromrev": "Прва преработка за споредба.",
@@ -50,37 +55,38 @@
"apihelp-createaccount-param-mailpassword": "Ако му се зададе било каква вредност, тогаш на корисникот ќе му биде испратена случајна лозинка.",
"apihelp-createaccount-param-reason": "Незадолжителна прочина за создавање на сметката која ќе стои во дневниците.",
"apihelp-createaccount-param-language": "Јазичен код кој ќе биде стандарден за корисникот (незадолжително, по основно: јазикот на самото вики).",
- "apihelp-createaccount-example-pass": "Создај го корисникот „testuser“ со лозинката „test123“",
- "apihelp-createaccount-example-mail": "Создај го корисникот „testmailuser“ и испрати случајно-создадена лозинка по е-пошта",
+ "apihelp-createaccount-example-pass": "Создај го корисникот <kbd>testuser</kbd> со лозинката <kbd>test123</kbd>.",
+ "apihelp-createaccount-example-mail": "Создај го корисникот <kbd>testmailuser</kbd> и испрати случајно-создадена лозинка по е-пошта.",
"apihelp-delete-description": "Избриши страница.",
- "apihelp-delete-param-title": "Наслов на страницата што сакате да ја избришете. Не може да се користи заедно со $1pageid.",
- "apihelp-delete-param-pageid": "Назнака на страницата што сакате да ја избришете. Не може да се користи заедно со $1title.",
+ "apihelp-delete-param-title": "Наслов на страницата што сакате да ја избришете. Не може да се користи заедно со <var>$1pageid</var>.",
+ "apihelp-delete-param-pageid": "Назнака на страницата што сакате да ја избришете. Не може да се користи заедно со <var>$1title</var>.",
"apihelp-delete-param-reason": "Причина за бришење. Ако не се зададе, ќе се наведе автоматска причина.",
- "apihelp-delete-param-watch": "Додај ја страницата во набљудуваните.",
- "apihelp-delete-param-watchlist": "Безусловно додај или отстрани ја страницата од набљудуваните, користете ги нагодувањата или не ги менувајте набљудуваните.",
- "apihelp-delete-param-unwatch": "Отстрани ја страницата од набљудуваните.",
+ "apihelp-delete-param-watch": "Додај ја страницата во набљудуваните на тековниот корисник.",
+ "apihelp-delete-param-watchlist": "Безусловно додај или отстрани ја страницата од набљудуваните на тековниот корисник, користете ги нагодувањата или не ги менувајте набљудуваните.",
+ "apihelp-delete-param-unwatch": "Отстрани ја страницата од набљудуваните на тековниот корисник.",
"apihelp-delete-param-oldimage": "Името на страта слика за бришење според добиеното од [[Special:ApiHelp/query+imageinfo|action=query&prop=imageinfo&iiprop=archivename]].",
- "apihelp-delete-example-simple": "Избриши ја Главната страница",
- "apihelp-delete-example-reason": "Избриши ја Главната страница со причината „Подготовка за преместување“",
+ "apihelp-delete-example-simple": "Избриши ја <kbd>Главна страница</kbd>.",
+ "apihelp-delete-example-reason": "Избриши ја <kbd>Главна страница</kbd> со причината <kbd>Подготовка за преместување</kbd>.",
"apihelp-disabled-description": "Модулот е деактивиран.",
"apihelp-edit-description": "Создај или уреди страници.",
- "apihelp-edit-param-title": "Наслов на страницата што сакате да ја уредите. Не може да се користи заедно со $1pageid.",
- "apihelp-edit-param-pageid": "Назнака на страницата што сакате да ја уредите. Не може да се користи заедно со $1title.",
- "apihelp-edit-param-section": "Број на поднасловот. 0 за првиот, „new“ за нов.",
+ "apihelp-edit-param-title": "Наслов на страницата што сакате да ја уредите. Не може да се користи заедно со <var>$1pageid</var>.",
+ "apihelp-edit-param-pageid": "Назнака на страницата што сакате да ја уредите. Не може да се користи заедно со <var>$1title</var>.",
+ "apihelp-edit-param-section": "Број на поднасловот. <kbd>0</kbd> за првиот, <kbd>new</kbd> за нов.",
"apihelp-edit-param-sectiontitle": "Назив на новиот поднаслов",
"apihelp-edit-param-text": "Содржина на страницата.",
"apihelp-edit-param-summary": "Опис на уредувањето. Ова е и назив на поднасловот кога не се зададени $1section=new и $1sectiontitle.",
+ "apihelp-edit-param-tags": "Ознаки за измена што се однесуваат на преработката.",
"apihelp-edit-param-minor": "Ситно уредување.",
"apihelp-edit-param-notminor": "Неситно уредување.",
"apihelp-edit-param-bot": "Означи го уредувањево како ботско.",
"apihelp-edit-param-basetimestamp": "Датум и време на преработката на базата, кои се користат за утврдување на спротиставености во уредувањето. Може да се добие преку [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
- "apihelp-edit-param-starttimestamp": "Датум и време кога сте го почнале уредувањето, кои се користат за утврдување на спротиставености во уредувањата. Соодветната вредност се добива користејќи [[Special:ApiHelp/main|curtimestamp]] кога ќе почнете со уредување (на пр. кога ќе се вчита содржината што ќе ја уредувате).",
- "apihelp-edit-param-recreate": "Занемари ги грешките што се појавуваат во врска со статијата што е избришана во меѓувреме.",
+ "apihelp-edit-param-starttimestamp": "Датум и време кога сте почнало уредувањето, кои се користат за утврдување на спротиставености во уредувањата. Соодветната вредност се добива користејќи <var>[[Special:ApiHelp/main|curtimestamp]]</var> кога ќе почнете со уредување (на пр. кога ќе се вчита содржината што ќе ја уредувате).",
+ "apihelp-edit-param-recreate": "Занемари ги грешките што се појавуваат во врска со страницата што е избришана во меѓувреме.",
"apihelp-edit-param-createonly": "Не ја уредувај страницата ако веќе постои.",
"apihelp-edit-param-nocreate": "Дај грешка ако страницата не постои.",
- "apihelp-edit-param-watch": "Додај ја страницата во набљудуваните.",
- "apihelp-edit-param-unwatch": "Отстрани ја страницата од набљудуваните.",
- "apihelp-edit-param-watchlist": "Безусловно додај или отстрани ја страницата од набљудуваните, користете ги нагодувањата или не ги менувајте набљудуваните.",
+ "apihelp-edit-param-watch": "Додај ја страницата во набљудуваните на тековниот корисник.",
+ "apihelp-edit-param-unwatch": "Отстрани ја страницата од набљудуваните на тековниот корисник.",
+ "apihelp-edit-param-watchlist": "Безусловно додај или отстрани ја страницата од набљудуваните на тековниот корисник, користете ги нагодувањата или не ги менувајте набљудуваните.",
"apihelp-edit-param-md5": "MD5-тарабата на параметарот $1text, или параметрите $1prependtext и $1appendtext поврзани. Ако е зададено, уредувањето нема да се изврши без тарабата да биде исправна.",
"apihelp-edit-param-prependtext": "Ставете го текстов на почетокот од страницата. Го заменува $1text.",
"apihelp-edit-param-appendtext": "Ставете го текстов на крајот од страницата. Го заменува $1text.\n\nКористете $1section=new наместо овој параметар за да приложите кон новиот поднаслов.",
@@ -98,15 +104,16 @@
"apihelp-emailuser-param-subject": "Наслов.",
"apihelp-emailuser-param-text": "Содржина.",
"apihelp-emailuser-param-ccme": "Прати ми примерок и мене.",
- "apihelp-emailuser-example-email": "Испрати е-пошта на корисникот „WikiSysop“ со текстот „Содржина“",
+ "apihelp-emailuser-example-email": "Испрати е-пошта на корисникот <kbd>WikiSysop</kbd> со текстот <kbd>Содржина</kbd>.",
"apihelp-expandtemplates-description": "Ги проширува сите шаблони во викитекст.",
"apihelp-expandtemplates-param-title": "Наслов на страница.",
"apihelp-expandtemplates-param-text": "Викитекст за претворање.",
"apihelp-expandtemplates-param-revid": "Назнака на преработката, за <nowiki>{{REVISIONID}}</nowiki> и слични променливи.",
- "apihelp-expandtemplates-param-prop": "Кои информации треба да ги добиете:\n;wikitext:The expanded wikitext.\n;categories: Категориите присутно во вносот кои не се претставени во викитекстуалниот извод.\n;volatile: Дали изводот е месно врзан и не треба да се преупотребува на други места во страницата.\n;ttl: Максималното време по кое треба да се поништи меѓускладираниот резултат.\n;parsetree: XML-дрвото на расчленување за изводот.\nИмајте на ум дека ако не изберете никаква вредност, резултатот ќе го содржи викитекстот, но изводот ќе биде во застарен формат.",
+ "apihelp-expandtemplates-param-prop": "Кои информации треба да ги добиете:\n\nИмајте на ум дека ако не изберете никаква вредност, резултатот ќе го содржи викитекстот, но изводот ќе биде во застарен формат.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "Проширениот викитекст.",
"apihelp-expandtemplates-param-includecomments": "Дали во изводот да се вклучени HTML-коментари.",
"apihelp-expandtemplates-param-generatexml": "Создај XML-дрво на расчленување (заменето со $1prop=parsetree).",
- "apihelp-expandtemplates-example-simple": "Прошири го викитекстот „<nowiki>{{Project:Sandbox}}</nowiki>“",
+ "apihelp-expandtemplates-example-simple": "Прошири го викитекстот <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
"apihelp-feedcontributions-description": "Дава канал со придонеси на корисник.",
"apihelp-feedcontributions-param-feedformat": "Формат на каналот.",
"apihelp-feedcontributions-param-user": "За кои корисници да се прикажуваат придонесите.",
@@ -118,7 +125,7 @@
"apihelp-feedcontributions-param-toponly": "Прикажувај само последни преработки.",
"apihelp-feedcontributions-param-newonly": "Прикажувај само новосоздадени страници",
"apihelp-feedcontributions-param-showsizediff": "Покажувај ја големинската разлика меѓу преработките.",
- "apihelp-feedcontributions-example-simple": "Покажувај придонеси на [[Корисник:Пример]]",
+ "apihelp-feedcontributions-example-simple": "Покажувај придонеси на <kbd>Пример</kbd>.",
"apihelp-feedrecentchanges-description": "Дава канал со скорешни промени.",
"apihelp-feedrecentchanges-param-feedformat": "Форматот на каналот.",
"apihelp-feedrecentchanges-param-namespace": "На кој именски простор да се ограничат резултатите.",
@@ -132,7 +139,7 @@
"apihelp-feedrecentchanges-param-hideanons": "Скриј ги промените направени од анонимни корисници.",
"apihelp-feedrecentchanges-param-hideliu": "Скриј ги промените направени од регистрирани корисници.",
"apihelp-feedrecentchanges-param-hidepatrolled": "Скриј ги испатролираните промени.",
- "apihelp-feedrecentchanges-param-hidemyself": "Скриј ги моите промени.",
+ "apihelp-feedrecentchanges-param-hidemyself": "Скриј ги промените на тековниот корисник.",
"apihelp-feedrecentchanges-param-tagfilter": "Филтрирање по ознака.",
"apihelp-feedrecentchanges-param-target": "Прикажи само промени на страници што водат од оваа.",
"apihelp-feedrecentchanges-param-showlinkedto": "Наместо тоа, прикажи ги промените на страниците поврзани со избраната страница.",
@@ -150,7 +157,7 @@
"apihelp-filerevert-param-archivename": "Архивски назив на преработката што ја повраќате.",
"apihelp-filerevert-example-revert": "Врати ја <kbd>Wiki.png</kbd> на верзијата од <kbd>2011-03-05T15:27:40Z</kbd>",
"apihelp-help-description": "Прикажувај помош за укажаните модули.",
- "apihelp-help-param-modules": "Модули за приказ на помош за (вредности на параметрите action= и format=, или пак „main“). Може да се укажат подмодули со „+“.",
+ "apihelp-help-param-modules": "Модули за приказ на помош за (вредности на параметрите <var>action</var> и <var>format</var>, или пак <kbd>main</kbd>). Може да се укажат подмодули со <kbd>+</kbd>.",
"apihelp-help-param-submodules": "Прикажувај и помош за подмодули на именуваниот модул.",
"apihelp-help-param-recursivesubmodules": "Прикажувај и помош за подмодули рекурзивно.",
"apihelp-help-param-helpformat": "Формат на изводот на помошта.",
@@ -162,18 +169,18 @@
"apihelp-help-example-query": "Помош за два подмодула за барања",
"apihelp-imagerotate-description": "Сврти една или повеќе слики.",
"apihelp-imagerotate-param-rotation": "За колку степени да се сврти надесно.",
- "apihelp-imagerotate-example-simple": "Сврти ја [[:Податотека:Пример.png]] за 90 степени",
- "apihelp-imagerotate-example-generator": "Сврти ги сите слики во [[:Категорија:Некоја]] за 180 степени",
- "apihelp-import-description": "Увези страница од друго вики или XML-податотека.\n\nИмајте на ум дека POST на HTTP мора да се изведе како подигање на податотеката (т.е. користејќи повеќеделни податоци/податоци од образец) кога ја испраќате податотеката за параметарот „xml“.",
+ "apihelp-imagerotate-example-simple": "Сврти ја <kbd>Податотека:Пример.png</kbd> за <kbd>90</kbd> степени.",
+ "apihelp-imagerotate-example-generator": "Сврти ги сите слики во <kbd>Категорија:Некоја</kbd> за <kbd>180</kbd> степени.",
+ "apihelp-import-description": "Увези страница од друго вики или од XML-податотека.\n\nИмајте на ум дека POST на HTTP мора да се изведе како подигање на податотеката (т.е. користејќи повеќеделни податоци/податоци од образец) кога ја испраќате податотеката за параметарот <var>xml</var>.",
"apihelp-import-param-summary": "Увези опис.",
"apihelp-import-param-xml": "Подигната XML-податотека.",
"apihelp-import-param-interwikisource": "За меѓујазични увози: од кое вики да се увезе.",
"apihelp-import-param-interwikipage": "За меѓујазични увози: страница за увоз.",
"apihelp-import-param-fullhistory": "За меѓујазични увози:: увези ја целата историја, а не само тековната верзија.",
"apihelp-import-param-templates": "За меѓујазични увози: увези ги и сите вклучени шаблони.",
- "apihelp-import-param-namespace": "За меѓујазични увози: увези во овој именски простор.",
- "apihelp-import-param-rootpage": "Увези како потстраница на страницава.",
- "apihelp-import-example-import": "Увези [[meta:Help:Parserfunctions]] во именскиот простор 100 со целата историја.",
+ "apihelp-import-param-namespace": "Увези во овој именски простор. Не може да се користи заедно со <kbd>$1rootpage</kbd>.",
+ "apihelp-import-param-rootpage": "Увези како потстраница на страницава. Не може да се користи заедно со <kbd>$1namespace</kbd>.",
+ "apihelp-import-example-import": "Увези [[meta:Help:ParserFunctions]] во именскиот простор 100 со целата историја.",
"apihelp-login-description": "Најавете се и добијте колачиња за заверка.\n\nВо случај кога ќе се најавите успешно, потребните колачиња ќе се придодадат кон заглавијата на HTTP-одѕивот. Во случај да не успеете да се најавите, понатамошните обиди може да се ограничат за да се ограничат нападите со автоматизирано погодување на лозинката.",
"apihelp-login-param-name": "Корисничко име.",
"apihelp-login-param-password": "Лозинка.",
@@ -184,46 +191,46 @@
"apihelp-logout-description": "Одјави се и исчисти ги податоците на седницата.",
"apihelp-logout-example-logout": "Одјави го тековниот корисник",
"apihelp-move-description": "Премести страница.",
- "apihelp-move-param-from": "Наслов на страницата што сакате да ја преместите. Не може да се користи заедно со $1fromid.",
- "apihelp-move-param-fromid": "Назнака на страницата што сакате да ја преместите. Не може да се користи заедно со $1from.",
- "apihelp-move-param-to": "Како сакате да гласи новиот наслов на страницата.",
- "apihelp-move-param-reason": "Причина за преместувањето.",
- "apihelp-move-param-movetalk": "Премести ја и страницата за разговор, ако ја има.",
- "apihelp-move-param-movesubpages": "Премести потстраници, ако има",
+ "apihelp-move-param-from": "Наслов на страницата што треба да се премести. Не може да се користи заедно со <var>$1fromid</var>.",
+ "apihelp-move-param-fromid": "Назнака на страницата што треба да се премести. Не може да се користи заедно со <var>$1from</var>.",
+ "apihelp-move-param-to": "Како да гласи новата страница.",
+ "apihelp-move-param-reason": "Причина за преименувањето.",
+ "apihelp-move-param-movetalk": "Преименувај ја и страницата за разговор, ако ја има.",
+ "apihelp-move-param-movesubpages": "Преименувај потстраници, ако има.",
"apihelp-move-param-noredirect": "Не прави пренасочување.",
- "apihelp-move-param-watch": "Додај ги страницата и пренасочувањето во набљудуваните.",
- "apihelp-move-param-unwatch": "Отстрани ги страницата и пренасочувањето од набљудуваните.",
- "apihelp-move-param-watchlist": "Безусловно додај или отстрани ја страницата од набљудуваните, користете ги нагодувањата или не ги менувајте набљудуваните.",
+ "apihelp-move-param-watch": "Додај ги страницата и пренасочувањето во набљудуваните на тековниот корисник.",
+ "apihelp-move-param-unwatch": "Отстрани ги страницата и пренасочувањето од набљудуваните на тековниот корисник.",
+ "apihelp-move-param-watchlist": "Безусловно додај или отстрани ја страницата од набљудуваните на тековниот корисник, користете ги нагодувањата или не ги менувајте набљудуваните.",
"apihelp-move-param-ignorewarnings": "Занемари предупредувања.",
- "apihelp-move-example-move": "Премести го „Лош наслов“ на „Добар наслов“, неоставајќи пренасочување",
+ "apihelp-move-example-move": "Премести го <kbd>Лош наслов</kbd> на <kbd>Добар наслов</kbd>, неоставајќи пренасочување",
"apihelp-opensearch-description": "Пребарување на викито со протоколот OpenSearch.",
"apihelp-opensearch-param-search": "Низа за пребарување.",
"apihelp-opensearch-param-limit": "Максималниот број на резултати за прикажување.",
"apihelp-opensearch-param-namespace": "Именски простори за пребарување.",
- "apihelp-opensearch-param-suggest": "Не прави ништо ако [https://www.mediawiki.org/wiki/Manual:$wgEnableOpenSearchSuggest $wgEnableOpenSearchSuggest] е неточно.",
+ "apihelp-opensearch-param-suggest": "Не прави ништо ако <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> е неточно.",
"apihelp-opensearch-param-redirects": "Како да се работи со пренасочувања:\n;return: Дај го самото пренасочување.\n;resolve: Дај ја целната страница. Може да даде помалку од $1limit резултати.\nОд историски причини, по основно е „return“ за $1format=json и „resolve“ за други формати.",
"apihelp-opensearch-param-format": "Формат на изводот.",
- "apihelp-opensearch-example-te": "Најди страници што почнуваат со „Те“",
- "apihelp-options-description": "Смени ги нагодувањата на тековниот корисник.\n\nМожат да се зададат само можностите заведени во јадрото или во едно од воспоставените додатоци, или пак можности со клуч кој ја има претставката „userjs-“ (предвиден за употреба од кориснички скрипти).",
+ "apihelp-opensearch-example-te": "Најди страници што почнуваат со <kbd>Те</kbd>.",
+ "apihelp-options-description": "Смени ги нагодувањата на тековниот корисник.\n\nМожат да се зададат само можностите заведени во јадрото или во едно од воспоставените додатоци, или пак можности со клуч кој ја има претставката <code>userjs-</code> (предвиден за употреба од кориснички скрипти).",
"apihelp-options-param-reset": "Ги враќа поставките по основно.",
- "apihelp-options-param-resetkinds": "Писок на типови можности за повраток кога е зададена можноста „$1reset“.",
+ "apihelp-options-param-resetkinds": "Писок на типови можности за повраток кога е зададена можноста <var>$1reset</var>.",
"apihelp-options-param-change": "Список на промени во форматот name=value (на пр. skin=vector). Вредностите не треба да содржат исправени црти. Ако не зададете вредност (дури ни знак за равенство), на пр., можност|другаможност|..., ќе биде зададена вредноста на можноста по основно.",
- "apihelp-options-param-optionname": "Назив на можноста што треба да ѝ се зададе на вредноста дадена од „$1optionvalue“.",
- "apihelp-options-param-optionvalue": "Вредноста на можноста укажана од „$1optionnam“. Може да содржи исправени црти.",
+ "apihelp-options-param-optionname": "Назив на можноста што треба да ѝ се зададе на вредноста дадена од <var>$1optionvalue</var>.",
+ "apihelp-options-param-optionvalue": "Вредноста на можноста укажана од <var>$1optionname</var>. Може да содржи исправени црти.",
"apihelp-options-example-reset": "Врати ги сите поставки по основно",
- "apihelp-options-example-change": "Смени ги поставките „skinЗ“ и „hideminor“",
- "apihelp-options-example-complex": "Врати ги сите нагодувања по основно, а потоа задај ги „skin“ и „nickname“",
+ "apihelp-options-example-change": "Смени ги поставките <kbd>skin</kbd и <kbd>hideminor</kbd>.",
+ "apihelp-options-example-complex": "Врати ги сите нагодувања по основно, а потоа задај ги <kbd>skin</kbd> и <kbd>nickname</kbd>.",
"apihelp-paraminfo-description": "Набави информации за извршнички (API) модули.",
- "apihelp-paraminfo-param-modules": "Список на називи на модули (вредности на параметрите action= и format=, или пак „main“). Може да се укажат подмодули со „+“.",
+ "apihelp-paraminfo-param-modules": "Список на називи на модули (вредности на параметрите <var>action</var> и <var>format</var>, или пак <kbd>main</kbd>). Може да се укажат подмодули со <kbd>+</kbd>.",
"apihelp-paraminfo-param-helpformat": "Формат на помошните низи.",
- "apihelp-paraminfo-param-querymodules": "Список на називи на модули за барања (вредност на параметарот prop=, meta= или list=). Користете го „$1modules=query+foo“ наместо „$1querymodules=foo“.",
- "apihelp-paraminfo-param-mainmodule": "Добави информации и за главниот (врховен) модул. Користете го „$1modules=main“ наместо тоа.",
+ "apihelp-paraminfo-param-querymodules": "Список на називи на модули за барања (вредност на параметарот <var>prop</var>, <var>meta</var> или <var>list</var>). Користете го <kbd>$1modules=query+foo</kbd> наместо <kbd>$1querymodules=foo</kbd>.",
+ "apihelp-paraminfo-param-mainmodule": "Добави информации и за главниот (врховен) модул. Користете го <kbd>$1modules=main</kbd> наместо тоа.",
"apihelp-paraminfo-param-pagesetmodule": "Дај ги сите информации и за модулот на збирот страници (укажувајќи titles= и сродни).",
- "apihelp-paraminfo-param-formatmodules": "Список на називи на форматни модули (вредностза параметарот format=). Наместо тоа, користете го „$1modules“.",
+ "apihelp-paraminfo-param-formatmodules": "Список на називи на форматни модули (вредностза параметарот <var>format</var>). Наместо тоа, користете го <var>$1modules</var>.",
"apihelp-parse-param-summary": "Опис за расчленување.",
"apihelp-parse-param-preview": "Расчлени во прегледен режим.",
"apihelp-parse-param-sectionpreview": "Расчлени во прегледен режим на поднасловот (го овозможува и прегледниот режим).",
- "apihelp-parse-param-disabletoc": "Изземи го преглед на содржината во изводеот.",
+ "apihelp-parse-param-disabletoc": "Изземи го преглед на содржината во изводот.",
"apihelp-parse-param-contentformat": "Формат на серијализацијата на содржината во вносниот текст. Важи само кога се користи со $1text.",
"apihelp-parse-example-page": "Расчлени страница.",
"apihelp-parse-example-text": "Расчлени викитекст.",
@@ -240,7 +247,7 @@
"apihelp-protect-param-reason": "Причиина за (од)заштитување",
"apihelp-protect-example-protect": "Заштити страница",
"apihelp-purge-param-forcelinkupdate": "Поднови ги табелите со врски.",
- "apihelp-purge-example-simple": "Превчитај ги „Главна страница“ и „Извршник“",
+ "apihelp-purge-example-simple": "Превчитај ги <kbd>Главна страница</kbd> и <kbd>Извршник</kbd>.",
"apihelp-query-param-list": "Кои списоци да се набават.",
"apihelp-query-param-meta": "Кои метаподатоци да се набават.",
"apihelp-query+allcategories-description": "Наброј ги сите категории.",
@@ -249,20 +256,23 @@
"apihelp-query+allcategories-param-dir": "Насока на подредувањето.",
"apihelp-query+alldeletedrevisions-param-from": "Почни го исписот од овој наслов.",
"apihelp-query+alldeletedrevisions-param-to": "Запри го исписот на овој наслов.",
- "apihelp-query+alldeletedrevisions-example-user": "Список на последните 50 избришани придонеси на Корисник:Пример",
- "apihelp-query+alldeletedrevisions-example-ns-main": "Список на последните 50 избришани преработки во главниот именски простор",
- "apihelp-query+allimages-example-B": "Прикажи список на податотеки што почнуваат со буквата „Б“",
+ "apihelp-query+alldeletedrevisions-example-user": "Список на последните 50 избришани придонеси на корисникот <kbd>Пример<kbd>.",
+ "apihelp-query+alldeletedrevisions-example-ns-main": "Список на последните 50 избришани преработки во главниот именски простор.",
+ "apihelp-query+allimages-example-B": "Прикажи список на податотеки што почнуваат со буквата <kbd>Б</kbd>.",
"apihelp-query+allimages-example-recent": "Прикажи список на неодамна подигнати податотеки сличен на [[Special:NewFiles]]",
- "apihelp-query+allimages-example-generator": "Прикажи информации за околу 4 податотеки што почнуваат со буквата „Т“",
+ "apihelp-query+allimages-example-generator": "Прикажи информации за околу 4 податотеки што почнуваат со буквата <kbd>Т</kbd>.",
"apihelp-query+alllinks-description": "Наброј ги сите врски што водат кон даден именски простор.",
"apihelp-query+alllinks-param-from": "Наслов на врската од која ќе почне набројувањето.",
"apihelp-query+alllinks-param-to": "Наслов на врската на која ќе запре набројувањето.",
"apihelp-query+alllinks-param-prefix": "Пребарај ги сите сврзани наслови што почнуваат со оваа вредност.",
- "apihelp-query+alllinks-param-unique": "Прикажувај само различни поврзани наслови. Не може да се користи со $1prop=ids.\nКога се користи како создавач, дава целни страници наместо изворни.",
+ "apihelp-query+alllinks-param-unique": "Прикажувај само различни поврзани наслови. Не може да се користи со <kbd>$1prop=ids</kbd>.\nКога се користи како создавач, дава целни страници наместо изворни.",
+ "apihelp-query+alllinks-param-prop": "Кои информации да се вклучат:",
+ "apihelp-query+alllinks-paramvalue-prop-ids": "Ја додава назнаката на страницата на која е врската (не може да се користи со <var>$1unique</var>).",
+ "apihelp-query+alllinks-paramvalue-prop-title": "Го додава насловот на врската.",
"apihelp-query+alllinks-param-namespace": "Именскиот простор што се набројува.",
"apihelp-query+alllinks-param-limit": "Колку вкупно ставки да се дадат.",
"apihelp-query+alllinks-param-dir": "Насока на исписот.",
- "apihelp-query+alllinks-example-B": "Списока на наслови со врски, вклучувајќи ги отсутните, со назнаки на нивните страници, почнувајќи од Б",
+ "apihelp-query+alllinks-example-B": "Списока на наслови со врски, вклучувајќи ги отсутните, со назнаки на нивните страници, почнувајќи од <kbd>Б</kbd>.",
"apihelp-query+alllinks-example-unique": "Испиши единствени наслови со врски",
"apihelp-query+alllinks-example-unique-generator": "Ги дава сите наслови со врски, означувајќи ги отсутните",
"apihelp-query+alllinks-example-generator": "Дава страници што ги содржат врските",
@@ -275,8 +285,8 @@
"apihelp-query+allmessages-param-to": "Дај пораки што завршуваат со оваа порака.",
"apihelp-query+allmessages-param-title": "Назив на страницата што ќе се користи во контекст кога се расчленува порака (за можноста $1enableparser).",
"apihelp-query+allmessages-param-prefix": "Дај пораки со оваа претставка.",
- "apihelp-query+allmessages-example-ipb": "Прикажи ги пораките што започнуваат со „ipb-“",
- "apihelp-query+allmessages-example-de": "Прикажи ги пораките „август“ и „главна страница“ на германски",
+ "apihelp-query+allmessages-example-ipb": "Прикажи ги пораките што започнуваат со <kbd>ipb-</kbd>.",
+ "apihelp-query+allmessages-example-de": "Прикажи ги пораките <kbd>august</kbd> and <kbd>mainpage</kbd> на германски.",
"apihelp-query+allpages-description": "Наброј ги сите страници последователно во даден именски простор.",
"apihelp-query+allpages-param-from": "Наслов на страницата од која ќе почне набројувањето.",
"apihelp-query+allpages-param-to": "Наслов на страницата на која ќе запре набројувањето.",
@@ -286,28 +296,29 @@
"apihelp-query+allpages-param-minsize": "Ограничи на страници со барем олку бајти.",
"apihelp-query+allpages-param-maxsize": "Ограничи на страници со највеќе олку бајти.",
"apihelp-query+allpages-param-prtype": "Ограничи на само заштитени страници.",
- "apihelp-query+backlinks-example-simple": "Прикажи врски до [[Главна страница|Главната страница]]",
- "apihelp-query+backlinks-example-generator": "Дава информации за страниците што водат до [[Главна страница|Главната страница]]",
+ "apihelp-query+backlinks-example-simple": "Прикажи врски до <kbd>Главна страница<kbd>.",
+ "apihelp-query+backlinks-example-generator": "Дава информации за страниците што водат до <kbd>Главна страница<kbd>.",
"apihelp-query+blocks-description": "Список на сите блокирани корисници и IP-адреси",
"apihelp-query+blocks-param-start": "Од кој датум и време да почне набројувањето.",
"apihelp-query+blocks-param-end": "На кој датум и време да запре набројувањето.",
"apihelp-query+blocks-param-ids": "Список на назнаки на блоковите за испис (незадолжително)",
"apihelp-query+blocks-param-users": "Список на корисници што ќе се пребаруваат (незадолжително)",
+ "apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|Режим|Режими}}: $2",
"apihelp-query+imageinfo-param-urlheight": "Слично на $1urlwidth.",
- "apihelp-query+revisions-example-last5": "Дај ги последните 5 преработки на „Главна страница“",
- "apihelp-query+revisions-example-first5": "Дај ги првите 5 преработки на „Главна страница“",
- "apihelp-query+revisions-example-first5-after": "Дај ги првите 5 преработки на „Главна страница“ направени по 2006-05-01 (1 мај 2006 г.)",
- "apihelp-query+revisions-example-first5-not-localhost": "Дај ги првите 5 преработки на „Главна страница“ кои не се направени од анонимниот корисник „127.0.0.1“",
- "apihelp-query+revisions-example-first5-user": "Дај ги првите 5 преработки на „Главна страница“ кои се направени од корисникот „зададен од МедијаВики“ (MediaWiki default)",
- "apihelp-query+search-example-simple": "Побарај „meaning“",
- "apihelp-query+search-example-text": "Побарај го „meaning“ по текстовите",
- "apihelp-query+search-example-generator": "Дај информации за страниците што излегуваат во резултатите од пребарувањето на „meaning“",
+ "apihelp-query+revisions-example-last5": "Дај ги последните 5 преработки на <kbd>Главна страница</kbd>.",
+ "apihelp-query+revisions-example-first5": "Дај ги првите 5 преработки на <kbd>Главна страница</kbd>.",
+ "apihelp-query+revisions-example-first5-after": "Дај ги првите 5 преработки на <kbd>Главна страница</kbd> направени по 2006-05-01 (1 мај 2006 г.)",
+ "apihelp-query+revisions-example-first5-not-localhost": "Дај ги првите 5 преработки на <kbd>Главна страница</kbd> кои не се направени од анонимниот корисник „127.0.0.1“",
+ "apihelp-query+revisions-example-first5-user": "Дај ги првите 5 преработки на <kbd>Главна страница</kbd> кои се направени од корисникот „зададен од МедијаВики“ (<kbd>MediaWiki default</kbd>)",
+ "apihelp-query+search-example-simple": "Побарај <kbd>meaning</kbd>.",
+ "apihelp-query+search-example-text": "Побарај го <kbd>meaning</kbd> по текстовите.",
+ "apihelp-query+search-example-generator": "Дај информации за страниците што излегуваат во резултатите од пребарувањето на <kbd>meaning</kbd>.",
"apihelp-query+siteinfo-description": "Дај општи информации за мрежното место.",
"apihelp-upload-param-filename": "Целно име на податотеката.",
- "apihelp-upload-param-comment": "Коментар при подигање. Се користи и како првичен текст на страницата за нови податотеки ако не е укажано „$1text“.",
+ "apihelp-upload-param-comment": "Коментар при подигање. Се користи и како првичен текст на страницата за нови податотеки ако не е укажано <var>$1text</var>.",
"apihelp-upload-param-text": "Првичен текст на страницата за нови податотеки.",
"apihelp-upload-param-watch": "Набљудувај ја страницата.",
- "apihelp-upload-param-watchlist": "Безусловно додај или отстрани ја страницата од набљудуваните, користете ги нагодувањата или не ги менувајте набљудуваните.",
+ "apihelp-upload-param-watchlist": "Безусловно додај или отстрани ја страницата од набљудуваните на тековниот корисник; користете ги нагодувањата или не ги менувајте набљудуваните.",
"apihelp-upload-param-ignorewarnings": "Занемари предупредувања.",
"apihelp-upload-param-file": "Содржина на податотеката.",
"apihelp-upload-param-url": "Од која URL-адреса да се преземе податотеката.",
@@ -323,44 +334,52 @@
"apihelp-upload-param-statuskey": "Дај ја состојбата на подигнатост за овој податотечен клуч (подигање по URL-адреса).",
"apihelp-upload-param-checkstatus": "Дај ја состојбата на подигнатост само за дадениот податотечен клуч.",
"apihelp-upload-example-url": "Подигни од URL-адреса",
+ "apihelp-userrights-param-user": "Корисничко име.",
"apihelp-userrights-param-userid": "Корисничка назнака.",
"apihelp-userrights-param-add": "Стави го корисникот во следниве групи.",
"apihelp-userrights-param-remove": "Отстрани го корисникот од следниве групи.",
"apihelp-userrights-param-reason": "Причина за промената.",
- "apihelp-watch-example-watch": "Набљудувај ја страницата „Главна страница“",
- "apihelp-watch-example-unwatch": "Отстрани ја страницата „Главна страница“ од набљудуваните",
+ "apihelp-userrights-example-user": "Додај го корисникот <kbd>FooBot</kbd> во групата <kbd>bot</kbd> и отстрани го од групите <kbd>sysop</kbd> и <kbd>bureaucrat</kbd>.",
+ "apihelp-userrights-example-userid": "Додај го корисникот со назнака <kbd>123</kbd> во групата <kbd>bot</kbd> и отстрани го од групите <kbd>sysop</kbd> и <kbd>bureaucrat</kbd>.",
+ "apihelp-watch-description": "Додај или отстрани страници од набљудуваните на тековниот корисник.",
+ "apihelp-watch-param-title": "Страницата што се става во или отстранува од набљудуваните. Наместо ова, користете <var>$1titles</var>.",
+ "apihelp-watch-param-unwatch": "Ако е зададено, страницата ќе биде отстранета од наместо ставена во набљуваните.",
+ "apihelp-watch-example-watch": "Набљудувај ја страницата <kbd>Главна страница</kbd>.",
+ "apihelp-watch-example-unwatch": "Отстрани ја страницата <kbd>Главна страница</kbd> од набљудуваните.",
"apihelp-watch-example-generator": "Набљудувај ги првите неколку страници во главниот именски простор",
- "apihelp-format-example-generic": "Форматирај го резултатот од барањето во $1-формат",
- "apihelp-dbg-description": "Давај го изводот во PHP-форматот var_export().",
- "apihelp-dbgfm-description": "Давај го изводот во PHP-форматот var_export() (подобрен испис во HTML).",
- "apihelp-dump-description": "Давај го изводот во PHP-форматот var_dump().",
- "apihelp-dumpfm-description": "Давај го изводот во PHP-форматот var_dump() (подобрен испис во HTML).",
+ "apihelp-format-example-generic": "Дај го исходот од барањето во $1-формат.",
+ "apihelp-dbg-description": "Давај го изводот во PHP-форматот <code>var_export()</code> .",
+ "apihelp-dbgfm-description": "Давај го изводот во PHP-форматот <code>var_export()</code> (подобрен испис во HTML).",
"apihelp-json-description": "Давај го изводот во JSON-формат.",
"apihelp-json-param-callback": "Ако е укажано, го обвива изводот во даден повик на функција. За безбедност, ќе се ограничат сите податоци што се однесуваат на корисниците.",
- "apihelp-json-param-utf8": "Ако е укажано, ја ги шифрира највеќето (но не сите) не-ASCII знаци како UTF-8 наместо да ги заменува со хексадецимални изводни низи.",
+ "apihelp-json-param-utf8": "Ако е укажано, ги шифрира највеќето (но не сите) не-ASCII знаци како UTF-8 наместо да ги заменува со хексадецимални изводни низи. Ова е стандардно кога <var>formatversion</var> не е <kbd>1</kbd>.",
+ "apihelp-json-param-ascii": "Ако е укажано, ги шифрира сите не-ASCII знаци како хексадецимални изводни низи. Ова е стандардно кога <var>formatversion</var> is <kbd>1</kbd>.",
+ "apihelp-json-param-formatversion": "Форматирање на изводот:\n;1:Назадно-складен формат (булови во XML-стил, клучеви <samp>*</samp> за содржински јазли и тн.).\n;2:Пробен современ формат. Поединостите може да се изменат!\n;најнов:Користење на најновиот формат (тековно <kbd>2</kbd>), може да се смени без предупредување.",
"apihelp-jsonfm-description": "Давај го изводот во JSON-формат (подобрен испис во HTML).",
"apihelp-none-description": "Де давај извод.",
"apihelp-php-description": "Давај го изводот во серијализиран PHP-формат.",
+ "apihelp-php-param-formatversion": "Форматирање на изводот:\n;1:Назадно-складен формат (булови во XML-стил, клучеви <samp>*</samp> за содржински јазли и тн.).\n;2:Пробен современ формат. Поединостите може да се изменат!\n;најнов:Користење на најновиот формат (тековно <kbd>2</kbd>), може да се смени без предупредување.",
"apihelp-phpfm-description": "Давај го изводот во серијализиран PHP-формат (подобрен испис во HTML).",
"apihelp-rawfm-description": "Давај го изводот со елементи за отстранување грешки во JSON-формат (подобрен испис во HTML).",
- "apihelp-txt-description": "Давај го изводот во PHP-форматот print_r().",
- "apihelp-txtfm-description": "Давај го изводот во PHP-форматот print_r() (подобрен испис во HTML).",
- "apihelp-wddx-description": "Давај го изводот во WDDX-формат.",
- "apihelp-wddxfm-description": "Давај го изводот во WDDX-формат (подобрен испис во HTML).",
+ "apihelp-txt-description": "Давај го изводот во PHP-форматот <code>print_r()</code>.",
+ "apihelp-txtfm-description": "Давај го изводот во PHP-форматот <code>print_r()</code> (подобрен испис во HTML).",
"apihelp-xml-description": "Давај го изводот во XML-формат.",
- "apihelp-xml-param-xslt": "Ако е укажано, додава &lt;xslt&gt; како стилска страница. Ова треба да е викистраница во именскиот простор МедијаВики (MediaWiki) чиј наслов завршува со „.xsl“.",
+ "apihelp-xml-param-xslt": "Ако е укажано, ја додава именуваната страница како XSL-стилска страница. Вредноста мора да биде наслов во именскиот простор „{{ns:mediawiki}}“ што ќе завршува со <code>.xsl</code>.",
"apihelp-xml-param-includexmlnamespace": "Ако е укажано, додава именски простор XML.",
"apihelp-xmlfm-description": "Давај го изводот во XML-формат (подобрен испис во HTML).",
"apihelp-yaml-description": "Давај го изводот во YAML-формат.",
"apihelp-yamlfm-description": "Давај го изводот во YAML-формат (подобрен испис во HTML).",
"api-format-title": "Резултат од Извршникот на МедијаВики",
- "api-format-prettyprint-header": "Ја гледате HTML-претставата на форматот $1. HTML е добар за отстранување на грешки, но не е погоден за употреба во извршник.\n\nУкажете го параметарот за формат за да го смените изводниот формат. За да ги видите претставите на форматот $1 вон HTML, задајте format=$2.\n\nПовеќе информации ќе најдете на [https://www.mediawiki.org/wiki/API целосната документација], или пак [[Special:ApiHelp/main|помош со извршникот]].",
+ "api-format-prettyprint-header": "Ова е HTML-претстава на форматот $1. HTML е добар за отстранување на грешки, но не е погоден за употреба во извршник.\n\nУкажете го параметарот <var>format</var> за да го смените изводниот формат. За да ги видите претставите на форматот $1 вон HTML, задајте <kbd>format=$2</kbd>.\n\nПовеќе информации ќе најдете на [[mw:API|целосната документација]], или пак [[Special:ApiHelp/main|помош со извршникот]].",
"api-orm-param-props": "Полиња за пребарување.",
"api-orm-param-limit": "Макс. број на редови во изводот.",
"api-pageset-param-titles": "Список на наслови на кои ќе се работи",
"api-pageset-param-pageids": "Список на назнаки за страници на кои ќе се работи",
"api-pageset-param-revids": "Список на назнаки на преработки на кои ќе се работи",
- "api-pageset-param-generator": "Дај го списокот на страници на кои ќе се работи исполнувајќи го укажаниот модул за барање.\n\n'''НАПОМЕНА:''' називите на создавачките параметри мора да ја имаат претставката „g“. Погледајте ги примерите.",
+ "api-pageset-param-generator": "Дај го списокот на страници на кои ќе се работи исполнувајќи го укажаниот модул за барање.\n\n<strong>Напомена:</strong> називите на создавачките параметри мора да ја имаат претставката „g“. Погледајте ги примерите.",
+ "api-pageset-param-redirects-generator": "Автоматски решавај пренасочувања во <var>$1titles</var>, <var>$1pageids</var> и <var>$1revids</var>, како и во страниците што ги дава <var>$1generator</var>.",
+ "api-pageset-param-redirects-nogenerator": "Автоамтски решавај пренасочувања во <var>$1titles</var>, <var>$1pageids</var> и <var>$1revids</var>.",
+ "api-pageset-param-converttitles": "Ако е потребно, претворај ги насловите во други варијанти. Работи само ако јазикот на викито поддржува претворање на варијанти. Такви се $1.",
"api-help-title": "Помош со Извршникот на МедијаВики",
"api-help-lead": "Ова е самосоздадена документациска страница за извршникот на МедијаВики.\n\nДокументација и примери: https://www.mediawiki.org/wiki/API",
"api-help-main-header": "Главен модул",
@@ -370,10 +389,21 @@
"api-help-flag-writerights": "За овој модул се потребни права на пишување.",
"api-help-flag-mustbeposted": "Овој модул прифаќа само POST-барања.",
"api-help-flag-generator": "Овој модул може да се користи како создавач.",
+ "api-help-source": "Извор: $1",
+ "api-help-source-unknown": "Извор: <span class=\"apihelp-unknown\">непознат</span>",
+ "api-help-license": "Лиценца: [[$1|$2]]",
+ "api-help-license-noname": "Лиценца: [[$1|Погл. врската]]",
+ "api-help-license-unknown": "Лиценца: <span class=\"apihelp-unknown\">непозната</span>",
"api-help-parameters": "{{PLURAL:$1|Параметар|Параметри}}:",
"api-help-param-deprecated": "Застарен.",
"api-help-param-required": "Овој параметар е задолжителен.",
- "api-help-param-list": "{{PLURAL:$1|1=Една вредност|2=Вредности (одделени со „{{!}}“)}}: $2",
+ "api-help-datatypes-header": "Типови на податоци",
+ "api-help-param-type-limit": "Тип: цел број или <kbd>max</kbd>",
+ "api-help-param-type-integer": "Тип: {{PLURAL:$1|1=цел број|2=список на цели броеви}}",
+ "api-help-param-type-boolean": "Тип: булов ([[Special:ApiHelp/main#main/datatypes|подробно]])",
+ "api-help-param-type-timestamp": "Тип: {{PLURAL:$1|1=време и датум|2=список на времиња и датуми}} ([[Special:ApiHelp/main#main/datatypes|допуштени формати]])",
+ "api-help-param-type-user": "Тип: {{PLURAL:$1|1=корисничко име|2=список на кориснички имиња}}",
+ "api-help-param-list": "{{PLURAL:$1|1=Една вредност|2=Вредности (одделете ги со <kbd>{{!}}</kbd>)}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Мора да биде празно|Може да биде празно или $2}}",
"api-help-param-limit": "Не се допушта повеќе од $1.",
"api-help-param-limit2": "Не се допушта повеќе од $1 ($2 за ботови).",
@@ -381,13 +411,16 @@
"api-help-param-integer-max": "{{PLURAL:$1|1=Вредноста не може да изнесува|2=Вредностите е може да изнесуваат}} повеќе од $3.",
"api-help-param-integer-minmax": "{{PLURAL:$1|1=Вредноста мора да изнесува|2=Вредностите мораат да изнесуваат}} помеѓу $2 и $3.",
"api-help-param-upload": "Мора да биде објавено како податотечно подигање користејќи податоци кои се повеќеделни или од образец.",
- "api-help-param-multi-separate": "Одделувајте ги вредностите со „|“.",
+ "api-help-param-multi-separate": "Одделувајте ги вредностите со <kbd>|</kbd>.",
"api-help-param-multi-max": "Максималниот број на вредности изнесува {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} за ботови).",
"api-help-param-default": "По основно: $1",
"api-help-param-default-empty": "По основно: <span class=\"apihelp-empty\">(празно)</span>",
"api-help-param-token": "Шифра „$1“ добиена од [[Special:ApiHelp/query+tokens|action=query&meta=tokens]]",
"api-help-param-token-webui": "За складност, се прифаќа и шифрата што се користи за обичниот кориснички посредник.",
- "api-help-param-disabled-in-miser-mode": "Исклучено поради [https://www.mediawiki.org/wiki/Manual:$wgMiserMode скржавиот режим].",
+ "api-help-param-disabled-in-miser-mode": "Исклучено поради [[mw:Manual:$wgMiserMode|скржавиот режим]].",
+ "api-help-param-limited-in-miser-mode": "<strong>Напомена:</strong> Бидејќи сте во [[mw:Manual:$wgMiserMode|скржав режим]], користејќи го ова може да добиете помалку од <var>$1limit</var> резултати пред да продолжите; во крајни случаи може да не добиете ниеден резултат.",
+ "api-help-param-direction": "Во која насока да се набројува:\n;понови:Прво најстарите. Напомена: $1start мора да биде пред $1end.\n;постари:Прво најновите (по основно). Напомена: $1start мора да биде подоцна од $1end.",
+ "api-help-param-continue": "Употребете го ова за да продолжите кога има повеќе расположиви резултати.",
"api-help-param-no-description": "<span class=\"apihelp-empty\">(нема опис)</span>",
"api-help-examples": "{{PLURAL:$1|Пример|Примери}}:",
"api-help-permissions": "{{PLURAL:$1|Дозвола|Дозволи}}:",
diff --git a/includes/api/i18n/mr.json b/includes/api/i18n/mr.json
new file mode 100644
index 00000000..74db7424
--- /dev/null
+++ b/includes/api/i18n/mr.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rahuldeshmukh101",
+ "V.narsikar"
+ ]
+ },
+ "apihelp-main-param-action": "कोणती कार्यवाही करावयाची.",
+ "apihelp-main-param-curtimestamp": "निकालात सद्य वेळठश्याचा अंतर्भाव करा.",
+ "apihelp-block-description": "सदस्यास प्रतिबंधित करा.",
+ "apihelp-block-param-user": "सदस्याचे नाव, अंक-पत्त्ता, किंवा प्रतिबंध करण्यासाठीचा आयपीचा आवाका."
+}
diff --git a/includes/api/i18n/nap.json b/includes/api/i18n/nap.json
index a285b04a..0d304401 100644
--- a/includes/api/i18n/nap.json
+++ b/includes/api/i18n/nap.json
@@ -1,10 +1,18 @@
{
"@metadata": {
"authors": [
- "Chelin"
+ "Chelin",
+ "C.R."
]
},
"apihelp-block-description": "Blocca n'utente.",
"apihelp-createaccount-param-name": "Nomme utente.",
- "apihelp-delete-description": "Scancella 'na paggena."
+ "apihelp-delete-description": "Scancella 'na paggena.",
+ "apihelp-edit-example-edit": "Cagna paggena.",
+ "apihelp-emailuser-description": "E-mail a n'utente.",
+ "apihelp-feedwatchlist-param-feedformat": "'O furmato d' 'o feed.",
+ "apihelp-login-example-login": "Tràse.",
+ "apihelp-move-description": "Mòve paggena.",
+ "apihelp-opensearch-param-search": "Ascìa stringa.",
+ "apihelp-opensearch-param-format": "'O furmato 'e ll'output."
}
diff --git a/includes/api/i18n/nb.json b/includes/api/i18n/nb.json
index 6dcba40a..ed665f23 100644
--- a/includes/api/i18n/nb.json
+++ b/includes/api/i18n/nb.json
@@ -1,13 +1,102 @@
{
"@metadata": {
"authors": [
- "Jeblad"
+ "Jeblad",
+ "Chameleon222"
]
},
"apihelp-main-param-action": "Hvilken handling skal utføres",
"apihelp-main-param-format": "Resultatets format.",
"apihelp-main-param-servedby": "Inkluder navnet på tjeneren som utførte forespørselen i resultatene.",
"apihelp-main-param-curtimestamp": "Inkluder det nåværende tidsmerket i resultatet.",
+ "apihelp-block-description": "Blokker en bruker.",
+ "apihelp-block-param-user": "Brukernavn, IP-adresse eller IP-intervall som skal blokkeres.",
+ "apihelp-block-param-reason": "Årsak for blokkering.",
+ "apihelp-block-param-anononly": "Blokker bare anonyme brukere (dvs. hindre anonyme redigeringer fra denne IP-adressen).",
+ "apihelp-block-param-nocreate": "Hindre kontoopprettelse.",
+ "apihelp-block-param-autoblock": "Blokker automatisk sist brukte IP-adresse og alle etterfølgende IP-adresser de prøver å logge inn fra.",
+ "apihelp-block-param-noemail": "Hindre brukeren å sende e-post via wikien. (Krever rettigheten <code>blockemail</code>).",
+ "apihelp-block-param-hidename": "Skjul brukernavnet fra blokkeringsloggen. (Krever rettigheten <code>hideuser</code>).",
+ "apihelp-clearhasmsg-description": "Fjerner <code>hasmsg</code>-flagget for den aktuelle brukeren.",
+ "apihelp-clearhasmsg-example-1": "Fjern <code>hasmsg</code>-flagget for aktuell bruker.",
+ "apihelp-compare-description": "Hent forskjellen mellom to sider.\n\nEt revisjonsnummer, en sidetittel eller en side-ID for både «fra» og «til» må sendes.",
+ "apihelp-compare-param-fromtitle": "Første tittel å sammenligne.",
+ "apihelp-compare-param-fromid": "Første side-ID å sammenligne.",
+ "apihelp-compare-param-fromrev": "Første revisjon å sammenligne.",
+ "apihelp-compare-param-totitle": "Andre tittel å sammenligne.",
+ "apihelp-compare-param-toid": "Andre side-ID å sammenligne.",
+ "apihelp-compare-param-torev": "Andre revisjon å sammenligne.",
+ "apihelp-compare-example-1": "Lag en diff mellom revisjon 1 og 2.",
+ "apihelp-createaccount-description": "Opprett en ny brukerkonto.",
+ "apihelp-createaccount-param-name": "Brukernavn.",
+ "apihelp-createaccount-param-password": "Passord (ignorert dersom <var>$1mailpassword</var> er satt).",
+ "apihelp-createaccount-param-domain": "Domene for ekstern autentisering (valgfritt).",
+ "apihelp-createaccount-param-email": "Brukerens e-postadresse (valgfritt).",
+ "apihelp-createaccount-param-realname": "Brukerens virkelige navn (valgfritt).",
+ "apihelp-createaccount-param-mailpassword": "Dersom satt til en verdi vil et tilfeldig passord bli sendt med e-post til brukeren.",
+ "apihelp-createaccount-param-reason": "Valgfri grunn for å opprette kontoen for å legges i loggene.",
+ "apihelp-createaccount-param-language": "Språkkode å bruke som standard for brukeren (valgfritt, standardverdien er innholdsspråket).",
+ "apihelp-createaccount-example-pass": "Opprett bruker <kbd>testuser</kbd> med passordet <kbd>test123</kbd>.",
+ "apihelp-createaccount-example-mail": "Opprett bruker <kbd>testmailuser</kbd> og send et tilfeldig generert passord med e-post.",
+ "apihelp-delete-description": "Slett en side.",
+ "apihelp-delete-param-title": "Tittel til siden som skal slettes. Kan ikke brukes sammen med <var>$1pageid</var>.",
+ "apihelp-delete-param-pageid": "Side-ID til siden som skal slettes. Kan ikke brukes sammen med <var>$1title</var>.",
+ "apihelp-delete-param-reason": "Årsak for slettingen. Dersom ikke satt vil en automatisk generert årsak bli brukt.",
+ "apihelp-delete-param-watch": "Legg til siden til aktuell brukers overvåkningsliste.",
+ "apihelp-delete-param-unwatch": "Fjern siden fra aktuell brukers overvåkningsliste.",
+ "apihelp-delete-example-simple": "Slett <kbd>Hovedside</kbd>.",
+ "apihelp-delete-example-reason": "Slett <kbd>Hovedside</kbd> med grunnen <kbd>Forbereder flytting</kbd>.",
+ "apihelp-disabled-description": "Denne modulen har blitt deaktivert",
+ "apihelp-edit-description": "Opprett og rediger sider.",
+ "apihelp-edit-param-title": "Tittelen til siden som skal redigeres. Kan ikke brukes sammen med <var>$1pageid</var>.",
+ "apihelp-edit-param-pageid": "Side-ID til siden som skal redigeres. Kan ikke brukes sammen med <var>$1title</var>.",
+ "apihelp-edit-param-section": "Avsnittsnummer. <kbd>0</kbd> for det øverste avsnittet, <kbd>new</kbd> for et nytt avsnitt.",
+ "apihelp-edit-param-sectiontitle": "Tittelen for et nytt avsnitt.",
+ "apihelp-edit-param-text": "Sideinnhold.",
+ "apihelp-edit-param-minor": "Mindre redigering.",
+ "apihelp-edit-param-bot": "Merk denne redigeringen som en botendring.",
+ "apihelp-edit-param-createonly": "Ikke rediger siden dersom den finnes allerede.",
+ "apihelp-edit-param-nocreate": "Gi en feilmelding dersom dersom siden ikke finnes.",
+ "apihelp-edit-param-watch": "Legg til siden til aktuell brukers overvåkningsliste.",
+ "apihelp-edit-param-unwatch": "Fjern siden fra aktuell brukers overvåkningsliste.",
+ "apihelp-edit-param-prependtext": "Legg til denne teksten til starten av siden. Overstyrer $1text.",
+ "apihelp-edit-param-redirect": "Bestem omdirigeringer automatisk.",
+ "apihelp-edit-param-contentformat": "Innholdsserialiseringsformat brukt for inndatateksten.",
+ "apihelp-edit-param-contentmodel": "Det nye innholdets innholdsmodell.",
+ "apihelp-edit-example-edit": "Rediger en side.",
+ "apihelp-emailuser-description": "Send e-post til en bruker.",
+ "apihelp-emailuser-param-target": "Bruker som det skal sendes e-post til.",
+ "apihelp-emailuser-param-subject": "Emne.",
+ "apihelp-emailuser-param-text": "E-post innhold.",
+ "apihelp-emailuser-param-ccme": "Send en kopi av denne e-posten til meg.",
+ "apihelp-expandtemplates-description": "Ekspanderer alle maler i wikitekst.",
+ "apihelp-expandtemplates-param-title": "Sidetittel.",
+ "apihelp-expandtemplates-param-text": "Wikitekst som skal konverteres.",
+ "apihelp-feedcontributions-param-year": "Fra år (og tidligere).",
+ "apihelp-feedcontributions-param-month": "Fra måned (og tidligere).",
+ "apihelp-feedcontributions-param-tagfilter": "Filtrer bidrag som har disse merkene.",
+ "apihelp-feedcontributions-param-deletedonly": "Vis bare slettede bidrag.",
+ "apihelp-feedcontributions-param-toponly": "Vis kun redigeringer som er gjeldende revisjoner.",
+ "apihelp-feedcontributions-param-newonly": "Bare vis bidrag som er sideopprettinger.",
+ "apihelp-feedcontributions-param-showsizediff": "Vis størrelsesforskjellen mellom revisjoner.",
+ "apihelp-feedrecentchanges-param-from": "Vis endringer siden da.",
+ "apihelp-feedrecentchanges-param-hideminor": "Skjul mindre endringer.",
+ "apihelp-feedrecentchanges-param-hidebots": "Skjul botendringer.",
+ "apihelp-help-param-toc": "Inkluder en innholdsfortegnelse i HTML-utdataen.",
+ "apihelp-help-example-main": "Hjelp for hovedmodulen.",
+ "apihelp-help-example-recursive": "All hjelp på en side.",
+ "apihelp-help-example-help": "Hjelp for selve hjelpemodulen.",
+ "apihelp-help-example-query": "Hjelp for to utspørringsundermoduler.",
+ "apihelp-imagerotate-description": "Roter ett eller flere bilder.",
+ "apihelp-import-param-summary": "Importsammendrag.",
+ "apihelp-import-param-xml": "Opplastet XML-fil.",
+ "apihelp-login-param-name": "Brukernavn.",
+ "apihelp-login-param-password": "Passord.",
+ "apihelp-login-param-domain": "Domene (valgfritt).",
+ "apihelp-login-example-login": "Logg inn.",
+ "apihelp-logout-description": "Logg ut og fjern sesjonsdata.",
+ "apihelp-logout-example-logout": "Logg ut den aktuelle brukeren.",
+ "apihelp-move-description": "Flytt en side.",
"apihelp-dbg-description": "Resultatdata i PHP's var_export() format.",
"apihelp-dbgfm-description": "Resultatdata i PHP's var_export() format (pen utskrift i HTML).",
"apihelp-dump-description": "Resultatdata i PHP's var_export() format.",
diff --git a/includes/api/i18n/ne.json b/includes/api/i18n/ne.json
new file mode 100644
index 00000000..f8718a55
--- /dev/null
+++ b/includes/api/i18n/ne.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nirjal stha",
+ "सरोज कुमार ढकाल"
+ ]
+ },
+ "apihelp-createaccount-param-name": "प्रयोगकर्ता नाम।",
+ "apihelp-edit-param-minor": "सामान्य सम्पादन।",
+ "apihelp-edit-example-edit": "पृष्ठ सम्पादन गर्नुहोस्।",
+ "apihelp-emailuser-description": "प्रयोगकर्तालाई इमेल गर्नुहोस्।",
+ "apihelp-parse-param-prop": "जानकारीको कुन भाग लिनेः"
+}
diff --git a/includes/api/i18n/nl.json b/includes/api/i18n/nl.json
index 72816b99..c9618725 100644
--- a/includes/api/i18n/nl.json
+++ b/includes/api/i18n/nl.json
@@ -8,15 +8,17 @@
"Valhallasw",
"Sikjes",
"Macofe",
- "SPQRobin"
+ "SPQRobin",
+ "HanV",
+ "Rangekill"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentatie]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-maillijst]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-aankondigingen]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bugs & verzoeken]\n</div>\n<strong>Status:</strong> Alle functies die op deze pagina worden weergegeven horen te werken. Aan de API wordt actief gewerkt, en deze kan gewijzigd worden. Abonneer u op de [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ e-maillijst mediawiki-api-announce] voor meldingen over aanpassingen.\n\n<strong>Foutieve verzoeken:</strong> als de API foutieve verzoeken ontvangt, wordt er geantwoord met een HTTP-header met de sleutel \"MediaWiki-API-Error\" en daarna worden de waarde van de header en de foutcode op dezelfde waarde ingesteld. Zie [[mw:API:Errors_and_warnings|API: Errors and warnings]] voor meer informatie.",
"apihelp-main-param-action": "Welke handeling uit te voeren.",
"apihelp-main-param-format": "De opmaak van de uitvoer.",
"apihelp-main-param-maxlag": "De maximale vertraging kan gebruikt worden als MediaWiki is geïnstalleerd op een databasecluster die gebruik maakt van replicatie. Om te voorkomen dat handelingen nog meer databasereplicatievertraging veroorzaken, kan deze parameter er voor zorgen dat de client wacht totdat de replicatievertraging lager is dan de aangegeven waarde. In het geval van buitensporige vertraging, wordt de foutcode <samp>maxlag</samp> teruggegeven met een bericht als <samp>Waiting for $host: $lag seconds lagged</samp>.<br />Zie [[mw:Manual:Maxlag_parameter|Handboek: Maxlag parameter]] voor mee informatie.",
- "apihelp-main-param-smaxage": "Stelt de header \"<code>s-maxage</code>\" in op het aangegeven aantal seconden. Foutmeldingen komen nooit in de cache.",
- "apihelp-main-param-maxage": "Stelt de header \"<code>max-age</code>\" in op het aangegeven aantal seconden. Foutmeldingen komen nooit in de cache.",
+ "apihelp-main-param-smaxage": "Stelt de \"<code>s-maxage</code>\" HTTP cache controle header in op het aangegeven aantal seconden. Foutmeldingen komen nooit in de cache.",
+ "apihelp-main-param-maxage": "Stelt de <code>max-age</code> HTTP cache controle header in op het aangegeven aantal seconden. Foutmeldingen komen nooit in de cache.",
"apihelp-main-param-assert": "Controleer of de gebruiker is aangemeld als <kbd>user</kbd> is meegegeven, en of de gebruiker het robotgebruikersrecht heeft als <kbd>bot</kbd> is meegegeven.",
"apihelp-main-param-requestid": "Elke waarde die hier gegeven wordt, wordt aan het antwoord toegevoegd. Dit kan gebruikt worden om verzoeken te onderscheiden.",
"apihelp-main-param-servedby": "Voeg de hostnaam van de server die de aanvraag heeft afgehandeld toe aan het antwoord.",
@@ -30,13 +32,14 @@
"apihelp-delete-example-simple": "Verwijder <kbd>Hoofdpagina</kbd>.",
"apihelp-delete-example-reason": "Verwijder <kbd>Hoofdpagina</kbd> met als reden <kbd>Voorbereiding voor verplaatsing</kbd>.",
"apihelp-disabled-description": "Deze module is uitgeschakeld.",
+ "apihelp-edit-param-text": "Pagina-inhoud.",
"apihelp-edit-param-minor": "Kleine bewerking.",
"apihelp-edit-param-notminor": "Geen kleine bewerking.",
"apihelp-edit-param-bot": "Markeer deze bewerking als bot.",
"apihelp-edit-param-createonly": "Bewerk de pagina niet als die al bestaat.",
"apihelp-edit-param-nocreate": "Geef een foutmelding als de pagina niet bestaat.",
- "apihelp-edit-param-watch": "Voeg de pagina toe aan je volglijst.",
- "apihelp-edit-param-unwatch": "Verwijder de pagina van je volglijst.",
+ "apihelp-edit-param-watch": "Voeg de pagina toe aan de volglijst van de huidige gebruiker.",
+ "apihelp-edit-param-unwatch": "Verwijder de pagina van de volglijst van de huidige gebruiker.",
"apihelp-edit-example-edit": "Pagina bewerken",
"apihelp-emailuser-description": "Gebruiker e-mailen.",
"apihelp-emailuser-param-target": "Gebruiker naar wie de e-mail moet worden gestuurd.",
@@ -46,15 +49,44 @@
"apihelp-expandtemplates-param-title": "Paginanaam.",
"apihelp-feedcontributions-param-year": "Van jaar (en eerder).",
"apihelp-feedcontributions-param-month": "Van maand (en eerder).",
+ "apihelp-import-param-namespace": "Importeren in deze naamruimte. Can niet samen gebruikt worden met <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Importeren als subpagina van deze pagina. Kan niet samen met <var>$1namespace</var> gebruikt worden.",
"apihelp-login-param-name": "Gebruikersnaam.",
"apihelp-login-param-password": "Wachtwoord.",
"apihelp-login-param-domain": "Domein (optioneel).",
"apihelp-login-example-login": "Aanmelden",
"apihelp-move-description": "Pagina hernoemen.",
+ "apihelp-move-param-watch": "Pagina en de omleiding toevoegen aan de volglijst van de huidige gebruiker.",
+ "apihelp-move-param-unwatch": "Verwijder de pagina en de doorverwijzing van de volglijst van de huidige gebruiker.",
+ "apihelp-move-param-watchlist": "De pagina onvoorwaardelijk toevoegen aan of verwijderen van de volglijst van de huidige gebruiker, gebruik voorkeuren of verander het volgen niet.",
+ "apihelp-move-param-ignorewarnings": "Eventuele waarschuwingen negeren.",
+ "apihelp-move-example-move": "Hernoem <kbd>Badtitle</kbd> naar <kbd>Goodtitle</kbd> zonder een doorverwijzing te laten staan.",
+ "apihelp-opensearch-description": "Zoeken in de wiki met het OpenSearchprotocol.",
+ "apihelp-opensearch-param-search": "Zoektekst.",
+ "apihelp-opensearch-param-limit": "Het maximaal aantal weer te geven resultaten.",
+ "apihelp-opensearch-param-namespace": "Te doorzoeken naamruimten.",
+ "apihelp-opensearch-param-suggest": "Niets doen als <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> onwaar is.",
+ "apihelp-opensearch-param-redirects": "Hoe om te gaan met doorverwijzingen:\n;return:Geef de doorverwijzing terug.\n;resolve:Geef de doelpagina terug. Kan minder dan de limiet $1 resultaten teruggeven.\nOm historische redenen is de standaardinstelling \"return\" voor <code>$1format=json<code> en \"resolve\" voor andere formaten.",
+ "apihelp-opensearch-param-format": "Het uitvoerformaat.",
+ "apihelp-opensearch-param-warningsaserror": "Als er waarschuwingen zijn met <kbd>format=json</kbd>, geef dan een API-fout terug in plaats van deze te negeren.",
+ "apihelp-opensearch-example-te": "Pagina's vinden die beginnen met <kbd>Te</kbd>.",
+ "apihelp-options-description": "Voorkeuren van de huidige gebruiker wijzigen.\n\nAlleen opties die zijn geregistreerd in core of in een van de geïnstalleerde uitbreidingen, of opties met de toetsen aangeduid met \"userjs-\" (bedoeld om te worden gebruikt door gebruikersscripts), kunnen worden ingesteld.",
+ "apihelp-options-param-reset": "Zet de voorkeuren terug naar de standaard van de website.",
+ "apihelp-options-param-resetkinds": "Lijst van de optiestypes die opnieuw ingesteld worden wanneer de optie <var>$1reset</var> is ingesteld.",
+ "apihelp-options-param-change": "Lijst van wijzigingen, opgemaakt als <kbd>naam=waarde</kbd> (bijvoorbeeld <kbd>skin=vector</kbd>). De waarde kan geen sluistekens bevatten. Als er geen waarde wordt opgegeven (zelfs niet een is-gelijk teken), bijvoorbeeld, <kbd>optienaam|otheroption|...</kbd>, wordt de optie ingesteld op de standaardwaarde.",
+ "apihelp-options-param-optionname": "Een naam van een optie die moet worden ingesteld op de waarde gegeven door <var>$1optiewaarde</var>.",
+ "apihelp-options-param-optionvalue": "Een waarde van de optie opgegeven door <var>$1optienaam</var>, kan sluistekens (verticale streepjes) bevatten.",
+ "apihelp-options-example-reset": "Alle voorkeuren opnieuw instellen.",
+ "apihelp-options-example-change": "Voorkeuren veranderen voor <kbd>skin</kbd> en <kbd>hideminor</kbd>.",
+ "apihelp-parse-example-page": "Een pagina parseren.",
+ "apihelp-parse-example-text": "Wikitext parseren.",
+ "apihelp-parse-example-summary": "Een samenvatting parseren.",
+ "apihelp-protect-example-protect": "Een pagina beveiligen",
"api-help-flag-readrights": "Voor deze module zijn leesrechten nodig.",
"api-help-flag-writerights": "Voor deze module zijn schrijfrechten nodig.",
"api-help-parameters": "{{PLURAL:$1|Parameter|Parameters}}:",
"api-help-param-deprecated": "Verouderd.",
+ "api-help-datatypes-header": "Gegevenstypen",
"api-help-param-default": "Standaard: $1",
"api-credits-header": "Vermeldingen",
"api-credits": "API-ontwikkelaars:\n* Roan Kattouw (hoofdontwikkelaar september 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (oorspronkelijke ontwikkelaar, hoofdontwikkelaar september 2006 – september 2007)\n* Brad Jorsch (hoofdontwikkelaar 2013 – heden)\n\nStuur uw opmerkingen, suggesties en vragen naar mediawiki-api@lists.wikimedia.org\nof maak een melding aan op https://phabricator.wikimedia.org/."
diff --git a/includes/api/i18n/oc.json b/includes/api/i18n/oc.json
index dc12b663..11c0a32d 100644
--- a/includes/api/i18n/oc.json
+++ b/includes/api/i18n/oc.json
@@ -10,8 +10,79 @@
"apihelp-block-param-reason": "Motiu del blocatge.",
"apihelp-block-param-nocreate": "Empachar la creacion de compte.",
"apihelp-checktoken-param-token": "Geton de testar.",
+ "apihelp-compare-param-fromtitle": "Primièr títol de comparar.",
+ "apihelp-compare-param-fromid": "ID de la primièra pagina de comparar.",
+ "apihelp-compare-param-fromrev": "Primièra revision de comparar.",
+ "apihelp-compare-param-totitle": "Segond títol de comparar.",
+ "apihelp-compare-param-toid": "ID de la segonda pagina de comparar.",
+ "apihelp-compare-param-torev": "Segonda revision de comparar.",
+ "apihelp-createaccount-description": "Creatz un novèl compte d'utilizaire.",
"apihelp-createaccount-param-name": "Nom d'utilizaire.",
+ "apihelp-createaccount-param-password": "Senhal (ignorat se <var>$1mailpassword</var> es definit).",
+ "apihelp-createaccount-param-realname": "Nom vertadièr de l’utilizaire (facultatiu).",
+ "apihelp-delete-description": "Suprimir una pagina.",
"apihelp-delete-example-simple": "Suprimir la <kbd>Pagina principala</kbd>.",
+ "apihelp-disabled-description": "Aqueste modul es estat desactivat.",
+ "apihelp-edit-description": "Crear e modificar las paginas.",
"apihelp-edit-param-text": "Contengut de la pagina.",
- "apihelp-edit-param-minor": "Modificacion menora."
+ "apihelp-edit-param-minor": "Modificacion menora.",
+ "apihelp-edit-param-notminor": "Modificacion pas menora.",
+ "apihelp-edit-param-bot": "Marcar aquesta modificacion coma robòt.",
+ "apihelp-edit-example-edit": "Modificar una pagina",
+ "apihelp-edit-example-prepend": "Prefixar una pagina per <kbd>_&#95;NOTOC_&#95;</kbd>",
+ "apihelp-emailuser-description": "Mandar un corrièr electronic un l’utilizaire.",
+ "apihelp-emailuser-param-subject": "Entèsta del subjècte.",
+ "apihelp-emailuser-param-text": "Còs del corrièr electronic.",
+ "apihelp-emailuser-param-ccme": "Me mandar una còpia d'aqueste corrièr electronic.",
+ "apihelp-expandtemplates-param-title": "Títol de la pagina.",
+ "apihelp-expandtemplates-param-text": "Wikitèxte de convertir.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "Lo wikitèxte desvolopat.",
+ "apihelp-feedcontributions-param-feedformat": "Lo format del flux.",
+ "apihelp-feedcontributions-param-year": "A partir de l’annada (e mai recent) :",
+ "apihelp-feedcontributions-param-month": "A partir del mes (e mai recent) :",
+ "apihelp-feedrecentchanges-param-feedformat": "Lo format del flux.",
+ "apihelp-feedrecentchanges-param-tagfilter": "Filtrar per balisa.",
+ "apihelp-filerevert-param-comment": "Telecargar lo comentari.",
+ "apihelp-filerevert-param-archivename": "Nom d’archiu de la revision de restablir.",
+ "apihelp-import-param-summary": "Importar lo resumit.",
+ "apihelp-import-param-xml": "Fichièr XML telecargat.",
+ "apihelp-login-param-name": "Nom d'utilizaire.",
+ "apihelp-login-param-password": "Senhal.",
+ "apihelp-login-param-domain": "Domeni (facultatiu).",
+ "apihelp-login-example-login": "Se connectar.",
+ "apihelp-managetags-description": "Efectuar de prètzfaches de gestion relatius a la modificacion de las balisas.",
+ "apihelp-move-description": "Desplaçar una pagina.",
+ "apihelp-opensearch-param-search": "Cadena de recèrca.",
+ "apihelp-parse-example-page": "Analisar una pagina.",
+ "apihelp-parse-example-text": "Analisar lo wikitèxte.",
+ "apihelp-parse-example-summary": "Analisar un resumit.",
+ "apihelp-patrol-description": "Patrolhar una pagina o una revision.",
+ "apihelp-protect-example-protect": "Protegir una pagina",
+ "apihelp-query-param-list": "Quinas listas obténer.",
+ "apihelp-query-param-meta": "Quinas metadonadas obténer.",
+ "apihelp-query+allcategories-description": "Enumerar totas las categorias.",
+ "apihelp-query+alldeletedrevisions-param-from": "Aviar la lista a aqueste títol.",
+ "apihelp-query+allimages-param-sort": "Proprietat per la quala cal triar.",
+ "apihelp-query+blocks-example-simple": "Listar los blocatges",
+ "apihelp-query+blocks-example-users": "Listar los blocatges dels utilizaires <kbd>Alice</kbd> e <kbd>Bob</kbd>.",
+ "apihelp-query+imageinfo-param-urlheight": "Similar a $1urlwidth.",
+ "apihelp-query+revisions+base-paramvalue-prop-content": "Tèxte de la revision.",
+ "apihelp-query+revisions+base-paramvalue-prop-tags": "Balisas de la revision.",
+ "apihelp-tag-param-reason": "Motiu de la modificacion.",
+ "apihelp-unblock-description": "Desblocar un utilizaire.",
+ "apihelp-unblock-param-reason": "Motiu del desblocatge.",
+ "apihelp-unblock-example-id": "Levar lo blocatge d’ID #<kbd>105</kbd>.",
+ "apihelp-userrights-param-user": "Nom d'utilizaire.",
+ "apihelp-userrights-param-userid": "ID de l'utilizaire.",
+ "api-help-main-header": "Modul principal",
+ "api-help-source": "Font : $1",
+ "api-help-source-unknown": "Font : <span class=\"apihelp-unknown\">desconeguda</span>",
+ "api-help-license": "Licéncia : [[$1|$2]]",
+ "api-help-license-noname": "Licéncia : [[$1|Veire lo ligam]]",
+ "api-help-license-unknown": "Licéncia : <span class=\"apihelp-unknown\">desconeguda</span>",
+ "api-help-parameters": "{{PLURAL:$1|Paramètre|Paramètres}} :",
+ "api-help-param-deprecated": "Obsolet.",
+ "api-help-datatypes-header": "Tipe de donadas",
+ "api-help-param-default": "Per defaut : $1",
+ "api-credits-header": "Mercejaments"
}
diff --git a/includes/api/i18n/olo.json b/includes/api/i18n/olo.json
new file mode 100644
index 00000000..99aef3f6
--- /dev/null
+++ b/includes/api/i18n/olo.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mashoi7"
+ ]
+ },
+ "apihelp-createaccount-param-name": "Käyttäitunnus.",
+ "apihelp-delete-description": "Ota sivu iäre.",
+ "apihelp-login-param-name": "Käyttäitunnus.",
+ "apihelp-login-param-password": "Peittosana.",
+ "apihelp-login-example-login": "Kirjuttai."
+}
diff --git a/includes/api/i18n/or.json b/includes/api/i18n/or.json
new file mode 100644
index 00000000..d7d0295a
--- /dev/null
+++ b/includes/api/i18n/or.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "ଶିତିକଣ୍ଠ ଦାଶ"
+ ]
+ },
+ "apihelp-main-param-action": "କେଉଁ କାମ କରାଯିବ ।",
+ "apihelp-main-param-format": "ଆଉଟପୁଟ୍‌ର ଫର୍ମାଟ ।",
+ "apihelp-block-description": "ଜଣେ ବ୍ୟବହାରକାରୀଙ୍କୁ ବ୍ଲକ କରନ୍ତୁ ।",
+ "apihelp-block-param-reason": "ବ୍ଲକ କରିବାର କାରଣ ।",
+ "apihelp-block-param-nocreate": "ଆକାଉଣ୍ଟ ତିଆରି ହେବାକୁ ପ୍ରତିରୋଧ କରନ୍ତୁ ।",
+ "apihelp-createaccount-param-name": "ବ୍ୟବହାରକାରୀଙ୍କ ନାମ",
+ "apihelp-delete-description": "ପୃଷ୍ଠାଟି ଲିଭାଇଦେବେ"
+}
diff --git a/includes/api/i18n/pl.json b/includes/api/i18n/pl.json
index 1a5c8975..791074ee 100644
--- a/includes/api/i18n/pl.json
+++ b/includes/api/i18n/pl.json
@@ -9,60 +9,285 @@
"Macofe",
"Pio387",
"Peter Bowman",
- "Darellur"
+ "Darellur",
+ "The Polish",
+ "Matma Rex"
]
},
"apihelp-main-param-action": "Wybierz akcję do wykonania.",
"apihelp-main-param-format": "Format danych wyjściowych.",
"apihelp-main-param-maxlag": "Maksymalne opóźnienie mogą być używane kiedy MediaWiki jest zainstalowana w klastrze zreplikowanej bazy danych. By zapisać działania powodujące większe opóźnienie replikacji, ten parametr może wymusić czekanie u klienta, dopóki opóźnienie replikacji jest mniejsze niż określona wartość. W przypadku nadmiernego opóźnienia, kod błędu <samp>maxlag</samp> jest zwracany z wiadomością jak <samp>Oczekiwanie na $host: $lag sekund opóźnienia</samp>.<br />Zobacz [[mw:Manual:Maxlag_parameter|Podręcznik:Parametr Maxlag]] by uzyskać więcej informacji.",
"apihelp-main-param-assert": "Sprawdź, czy użytkownik jest zalogowany jeżeli jest ustawiony na <kbd>użytkownik</kbd>, lub ma prawa bota jeśli <kbd>bot</kbd>.",
+ "apihelp-main-param-curtimestamp": "Dołącz obecny znacznik czasu do wyniku.",
"apihelp-block-description": "Zablokuj użytkownika.",
"apihelp-block-param-user": "Nazwa użytkownika, adres IP lub zakres adresów IP, które chcesz zablokować.",
"apihelp-block-param-reason": "Powód blokady.",
+ "apihelp-block-param-anononly": "Blokuj tylko anonimowych użytkowników (blokuje anonimowe edycje z tego adresu IP).",
"apihelp-block-param-nocreate": "Zapobiegnij utworzeniu konta.",
- "apihelp-block-param-watchuser": "Obserwuj stronę użytkownika i jego IP oraz jego stronę dyskusji.",
+ "apihelp-block-param-autoblock": "Zablokuj ostatni adres IP tego użytkownika i automatycznie wszystkie kolejne, z których będzie się logował.",
+ "apihelp-block-param-reblock": "Jeżeli ten użytkownik jest już zablokowany, nadpisz blokadę.",
+ "apihelp-block-param-watchuser": "Obserwuj stronę użytkownika i jego IP oraz ich strony dyskusji.",
"apihelp-block-example-ip-simple": "Zablokuj IP <kbd>192.0.2.5</kbd> na 3 dni za <kbd>Pierwszy atak</kbd>.",
+ "apihelp-block-example-user-complex": "Zablokuj użytkownika <kbd>Vandal</kbd> na zawsze za <kbd>Vandalism</kbd> i uniemożliwij utworzenie nowego konta oraz wysyłanie emaili.",
+ "apihelp-checktoken-param-type": "Typ tokenu do przetestowania.",
+ "apihelp-checktoken-param-token": "Token do przetestowania.",
+ "apihelp-checktoken-param-maxtokenage": "Maksymalny wiek tokenu, w sekundach.",
+ "apihelp-compare-param-fromtitle": "Pierwszy tytuł do porównania.",
+ "apihelp-compare-param-fromid": "ID pierwszej strony do porównania.",
+ "apihelp-compare-param-fromrev": "Pierwsza wersja do porównania.",
+ "apihelp-compare-param-totitle": "Drugi tytuł do porównania.",
+ "apihelp-compare-param-toid": "Numer drugiej strony do porównania.",
+ "apihelp-compare-param-torev": "Druga wersja do porównania.",
+ "apihelp-createaccount-description": "Utwórz nowe konto.",
"apihelp-createaccount-param-name": "Nazwa użytkownika",
+ "apihelp-createaccount-param-password": "Hasło (ignorowane jeśli <var>$1mailpassword</var> jest ustawione).",
+ "apihelp-createaccount-param-domain": "Domena uwierzytelniania zewnętrznego (opcjonalnie).",
+ "apihelp-createaccount-param-token": "Token tworzenia konta uzyskany w pierwszym zapytaniu.",
+ "apihelp-createaccount-param-email": "Adres email użytkownika (opcjonalne).",
+ "apihelp-createaccount-param-realname": "Prawdziwe imię i nazwisko użytkownika (opcjonalne).",
+ "apihelp-createaccount-param-reason": "Opcjionalny powód tworzenia konta (aby został umieszczony w logu).",
+ "apihelp-createaccount-example-pass": "Utwórz użytkownika <kbd>testuser</kbd> z hasłem <kbd>test123</kbd>.",
+ "apihelp-createaccount-example-mail": "Utwórz użytkownika <kbd>testmailuser</kbd> i wyślij losowo wygenerowane hasło na emaila.",
"apihelp-delete-description": "Usuń stronę.",
- "apihelp-delete-param-watch": "Dodaj stronę do twojej listy obserwowanych.",
- "apihelp-delete-param-unwatch": "Usuń stronę z twojej listy obserwowanych.",
- "apihelp-delete-example-simple": "Usuń stronę główną",
+ "apihelp-delete-param-reason": "Powód usuwania. Jeśli pozostaiwsz to pole puste, zostanie on wygenerowany automatycznie.",
+ "apihelp-delete-param-watch": "Dodaj stronę do obecnej listy obserwowanych.",
+ "apihelp-delete-param-unwatch": "Usuń stronę z obecnej listy obserwowanych.",
+ "apihelp-delete-example-simple": "Usuń <kbd>Stronę Główną</kbd>.",
+ "apihelp-delete-example-reason": "Usuń <kbd>Stronę Główną</kbd> z powodem <kbd>Przygotowania do przenoszenia</kbd>.",
"apihelp-disabled-description": "Ten moduł został wyłączony.",
"apihelp-edit-description": "Utwórz i edytuj strony.;",
+ "apihelp-edit-param-section": "Numer sekcji. <kbd>0</kbd> dla górnej sekcji, <kbd>new</kbd> dla nowej sekcji.",
+ "apihelp-edit-param-sectiontitle": "Tytuł nowej sekcji.",
"apihelp-edit-param-text": "Zawartość strony.",
+ "apihelp-edit-param-tags": "Zmień tagi do przypisania do tej edycji.",
"apihelp-edit-param-minor": "Drobna zmiana.",
"apihelp-edit-param-notminor": "Nie drobna zmiana.",
"apihelp-edit-param-bot": "Oznacz tę edycję jako edycję bota.",
+ "apihelp-edit-param-createonly": "Nie edytuj strony, jesli już istnieje.",
+ "apihelp-edit-param-nocreate": "Zwróć błąd, jeśli strona nie istnieje.",
"apihelp-edit-param-watch": "Dodaj stronę do aktualnej listy obserwacji użytkownika.",
"apihelp-edit-param-unwatch": "Usuń stronę z aktualnej listy obserwacji użytkownika.",
+ "apihelp-edit-param-redirect": "Automatycznie rozwiązuj przekierowania.",
"apihelp-edit-example-edit": "Edytuj stronę",
"apihelp-emailuser-description": "Wyślij e‐mail do użytkownika.",
+ "apihelp-emailuser-param-target": "Użytkownik, do którego wysyłany jest e-mail.",
+ "apihelp-emailuser-param-subject": "Nagłówek tematu.",
+ "apihelp-emailuser-param-text": "Treść emaila.",
+ "apihelp-emailuser-param-ccme": "Wyślij kopię wiadomości do mnie.",
+ "apihelp-emailuser-example-email": "Wyślij e-mail do użytkownika <kbd>WikiSysop</kbd> z tekstem <kbd>treścią</kbd>.",
+ "apihelp-expandtemplates-description": "Rozwiń wszystkie szablony w wikitexcie.",
+ "apihelp-expandtemplates-param-title": "Tytuł strony.",
+ "apihelp-expandtemplates-param-text": "Wikitext do przekonwertowania.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "Rozszerzony wikitext.",
+ "apihelp-feedcontributions-param-feedformat": "Format danych wyjściowych.",
+ "apihelp-feedcontributions-param-year": "Od roku (i wcześniej).",
+ "apihelp-feedcontributions-param-month": "Od miesiąca (i wcześniej).",
+ "apihelp-feedcontributions-param-deletedonly": "Pokazuj tylko usunięty wkład.",
+ "apihelp-feedcontributions-param-toponly": "Pokazuj tylko edycje będące ostatnią zmianą strony.",
+ "apihelp-feedcontributions-param-newonly": "Pokazuj tylko edycje tworzące stronę.",
+ "apihelp-feedcontributions-param-showsizediff": "Pokaż różnicę rozmiaru między wersjami.",
+ "apihelp-feedrecentchanges-param-namespace": "Przestrzeń nazw, do której ograniczone są wyniki.",
+ "apihelp-feedrecentchanges-param-invert": "Wszystkie przestrzenie nazw oprócz wybranej.",
+ "apihelp-feedrecentchanges-param-days": "Dni, do których ograniczone są wyniki.",
+ "apihelp-feedrecentchanges-param-limit": "Maksymalna liczba zwracanych wyników.",
+ "apihelp-feedrecentchanges-param-from": "Pokaż zmiany od tamtej chwili.",
+ "apihelp-feedrecentchanges-param-hideminor": "Ukryj drobne zmiany.",
+ "apihelp-feedrecentchanges-param-hidebots": "Ukryj zmiany zrobione przez boty.",
+ "apihelp-feedrecentchanges-param-hideanons": "Ukryj zmiany zrobione przez anonimowych użytkowników.",
+ "apihelp-feedrecentchanges-param-hideliu": "Ukryj zmiany zrobione przez zarejestrowanych użytkowników.",
+ "apihelp-feedrecentchanges-param-hidepatrolled": "Ukryj sprawdzone zmiany.",
+ "apihelp-feedrecentchanges-param-hidemyself": "Ukryj zmiany zrobione przez obecnego użytkownika.",
+ "apihelp-feedrecentchanges-param-tagfilter": "Filtruj po znacznikach.",
"apihelp-feedrecentchanges-example-simple": "Pokaż ostatnie zmiany.",
+ "apihelp-feedrecentchanges-example-30days": "Pokaż ostatnie zmiany z 30 dni.",
+ "apihelp-filerevert-description": "Przywróć plik do starej wersji.",
+ "apihelp-filerevert-param-filename": "Docelowa nazwa pliku bez prefiksu Plik:",
+ "apihelp-filerevert-param-comment": "Prześlij komentarz.",
+ "apihelp-filerevert-example-revert": "Przywróć <kbd>Wiki.png</kbd> do wersji z <kbd>2011-03-05T15:27:40Z</kbd>.",
"apihelp-help-description": "Wyświetl pomoc dla określonych modułów.",
"apihelp-help-param-modules": "Moduły do wyświetlenia pomocy dla (wartości <var>action</var> i <var>format</var> parametry, lub <kbd>main</kbd>). Może określić podmoduły z <kbd>+</kbd>.",
"apihelp-help-param-recursivesubmodules": "Zawiera pomoc dla podmodułów rekursywnie.",
+ "apihelp-help-param-helpformat": "Format wyjściowy pomocy.",
+ "apihelp-help-param-toc": "Dołącz spis treści do wyjściowego HTML.",
"apihelp-help-example-main": "Pomoc dla modułu głównego",
"apihelp-help-example-recursive": "Cała pomoc na jednej stronie.",
"apihelp-help-example-help": "Pomoc dla modułu pomocy",
+ "apihelp-help-example-query": "Pomoc dla dwóch podmodułów zapytań.",
+ "apihelp-imagerotate-description": "Obróć jeden lub wiecej obrazków.",
+ "apihelp-imagerotate-param-rotation": "Stopni w prawo, aby obrócić zdjęcie.",
+ "apihelp-imagerotate-example-simple": "Obróć <kbd>Plik:Przykład.png</kbd> o <kbd>90</kbd> stopni.",
+ "apihelp-imagerotate-example-generator": "Obróć wszystkie obrazki w <kbd>Kategorii:Flip</kbd> o <kbd>180</kbd> stopni.",
+ "apihelp-import-param-summary": "Podsumowanie importu.",
+ "apihelp-import-param-xml": "Przesłany plik XML.",
+ "apihelp-import-param-interwikisource": "Dla importów mediawiki: źródłowa wiki.",
+ "apihelp-import-param-interwikipage": "Dla importów interwiki: strona do importu.",
+ "apihelp-import-param-fullhistory": "Dla importów interwiki: importuj całą historię, a nie tylko obecną wersję.",
+ "apihelp-import-param-templates": "Dla importów mediawiki: importuj też wszystkie użyte szablony.",
+ "apihelp-import-param-namespace": "Importuj do tej przestrzeni nazw. Nie może być użyte razem z <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Importuj jako podstronę tej strony. Nie może być użyte razem z <var>$1namespace</var>.",
"apihelp-login-param-name": "Nazwa użytkownika.",
"apihelp-login-param-password": "Hasło.",
+ "apihelp-login-param-domain": "Domena (opcjonalnie).",
+ "apihelp-login-param-token": "Token logowania zdobyty w pierwszym zapytaniu.",
+ "apihelp-login-example-gettoken": "Zdobądź token logowania.",
"apihelp-login-example-login": "Zaloguj się",
+ "apihelp-logout-description": "Wyloguj i wyczyść dane sesji.",
+ "apihelp-logout-example-logout": "Wyloguj obecnego użytkownika.",
+ "apihelp-managetags-param-reason": "Opcjonalny powód utworzenia, usunięcia, włączenia lub wyłączenia znacznika.",
"apihelp-managetags-param-ignorewarnings": "Czy zignorować ostrzeżenia, które pojawiają się w trakcie operacji.",
"apihelp-move-description": "Przenieś stronę.",
"apihelp-move-param-reason": "Powód zmiany nazwy.",
+ "apihelp-move-param-movetalk": "Zmień nazwę strony dyskusji, jeśli istnieje.",
+ "apihelp-move-param-movesubpages": "Zmień nazwy podstron, jeśli możliwe.",
+ "apihelp-move-param-noredirect": "Nie twórz przekierowania.",
"apihelp-move-param-ignorewarnings": "Ignoruj wszystkie ostrzeżenia.",
+ "apihelp-opensearch-param-search": "Wyszukaj tekst.",
+ "apihelp-opensearch-param-limit": "Maksymalna liczba zwracanych wyników.",
+ "apihelp-opensearch-param-namespace": "Przestrzenie nazw do przeszukania.",
+ "apihelp-opensearch-param-format": "Format danych wyjściowych.",
+ "apihelp-opensearch-example-te": "Znajdź strony zaczynające się od <kbd>Te</kbd>.",
+ "apihelp-options-param-reset": "Resetuj preferencje do domyślnych.",
+ "apihelp-options-param-optionname": "Nazwa opcji, która powinna być ustawiona na wartość <var>$1optionvalue</var>.",
+ "apihelp-options-param-optionvalue": "Wartość opcji, określona w <var>$1optionname</var>, może zawierać znaki pionowej kreski.",
+ "apihelp-options-example-reset": "Resetuj wszystkie preferencje.",
+ "apihelp-paraminfo-description": "Zdobądź informacje o modułach API.",
+ "apihelp-paraminfo-param-helpformat": "Format tekstów pomocnicznych.",
+ "apihelp-parse-param-summary": "Powód do analizy.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Zwróć oryginalny wikitext, który został przeanalizowany.",
+ "apihelp-parse-param-preview": "Analizuj w trybie podglądu.",
+ "apihelp-parse-param-disabletoc": "Pomiń spis treści na wyjściu.",
+ "apihelp-parse-example-page": "Przeanalizuj stronę.",
+ "apihelp-parse-example-text": "Analizuj wikitext.",
+ "apihelp-parse-example-summary": "Analizuj powód.",
+ "apihelp-patrol-description": "Sprawdź stronę lub edycję.",
+ "apihelp-patrol-param-rcid": "ID ostatnich zmian do patrolowania.",
+ "apihelp-patrol-param-revid": "Numer edycji do sprawdzenia.",
+ "apihelp-patrol-example-rcid": "Sprawdź ostatnią zmianę.",
+ "apihelp-patrol-example-revid": "Sprawdź edycje.",
+ "apihelp-protect-description": "Zmień poziom zabezpieczenia strony.",
+ "apihelp-protect-param-reason": "Powód zabezpieczania/odbezpieczania.",
+ "apihelp-protect-param-cascade": "Włącz ochronę kaskadową (chronione są wszystkie osadzone szablony i obrazki na tej stronie). Ignorowane, jeśli żaden z danych poziomów ochrony nie wspiera kaskadowania.",
"apihelp-protect-example-protect": "Zabezpiecz stronę",
+ "apihelp-protect-example-unprotect": "Odbezpiecz stronę ustawiając ograniczenia na <kbd>wszystkie</kbd>.",
+ "apihelp-protect-example-unprotect2": "Odbezpiecz stronę ustawiając brak ograniczeń.",
+ "apihelp-purge-param-forcelinkupdate": "Uaktualnij tabele linków.",
+ "apihelp-purge-example-generator": "Przeczyść pierwsze 10 stron w przestrzeni głównej.",
+ "apihelp-query+allcategories-description": "Emuluj wszystkie kategorie.",
+ "apihelp-query+allcategories-param-dir": "Kierunek sortowania.",
+ "apihelp-query+allcategories-param-limit": "Liczba kategorii do zwórcenia.",
+ "apihelp-query+alldeletedrevisions-paraminfo-useronly": "Może być użyte tylko z <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "Nie może być używane z <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-param-from": "Zacznij nasłuchiwanie na tym tytule.",
+ "apihelp-query+alldeletedrevisions-param-to": "Skończ nasłuchiwanie na tym tytule.",
+ "apihelp-query+alldeletedrevisions-param-tag": "Pokazuj tylko zmiany oznaczone tym znacznikiem.",
+ "apihelp-query+alldeletedrevisions-param-user": "Pokazuj tylko zmiany dokonane przez tego użytkownika.",
+ "apihelp-query+alldeletedrevisions-param-excludeuser": "Nie pokazuj zmian dokonanych przez tego użytkownika.",
+ "apihelp-query+alldeletedrevisions-param-namespace": "Listuj tylko strony z tej przestrzeni nazw.",
+ "apihelp-query+allfileusages-param-limit": "Łączna ilość obiektów do zwrócenia.",
+ "apihelp-query+allfileusages-example-unique": "Lista unikatowych tytułów plików.",
+ "apihelp-query+allimages-param-sort": "Sortowanie według właściwości.",
+ "apihelp-query+allimages-example-recent": "Pokaż listę ostatnio przesłanych plików, podobnie do [[Special:NewFiles]].",
+ "apihelp-query+allimages-example-mimetypes": "Pokaż listę plików z typem MIME <kbd>image/png</kbd> lub <kbd>image/gif</kbd>",
+ "apihelp-query+alllinks-param-namespace": "Przestrzeń nazw do emulacji.",
+ "apihelp-query+alllinks-param-limit": "Łączna ilość obiektów do zwrócenia.",
+ "apihelp-query+alllinks-example-unique": "Lista unikatowych tytułów plików.",
+ "apihelp-query+allmessages-param-prop": "Właściwości do odczytu.",
+ "apihelp-query+allmessages-param-prefix": "Zwróć wiadomości z tym prefixem.",
+ "apihelp-query+allpages-param-prtype": "Ogranicz tylko do zabezpieczonych stron.",
+ "apihelp-query+allpages-param-limit": "Ilość stron do zwrócenia.",
"apihelp-query+allpages-example-B": "Pokaż listę stron rozpoczynających się na literę <kbd>B</kbd>.",
+ "apihelp-query+allredirects-description": "Lista wszystkich przekierowań do przestrzeni nazw.",
+ "apihelp-query+allredirects-param-namespace": "Przestrzeń nazw do emulacji.",
+ "apihelp-query+allredirects-param-limit": "Łączna ilość obiektów do zwrócenia.",
+ "apihelp-query+alltransclusions-param-namespace": "Przestrzeń nazw do emulacji.",
+ "apihelp-query+allusers-param-witheditsonly": "Tylko użytkownicy, którzy edytowali.",
+ "apihelp-query+backlinks-param-namespace": "Przestrzeń nazw do emulacji.",
+ "apihelp-query+blocks-param-ids": "Lista zablokowanych ID do wylistowania (opcjonalne).",
+ "apihelp-query+blocks-param-users": "Lista użytkowników do wyszukania (opcjonalne).",
+ "apihelp-query+blocks-param-limit": "Maksymalna liczba blokad do wylistowania.",
+ "apihelp-query+blocks-example-simple": "Listuj blokady.",
+ "apihelp-query+categories-param-limit": "Ilość kategorii do zwrócenia.",
+ "apihelp-query+categorymembers-description": "Wszystkie strony w danej kategorii.",
+ "apihelp-query+categorymembers-param-limit": "Maksymalna liczba zwracanych wyników.",
+ "apihelp-query+categorymembers-param-sort": "Sortowanie według właściwości.",
+ "apihelp-query+deletedrevisions-param-tag": "Pokazuj tylko zmiany oznaczone tym tagiem.",
+ "apihelp-query+deletedrevisions-param-user": "Pokazuj tylko zmiany dokonane przez tego użytkownika.",
+ "apihelp-query+deletedrevisions-param-excludeuser": "Nie pokazuj zmian dokonanych przez tego użytkownika.",
+ "apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|Tryb|Tryby}}: $2",
+ "apihelp-query+deletedrevs-param-unique": "Liatuj tylko jedną edycję dla każdej strony.",
+ "apihelp-query+deletedrevs-param-tag": "Pokazuj tylko zmiany oznaczone tym tagiem.",
+ "apihelp-query+deletedrevs-param-user": "Listuj tylko zmiany dokonane przez tego użytkownika.",
+ "apihelp-query+deletedrevs-param-excludeuser": "Nie listuj zmian dokonanych przez tego użytkownika.",
+ "apihelp-query+deletedrevs-param-namespace": "Listuj tylko strony z tej przestrzeni nazw.",
+ "apihelp-query+deletedrevs-param-limit": "Maksymalna ilość zmian do wylistowania.",
+ "apihelp-query+duplicatefiles-example-generated": "Szukaj duplikatów wszystkich plików.",
+ "apihelp-query+embeddedin-param-filterredir": "Jaki filtrować przekierowania.",
+ "apihelp-query+extlinks-param-limit": "Ilość linków do zwrócenia.",
+ "apihelp-query+exturlusage-param-limit": "Ilość stron do zwrócenia.",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "Alias rozmiaru.",
"apihelp-query+filearchive-example-simple": "Pokaż listę wszystkich usuniętych plików.",
+ "apihelp-query+filerepoinfo-example-simple": "Uzyskaj informacje na temat repozytoriów plików.",
+ "apihelp-query+fileusage-paramvalue-prop-title": "Nazwa każdej strony.",
+ "apihelp-query+fileusage-param-limit": "Ilość do zwrócenia.",
"apihelp-query+imageinfo-paramvalue-prop-canonicaltitle": "Dodaje kanoniczny tytuł pliku.",
"apihelp-query+imageinfo-paramvalue-prop-dimensions": "Alias rozmiaru.",
+ "apihelp-query+imageinfo-paramvalue-prop-sha1": "Dodaj sumę kontrolną SHA-1 dla tego pliku.",
"apihelp-query+imageinfo-paramvalue-prop-mime": "Dodaje typ MIME pliku.",
+ "apihelp-query+imageinfo-param-urlheight": "Podobne do $1urlwidth.",
+ "apihelp-query+images-param-limit": "Ilość plików do zwrócenia.",
+ "apihelp-query+info-description": "Pokaż podstawowe informacje o stronie.",
"apihelp-query+info-paramvalue-prop-watchers": "Liczba obserwujących, jeśli jest to dozwolone.",
"apihelp-query+info-paramvalue-prop-readable": "Czy użytkownik może przeczytać tę stronę.",
+ "apihelp-query+iwbacklinks-param-prefix": "Prefix interwiki.",
+ "apihelp-query+iwbacklinks-param-limit": "Łączna ilość stron do zwrócenia.",
+ "apihelp-query+iwlinks-paramvalue-prop-url": "Dodaje pełny adres URL.",
+ "apihelp-query+links-param-limit": "Ilość linków do zwrócenia.",
+ "apihelp-query+linkshere-paramvalue-prop-title": "Nazwa każdej strony.",
+ "apihelp-query+linkshere-param-limit": "Ilość do zwrócenia.",
+ "apihelp-query+logevents-description": "Pobierz eventy z logu.",
+ "apihelp-query+logevents-example-simple": "Lista ostatnich zarejestrowanych zdarzeń.",
+ "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+prefixsearch-param-limit": "Maksymalna liczba zwracanych wyników.",
"apihelp-query+prefixsearch-param-offset": "Liczba wyników do pominięcia.",
+ "apihelp-query+protectedtitles-description": "Lista wszystkich tytułów zabezpieczonych przed tworzeniem.",
+ "apihelp-query+protectedtitles-param-namespace": "Listuj tylko strony z tych przestrzeni nazw.",
+ "apihelp-query+protectedtitles-param-limit": "Łączna liczba stron do zwrócenia.",
+ "apihelp-query+protectedtitles-example-simple": "Lista chronionych nagłówków",
+ "apihelp-query+recentchanges-param-user": "Listuj tylko zmiany dokonane przez tego użytkownika.",
+ "apihelp-query+recentchanges-param-excludeuser": "Nie listuj zmian dokonanych przez tego użytkownika.",
+ "apihelp-query+recentchanges-param-tag": "Pokazuj tylko zmiany oznaczone tym tagiem.",
"apihelp-query+recentchanges-example-simple": "Lista ostatnich zmian.",
+ "apihelp-query+redirects-paramvalue-prop-title": "Nazwa każdego przekierowania.",
+ "apihelp-query+redirects-param-limit": "Ile przekierowań zwrócić.",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "Identyfikator wersji.",
+ "apihelp-query+revisions+base-paramvalue-prop-flags": "Znaczniki wersji (drobne).",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "Znacznik czasu wersji.",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "SHA-1 (base 16) wersji.",
+ "apihelp-query+revisions+base-paramvalue-prop-content": "Tekst wersji.",
+ "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-description": "Wykonaj wyszukiwanie pełnotekstowe.",
+ "apihelp-query+search-param-info": "Które metadane zwrócić.",
+ "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+search-example-simple": "Szukaj <kbd>meaning</kbd>.",
+ "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-example-simple": "Pobierz informacje o stronie.",
+ "apihelp-query+tags-description": "Lista zmian tagów.",
+ "apihelp-query+tags-param-limit": "Maksymalna liczba tagów do wyświetlenia.",
+ "apihelp-query+tags-example-simple": "Lista dostęnych tagów.",
+ "apihelp-query+templates-param-limit": "Ile szablonów zwrócić?",
+ "apihelp-query+transcludedin-param-limit": "Ile zwrócić.",
"apihelp-query+watchlist-param-excludeuser": "Nie wyświetlaj zmian wykonanych przez tego użytkownika.",
+ "apihelp-query+watchlist-paramvalue-prop-title": "Dodaje tytuł strony.",
+ "apihelp-query+watchlist-paramvalue-prop-user": "Dodaje użytkownika, który wykonał edycję.",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "Dodaje komentarz do edycji.",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "Dodaje znacznik czasu edycji.",
+ "apihelp-query+watchlist-paramvalue-prop-sizes": "Dodaje starą i nową długość strony.",
+ "apihelp-tag-param-reason": "Powód zmiany.",
"apihelp-unblock-param-reason": "Powód odblokowania.",
"apihelp-undelete-param-reason": "Powód przywracania.",
"apihelp-upload-param-filename": "Nazwa pliku docelowego.",
@@ -70,16 +295,12 @@
"apihelp-userrights-param-reason": "Powód zmiany.",
"apihelp-dbg-description": "Dane wyjściowe w formacie <code>var_export()</code> (funkcji PHP).",
"apihelp-dbgfm-description": "Dane wyjściowe w formacie <code>var_export()</code> (funkcji PHP) (prawidłowo wyświetlane w HTML).",
- "apihelp-dump-description": "Dane wyjściowe w formacie <code>var_dump()</code> (funkcji PHP).",
- "apihelp-dumpfm-description": "Dane wyjściowe w formacie <code>var_dump()</code> (funkcji PHP) (prawidłowo wyświetlane w HTML).",
"apihelp-json-description": "Dane wyjściowe w formacie JSON.",
"apihelp-jsonfm-description": "Dane wyjściowe w formacie JSON (prawidłowo wyświetlane w HTML).",
"apihelp-php-description": "Dane wyjściowe w serializowany formacie PHP.",
"apihelp-phpfm-description": "Dane wyjściowe w serializowanym formacie PHP (prawidłowo wyświetlane w HTML).",
"apihelp-txt-description": "Dane wyjściowe w formacie <code>print_r()</code> (funkcji PHP).",
"apihelp-txtfm-description": "Dane wyjściowe w formacie <code>print_r()</code> (funkcji PHP) (prawidłowo wyświetlane w HTML).",
- "apihelp-wddx-description": "Dane wyjściowe w formacie WDDX.",
- "apihelp-wddxfm-description": "Dane wyjściowe w formacie WDDX (prawidłowo wyświetlane w HTML).",
"apihelp-xml-description": "Dane wyjściowe w formacie XML.",
"apihelp-xml-param-xslt": "Jeśli określony, dodaje &lt;xslt&gt; jako arkusz styli. Powinna to być strona wiki w przestrzeni nazw MediaWiki, której nazwy stron kończą się na \".xsl\".",
"apihelp-xmlfm-description": "Dane wyjściowe w formacie XML (prawidłowo wyświetlane w HTML).",
@@ -95,17 +316,26 @@
"api-help-flag-writerights": "Ten moduł wymaga praw zapisu.",
"api-help-flag-mustbeposted": "Ten moduł akceptuje tylko żądania POST.",
"api-help-flag-generator": "Ten moduł może być użyty jako generator.",
+ "api-help-source": "Źródło: $1",
+ "api-help-source-unknown": "Źródło: <span class=\"apihelp-unknown\">nieznane</span>",
+ "api-help-license": "Licencja: [[$1|$2]]",
+ "api-help-license-noname": "Licencja: [[$1|Zobacz link]]",
+ "api-help-license-unknown": "Licencja: <span class=\"apihelp-unknown\">nieznana</span>",
"api-help-parameters": "{{PLURAL:$1|Parametr|Parametry}}:",
"api-help-param-deprecated": "Przestarzałe.",
"api-help-param-required": "Ten parametr jest wymagany.",
- "api-help-param-list": "{{PLURAL:$1|1=Jedna wartość|2=Wartości (oddziel za pomocą <kbd>{{!}}</kbd>)}}: $2",
+ "api-help-datatypes-header": "Typy danych",
+ "api-help-param-type-boolean": "Typ: wartość logiczna ([[Special:ApiHelp/main#main/datatypes|szczegóły]])",
+ "api-help-param-type-timestamp": "Typ: {{PLURAL:$1|1=znacznik czasu|2=lista znaczników czasu}} ([[Special:ApiHelp/main#main/datatypes|dozwolone formaty]])",
+ "api-help-param-type-user": "Typ: {{PLURAL:$1|1=nazwa użytkownika|2=lista nazw uzytkowników}}",
+ "api-help-param-list": "{{PLURAL:$1|1=Jedna z następujących wartość|2=Wartości (oddziel za pomocą <kbd>{{!}}</kbd>)}}: $2",
"api-help-param-limit": "Nie więcej niż $1 dozwolone.",
"api-help-param-limit2": "Nie więcej niż $1 ($2 dla botów) dozwolone.",
- "api-help-param-integer-min": "{{PLURAL:$1|1=Wartość|2=Wartości}} musza być mniejsze niż $2.",
- "api-help-param-integer-max": "{{PLURAL:$1|1=Wartość musi|2=Wartości muszą}} być nie większa niż $3.",
+ "api-help-param-integer-min": "{{PLURAL:$1|1=Wartość musi być nie mniejsza|2=Wartości muszą być nie mniejsze}} niż $2.",
+ "api-help-param-integer-max": "{{PLURAL:$1|1=Wartość musi być nie większa|2=Wartości muszą być nie większe}} niż $3.",
"api-help-param-integer-minmax": "{{PLURAL:$1|1=Wartość musi|2=Wartości muszą}} być pomiędzy $2 a $3.",
"api-help-param-multi-separate": "Oddziel wartości za pomocą <kbd>|</kbd>.",
- "api-help-param-multi-max": "Maksymalna ilość wartości to {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} dla botów).",
+ "api-help-param-multi-max": "Maksymalna liczba wartości to {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} dla botów).",
"api-help-param-default": "Domyślnie: $1",
"api-help-param-default-empty": "Domyślnie: <span class=\"apihelp-empty\">(puste)</span>",
"api-help-param-no-description": "<span class=\"apihelp-empty\">(bez opisu)</span>",
diff --git a/includes/api/i18n/ps.json b/includes/api/i18n/ps.json
index b9399024..9d242817 100644
--- a/includes/api/i18n/ps.json
+++ b/includes/api/i18n/ps.json
@@ -9,10 +9,19 @@
"apihelp-block-param-reason": "د بنديز سبب.",
"apihelp-createaccount-param-name": "کارن-نوم.",
"apihelp-delete-description": "يو مخ ړنگول.",
+ "apihelp-edit-description": "مخونه جوړول او سمول.",
"apihelp-edit-param-text": "مخ مېنځپانگه.",
+ "apihelp-edit-param-minor": "وړوکی سمون.",
"apihelp-edit-example-edit": "يو مخ سمول.",
"apihelp-emailuser-description": "کارن ته برېښليک لېږل.",
"apihelp-expandtemplates-param-title": "د مخ سرليک.",
+ "apihelp-feedrecentchanges-param-hideminor": "وړوکي بدلونونه پټول.",
+ "apihelp-feedrecentchanges-param-hidebots": "د روباټونو لخوا ترسره شوي بدلونونه پټول.",
+ "apihelp-feedrecentchanges-param-hideanons": "د ورکنومو کارنانو لخوا ترسره شوي بدلونونه پټول.",
+ "apihelp-feedrecentchanges-param-hideliu": "د ثبت شويو کارنانو لخوا ترسره شوي بدلونونه پټول.",
+ "apihelp-feedrecentchanges-param-hidepatrolled": "څارل شوي بدلونونه پټول.",
+ "apihelp-feedrecentchanges-param-hidemyself": "د اوسني کارن لخوا ترسره شوي بدلونونه پټول.",
+ "apihelp-feedrecentchanges-param-tagfilter": "د نښلن له مخې چاڼول.",
"apihelp-login-param-name": "کارن نوم.",
"apihelp-login-param-password": "پټنوم.",
"apihelp-login-param-domain": "شپول (اختياري).",
@@ -20,8 +29,20 @@
"apihelp-move-description": "يو مخ لېږدول.",
"apihelp-query+search-example-simple": "د <kbd>مانا</kbd> پلټل.",
"apihelp-query+search-example-text": "د <kbd>مانا</kbd> لپاره متنونه پلټل.",
+ "apihelp-query+watchlist-paramvalue-prop-title": "د يو مخ سرليک ورگډوي.",
+ "apihelp-tag-param-reason": "د بدلون سبب.",
+ "apihelp-unblock-param-reason": "د بنديز ليرې کولو سبب.",
+ "apihelp-upload-param-watch": "مخ کتل.",
+ "apihelp-upload-param-file": "د دوتنې مېنځپانگه.",
"apihelp-userrights-param-user": "کارن نوم.",
"apihelp-userrights-param-userid": "کارن پېژند.",
+ "apihelp-userrights-param-reason": "د بدلون سبب.",
+ "api-help-source": "سرچينه: $1",
+ "api-help-source-unknown": "سرچينه: <span class=\"apihelp-unknown\">ناجوت</span>",
+ "api-help-license": "منښتليک: [[$1|$2]]",
+ "api-help-license-noname": "منښتليک: [[$1|تړنه وڅارئ]]",
+ "api-help-license-unknown": "منښتليک: <span class=\"apihelp-unknown\">ناجوت</span>",
+ "api-help-datatypes-header": "اومتوگ ډولونه",
"api-help-param-default": "تلواليز: $1",
"api-help-param-default-empty": "تلواليز: <span class=\"apihelp-empty\">(تش)</span>",
"api-help-examples": "{{PLURAL:$1|بېلگه|بېلگې}}:",
diff --git a/includes/api/i18n/pt-br.json b/includes/api/i18n/pt-br.json
index 5af806d0..9c1c623c 100644
--- a/includes/api/i18n/pt-br.json
+++ b/includes/api/i18n/pt-br.json
@@ -1,14 +1,286 @@
{
"@metadata": {
"authors": [
- "Fasouzafreitas"
+ "Fasouzafreitas",
+ "Dianakc",
+ "Cainamarques"
]
},
+ "apihelp-main-param-action": "Qual ação executar.",
+ "apihelp-main-param-format": "O formato da saída.",
+ "apihelp-main-param-smaxage": "Define o cabeçalho <code>s-maxage</code> para esta quantidade de segundos. Os erros não são armazenados em cache.",
+ "apihelp-main-param-maxage": "Define o cabeçalho <code>max-age</code> para esta quantidade de segundos. Os erros não são armazenados em cache.",
"apihelp-main-param-requestid": "Qualquer valor dado aqui será incluído na resposta. Pode ser usado para distinguir requisições.",
+ "apihelp-main-param-curtimestamp": "Inclui a data atual no resultado.",
"apihelp-block-description": "Bloquear um usuário",
"apihelp-block-param-user": "Nome de usuário, endereço IP ou faixa de IP para bloquear.",
+ "apihelp-block-param-reason": "Razão do bloqueio.",
+ "apihelp-block-param-anononly": "Bloqueia apenas usuários anônimos (ou seja desativa edições anônimas para este endereço IP).",
+ "apihelp-block-param-nocreate": "Prevenir a criação de conta.",
+ "apihelp-block-param-autoblock": "Bloquear automaticamente o endereço IP usado e quaisquer endereços IPs subseqüentes que tentarem acessar a partir deles.",
+ "apihelp-block-param-hidename": "Oculta o nome do usuário do ''log'' de bloqueio. (Requer o direito <code>hideuser</code>).",
+ "apihelp-block-param-reblock": "Se o usuário já estiver bloqueado, sobrescrever o bloqueio existente.",
+ "apihelp-block-example-ip-simple": "Bloquear endereço IP <kbd>192.0.2.5</kbd> por três dias com razão <kbd>Primeira medida</kbd>.",
+ "apihelp-block-example-user-complex": "Bloquear usuário <kbd>Vândalo</kbd> indefinidamente com razão <kbd>Vandalismo</kbd> e o impede de criar nova conta e envio de emails.",
+ "apihelp-compare-param-fromtitle": "Primeiro título para comparar.",
+ "apihelp-compare-param-fromid": "Primeiro ID de página para comparar.",
+ "apihelp-compare-param-fromrev": "Primeira revisão para comparar.",
+ "apihelp-compare-param-totitle": "Segundo título para comparar.",
+ "apihelp-compare-param-toid": "Segundo ID de página para comparar.",
+ "apihelp-compare-param-torev": "Segunda revisão para comparar.",
+ "apihelp-compare-example-1": "Criar um diff entre a revisão 1 e 2.",
+ "apihelp-createaccount-description": "Criar uma nova conta de usuário.",
+ "apihelp-createaccount-param-name": "Nome de usuário.",
+ "apihelp-createaccount-param-password": "Senha (ignorada se <var>$1mailpassword</var> está definida).",
+ "apihelp-createaccount-param-domain": "Domínio para autenticação externa (opcional).",
+ "apihelp-createaccount-param-email": "Endereço de email para o usuário (opcional).",
+ "apihelp-createaccount-param-realname": "Nome real do usuário (opcional).",
+ "apihelp-delete-description": "Excluir uma página.",
+ "apihelp-delete-param-title": "Título da página para excluir. Não pode ser usado em conjunto com <var>$1pageid</var>.",
+ "apihelp-delete-param-pageid": "ID da página para excluir. Não pode ser usada juntamente com <var>$1title</var>.",
+ "apihelp-delete-param-watch": "Adiciona a página para a lista de vigiados do usuário atual.",
+ "apihelp-delete-param-unwatch": "Remove a página para a lista de vigiados do usuário atual.",
+ "apihelp-delete-example-simple": "Excluir <kbd>Página principal</kbd>.",
+ "apihelp-disabled-description": "Este módulo foi desativado.",
+ "apihelp-edit-description": "Criar e editar páginas.",
+ "apihelp-edit-param-title": "Título da página para editar. Não pode ser usado em conjunto com <var>$1pageid</var>.",
+ "apihelp-edit-param-pageid": "ID da página para editar. Não pode ser usada juntamente com <var>$1title</var>.",
+ "apihelp-edit-param-sectiontitle": "O título para uma nova seção.",
+ "apihelp-edit-param-text": "Conteúdo da página",
+ "apihelp-edit-param-minor": "Edição menor.",
+ "apihelp-edit-param-bot": "Marcar esta edição como feita por bot.",
+ "apihelp-edit-param-createonly": "Não editar a página se já existir.",
+ "apihelp-edit-param-nocreate": "Mostra um erro se a página não existir.",
+ "apihelp-edit-param-watch": "Adiciona a página para a lista de vigiados do usuário atual.",
+ "apihelp-edit-param-unwatch": "Remove a página para a lista de vigiados do usuário atual.",
+ "apihelp-edit-param-watchlist": "Incondicionalmente adiciona ou página para a lista de vigiados do usuário atual, usa as preferências ou não modifica.",
+ "apihelp-edit-param-contentformat": "Formato de serialização de conteúdo usado para o texto de entrada.",
+ "apihelp-edit-param-contentmodel": "Modelo de conteúdo do novo conteúdo.",
+ "apihelp-edit-example-edit": "Edita uma página.",
+ "apihelp-edit-example-prepend": "Antecende <kbd>_&#95;NOTOC_&#95;</kbd> a página.",
+ "apihelp-emailuser-description": "Envia email para o usuário.",
+ "apihelp-emailuser-param-target": "Usuário a se enviar o email.",
+ "apihelp-emailuser-param-subject": "Cabeçalho do assunto.",
+ "apihelp-emailuser-param-text": "Corpo do email.",
+ "apihelp-emailuser-param-ccme": "Envie uma cópia deste email para mim.",
+ "apihelp-expandtemplates-description": "Expande todas a predefinições em wikitexto.",
+ "apihelp-expandtemplates-param-title": "Título da página.",
+ "apihelp-expandtemplates-param-text": "Wikitexto para converter.",
+ "apihelp-feedcontributions-description": "Retorna o feed de contribuições de um usuário.",
+ "apihelp-feedcontributions-param-feedformat": "O formato do feed.",
+ "apihelp-feedcontributions-param-namespace": "A partir de qual espaço nominal filtrar contribuições.",
+ "apihelp-feedcontributions-param-year": "Ano (inclusive anteriores):",
+ "apihelp-feedcontributions-param-month": "Mês (inclusive anteriores).",
+ "apihelp-feedcontributions-param-tagfilter": "Filtrar contribuições que têm essas tags.",
+ "apihelp-feedcontributions-param-deletedonly": "Mostrar apenas contribuições excluídas.",
+ "apihelp-feedcontributions-param-toponly": "Mostrar somente as edições que sejam a última revisão.",
+ "apihelp-feedcontributions-param-newonly": "Mostrar somente as edições que são criação de páginas.",
+ "apihelp-feedcontributions-param-showsizediff": "Mostrar a diferença de tamanho entre as revisões.",
+ "apihelp-feedrecentchanges-description": "Retorna um feed de alterações recentes.",
+ "apihelp-feedrecentchanges-param-feedformat": "O formato do feed.",
+ "apihelp-feedrecentchanges-param-namespace": "Espaço nominal a partir do qual limitar resultados.",
+ "apihelp-feedrecentchanges-param-invert": "Todos os espaços nominais, exceto o selecionado.",
+ "apihelp-feedrecentchanges-param-limit": "O número máximo a se retornar.",
+ "apihelp-feedrecentchanges-param-from": "Mostra modificações desde então.",
+ "apihelp-feedrecentchanges-param-hideminor": "Ocultar modificações menores.",
+ "apihelp-feedrecentchanges-param-hidebots": "Ocultar modificações menores feitas por bots.",
"apihelp-feedrecentchanges-param-hidemyself": "Ocultar alterações feitas pelo usuário atual.",
+ "apihelp-feedrecentchanges-param-tagfilter": "Filtrar por tag.",
+ "apihelp-feedrecentchanges-example-simple": "Mostrar as mudanças recentes.",
"apihelp-feedrecentchanges-example-30days": "Mostrar as alterações recentes por 30 dias.",
+ "apihelp-feedwatchlist-description": "Retornar um feed da lista de vigiados.",
+ "apihelp-feedwatchlist-param-feedformat": "O formato do feed.",
+ "apihelp-feedwatchlist-param-hours": "Lista páginas modificadas dentro dessa quantia de horas a partir de agora.",
+ "apihelp-feedwatchlist-param-linktosections": "Cria link diretamente para seções alteradas, se possível.",
+ "apihelp-feedwatchlist-example-default": "Mostra o feed de páginas vigiadas.",
+ "apihelp-filerevert-description": "Reverte um arquivo para uma versão antiga.",
+ "apihelp-filerevert-param-filename": "Nome do arquivo destino, sem o prefixo File:.",
+ "apihelp-filerevert-param-comment": "Enviar comentário.",
+ "apihelp-filerevert-param-archivename": "Nome do arquivo da revisão para qual reverter.",
+ "apihelp-filerevert-example-revert": "Reverter <kbd>Wiki.png</kbd> para a versão de <kbd>2011-03-05T15:27:40Z</kbd>.",
+ "apihelp-help-description": "Mostra a ajuda para os módulos especificados.",
+ "apihelp-help-param-submodules": "Inclui a ajuda para submódulos do módulo nomeado.",
+ "apihelp-help-param-recursivesubmodules": "Inclui a ajuda para submódulos de forma recursiva.",
+ "apihelp-help-param-helpformat": "Formato da saída da ajuda.",
+ "apihelp-help-param-wrap": "Encapsula a saída em uma estrutura de resposta da API padrão.",
+ "apihelp-help-param-toc": "Inclui uma tabela de conteúdo na saída HTML.",
+ "apihelp-help-example-main": "Ajuda para o módulo principal.",
+ "apihelp-help-example-recursive": "Toda ajuda em uma página.",
+ "apihelp-help-example-help": "Ajuda para o próprio módulo de ajuda",
+ "apihelp-imagerotate-description": "Gira uma ou mais imagens.",
+ "apihelp-imagerotate-param-rotation": "Graus para girar imagem no sentido horário.",
+ "apihelp-imagerotate-example-simple": "Girar <kbd>File:Example.png</kbd> em <kbd>90</kbd> graus.",
+ "apihelp-imagerotate-example-generator": "Girar todas as imagens em <kbd>Category:Flip</kbd> em <kbd>180</kbd> graus.",
+ "apihelp-import-param-summary": "Importar sumário.",
+ "apihelp-import-param-xml": "Enviar arquivo XML.",
+ "apihelp-import-param-namespace": "Importar para este espaço nominal. Não pode ser usado em conjunto com <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Importar como subpágina para esta página. Não pode ser usada juntamente com <var>$1namespace</var>.",
+ "apihelp-login-param-name": "Nome de usuário.",
+ "apihelp-login-param-password": "Senha.",
+ "apihelp-login-param-domain": "Domínio (opcional).",
+ "apihelp-login-example-login": "Log in.",
+ "apihelp-move-description": "Mover uma página.",
+ "apihelp-move-param-from": "Título da página para renomear. Não pode ser usado em conjunto com <var>$1fromid</var>.",
+ "apihelp-move-param-fromid": "ID da página a se renomear. Não pode ser usado em conjunto com <var>$1from</var>.",
"apihelp-move-param-movetalk": "Renomear a página de discussão, se existir.",
- "apihelp-options-example-reset": "Resetar todas as preferências"
+ "apihelp-move-param-movesubpages": "Renomeia subpáginas, se aplicável.",
+ "apihelp-move-param-noredirect": "Não cria um redirecionamento.",
+ "apihelp-move-param-watch": "Adiciona a página e o redirecionamento para a lista de vigiados do usuário atual.",
+ "apihelp-move-param-unwatch": "Remove a página e o redirecionamento para a lista de vigiados do usuário atual.",
+ "apihelp-opensearch-param-limit": "O número máximo a se retornar.",
+ "apihelp-opensearch-param-namespace": "Espaço nominal para pesquisar.",
+ "apihelp-opensearch-example-te": "Encontra páginas começando com <kbd>Te</kbd>.",
+ "apihelp-options-param-reset": "Redefinir preferências para os padrões do site.",
+ "apihelp-options-example-reset": "Resetar todas as preferências",
+ "apihelp-options-example-complex": "Redefine todas as preferências, então define <kbd>skin</kbd> e <kbd>apelido</kbd>.",
+ "apihelp-paraminfo-description": "Obtém informações sobre módulos de API.",
+ "apihelp-parse-param-summary": "Sumário para analisar.",
+ "apihelp-parse-param-page": "Analisa o conteúdo desta página. Não pode ser usado em conjunto com <var>$1text</var> e <var>$1title</var>.",
+ "apihelp-parse-param-pageid": "Analisa o conteúdo desta página. sobrepõe <var>$1page</var>.",
+ "apihelp-parse-param-prop": "Qual pedaço de informação obter:",
+ "apihelp-parse-paramvalue-prop-text": "Fornece o texto analisado do wikitexto.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Fornece os links de idiomas do wikitexto analisado",
+ "apihelp-parse-paramvalue-prop-categories": "Fornece as categorias no wikitexto analisado.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Fornece a versão HTML das categorias.",
+ "apihelp-parse-paramvalue-prop-links": "Fornece os links internos do wikitexto analisado.",
+ "apihelp-parse-paramvalue-prop-templates": "Fornece a predefinição no wikitexto analisado.",
+ "apihelp-parse-paramvalue-prop-images": "Fornece as imagens no wikitexto analisado.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Fornece os links externos no wikitexto analisado.",
+ "apihelp-parse-paramvalue-prop-sections": "Fornece as seções no wikitexto analisado.",
+ "apihelp-parse-paramvalue-prop-headitems": "Fornece itens para colocar no <code>&lt;head&gt;</code> da página.",
+ "apihelp-parse-paramvalue-prop-headhtml": "Fornece <code>&lt;head&gt;</code> analisado da página.",
+ "apihelp-parse-paramvalue-prop-modules": "Fornece os módulos do ResourceLoader usados na página. Ou <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> deve ser solicitado conjuntamente com <kbd>modules</kbd>.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Fornece as variáveis de configuração JavaScript específicas da página.",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Fornece as variáveis de configuração JavaScript específicas da página como uma string JSON.",
+ "apihelp-parse-paramvalue-prop-indicators": "Fornece o HTML de indicadores de ''status'' de página utilizados na página.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "Fornece links interwiki no wikitexto analisado.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Fornece o wikitexto original que foi analisado.",
+ "apihelp-parse-paramvalue-prop-properties": "Fornece várias propriedades definidas no wikitexto analisado.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "Fornece o relatório limite de uma forma estruturada. Não informa dado, quando<var>$1disablelimitreport</var> se definido.",
+ "apihelp-parse-example-page": "Analisa uma página.",
+ "apihelp-parse-example-text": "Analisa wikitexto.",
+ "apihelp-parse-example-texttitle": "Analisa wikitexto, especificando o título da página.",
+ "apihelp-parse-example-summary": "Analisa uma sumário.",
+ "apihelp-patrol-description": "Patrulha uma página ou revisão.",
+ "apihelp-patrol-param-rcid": "ID de Mudanças recentes para patrulhar.",
+ "apihelp-patrol-param-revid": "ID de revisão para patrulhar.",
+ "apihelp-patrol-example-rcid": "Patrulha uma modificação recente.",
+ "apihelp-patrol-example-revid": "Patrulha uma revisão.",
+ "apihelp-protect-description": "Modifica o nível de proteção de uma página.",
+ "apihelp-protect-param-title": "Título da página para (des)proteger. Não pode ser usado em conjunto com $1pageid.",
+ "apihelp-protect-param-pageid": "ID da página a se (des)proteger. Não pode ser usado em conjunto com $1title.",
+ "apihelp-protect-param-reason": "Motivo para (des)proteger.",
+ "apihelp-protect-example-protect": "Protege uma página.",
+ "apihelp-protect-example-unprotect": "Desprotege uma página definindo restrições para <kbd>tudo</kbd>.",
+ "apihelp-protect-example-unprotect2": "Desprotege uma página ao não definir restrições.",
+ "apihelp-purge-param-forcelinkupdate": "Atualiza as tabelas de links.",
+ "apihelp-purge-param-forcerecursivelinkupdate": "Atualiza a tabela de links, e atualiza as tabelas de links para qualquer página que usa essa página como um modelo.",
+ "apihelp-query-param-list": "Quais listas obter.",
+ "apihelp-query-param-meta": "Quais metadados obter.",
+ "apihelp-query+allcategories-description": "Enumera todas as categorias.",
+ "apihelp-query+allcategories-param-prefix": "Pesquisa por todo os título de categoria que começam com este valor.",
+ "apihelp-query+allcategories-param-dir": "Direção para ordenar.",
+ "apihelp-query+allcategories-param-min": "Retorna apenas as categorias com pelo menos esta quantidade de membros.",
+ "apihelp-query+allcategories-param-max": "Retorna apenas as categorias com no máximo esta quantidade de membros.",
+ "apihelp-query+allcategories-param-limit": "Quantas categorias retornar.",
+ "apihelp-query+allcategories-example-size": "Lista categorias com a informação sobre o número de páginas em cada uma.",
+ "apihelp-query+alldeletedrevisions-description": "Lista todas as revisões excluídas por um usuário ou em um espaço nominal.",
+ "apihelp-query+alldeletedrevisions-paraminfo-useronly": "Só pode ser usada com <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "Não pode ser usada com <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-param-start": "A data a partir da qual começar a enumeração.",
+ "apihelp-query+alldeletedrevisions-param-end": "A data onde parar a enumeração.",
+ "apihelp-query+alldeletedrevisions-param-from": "Começar listando desse título.",
+ "apihelp-query+alldeletedrevisions-param-to": "Parar a listagem neste título.",
+ "apihelp-query+alldeletedrevisions-param-prefix": "Pesquisa por todo os título que começam com este valor.",
+ "apihelp-query+alldeletedrevisions-param-tag": "Lista apenas as revisões com esta tag.",
+ "apihelp-query+alldeletedrevisions-param-user": "Lista apenas revisões desse usuário.",
+ "apihelp-query+alldeletedrevisions-param-excludeuser": "Não lista as revisões deste usuário.",
+ "apihelp-query+alldeletedrevisions-param-namespace": "Lista páginas apenas neste espaço nominal.",
+ "apihelp-query+alldeletedrevisions-example-user": "Lista as últimas 50 contribuições excluídas pelo usuário <kbd>Exemplo<kbd>.",
+ "apihelp-query+alldeletedrevisions-example-ns-main": "Lista as primeiras 50 edições excluídas no espaço nominal principal.",
+ "apihelp-query+allfileusages-description": "Lista todas as utilizações de arquivo, incluindo os não-existentes.",
+ "apihelp-query+allfileusages-param-from": "O título do arquivo a partir do qual começar a enumerar.",
+ "apihelp-query+allfileusages-param-to": "O título do arquivo onde parar de enumerar.",
+ "apihelp-query+allfileusages-param-limit": "Quantos itens retornar.",
+ "apihelp-query+allimages-param-user": "Retorna apenas os arquivos enviados por este usuário. Só pode ser usado com $1sort=timestamp. Não pode ser usado em conjunto com $1filterbots.",
+ "apihelp-query+allimages-param-filterbots": "Como filtrar arquivos enviados por bots. Só pode ser usado com $1sort=timestamp. Não pode ser usado em conjunto com $1user.",
+ "apihelp-query+allimages-param-mime": "Quais tipos MIME pesquisar, ex.: <kbd>image/jpeg</kbd>.",
+ "apihelp-query+allimages-param-limit": "Quantas imagens retornar.",
+ "apihelp-query+allimages-example-B": "Mostra uma lista de arquivos começando com a letra <kbd>B</kbd>.",
+ "apihelp-query+allimages-example-recent": "Mostra uma lista de arquivos recentemente enviados, semelhante ao [[Special:NewFiles]].",
+ "apihelp-query+allimages-example-mimetypes": "Mostra uma lista de arquivos com o tipo MIME <kbd>image/png</kbd> ou <kbd>image/gif</kbd>",
+ "apihelp-query+allimages-example-generator": "Mostra informações sobre 4 arquivos começando com a letra <kbd>T</kbd>.",
+ "apihelp-query+alllinks-description": "Enumerar todos os links que apontam para um determinado espaço nominal.",
+ "apihelp-query+alllinks-param-from": "O título do link a partir do qual começar a enumerar.",
+ "apihelp-query+alllinks-param-to": "O título do link onde parar de enumerar.",
+ "apihelp-query+alllinks-param-prefix": "Pesquisa por todos os títulos com link que começam com este valor.",
+ "apihelp-query+alllinks-param-namespace": "O espaço nominal a se enumerar.",
+ "apihelp-query+alllinks-param-limit": "Quantos itens retornar.",
+ "apihelp-query+alllinks-example-generator": "Obtém páginas contendo os links.",
+ "apihelp-query+allmessages-param-prop": "Quais propriedades obter.",
+ "apihelp-query+allmessages-param-customised": "Retornar apenas mensagens neste estado personalização.",
+ "apihelp-query+allmessages-param-lang": "Retornar mensagens neste idioma.",
+ "apihelp-query+allmessages-param-from": "Retornar mensagens começando com esta mensagem.",
+ "apihelp-query+allmessages-param-to": "Retornar mensagens terminando com esta mensagem.",
+ "apihelp-query+allmessages-param-prefix": "Retornar apenas mensagens com este prefixo.",
+ "apihelp-query+allmessages-example-ipb": "Mostrar mensagens começando com <kbd>ipb-</kbd>.",
+ "apihelp-query+allpages-param-namespace": "O espaço nominal a se enumerar.",
+ "apihelp-query+allpages-param-filterredir": "Quais páginas listar.",
+ "apihelp-query+allpages-param-minsize": "Limitar a páginas com pelo menos essa quantidade de bytes.",
+ "apihelp-query+allpages-param-maxsize": "Limitar a páginas com no máximo essa quantidade de bytes.",
+ "apihelp-query+allpages-param-limit": "Quantas páginas retornar.",
+ "apihelp-query+allredirects-description": "Lista todos os redirecionamentos para um espaço nominal.",
+ "apihelp-query+allredirects-param-from": "O título do redirecionamento a partir do qual começar a enumerar.",
+ "apihelp-query+allredirects-param-to": "O título do redirecionamento onde parar de enumerar.",
+ "apihelp-query+allredirects-param-namespace": "O espaço nominal a se enumerar.",
+ "apihelp-query+alltransclusions-param-namespace": "O espaço nominal a se enumerar.",
+ "apihelp-query+alltransclusions-param-limit": "Quantos itens retornar.",
+ "apihelp-query+backlinks-param-title": "Título a se pesquisar. Não pode ser usado em conjunto com <var>$1pageid</var>.",
+ "apihelp-query+backlinks-param-pageid": "ID da página a se pesquisar. Não pode ser usado em conjunto com <var>$1title</var>.",
+ "apihelp-query+backlinks-param-namespace": "O espaço nominal a se enumerar.",
+ "apihelp-query+blocks-param-ip": "Obtém todos os blocos aplicando a este IP ou intervalos CIDR, incluindo intervalos de blocos.\nNão pode ser usado em conjunto com <var>$3users</var>. Intervalos CIDR mais largos do que IPv4/$1 ou IPv6/$2 não são aceitos.",
+ "apihelp-query+categories-param-limit": "Quantas categorias retornar.",
+ "apihelp-query+categorymembers-param-title": "Qual categoria enumerar (obrigatório). Deve incluir o prefixo <kbd>{{ns:category}}:</kbd>. Não pode ser usado em conjunto com <var>$1pageid</var>.",
+ "apihelp-query+categorymembers-param-pageid": "ID da página da categoria para enumerar. Não pode ser usado em conjunto com <var>$1title</var>.",
+ "apihelp-query+contributors-param-limit": "Quantas contribuições retornar.",
+ "apihelp-query+duplicatefiles-param-limit": "Quantos arquivos duplicados retornar.",
+ "apihelp-query+embeddedin-param-title": "Título a se pesquisar. Não pode ser usado em conjunto com $1pageid.",
+ "apihelp-query+embeddedin-param-pageid": "ID da página a se pesquisar. Não pode ser usado em conjunto com $1title.",
+ "apihelp-query+embeddedin-param-namespace": "O espaço nominal a se enumerar.",
+ "apihelp-query+embeddedin-param-filterredir": "Como filtrar por redirecionamentos.",
+ "apihelp-query+embeddedin-param-limit": "Quantas páginas retornar.",
+ "apihelp-query+embeddedin-example-simple": "Mostrar páginas transcluíndo <kbd>Template:Stub</kbd>.",
+ "apihelp-query+embeddedin-example-generator": "Obtém informação sobre páginas transcluindo <kbd>Template:Stub</kbd>.",
+ "apihelp-query+extlinks-description": "Retorna todas as URLs externas (não interwikis) a partir das páginas de dados.",
+ "apihelp-query+extlinks-param-limit": "Quantos links retornar.",
+ "apihelp-query+exturlusage-param-limit": "Quantas páginas retornar.",
+ "apihelp-query+filearchive-param-limit": "Quantas imagens retornar.",
+ "apihelp-query+fileusage-param-limit": "Quantos retornar.",
+ "apihelp-query+imageinfo-param-limit": "Quantas revisões de arquivos retornar por arquivo.",
+ "apihelp-query+images-param-limit": "Quantos arquivos retornar.",
+ "apihelp-query+imageusage-param-title": "Título a se pesquisar. Não pode ser usado em conjunto com $1pageid.",
+ "apihelp-query+imageusage-param-pageid": "ID da página para pesquisar. Não pode ser usado em conjunto com $1title.",
+ "apihelp-query+imageusage-param-namespace": "O espaço nominal a se enumerar.",
+ "apihelp-query+info-paramvalue-prop-readable": "Se o usuário pode ler esta página.",
+ "apihelp-query+info-paramvalue-prop-preload": "Fornece o texto retornado por EditFormPreloadText.",
+ "apihelp-query+info-paramvalue-prop-displaytitle": "Fornece o modo como o título da página é exibido.",
+ "apihelp-query+info-param-testactions": "Testa se o usuário atual pode executar determinadas ações na página.",
+ "apihelp-query+info-example-simple": "Obtém informações sobre a página <kbd>Página principal</kbd>.",
+ "apihelp-query+iwbacklinks-description": "Encontra todas as páginas que apontam para o determinado link interwiki.\n\nPode ser usado para encontrar todos os links com um prefixo, ou todos os links para um título (com um determinado prefixo). Usar nenhum parâmetro é efetivamente \"todos os links interwiki\".",
+ "apihelp-query+iwbacklinks-param-prefix": "Prefixo para o interwiki.",
+ "apihelp-query+iwbacklinks-param-limit": "Quantas páginas retornar.",
+ "apihelp-query+langbacklinks-param-limit": "Quantas páginas retornar.",
+ "apihelp-query+langlinks-param-limit": "Quantos links de idioma retornar.",
+ "apihelp-query+links-param-limit": "Quantos links retornar.",
+ "apihelp-query+linkshere-param-limit": "Quantos retornar.",
+ "apihelp-query+prefixsearch-param-limit": "O número máximo a se retornar.",
+ "apihelp-query+search-param-limit": "Quantas páginas retornar.",
+ "apihelp-query+templates-param-limit": "Quantas predefinições retornar.",
+ "apihelp-query+transcludedin-param-limit": "Quantos retornar.",
+ "apihelp-query+watchlist-param-limit": "Quantos resultados retornar por solicitação.",
+ "apihelp-query+watchlistraw-param-limit": "Quantos resultados retornar por solicitação.",
+ "apihelp-rollback-param-title": "Título da página para reverter. Não pode ser usado em conjunto com <var>$1pageid</var>.",
+ "apihelp-rollback-param-pageid": "ID da página para reverter. Não pode ser usado em conjunto com <var>$1title</var>.",
+ "apihelp-unblock-param-id": "ID do bloco para desbloquear (obtido através de <kbd>list=blocks</kbd>). Não pode ser usado em conjunto com <var>$1user</var>.",
+ "apihelp-unblock-param-user": "Nome de usuário, endereço IP ou intervalo de IP para a se desbloquear. Não pode ser usado em conjunto com <var>$1id</var>."
}
diff --git a/includes/api/i18n/pt.json b/includes/api/i18n/pt.json
index 72044db9..b919c448 100644
--- a/includes/api/i18n/pt.json
+++ b/includes/api/i18n/pt.json
@@ -3,7 +3,8 @@
"authors": [
"Vitorvicentevalente",
"Fúlvio",
- "Macofe"
+ "Macofe",
+ "Jkb8"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentação]]\n* [[mw: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 Erros e solicitações]\n</div>\n<strong>Estado:</strong> Todas as funcionalidades mostradas nesta página deveriam estar a funcionar, mas a API ainda está em activo desenvolvimento, e pode ser alterada a qualquer momento. Inscreva-se na [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ lista de discussão mediawiki-api-announce] para ser informado acerca das actualizações.\n\n<strong>Solicitações erradas:</strong> Quando solicitações erradas são enviadas à API, um cabeçalho em HTTP será enviado com a chave \"MediaWiki-API-Error\" e, em seguida, tanto o valor do cabeçalho quanto o código de erro retornado serão definidos com o mesmo valor. Para mais informação, consulte [[mw:API:Errors_and_warnings|API: Errors and warnings]].",
@@ -18,8 +19,8 @@
"apihelp-createaccount-param-email": "Endereço de correio eletrónico do utilizador (opcional).",
"apihelp-createaccount-param-realname": "Nome verdadeiro do utilizador (opcional).",
"apihelp-delete-description": "Eliminar uma página.",
- "apihelp-delete-param-watch": "Adicionar esta página à lista de vigiadas.",
- "apihelp-delete-param-unwatch": "Remover esta página da lista de vigiadas.",
+ "apihelp-delete-param-watch": "Adicionar a página à lista de vigiadas do utilizador atual.",
+ "apihelp-delete-param-unwatch": "Remover a página da lista de vigiadas do utilizador atual.",
"apihelp-delete-example-simple": "Eliminar <kbd>Página Principal</kbd>.",
"apihelp-disabled-description": "O módulo foi desativado.",
"apihelp-edit-description": "Criar e editar páginas.",
@@ -41,7 +42,7 @@
"apihelp-feedrecentchanges-param-hideminor": "Ocultar edições menores.",
"apihelp-feedrecentchanges-param-hidebots": "Ocultar alterações feitas por robôs.",
"apihelp-feedrecentchanges-param-hidepatrolled": "Ocultar alterações patrulhadas.",
- "apihelp-feedrecentchanges-param-hidemyself": "Ocultar alterações feitas por mim.",
+ "apihelp-feedrecentchanges-param-hidemyself": "Ocultar alterações feitas pelo utilizador atual.",
"apihelp-feedrecentchanges-param-target": "Mostrar apenas mudanças em páginas afluentes a esta.",
"apihelp-feedrecentchanges-example-simple": "Mostrar mudanças recentes",
"apihelp-help-example-main": "Ajuda para o módulo principal",
@@ -75,6 +76,7 @@
"apihelp-query+filearchive-example-simple": "Mostrar lista de todos os ficheiros eliminados",
"apihelp-query+info-description": "Obter informação básica da página.",
"apihelp-query+recentchanges-example-simple": "Lista de mudanças recentes",
+ "apihelp-query+search-param-enablerewrites": "Habilitar rescrever a pesquisa interna. Alguns motores de busca podem rescrever a consulta para outra que acha dará melhores resultados, como a corrigir erros de ortografia.",
"apihelp-unblock-description": "Desbloquear um utilizador.",
"apihelp-unblock-param-reason": "Motivo para o desbloqueio.",
"apihelp-undelete-param-title": "Título da página a restaurar.",
@@ -89,9 +91,14 @@
"api-help-title": "Ajuda API da MediaWiki",
"api-help-main-header": "Módulo principal",
"api-help-flag-deprecated": "Este módulo está obsoleto.",
+ "api-help-license": "Licença: [[$1|$2]]",
+ "api-help-license-noname": "Licença: [[$1|Ver ligaçã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.",
"api-help-param-required": "Este parâmetro é obrigatório.",
+ "api-help-datatypes-header": "Tipo de dados",
+ "api-help-param-list": "{{PLURAL:$1|1=Um dos seguintes valores|2=Valores (separar com <kbd>{{!}}</kbd>)}}: $2",
"api-help-param-multi-separate": "Separe os valores com <kbd>|</kbd>.",
"api-help-param-default": "Padrão: $1",
"api-help-param-default-empty": "Padrão: <span class=\"apihelp-empty\">(vazio)</span>",
diff --git a/includes/api/i18n/qqq.json b/includes/api/i18n/qqq.json
index 9bf98247..da0319f4 100644
--- a/includes/api/i18n/qqq.json
+++ b/includes/api/i18n/qqq.json
@@ -7,7 +7,11 @@
"Umherirrender",
"McDutchie",
"Raymond",
- "Anomie"
+ "Anomie",
+ "Nemo bis",
+ "Amire80",
+ "Siebrand",
+ "Purodha"
]
},
"apihelp-main-description": "{{doc-apihelp-description|main}}",
@@ -52,7 +56,7 @@
"apihelp-compare-param-torev": "{{doc-apihelp-param|compare|torev}}",
"apihelp-compare-example-1": "{{doc-apihelp-example|compare}}",
"apihelp-createaccount-description": "{{doc-apihelp-description|createaccount}}",
- "apihelp-createaccount-param-name": "{{doc-apihelp-param|createaccount|name}}",
+ "apihelp-createaccount-param-name": "{{doc-apihelp-param|createaccount|name}}\n{{Identical|Username}}",
"apihelp-createaccount-param-password": "{{doc-apihelp-param|createaccount|password}}",
"apihelp-createaccount-param-domain": "{{doc-apihelp-param|createaccount|domain}}",
"apihelp-createaccount-param-token": "{{doc-apihelp-param|createaccount|token}}",
@@ -115,7 +119,16 @@
"apihelp-expandtemplates-param-title": "{{doc-apihelp-param|expandtemplates|title}}",
"apihelp-expandtemplates-param-text": "{{doc-apihelp-param|expandtemplates|text}}",
"apihelp-expandtemplates-param-revid": "{{doc-apihelp-param|expandtemplates|revid}}\n{{doc-important|Do not translate <code><<nowiki />nowiki>{{<nowiki />REVISIONID}}<<nowiki />/nowiki></code>}}",
- "apihelp-expandtemplates-param-prop": "{{doc-apihelp-param|expandtemplates|prop}}",
+ "apihelp-expandtemplates-param-prop": "{{doc-apihelp-param|expandtemplates|prop|paramvalues=1}}",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "{{doc-apihelp-paramvalue|expandtemplates|prop|wikitext}}",
+ "apihelp-expandtemplates-paramvalue-prop-categories": "{{doc-apihelp-paramvalue|expandtemplates|prop|categories}}",
+ "apihelp-expandtemplates-paramvalue-prop-properties": "{{doc-apihelp-paramvalue|expandtemplates|prop|properties}}",
+ "apihelp-expandtemplates-paramvalue-prop-volatile": "{{doc-apihelp-paramvalue|expandtemplates|prop|volatile}}",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "{{doc-apihelp-paramvalue|expandtemplates|prop|ttl}}",
+ "apihelp-expandtemplates-paramvalue-prop-modules": "{{doc-apihelp-paramvalue|expandtemplates|prop|modules}}",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "{{doc-apihelp-paramvalue|expandtemplates|prop|jsconfigvars}}",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "{{doc-apihelp-paramvalue|expandtemplates|prop|encodedjsconfigvars}}",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "{{doc-apihelp-paramvalue|expandtemplates|prop|parsetree}}",
"apihelp-expandtemplates-param-includecomments": "{{doc-apihelp-param|expandtemplates|includecomments}}",
"apihelp-expandtemplates-param-generatexml": "{{doc-apihelp-param|expandtemplates|generatexml}}",
"apihelp-expandtemplates-example-simple": "{{doc-apihelp-example|expandtemplates}}",
@@ -158,7 +171,7 @@
"apihelp-feedwatchlist-example-all6hrs": "{{doc-apihelp-example|feedwatchlist}}",
"apihelp-filerevert-description": "{{doc-apihelp-description|filerevert}}",
"apihelp-filerevert-param-filename": "{{doc-apihelp-param|filerevert|filename}}",
- "apihelp-filerevert-param-comment": "{{doc-apihelp-param|filerevert|comment}}",
+ "apihelp-filerevert-param-comment": "Translate as \"a comment about the upload\".\n\n{{doc-apihelp-param|filerevert|comment}}",
"apihelp-filerevert-param-archivename": "{{doc-apihelp-param|filerevert|archivename}}",
"apihelp-filerevert-example-revert": "{{doc-apihelp-example|filerevert}}",
"apihelp-help-description": "{{doc-apihelp-description|help}}",
@@ -192,7 +205,7 @@
"apihelp-login-param-domain": "{{doc-apihelp-param|login|domain}}",
"apihelp-login-param-token": "{{doc-apihelp-param|login|token}}",
"apihelp-login-example-gettoken": "{{doc-apihelp-example|login}}",
- "apihelp-login-example-login": "{{doc-apihelp-example|login}}",
+ "apihelp-login-example-login": "{{doc-apihelp-example|login}}\n{{Identical|Log in}}",
"apihelp-logout-description": "{{doc-apihelp-description|logout}}",
"apihelp-logout-example-logout": "{{doc-apihelp-example|logout}}",
"apihelp-managetags-description": "{{doc-apihelp-description|managetags}}",
@@ -251,14 +264,39 @@
"apihelp-parse-param-pageid": "{{doc-apihelp-param|parse|pageid}}",
"apihelp-parse-param-redirects": "{{doc-apihelp-param|parse|redirects}}",
"apihelp-parse-param-oldid": "{{doc-apihelp-param|parse|oldid}}",
- "apihelp-parse-param-prop": "{{doc-apihelp-param|parse|prop}}",
+ "apihelp-parse-param-prop": "{{doc-apihelp-param|parse|prop|paramvalues=1}}",
+ "apihelp-parse-paramvalue-prop-text": "{{doc-apihelp-paramvalue|parse|prop|text}}",
+ "apihelp-parse-paramvalue-prop-langlinks": "{{doc-apihelp-paramvalue|parse|prop|langlinks}}",
+ "apihelp-parse-paramvalue-prop-categories": "{{doc-apihelp-paramvalue|parse|prop|categories}}",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "{{doc-apihelp-paramvalue|parse|prop|categorieshtml}}",
+ "apihelp-parse-paramvalue-prop-links": "{{doc-apihelp-paramvalue|parse|prop|links}}",
+ "apihelp-parse-paramvalue-prop-templates": "{{doc-apihelp-paramvalue|parse|prop|templates}}",
+ "apihelp-parse-paramvalue-prop-images": "{{doc-apihelp-paramvalue|parse|prop|images}}",
+ "apihelp-parse-paramvalue-prop-externallinks": "{{doc-apihelp-paramvalue|parse|prop|externallinks}}",
+ "apihelp-parse-paramvalue-prop-sections": "{{doc-apihelp-paramvalue|parse|prop|sections}}",
+ "apihelp-parse-paramvalue-prop-revid": "{{doc-apihelp-paramvalue|parse|prop|revid}}",
+ "apihelp-parse-paramvalue-prop-displaytitle": "{{doc-apihelp-paramvalue|parse|prop|displaytitle}}",
+ "apihelp-parse-paramvalue-prop-headitems": "{{doc-apihelp-paramvalue|parse|prop|headitems}}",
+ "apihelp-parse-paramvalue-prop-headhtml": "{{doc-apihelp-paramvalue|parse|prop|headhtml}}",
+ "apihelp-parse-paramvalue-prop-modules": "{{doc-apihelp-paramvalue|parse|prop|modules}}",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "{{doc-apihelp-paramvalue|parse|prop|jsconfigvars}}",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "{{doc-apihelp-paramvalue|parse|prop|encodedjsconfigvars}}",
+ "apihelp-parse-paramvalue-prop-indicators": "{{doc-apihelp-paramvalue|parse|prop|indicators}}",
+ "apihelp-parse-paramvalue-prop-iwlinks": "{{doc-apihelp-paramvalue|parse|prop|iwlinks}}",
+ "apihelp-parse-paramvalue-prop-wikitext": "{{doc-apihelp-paramvalue|parse|prop|wikitext}}",
+ "apihelp-parse-paramvalue-prop-properties": "{{doc-apihelp-paramvalue|parse|prop|properties}}",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "{{doc-apihelp-paramvalue|parse|prop|limitreportdata}}",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "{{doc-apihelp-paramvalue|parse|prop|limitreporthtml}}",
+ "apihelp-parse-paramvalue-prop-parsetree": "{{doc-apihelp-paramvalue|parse|prop|parsetree|params=* $1 - Value of the constant CONTENT_MODEL_WIKITEXT|paramstart=2}}",
"apihelp-parse-param-pst": "{{doc-apihelp-param|parse|pst}}",
"apihelp-parse-param-onlypst": "{{doc-apihelp-param|parse|onlypst}}",
"apihelp-parse-param-effectivelanglinks": "{{doc-apihelp-param|parse|effectivelanglinks}}",
"apihelp-parse-param-section": "{{doc-apihelp-param|parse|section}}",
"apihelp-parse-param-sectiontitle": "{{doc-apihelp-param|parse|sectiontitle}}",
+ "apihelp-parse-param-disablelimitreport": "{{doc-apihelp-param|parse|disablelimitreport}}",
"apihelp-parse-param-disablepp": "{{doc-apihelp-param|parse|disablepp}}",
"apihelp-parse-param-disableeditsection": "{{doc-apihelp-param|parse|disableeditsection}}",
+ "apihelp-parse-param-disabletidy": "{{doc-apihelp-param|parse|disabletidy}}",
"apihelp-parse-param-generatexml": "{{doc-apihelp-param|parse|generatexml|params=* $1 - Value of the constant CONTENT_MODEL_WIKITEXT|paramstart=2}}",
"apihelp-parse-param-preview": "{{doc-apihelp-param|parse|preview}}",
"apihelp-parse-param-sectionpreview": "{{doc-apihelp-param|parse|sectionpreview}}",
@@ -299,7 +337,6 @@
"apihelp-query-param-export": "{{doc-apihelp-param|query|export}}",
"apihelp-query-param-exportnowrap": "{{doc-apihelp-param|query|exportnowrap}}",
"apihelp-query-param-iwurl": "{{doc-apihelp-param|query|iwurl}}",
- "apihelp-query-param-continue": "{{doc-apihelp-param|query|continue}}",
"apihelp-query-param-rawcontinue": "{{doc-apihelp-param|query|rawcontinue}}",
"apihelp-query-example-revisions": "{{doc-apihelp-example|query}}",
"apihelp-query-example-allpages": "{{doc-apihelp-example|query}}",
@@ -311,7 +348,9 @@
"apihelp-query+allcategories-param-min": "{{doc-apihelp-param|query+allcategories|min}}",
"apihelp-query+allcategories-param-max": "{{doc-apihelp-param|query+allcategories|max}}",
"apihelp-query+allcategories-param-limit": "{{doc-apihelp-param|query+allcategories|limit}}",
- "apihelp-query+allcategories-param-prop": "{{doc-apihelp-param|query+allcategories|prop}}",
+ "apihelp-query+allcategories-param-prop": "{{doc-apihelp-param|query+allcategories|prop|paramvalues=1}}",
+ "apihelp-query+allcategories-paramvalue-prop-size": "{{doc-apihelp-paramvalue|query+allcategories|prop|size}}",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "{{doc-apihelp-paramvalue|query+allcategories|prop|hidden}}",
"apihelp-query+allcategories-example-size": "{{doc-apihelp-example|query+allcategories}}",
"apihelp-query+allcategories-example-generator": "{{doc-apihelp-example|query+allcategories}}",
"apihelp-query+alldeletedrevisions-description": "{{doc-apihelp-description|query+alldeletedrevisions}}",
@@ -335,7 +374,9 @@
"apihelp-query+allfileusages-param-to": "{{doc-apihelp-param|query+allfileusages|to}}",
"apihelp-query+allfileusages-param-prefix": "{{doc-apihelp-param|query+allfileusages|prefix}}",
"apihelp-query+allfileusages-param-unique": "{{doc-apihelp-param|query+allfileusages|unique}}",
- "apihelp-query+allfileusages-param-prop": "{{doc-apihelp-param|query+allfileusages|prop}}",
+ "apihelp-query+allfileusages-param-prop": "{{doc-apihelp-param|query+allfileusages|prop|paramvalues=1}}",
+ "apihelp-query+allfileusages-paramvalue-prop-ids": "{{doc-apihelp-param|query+allfileusages|prop|ids}}",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "{{doc-apihelp-param|query+allfileusages|prop|title}}",
"apihelp-query+allfileusages-param-limit": "{{doc-apihelp-param|query+allfileusages|limit}}",
"apihelp-query+allfileusages-param-dir": "{{doc-apihelp-param|query+allfileusages|dir}}",
"apihelp-query+allfileusages-example-B": "{{doc-apihelp-example|query+allfileusages}}",
@@ -367,7 +408,9 @@
"apihelp-query+alllinks-param-to": "{{doc-apihelp-param|query+alllinks|to}}",
"apihelp-query+alllinks-param-prefix": "{{doc-apihelp-param|query+alllinks|prefix}}",
"apihelp-query+alllinks-param-unique": "{{doc-apihelp-param|query+alllinks|unique}}",
- "apihelp-query+alllinks-param-prop": "{{doc-apihelp-param|query+alllinks|prop}}",
+ "apihelp-query+alllinks-param-prop": "{{doc-apihelp-param|query+alllinks|prop|paramvalues=1}}",
+ "apihelp-query+alllinks-paramvalue-prop-ids": "{{doc-apihelp-paramvalue|query+alllinks|prop|ids}}",
+ "apihelp-query+alllinks-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+alllinks|prop|title}}",
"apihelp-query+alllinks-param-namespace": "{{doc-apihelp-param|query+alllinks|namespace}}",
"apihelp-query+alllinks-param-limit": "{{doc-apihelp-param|query+alllinks|limit}}",
"apihelp-query+alllinks-param-dir": "{{doc-apihelp-param|query+alllinks|dir}}",
@@ -383,7 +426,7 @@
"apihelp-query+allmessages-param-includelocal": "{{doc-apihelp-param|query+allmessages|includelocal}}",
"apihelp-query+allmessages-param-args": "{{doc-apihelp-param|query+allmessages|args}}",
"apihelp-query+allmessages-param-filter": "{{doc-apihelp-param|query+allmessages|filter}}",
- "apihelp-query+allmessages-param-customised": "{{doc-apihelp-param|query+allmessages|customised}}",
+ "apihelp-query+allmessages-param-customised": "\"Customisation state\" means the choice made by the user to only list locally customised system messages or not.\n----\n{{doc-apihelp-param|query+allmessages|customised}}",
"apihelp-query+allmessages-param-lang": "{{doc-apihelp-param|query+allmessages|lang}}",
"apihelp-query+allmessages-param-from": "{{doc-apihelp-param|query+allmessages|from}}",
"apihelp-query+allmessages-param-to": "{{doc-apihelp-param|query+allmessages|to}}",
@@ -414,7 +457,11 @@
"apihelp-query+allredirects-param-to": "{{doc-apihelp-param|query+allredirects|to}}",
"apihelp-query+allredirects-param-prefix": "{{doc-apihelp-param|query+allredirects|prefix}}",
"apihelp-query+allredirects-param-unique": "{{doc-apihelp-param|query+allredirects|unique}}",
- "apihelp-query+allredirects-param-prop": "{{doc-apihelp-param|query+allredirects|prop}}",
+ "apihelp-query+allredirects-param-prop": "{{doc-apihelp-param|query+allredirects|prop|paramvalues=1}}",
+ "apihelp-query+allredirects-paramvalue-prop-ids": "{{doc-apihelp-param|query+allredirects|prop|ids}}",
+ "apihelp-query+allredirects-paramvalue-prop-title": "{{doc-apihelp-param|query+allredirects|prop|title}}",
+ "apihelp-query+allredirects-paramvalue-prop-fragment": "{{doc-apihelp-param|query+allredirects|prop|fragment}}",
+ "apihelp-query+allredirects-paramvalue-prop-interwiki": "{{doc-apihelp-param|query+allredirects|prop|interwiki}}",
"apihelp-query+allredirects-param-namespace": "{{doc-apihelp-param|query+allredirects|namespace}}",
"apihelp-query+allredirects-param-limit": "{{doc-apihelp-param|query+allredirects|limit}}",
"apihelp-query+allredirects-param-dir": "{{doc-apihelp-param|query+allredirects|dir}}",
@@ -427,7 +474,9 @@
"apihelp-query+alltransclusions-param-to": "{{doc-apihelp-param|query+alltransclusions|to}}",
"apihelp-query+alltransclusions-param-prefix": "{{doc-apihelp-param|query+alltransclusions|prefix}}",
"apihelp-query+alltransclusions-param-unique": "{{doc-apihelp-param|query+alltransclusions|unique}}",
- "apihelp-query+alltransclusions-param-prop": "{{doc-apihelp-param|query+alltransclusions|prop}}",
+ "apihelp-query+alltransclusions-param-prop": "{{doc-apihelp-param|query+alltransclusions|prop|paramvalues=1}}",
+ "apihelp-query+alltransclusions-paramvalue-prop-ids": "{{doc-apihelp-paramvalue|query+alltransclusions|prop|ids}}",
+ "apihelp-query+alltransclusions-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+alltransclusions|prop|title}}",
"apihelp-query+alltransclusions-param-namespace": "{{doc-apihelp-param|query+alltransclusions|namespace}}",
"apihelp-query+alltransclusions-param-limit": "{{doc-apihelp-param|query+alltransclusions|limit}}",
"apihelp-query+alltransclusions-param-dir": "{{doc-apihelp-param|query+alltransclusions|dir}}",
@@ -443,7 +492,13 @@
"apihelp-query+allusers-param-group": "{{doc-apihelp-param|query+allusers|group}}",
"apihelp-query+allusers-param-excludegroup": "{{doc-apihelp-param|query+allusers|excludegroup}}",
"apihelp-query+allusers-param-rights": "{{doc-apihelp-param|query+allusers|rights}}",
- "apihelp-query+allusers-param-prop": "{{doc-apihelp-param|query+allusers|prop}}",
+ "apihelp-query+allusers-param-prop": "{{doc-apihelp-param|query+allusers|prop|paramvalues=1}}",
+ "apihelp-query+allusers-paramvalue-prop-blockinfo": "{{doc-apihelp-paramvalue|query+allusers|prop|blockinfo}}",
+ "apihelp-query+allusers-paramvalue-prop-groups": "{{doc-apihelp-paramvalue|query+allusers|prop|groups}}",
+ "apihelp-query+allusers-paramvalue-prop-implicitgroups": "{{doc-apihelp-paramvalue|query+allusers|prop|implicitgroups}}",
+ "apihelp-query+allusers-paramvalue-prop-rights": "{{doc-apihelp-paramvalue|query+allusers|prop|rights}}",
+ "apihelp-query+allusers-paramvalue-prop-editcount": "{{doc-apihelp-paramvalue|query+allusers|prop|editcount}}",
+ "apihelp-query+allusers-paramvalue-prop-registration": "{{doc-apihelp-paramvalue|query+allusers|prop|registration}}",
"apihelp-query+allusers-param-limit": "{{doc-apihelp-param|query+allusers|limit}}",
"apihelp-query+allusers-param-witheditsonly": "{{doc-apihelp-param|query+allusers|witheditsonly}}",
"apihelp-query+allusers-param-activeusers": "{{doc-apihelp-param|query+allusers|activeusers|params=* $1 - Value of [[mw:Manual:$wgActiveUserDays]]|paramstart=2}}",
@@ -455,7 +510,7 @@
"apihelp-query+backlinks-param-dir": "{{doc-apihelp-param|query+backlinks|dir}}",
"apihelp-query+backlinks-param-filterredir": "{{doc-apihelp-param|query+backlinks|filterredir}}",
"apihelp-query+backlinks-param-limit": "{{doc-apihelp-param|query+backlinks|limit}}",
- "apihelp-query+backlinks-param-redirect": "{{doc-apihelp-param|query+backlinks|redirect}}",
+ "apihelp-query+backlinks-param-redirect": "\"Is halved\" means that the limits are half of the usual ones.\n----\n{{doc-apihelp-param|query+backlinks|redirect}}",
"apihelp-query+backlinks-example-simple": "{{doc-apihelp-example|query+backlinks}}",
"apihelp-query+backlinks-example-generator": "{{doc-apihelp-example|query+backlinks}}",
"apihelp-query+blocks-description": "{{doc-apihelp-description|query+blocks}}",
@@ -465,12 +520,25 @@
"apihelp-query+blocks-param-users": "{{doc-apihelp-param|query+blocks|users}}",
"apihelp-query+blocks-param-ip": "{{doc-apihelp-param|query+blocks|ip|params=* $1 - Minimum CIDR prefix for IPv4\n* $2 - Minimum CIDR prefix for IPv6|paramstart=3}}",
"apihelp-query+blocks-param-limit": "{{doc-apihelp-param|query+blocks|limit}}",
- "apihelp-query+blocks-param-prop": "{{doc-apihelp-param|query+blocks|prop}}",
+ "apihelp-query+blocks-param-prop": "{{doc-apihelp-param|query+blocks|prop|paramvalues=1}}",
+ "apihelp-query+blocks-paramvalue-prop-id": "{{doc-apihelp-paramvalue|query+blocks|prop|id}}",
+ "apihelp-query+blocks-paramvalue-prop-user": "{{doc-apihelp-paramvalue|query+blocks|prop|user}}",
+ "apihelp-query+blocks-paramvalue-prop-userid": "{{doc-apihelp-paramvalue|query+blocks|prop|userid}}",
+ "apihelp-query+blocks-paramvalue-prop-by": "{{doc-apihelp-paramvalue|query+blocks|prop|by}}",
+ "apihelp-query+blocks-paramvalue-prop-byid": "{{doc-apihelp-paramvalue|query+blocks|prop|byid}}",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+blocks|prop|timestamp}}",
+ "apihelp-query+blocks-paramvalue-prop-expiry": "{{doc-apihelp-paramvalue|query+blocks|prop|expiry}}",
+ "apihelp-query+blocks-paramvalue-prop-reason": "{{doc-apihelp-paramvalue|query+blocks|prop|reason}}",
+ "apihelp-query+blocks-paramvalue-prop-range": "{{doc-apihelp-paramvalue|query+blocks|prop|range}}",
+ "apihelp-query+blocks-paramvalue-prop-flags": "{{doc-apihelp-paramvalue|query+blocks|prop|flags}}",
"apihelp-query+blocks-param-show": "{{doc-apihelp-param|query+blocks|show}}",
"apihelp-query+blocks-example-simple": "{{doc-apihelp-example|query+blocks}}",
"apihelp-query+blocks-example-users": "{{doc-apihelp-example|query+blocks}}",
"apihelp-query+categories-description": "{{doc-apihelp-description|query+categories}}",
- "apihelp-query+categories-param-prop": "{{doc-apihelp-param|query+categories|prop}}",
+ "apihelp-query+categories-param-prop": "{{doc-apihelp-param|query+categories|prop|paramvalues=1}}",
+ "apihelp-query+categories-paramvalue-prop-sortkey": "{{doc-apihelp-paramvalue|query+categories|prop|sortkey}}",
+ "apihelp-query+categories-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+categories|prop|timestamp}}",
+ "apihelp-query+categories-paramvalue-prop-hidden": "{{doc-apihelp-paramvalue|query+categories|prop|hidden}}",
"apihelp-query+categories-param-show": "{{doc-apihelp-param|query+categories|show}}",
"apihelp-query+categories-param-limit": "{{doc-apihelp-param|query+categories|limit}}",
"apihelp-query+categories-param-categories": "{{doc-apihelp-param|query+categories|categories}}",
@@ -482,7 +550,13 @@
"apihelp-query+categorymembers-description": "{{doc-apihelp-description|query+categorymembers}}",
"apihelp-query+categorymembers-param-title": "{{doc-apihelp-param|query+categorymembers|title}}",
"apihelp-query+categorymembers-param-pageid": "{{doc-apihelp-param|query+categorymembers|pageid}}",
- "apihelp-query+categorymembers-param-prop": "{{doc-apihelp-param|query+categorymembers|prop}}",
+ "apihelp-query+categorymembers-param-prop": "{{doc-apihelp-param|query+categorymembers|prop|paramvalues=1}}",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "{{doc-apihelp-param|query+categorymembers|prop|ids}}",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "{{doc-apihelp-param|query+categorymembers|prop|title}}",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkey": "{{doc-apihelp-param|query+categorymembers|prop|sortkey}}",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "{{doc-apihelp-param|query+categorymembers|prop|sortkeyprefix}}",
+ "apihelp-query+categorymembers-paramvalue-prop-type": "{{doc-apihelp-param|query+categorymembers|prop|type}}",
+ "apihelp-query+categorymembers-paramvalue-prop-timestamp": "{{doc-apihelp-param|query+categorymembers|prop|timestamp}}",
"apihelp-query+categorymembers-param-namespace": "{{doc-apihelp-param|query+categorymembers|namespace}}",
"apihelp-query+categorymembers-param-type": "{{doc-apihelp-param|query+categorymembers|type}}",
"apihelp-query+categorymembers-param-limit": "{{doc-apihelp-param|query+categorymembers|limit}}",
@@ -511,8 +585,6 @@
"apihelp-query+deletedrevisions-param-tag": "{{doc-apihelp-param|query+deletedrevisions|tag}}",
"apihelp-query+deletedrevisions-param-user": "{{doc-apihelp-param|query+deletedrevisions|user}}",
"apihelp-query+deletedrevisions-param-excludeuser": "{{doc-apihelp-param|query+deletedrevisions|excludeuser}}",
- "apihelp-query+deletedrevisions-param-limit": "{{doc-apihelp-param|query+deletedrevisions|limit}}",
- "apihelp-query+deletedrevisions-param-prop": "{{doc-apihelp-param|query+deletedrevisions|prop}}",
"apihelp-query+deletedrevisions-example-titles": "{{doc-apihelp-example|query+deletedrevisions}}",
"apihelp-query+deletedrevisions-example-revids": "{{doc-apihelp-example|query+deletedrevisions}}",
"apihelp-query+deletedrevs-description": "{{doc-apihelp-description|query+deletedrevs}}",
@@ -556,7 +628,10 @@
"apihelp-query+extlinks-param-expandurl": "{{doc-apihelp-param|query+extlinks|expandurl}}",
"apihelp-query+extlinks-example-simple": "{{doc-apihelp-example|query+extlinks}}",
"apihelp-query+exturlusage-description": "{{doc-apihelp-description|query+exturlusage}}",
- "apihelp-query+exturlusage-param-prop": "{{doc-apihelp-param|query+exturlusage|prop}}",
+ "apihelp-query+exturlusage-param-prop": "{{doc-apihelp-param|query+exturlusage|prop|paramvalues=1}}",
+ "apihelp-query+exturlusage-paramvalue-prop-ids": "{{doc-apihelp-paramvalue|query+exturlusage|prop|ids}}",
+ "apihelp-query+exturlusage-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+exturlusage|prop|title}}",
+ "apihelp-query+exturlusage-paramvalue-prop-url": "{{doc-apihelp-paramvalue|query+exturlusage|prop|url}}",
"apihelp-query+exturlusage-param-protocol": "{{doc-apihelp-param|query+exturlusage|protocol}}",
"apihelp-query+exturlusage-param-query": "{{doc-apihelp-param|query+exturlusage|query}}",
"apihelp-query+exturlusage-param-namespace": "{{doc-apihelp-param|query+exturlusage|namespace}}",
@@ -571,13 +646,28 @@
"apihelp-query+filearchive-param-dir": "{{doc-apihelp-param|query+filearchive|dir}}",
"apihelp-query+filearchive-param-sha1": "{{doc-apihelp-param|query+filearchive|sha1}}",
"apihelp-query+filearchive-param-sha1base36": "{{doc-apihelp-param|query+filearchive|sha1base36}}",
- "apihelp-query+filearchive-param-prop": "{{doc-apihelp-param|query+filearchive|prop}}",
+ "apihelp-query+filearchive-param-prop": "{{doc-apihelp-param|query+filearchive|prop|paramvalues=1}}",
+ "apihelp-query+filearchive-paramvalue-prop-sha1": "{{doc-apihelp-paramvalue|query+filearchive|prop|sha1}}",
+ "apihelp-query+filearchive-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+filearchive|prop|timestamp}}",
+ "apihelp-query+filearchive-paramvalue-prop-user": "{{doc-apihelp-paramvalue|query+filearchive|prop|user}}",
+ "apihelp-query+filearchive-paramvalue-prop-size": "{{doc-apihelp-paramvalue|query+filearchive|prop|size}}",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "{{doc-apihelp-paramvalue|query+filearchive|prop|dimensions}}",
+ "apihelp-query+filearchive-paramvalue-prop-description": "{{doc-apihelp-paramvalue|query+filearchive|prop|description}}",
+ "apihelp-query+filearchive-paramvalue-prop-parseddescription": "{{doc-apihelp-paramvalue|query+filearchive|prop|parseddescription}}",
+ "apihelp-query+filearchive-paramvalue-prop-mime": "{{doc-apihelp-paramvalue|query+filearchive|prop|mime}}",
+ "apihelp-query+filearchive-paramvalue-prop-mediatype": "{{doc-apihelp-paramvalue|query+filearchive|prop|mediatype}}",
+ "apihelp-query+filearchive-paramvalue-prop-metadata": "{{doc-apihelp-paramvalue|query+filearchive|prop|metadata}}",
+ "apihelp-query+filearchive-paramvalue-prop-bitdepth": "{{doc-apihelp-paramvalue|query+filearchive|prop|bitdepth}}",
+ "apihelp-query+filearchive-paramvalue-prop-archivename": "{{doc-apihelp-paramvalue|query+filearchive|prop|archivename}}",
"apihelp-query+filearchive-example-simple": "{{doc-apihelp-example|query+filearchive}}",
"apihelp-query+filerepoinfo-description": "{{doc-apihelp-description|query+filerepoinfo}}",
"apihelp-query+filerepoinfo-param-prop": "{{doc-apihelp-param|query+filerepoinfo|prop}}",
"apihelp-query+filerepoinfo-example-simple": "{{doc-apihelp-example|query+filerepoinfo}}",
"apihelp-query+fileusage-description": "{{doc-apihelp-description|query+fileusage}}",
- "apihelp-query+fileusage-param-prop": "{{doc-apihelp-param|query+fileusage|prop}}",
+ "apihelp-query+fileusage-param-prop": "{{doc-apihelp-param|query+fileusage|prop|paramvalues=1}}",
+ "apihelp-query+fileusage-paramvalue-prop-pageid": "{{doc-apihelp-paramvalue|query+fileusage|prop|pageid}}",
+ "apihelp-query+fileusage-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+fileusage|prop|title}}",
+ "apihelp-query+fileusage-paramvalue-prop-redirect": "{{doc-apihelp-paramvalue|query+fileusage|prop|redirect}}",
"apihelp-query+fileusage-param-namespace": "{{doc-apihelp-param|query+fileusage|namespace}}",
"apihelp-query+fileusage-param-limit": "{{doc-apihelp-param|query+fileusage|limit}}",
"apihelp-query+fileusage-param-show": "{{doc-apihelp-param|query+fileusage|show}}",
@@ -587,10 +677,10 @@
"apihelp-query+imageinfo-param-prop": "{{doc-apihelp-param|query+imageinfo|prop|paramvalues=1}}",
"apihelp-query+imageinfo-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+imageinfo|prop|timestamp}}",
"apihelp-query+imageinfo-paramvalue-prop-user": "{{doc-apihelp-paramvalue|query+imageinfo|prop|user}}",
- "apihelp-query+imageinfo-paramvalue-prop-userid": "{{doc-apihelp-paramvalue|query+imageinfo|prop|userid}}",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "Imageinfo returns information about file revisions (normally the last revision since <code>iilimit</code> defaults to 1). <code>userid</code> includes the ID of the user who made the (re)upload which created that revision. So there will be one user ID per imageinfo item; if you set the limit high enough, you will get all revisions of all files as separate imageinfo items.\n\n{{doc-apihelp-paramvalue|query+imageinfo|prop|userid}}",
"apihelp-query+imageinfo-paramvalue-prop-comment": "{{doc-apihelp-paramvalue|query+imageinfo|prop|comment}}",
"apihelp-query+imageinfo-paramvalue-prop-parsedcomment": "{{doc-apihelp-paramvalue|query+imageinfo|prop|parsedcomment}}",
- "apihelp-query+imageinfo-paramvalue-prop-canonicaltitle": "{{doc-apihelp-paramvalue|query+imageinfo|prop|canonicaltitle}}",
+ "apihelp-query+imageinfo-paramvalue-prop-canonicaltitle": "A canonocal title is aa title formatted in the same way you would see it on the top of the page (localized namespace name, first letters capitalized, spaces instead of underscores). \n{{doc-apihelp-paramvalue|query+imageinfo|prop|canonicaltitle}}",
"apihelp-query+imageinfo-paramvalue-prop-url": "{{doc-apihelp-paramvalue|query+imageinfo|prop|url}}",
"apihelp-query+imageinfo-paramvalue-prop-size": "{{doc-apihelp-paramvalue|query+imageinfo|prop|size}}",
"apihelp-query+imageinfo-paramvalue-prop-dimensions": "{{doc-apihelp-paramvalue|query+imageinfo|prop|dimensions}}",
@@ -653,13 +743,16 @@
"apihelp-query+iwbacklinks-param-prefix": "{{doc-apihelp-param|query+iwbacklinks|prefix}}",
"apihelp-query+iwbacklinks-param-title": "{{doc-apihelp-param|query+iwbacklinks|title}}",
"apihelp-query+iwbacklinks-param-limit": "{{doc-apihelp-param|query+iwbacklinks|limit}}",
- "apihelp-query+iwbacklinks-param-prop": "{{doc-apihelp-param|query+iwbacklinks|prop}}",
+ "apihelp-query+iwbacklinks-param-prop": "{{doc-apihelp-param|query+iwbacklinks|prop|paramvalues=1}}",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "{{doc-apihelp-paramvalue|query+iwbacklinks|prop|iwprefix}}",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "{{doc-apihelp-paramvalue|query+iwbacklinks|prop|iwtitle}}",
"apihelp-query+iwbacklinks-param-dir": "{{doc-apihelp-param|query+iwbacklinks|dir}}",
"apihelp-query+iwbacklinks-example-simple": "{{doc-apihelp-example|query+iwbacklinks}}",
"apihelp-query+iwbacklinks-example-generator": "{{doc-apihelp-example|query+iwbacklinks}}",
"apihelp-query+iwlinks-description": "{{doc-apihelp-description|query+iwlinks}}",
"apihelp-query+iwlinks-param-url": "{{doc-apihelp-param|query+iwlinks|url}}",
- "apihelp-query+iwlinks-param-prop": "{{doc-apihelp-param|query+iwlinks|prop}}",
+ "apihelp-query+iwlinks-param-prop": "{{doc-apihelp-param|query+iwlinks|prop|paramvalues=1}}",
+ "apihelp-query+iwlinks-paramvalue-prop-url": "{{doc-apihelp-paramvalue|query+iwlinks|prop|url}}",
"apihelp-query+iwlinks-param-limit": "{{doc-apihelp-param|query+iwlinks|limit}}",
"apihelp-query+iwlinks-param-prefix": "{{doc-apihelp-param|query+iwlinks|prefix}}",
"apihelp-query+iwlinks-param-title": "{{doc-apihelp-param|query+iwlinks|title}}",
@@ -669,14 +762,19 @@
"apihelp-query+langbacklinks-param-lang": "{{doc-apihelp-param|query+langbacklinks|lang}}",
"apihelp-query+langbacklinks-param-title": "{{doc-apihelp-param|query+langbacklinks|title}}",
"apihelp-query+langbacklinks-param-limit": "{{doc-apihelp-param|query+langbacklinks|limit}}",
- "apihelp-query+langbacklinks-param-prop": "{{doc-apihelp-param|query+langbacklinks|prop}}",
+ "apihelp-query+langbacklinks-param-prop": "{{doc-apihelp-param|query+langbacklinks|prop|paramvalues=1}}",
+ "apihelp-query+langbacklinks-paramvalue-prop-lllang": "{{doc-apihelp-param|query+langbacklinks|prop|lllang}}",
+ "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "{{doc-apihelp-param|query+langbacklinks|prop|lltitle}}",
"apihelp-query+langbacklinks-param-dir": "{{doc-apihelp-param|query+langbacklinks|dir}}",
"apihelp-query+langbacklinks-example-simple": "{{doc-apihelp-example|query+langbacklinks}}",
"apihelp-query+langbacklinks-example-generator": "{{doc-apihelp-example|query+langbacklinks}}",
"apihelp-query+langlinks-description": "{{doc-apihelp-description|query+langlinks}}",
"apihelp-query+langlinks-param-limit": "{{doc-apihelp-param|query+langlinks|limit}}",
"apihelp-query+langlinks-param-url": "{{doc-apihelp-param|query+langlinks|url}}",
- "apihelp-query+langlinks-param-prop": "{{doc-apihelp-param|query+langlinks|prop}}",
+ "apihelp-query+langlinks-param-prop": "{{doc-apihelp-param|query+langlinks|prop|paramvalues=1}}",
+ "apihelp-query+langlinks-paramvalue-prop-url": "{{doc-apihelp-paramvalue|query+langlinks|prop|url}}",
+ "apihelp-query+langlinks-paramvalue-prop-langname": "{{doc-apihelp-paramvalue|query+langlinks|prop|langname}}",
+ "apihelp-query+langlinks-paramvalue-prop-autonym": "{{doc-apihelp-paramvalue|query+langlinks|prop|autonym}}",
"apihelp-query+langlinks-param-lang": "{{doc-apihelp-param|query+langlinks|lang}}",
"apihelp-query+langlinks-param-title": "{{doc-apihelp-param|query+langlinks|title}}",
"apihelp-query+langlinks-param-dir": "{{doc-apihelp-param|query+langlinks|dir}}",
@@ -691,14 +789,27 @@
"apihelp-query+links-example-generator": "{{doc-apihelp-example|query+links}}",
"apihelp-query+links-example-namespaces": "{{doc-apihelp-example|query+links}}",
"apihelp-query+linkshere-description": "{{doc-apihelp-description|query+linkshere}}",
- "apihelp-query+linkshere-param-prop": "{{doc-apihelp-param|query+linkshere|prop}}",
+ "apihelp-query+linkshere-param-prop": "{{doc-apihelp-param|query+linkshere|prop|paramvalues=1}}",
+ "apihelp-query+linkshere-paramvalue-prop-pageid": "{{doc-apihelp-paramvalue|query+linkshere|prop|pageid}}",
+ "apihelp-query+linkshere-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+linkshere|prop|title}}",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "{{doc-apihelp-paramvalue|query+linkshere|prop|redirect}}",
"apihelp-query+linkshere-param-namespace": "{{doc-apihelp-param|query+linkshere|namespace}}",
"apihelp-query+linkshere-param-limit": "{{doc-apihelp-param|query+linkshere|limit}}",
"apihelp-query+linkshere-param-show": "{{doc-apihelp-param|query+linkshere|show}}",
"apihelp-query+linkshere-example-simple": "{{doc-apihelp-example|query+linkshere}}",
"apihelp-query+linkshere-example-generator": "{{doc-apihelp-example|query+linkshere}}",
"apihelp-query+logevents-description": "{{doc-apihelp-description|query+logevents}}",
- "apihelp-query+logevents-param-prop": "{{doc-apihelp-param|query+logevents|prop}}",
+ "apihelp-query+logevents-param-prop": "{{doc-apihelp-param|query+logevents|prop|paramvalues=1}}",
+ "apihelp-query+logevents-paramvalue-prop-ids": "{{doc-apihelp-paramvalue|query+logevents|prop|ids}}",
+ "apihelp-query+logevents-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+logevents|prop|title}}",
+ "apihelp-query+logevents-paramvalue-prop-type": "{{doc-apihelp-paramvalue|query+logevents|prop|type}}",
+ "apihelp-query+logevents-paramvalue-prop-user": "{{doc-apihelp-paramvalue|query+logevents|prop|user}}",
+ "apihelp-query+logevents-paramvalue-prop-userid": "{{doc-apihelp-paramvalue|query+logevents|prop|userid}}",
+ "apihelp-query+logevents-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+logevents|prop|timestamp}}",
+ "apihelp-query+logevents-paramvalue-prop-comment": "{{doc-apihelp-paramvalue|query+logevents|prop|comment}}",
+ "apihelp-query+logevents-paramvalue-prop-parsedcomment": "{{doc-apihelp-paramvalue|query+logevents|prop|parsedcomment}}",
+ "apihelp-query+logevents-paramvalue-prop-details": "{{doc-apihelp-paramvalue|query+logevents|prop|details}}",
+ "apihelp-query+logevents-paramvalue-prop-tags": "{{doc-apihelp-paramvalue|query+logevents|prop|tags}}",
"apihelp-query+logevents-param-type": "{{doc-apihelp-param|query+logevents|type}}",
"apihelp-query+logevents-param-action": "{{doc-apihelp-param|query+logevents|action}}",
"apihelp-query+logevents-param-start": "{{doc-apihelp-param|query+logevents|start}}",
@@ -718,7 +829,10 @@
"apihelp-query+pageprops-example-simple": "{{doc-apihelp-example|query+pageprops}}",
"apihelp-query+pageswithprop-description": "{{doc-apihelp-description|query+pageswithprop}}",
"apihelp-query+pageswithprop-param-propname": "{{doc-apihelp-param|query+pageswithprop|propname}}",
- "apihelp-query+pageswithprop-param-prop": "{{doc-apihelp-param|query+pageswithprop|prop}}",
+ "apihelp-query+pageswithprop-param-prop": "{{doc-apihelp-param|query+pageswithprop|prop|paramvalues=1}}",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "{{doc-apihelp-param|query+pageswithprop|prop|ids}}",
+ "apihelp-query+pageswithprop-paramvalue-prop-title": "{{doc-apihelp-param|query+pageswithprop|prop|title}}",
+ "apihelp-query+pageswithprop-paramvalue-prop-value": "{{doc-apihelp-param|query+pageswithprop|prop|value}}",
"apihelp-query+pageswithprop-param-limit": "{{doc-apihelp-param|query+pageswithprop|limit}}",
"apihelp-query+pageswithprop-param-dir": "{{doc-apihelp-param|query+pageswithprop|dir}}",
"apihelp-query+pageswithprop-example-simple": "{{doc-apihelp-example|query+pageswithprop}}",
@@ -735,7 +849,14 @@
"apihelp-query+protectedtitles-param-limit": "{{doc-apihelp-param|query+protectedtitles|limit}}",
"apihelp-query+protectedtitles-param-start": "{{doc-apihelp-param|query+protectedtitles|start}}",
"apihelp-query+protectedtitles-param-end": "{{doc-apihelp-param|query+protectedtitles|end}}",
- "apihelp-query+protectedtitles-param-prop": "{{doc-apihelp-param|query+protectedtitles|prop}}",
+ "apihelp-query+protectedtitles-param-prop": "{{doc-apihelp-param|query+protectedtitles|prop|paramvalues=1}}",
+ "apihelp-query+protectedtitles-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+protectedtitles|prop|timestamp}}",
+ "apihelp-query+protectedtitles-paramvalue-prop-user": "{{doc-apihelp-paramvalue|query+protectedtitles|prop|user}}",
+ "apihelp-query+protectedtitles-paramvalue-prop-userid": "{{doc-apihelp-paramvalue|query+protectedtitles|prop|userid}}",
+ "apihelp-query+protectedtitles-paramvalue-prop-comment": "{{doc-apihelp-paramvalue|query+protectedtitles|prop|comment}}",
+ "apihelp-query+protectedtitles-paramvalue-prop-parsedcomment": "{{doc-apihelp-paramvalue|query+protectedtitles|prop|parsedcomment}}",
+ "apihelp-query+protectedtitles-paramvalue-prop-expiry": "{{doc-apihelp-paramvalue|query+protectedtitles|prop|expiry}}",
+ "apihelp-query+protectedtitles-paramvalue-prop-level": "{{doc-apihelp-paramvalue|query+protectedtitles|prop|level}}",
"apihelp-query+protectedtitles-example-simple": "{{doc-apihelp-example|query+protectedtitles}}",
"apihelp-query+protectedtitles-example-generator": "{{doc-apihelp-example|query+protectedtitles}}",
"apihelp-query+querypage-description": "{{doc-apihelp-description|query+querypage}}",
@@ -746,6 +867,7 @@
"apihelp-query+random-param-namespace": "{{doc-apihelp-param|query+random|namespace}}",
"apihelp-query+random-param-limit": "{{doc-apihelp-param|query+random|limit}}",
"apihelp-query+random-param-redirect": "{{doc-apihelp-param|query+random|redirect}}",
+ "apihelp-query+random-param-filterredir": "{{apihelp-param|query+random|filterredir}}",
"apihelp-query+random-example-simple": "{{doc-apihelp-example|query+random}}",
"apihelp-query+random-example-generator": "{{doc-apihelp-example|query+random}}",
"apihelp-query+recentchanges-description": "{{doc-apihelp-description|query+recentchanges}}",
@@ -755,7 +877,21 @@
"apihelp-query+recentchanges-param-user": "{{doc-apihelp-param|query+recentchanges|user}}",
"apihelp-query+recentchanges-param-excludeuser": "{{doc-apihelp-param|query+recentchanges|excludeuser}}",
"apihelp-query+recentchanges-param-tag": "{{doc-apihelp-param|query+recentchanges|tag}}",
- "apihelp-query+recentchanges-param-prop": "{{doc-apihelp-param|query+recentchanges|prop}}",
+ "apihelp-query+recentchanges-param-prop": "{{doc-apihelp-param|query+recentchanges|prop|paramvalues=1}}",
+ "apihelp-query+recentchanges-paramvalue-prop-user": "{{doc-apihelp-paramvalue|query+recentchanges|prop|user}}",
+ "apihelp-query+recentchanges-paramvalue-prop-userid": "{{doc-apihelp-paramvalue|query+recentchanges|prop|userid}}",
+ "apihelp-query+recentchanges-paramvalue-prop-comment": "{{doc-apihelp-paramvalue|query+recentchanges|prop|comment}}",
+ "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "{{doc-apihelp-paramvalue|query+recentchanges|prop|parsedcomment}}",
+ "apihelp-query+recentchanges-paramvalue-prop-flags": "{{doc-apihelp-paramvalue|query+recentchanges|prop|flags}}",
+ "apihelp-query+recentchanges-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+recentchanges|prop|timestamp}}",
+ "apihelp-query+recentchanges-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+recentchanges|prop|title}}",
+ "apihelp-query+recentchanges-paramvalue-prop-ids": "{{doc-apihelp-paramvalue|query+recentchanges|prop|ids}}",
+ "apihelp-query+recentchanges-paramvalue-prop-sizes": "{{doc-apihelp-paramvalue|query+recentchanges|prop|sizes}}",
+ "apihelp-query+recentchanges-paramvalue-prop-redirect": "{{doc-apihelp-paramvalue|query+recentchanges|prop|redirect}}",
+ "apihelp-query+recentchanges-paramvalue-prop-patrolled": "{{doc-apihelp-paramvalue|query+recentchanges|prop|patrolled}}",
+ "apihelp-query+recentchanges-paramvalue-prop-loginfo": "{{doc-apihelp-paramvalue|query+recentchanges|prop|loginfo}}",
+ "apihelp-query+recentchanges-paramvalue-prop-tags": "{{doc-apihelp-paramvalue|query+recentchanges|prop|tags}}",
+ "apihelp-query+recentchanges-paramvalue-prop-sha1": "{{doc-apihelp-paramvalue|query+recentchanges|prop|sha1}}",
"apihelp-query+recentchanges-param-token": "{{doc-apihelp-param|query+recentchanges|token}}",
"apihelp-query+recentchanges-param-show": "{{doc-apihelp-param|query+recentchanges|show}}",
"apihelp-query+recentchanges-param-limit": "{{doc-apihelp-param|query+recentchanges|limit}}",
@@ -764,7 +900,10 @@
"apihelp-query+recentchanges-example-simple": "{{doc-apihelp-example|query+recentchanges}}",
"apihelp-query+recentchanges-example-generator": "{{doc-apihelp-example|query+recentchanges}}",
"apihelp-query+redirects-description": "{{doc-apihelp-description|query+redirects}}",
- "apihelp-query+redirects-param-prop": "{{doc-apihelp-param|query+redirects|prop}}",
+ "apihelp-query+redirects-param-prop": "{{doc-apihelp-param|query+redirects|prop|paramvalues=1}}",
+ "apihelp-query+redirects-paramvalue-prop-pageid": "{{doc-apihelp-paramvalue|query+redirects|prop|pageid}}",
+ "apihelp-query+redirects-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+redirects|prop|title}}",
+ "apihelp-query+redirects-paramvalue-prop-fragment": "{{doc-apihelp-paramvalue|query+redirects|prop|fragment}}",
"apihelp-query+redirects-param-namespace": "{{doc-apihelp-param|query+redirects|namespace}}",
"apihelp-query+redirects-param-limit": "{{doc-apihelp-param|query+redirects|limit}}",
"apihelp-query+redirects-param-show": "{{doc-apihelp-param|query+redirects|show}}",
@@ -786,7 +925,20 @@
"apihelp-query+revisions-example-first5-after": "{{doc-apihelp-example|query+revisions}}",
"apihelp-query+revisions-example-first5-not-localhost": "{{doc-apihelp-example|query+revisions}}",
"apihelp-query+revisions-example-first5-user": "{{doc-apihelp-example|query+revisions}}",
- "apihelp-query+revisions+base-param-prop": "{{doc-apihelp-param|query+revisions+base|prop|description=the \"prop\" parameter to revision querying modules|noseealso=1}}",
+ "apihelp-query+revisions+base-param-prop": "{{doc-apihelp-param|query+revisions+base|prop|description=the \"prop\" parameter to revision querying modules|noseealso=1|paramvalues=1}}",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "{{doc-apihelp-paramvalue|query+revisions+base|prop|ids}}",
+ "apihelp-query+revisions+base-paramvalue-prop-flags": "{{doc-apihelp-paramvalue|query+revisions+base|prop|flags}}",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+revisions+base|prop|timestamp}}",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "{{doc-apihelp-paramvalue|query+revisions+base|prop|user}}",
+ "apihelp-query+revisions+base-paramvalue-prop-userid": "{{doc-apihelp-paramvalue|query+revisions+base|prop|userid}}",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "{{doc-apihelp-paramvalue|query+revisions+base|prop|size}}",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "{{doc-apihelp-paramvalue|query+revisions+base|prop|sha1}}",
+ "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "{{doc-apihelp-paramvalue|query+revisions+base|prop|contentmodel}}",
+ "apihelp-query+revisions+base-paramvalue-prop-comment": "{{doc-apihelp-paramvalue|query+revisions+base|prop|comment}}",
+ "apihelp-query+revisions+base-paramvalue-prop-parsedcomment": "{{doc-apihelp-paramvalue|query+revisions+base|prop|parsedcomment}}",
+ "apihelp-query+revisions+base-paramvalue-prop-content": "{{doc-apihelp-paramvalue|query+revisions+base|prop|content}}",
+ "apihelp-query+revisions+base-paramvalue-prop-tags": "{{doc-apihelp-paramvalue|query+revisions+base|prop|tags}}",
+ "apihelp-query+revisions+base-paramvalue-prop-parsetree": "{{doc-apihelp-paramvalue|query+revisions+base|prop|parsetree|params=* $1 - Value of the constant CONTENT_MODEL_WIKITEXT|paramstart=2}}",
"apihelp-query+revisions+base-param-limit": "{{doc-apihelp-param|query+revisions+base|limit|description=the \"limit\" parameter to revision querying modules|noseealso=1}}",
"apihelp-query+revisions+base-param-expandtemplates": "{{doc-apihelp-param|query+revisions+base|expandtemplates|description=the \"expandtemplates\" parameter to revision querying modules|noseealso=1}}",
"apihelp-query+revisions+base-param-generatexml": "{{doc-apihelp-param|query+revisions+base|generatexml|description=the \"generatexml\" parameter to revision querying modules|noseealso=1}}",
@@ -800,15 +952,51 @@
"apihelp-query+search-param-namespace": "{{doc-apihelp-param|query+search|namespace}}",
"apihelp-query+search-param-what": "{{doc-apihelp-param|query+search|what}}",
"apihelp-query+search-param-info": "{{doc-apihelp-param|query+search|info}}",
- "apihelp-query+search-param-prop": "{{doc-apihelp-param|query+search|prop}}",
+ "apihelp-query+search-param-prop": "{{doc-apihelp-param|query+search|prop|paramvalues=1}}",
+ "apihelp-query+search-paramvalue-prop-size": "{{doc-apihelp-paramvalue|query+search|prop|size}}",
+ "apihelp-query+search-paramvalue-prop-wordcount": "{{doc-apihelp-paramvalue|query+search|prop|wordcount}}",
+ "apihelp-query+search-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+search|prop|timestamp}}",
+ "apihelp-query+search-paramvalue-prop-snippet": "{{doc-apihelp-paramvalue|query+search|prop|snippet}}",
+ "apihelp-query+search-paramvalue-prop-titlesnippet": "{{doc-apihelp-paramvalue|query+search|prop|titlesnippet}}",
+ "apihelp-query+search-paramvalue-prop-redirectsnippet": "{{doc-apihelp-paramvalue|query+search|prop|redirectsnippet}}",
+ "apihelp-query+search-paramvalue-prop-redirecttitle": "{{doc-apihelp-paramvalue|query+search|prop|redirecttitle}}",
+ "apihelp-query+search-paramvalue-prop-sectionsnippet": "{{doc-apihelp-paramvalue|query+search|prop|sectionsnippet}}",
+ "apihelp-query+search-paramvalue-prop-sectiontitle": "{{doc-apihelp-paramvalue|query+search|prop|sectiontitle}}",
+ "apihelp-query+search-paramvalue-prop-categorysnippet": "{{doc-apihelp-paramvalue|query+search|prop|categorysnippet}}",
+ "apihelp-query+search-paramvalue-prop-isfilematch": "{{doc-apihelp-paramvalue|query+search|prop|isfilematch}}",
+ "apihelp-query+search-paramvalue-prop-score": "{{doc-apihelp-paramvalue|query+search|prop|score}}",
+ "apihelp-query+search-paramvalue-prop-hasrelated": "{{doc-apihelp-paramvalue|query+search|prop|hasrelated}}",
"apihelp-query+search-param-limit": "{{doc-apihelp-param|query+search|limit}}",
"apihelp-query+search-param-interwiki": "{{doc-apihelp-param|query+search|interwiki}}",
"apihelp-query+search-param-backend": "{{doc-apihelp-param|query+search|backend}}",
+ "apihelp-query+search-param-enablerewrites": "{{doc-apihelp-param|query+search|enablerewrites}}",
"apihelp-query+search-example-simple": "{{doc-apihelp-example|query+search}}",
"apihelp-query+search-example-text": "{{doc-apihelp-example|query+search}}",
"apihelp-query+search-example-generator": "{{doc-apihelp-example|query+search}}",
"apihelp-query+siteinfo-description": "{{doc-apihelp-description|query+siteinfo}}",
- "apihelp-query+siteinfo-param-prop": "{{doc-apihelp-param|query+siteinfo|prop}}",
+ "apihelp-query+siteinfo-param-prop": "{{doc-apihelp-param|query+siteinfo|prop|paramvalues=1}}",
+ "apihelp-query+siteinfo-paramvalue-prop-general": "{{doc-apihelp-paramvalue|query+siteinfo|prop|general}}",
+ "apihelp-query+siteinfo-paramvalue-prop-namespaces": "{{doc-apihelp-paramvalue|query+siteinfo|prop|namespaces}}",
+ "apihelp-query+siteinfo-paramvalue-prop-namespacealiases": "{{doc-apihelp-paramvalue|query+siteinfo|prop|namespacealiases}}",
+ "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "{{doc-apihelp-paramvalue|query+siteinfo|prop|specialpagealiases}}",
+ "apihelp-query+siteinfo-paramvalue-prop-magicwords": "{{doc-apihelp-paramvalue|query+siteinfo|prop|magicwords}}",
+ "apihelp-query+siteinfo-paramvalue-prop-statistics": "{{doc-apihelp-paramvalue|query+siteinfo|prop|statistics}}",
+ "apihelp-query+siteinfo-paramvalue-prop-interwikimap": "{{doc-apihelp-paramvalue|query+siteinfo|prop|interwikimap}}",
+ "apihelp-query+siteinfo-paramvalue-prop-dbrepllag": "{{doc-apihelp-paramvalue|query+siteinfo|prop|dbrepllag}}",
+ "apihelp-query+siteinfo-paramvalue-prop-usergroups": "{{doc-apihelp-paramvalue|query+siteinfo|prop|usergroups}}",
+ "apihelp-query+siteinfo-paramvalue-prop-libraries": "{{doc-apihelp-paramvalue|query+siteinfo|prop|libraries}}",
+ "apihelp-query+siteinfo-paramvalue-prop-extensions": "{{doc-apihelp-paramvalue|query+siteinfo|prop|extensions}}",
+ "apihelp-query+siteinfo-paramvalue-prop-fileextensions": "{{doc-apihelp-paramvalue|query+siteinfo|prop|fileextensions}}",
+ "apihelp-query+siteinfo-paramvalue-prop-rightsinfo": "{{doc-apihelp-paramvalue|query+siteinfo|prop|rightsinfo}}",
+ "apihelp-query+siteinfo-paramvalue-prop-restrictions": "{{doc-apihelp-paramvalue|query+siteinfo|prop|restrictions}}",
+ "apihelp-query+siteinfo-paramvalue-prop-languages": "{{doc-apihelp-paramvalue|query+siteinfo|prop|languages}}",
+ "apihelp-query+siteinfo-paramvalue-prop-skins": "{{doc-apihelp-paramvalue|query+siteinfo|prop|skins}}",
+ "apihelp-query+siteinfo-paramvalue-prop-extensiontags": "{{doc-apihelp-paramvalue|query+siteinfo|prop|extensiontags}}",
+ "apihelp-query+siteinfo-paramvalue-prop-functionhooks": "{{doc-apihelp-paramvalue|query+siteinfo|prop|functionhooks}}",
+ "apihelp-query+siteinfo-paramvalue-prop-showhooks": "{{doc-apihelp-paramvalue|query+siteinfo|prop|showhooks}}",
+ "apihelp-query+siteinfo-paramvalue-prop-variables": "{{doc-apihelp-paramvalue|query+siteinfo|prop|variables}}",
+ "apihelp-query+siteinfo-paramvalue-prop-protocols": "{{doc-apihelp-paramvalue|query+siteinfo|prop|protocols}}",
+ "apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "{{doc-apihelp-paramvalue|query+siteinfo|prop|defaultoptions}}",
"apihelp-query+siteinfo-param-filteriw": "{{doc-apihelp-param|query+siteinfo|filteriw}}",
"apihelp-query+siteinfo-param-showalldb": "{{doc-apihelp-param|query+siteinfo|showalldb}}",
"apihelp-query+siteinfo-param-numberingroup": "{{doc-apihelp-param|query+siteinfo|numberingroup}}",
@@ -823,7 +1011,14 @@
"apihelp-query+stashimageinfo-example-params": "{{doc-apihelp-example|query+stashimageinfo}}",
"apihelp-query+tags-description": "{{doc-apihelp-description|query+tags}}",
"apihelp-query+tags-param-limit": "{{doc-apihelp-param|query+tags|limit}}",
- "apihelp-query+tags-param-prop": "{{doc-apihelp-param|query+tags|prop}}",
+ "apihelp-query+tags-param-prop": "{{doc-apihelp-param|query+tags|prop|paramvalues=1}}",
+ "apihelp-query+tags-paramvalue-prop-name": "{{doc-apihelp-paramvalue|query+tags|prop|name}}",
+ "apihelp-query+tags-paramvalue-prop-displayname": "{{doc-apihelp-paramvalue|query+tags|prop|displayname}}",
+ "apihelp-query+tags-paramvalue-prop-description": "{{doc-apihelp-paramvalue|query+tags|prop|description}}",
+ "apihelp-query+tags-paramvalue-prop-hitcount": "{{doc-apihelp-paramvalue|query+tags|prop|hitcount}}",
+ "apihelp-query+tags-paramvalue-prop-defined": "{{doc-apihelp-paramvalue|query+tags|prop|defined}}",
+ "apihelp-query+tags-paramvalue-prop-source": "{{doc-apihelp-paramvalue|query+tags|prop|source}}",
+ "apihelp-query+tags-paramvalue-prop-active": "{{doc-apihelp-paramvalue|query+tags|prop|active}}",
"apihelp-query+tags-example-simple": "{{doc-apihelp-example|query+tags}}",
"apihelp-query+templates-description": "{{doc-apihelp-description|query+templates}}",
"apihelp-query+templates-param-namespace": "{{doc-apihelp-param|query+templates|namespace}}",
@@ -838,7 +1033,10 @@
"apihelp-query+tokens-example-simple": "{{doc-apihelp-example|query+tokens}}",
"apihelp-query+tokens-example-types": "{{doc-apihelp-example|query+tokens}}",
"apihelp-query+transcludedin-description": "{{doc-apihelp-description|query+transcludedin}}",
- "apihelp-query+transcludedin-param-prop": "{{doc-apihelp-param|query+transcludedin|prop}}",
+ "apihelp-query+transcludedin-param-prop": "{{doc-apihelp-param|query+transcludedin|prop|paramvalues=1}}",
+ "apihelp-query+transcludedin-paramvalue-prop-pageid": "{{doc-apihelp-paramvalue|query+transcludedin|prop|pageid}}",
+ "apihelp-query+transcludedin-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+transcludedin|prop|title}}",
+ "apihelp-query+transcludedin-paramvalue-prop-redirect": "{{doc-apihelp-paramvalue|query+transcludedin|prop|redirect}}",
"apihelp-query+transcludedin-param-namespace": "{{doc-apihelp-param|query+transcludedin|namespace}}",
"apihelp-query+transcludedin-param-limit": "{{doc-apihelp-param|query+transcludedin|limit}}",
"apihelp-query+transcludedin-param-show": "{{doc-apihelp-param|query+transcludedin|show}}",
@@ -851,18 +1049,51 @@
"apihelp-query+usercontribs-param-user": "{{doc-apihelp-param|query+usercontribs|user}}",
"apihelp-query+usercontribs-param-userprefix": "{{doc-apihelp-param|query+usercontribs|userprefix}}",
"apihelp-query+usercontribs-param-namespace": "{{doc-apihelp-param|query+usercontribs|namespace}}",
- "apihelp-query+usercontribs-param-prop": "{{doc-apihelp-param|query+usercontribs|prop}}",
+ "apihelp-query+usercontribs-param-prop": "{{doc-apihelp-param|query+usercontribs|prop|paramvalues=1}}",
+ "apihelp-query+usercontribs-paramvalue-prop-ids": "{{doc-apihelp-paramvalue|query+usercontribs|prop|ids}}",
+ "apihelp-query+usercontribs-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+usercontribs|prop|title}}",
+ "apihelp-query+usercontribs-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+usercontribs|prop|timestamp}}",
+ "apihelp-query+usercontribs-paramvalue-prop-comment": "{{doc-apihelp-paramvalue|query+usercontribs|prop|comment}}",
+ "apihelp-query+usercontribs-paramvalue-prop-parsedcomment": "{{doc-apihelp-paramvalue|query+usercontribs|prop|parsedcomment}}",
+ "apihelp-query+usercontribs-paramvalue-prop-size": "{{doc-apihelp-paramvalue|query+usercontribs|prop|size}}",
+ "apihelp-query+usercontribs-paramvalue-prop-sizediff": "{{doc-apihelp-paramvalue|query+usercontribs|prop|sizediff}}",
+ "apihelp-query+usercontribs-paramvalue-prop-flags": "{{doc-apihelp-paramvalue|query+usercontribs|prop|flags}}",
+ "apihelp-query+usercontribs-paramvalue-prop-patrolled": "{{doc-apihelp-paramvalue|query+usercontribs|prop|patrolled}}",
+ "apihelp-query+usercontribs-paramvalue-prop-tags": "{{doc-apihelp-paramvalue|query+usercontribs|prop|tags}}",
"apihelp-query+usercontribs-param-show": "{{doc-apihelp-param|query+usercontribs|show|params=* $1 - Value of [[mw:Manual:$RCMaxAge|$RCMaxAge]]|paramstart=2}}",
"apihelp-query+usercontribs-param-tag": "{{doc-apihelp-param|query+usercontribs|tag}}",
"apihelp-query+usercontribs-param-toponly": "{{doc-apihelp-param|query+usercontribs|toponly}}",
"apihelp-query+usercontribs-example-user": "{{doc-apihelp-example|query+usercontribs}}",
"apihelp-query+usercontribs-example-ipprefix": "{{doc-apihelp-example|query+usercontribs}}",
"apihelp-query+userinfo-description": "{{doc-apihelp-description|query+userinfo}}",
- "apihelp-query+userinfo-param-prop": "{{doc-apihelp-param|query+userinfo|prop|params=* $1 - Maximum value for the \"unreadcount\" property.\n$2 - Return value when there are more unread pages.|paramstart=3}}",
+ "apihelp-query+userinfo-param-prop": "{{doc-apihelp-param|query+userinfo|prop|paramvalues=1}}",
+ "apihelp-query+userinfo-paramvalue-prop-blockinfo": "{{doc-apihelp-paramvalue|query+userinfo|prop|blockinfo}}",
+ "apihelp-query+userinfo-paramvalue-prop-hasmsg": "{{doc-apihelp-paramvalue|query+userinfo|prop|hasmsg}}",
+ "apihelp-query+userinfo-paramvalue-prop-groups": "{{doc-apihelp-paramvalue|query+userinfo|prop|groups}}",
+ "apihelp-query+userinfo-paramvalue-prop-implicitgroups": "{{doc-apihelp-paramvalue|query+userinfo|prop|implicitgroups}}",
+ "apihelp-query+userinfo-paramvalue-prop-rights": "{{doc-apihelp-paramvalue|query+userinfo|prop|rights}}",
+ "apihelp-query+userinfo-paramvalue-prop-changeablegroups": "{{doc-apihelp-paramvalue|query+userinfo|prop|changeablegroups}}",
+ "apihelp-query+userinfo-paramvalue-prop-options": "{{doc-apihelp-paramvalue|query+userinfo|prop|options}}",
+ "apihelp-query+userinfo-paramvalue-prop-preferencestoken": "{{doc-apihelp-paramvalue|query+userinfo|prop|preferencestoken}}",
+ "apihelp-query+userinfo-paramvalue-prop-editcount": "{{doc-apihelp-paramvalue|query+userinfo|prop|editcount}}",
+ "apihelp-query+userinfo-paramvalue-prop-ratelimits": "{{doc-apihelp-paramvalue|query+userinfo|prop|ratelimits}}",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "{{doc-apihelp-paramvalue|query+userinfo|prop|realname}}",
+ "apihelp-query+userinfo-paramvalue-prop-email": "{{doc-apihelp-paramvalue|query+userinfo|prop|email}}",
+ "apihelp-query+userinfo-paramvalue-prop-acceptlang": "{{doc-apihelp-paramvalue|query+userinfo|prop|acceptlang}}",
+ "apihelp-query+userinfo-paramvalue-prop-registrationdate": "{{doc-apihelp-paramvalue|query+userinfo|prop|registrationdate}}",
+ "apihelp-query+userinfo-paramvalue-prop-unreadcount": "{{doc-apihelp-paramvalue|query+userinfo|prop|unreadcount|params=* $1 - Maximum value for the \"unreadcount\" property.\n* $2 - Return value when there are more unread pages.|paramstart=3}}",
"apihelp-query+userinfo-example-simple": "{{doc-apihelp-example|query+userinfo}}",
"apihelp-query+userinfo-example-data": "{{doc-apihelp-example|query+userinfo}}",
"apihelp-query+users-description": "{{doc-apihelp-description|query+users}}",
- "apihelp-query+users-param-prop": "{{doc-apihelp-param|query+users|prop}}",
+ "apihelp-query+users-param-prop": "{{doc-apihelp-param|query+users|prop|paramvalues=1}}",
+ "apihelp-query+users-paramvalue-prop-blockinfo": "{{doc-apihelp-paramvalue|query+users|prop|blockinfo}}",
+ "apihelp-query+users-paramvalue-prop-groups": "{{doc-apihelp-paramvalue|query+users|prop|groups}}",
+ "apihelp-query+users-paramvalue-prop-implicitgroups": "{{doc-apihelp-paramvalue|query+users|prop|implicitgroups}}",
+ "apihelp-query+users-paramvalue-prop-rights": "{{doc-apihelp-paramvalue|query+users|prop|rights}}",
+ "apihelp-query+users-paramvalue-prop-editcount": "{{doc-apihelp-paramvalue|query+users|prop|editcount}}",
+ "apihelp-query+users-paramvalue-prop-registration": "{{doc-apihelp-paramvalue|query+users|prop|registration}}",
+ "apihelp-query+users-paramvalue-prop-emailable": "{{doc-apihelp-paramvalue|query+users|prop|emailable}}",
+ "apihelp-query+users-paramvalue-prop-gender": "{{doc-apihelp-paramvalue|query+users|prop|gender}}",
"apihelp-query+users-param-users": "{{doc-apihelp-param|query+users|users}}",
"apihelp-query+users-param-token": "{{doc-apihelp-param|query+users|token}}",
"apihelp-query+users-example-simple": "{{doc-apihelp-example|query+users}}",
@@ -874,7 +1105,19 @@
"apihelp-query+watchlist-param-user": "{{doc-apihelp-param|query+watchlist|user}}",
"apihelp-query+watchlist-param-excludeuser": "{{doc-apihelp-param|query+watchlist|excludeuser}}",
"apihelp-query+watchlist-param-limit": "{{doc-apihelp-param|query+watchlist|limit}}",
- "apihelp-query+watchlist-param-prop": "{{doc-apihelp-param|query+watchlist|prop}}",
+ "apihelp-query+watchlist-param-prop": "{{doc-apihelp-param|query+watchlist|prop|paramvalues=1}}",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "{{doc-apihelp-paramvalue|query+watchlist|prop|ids}}",
+ "apihelp-query+watchlist-paramvalue-prop-title": "{{doc-apihelp-paramvalue|query+watchlist|prop|title}}",
+ "apihelp-query+watchlist-paramvalue-prop-flags": "{{doc-apihelp-paramvalue|query+watchlist|prop|flags}}",
+ "apihelp-query+watchlist-paramvalue-prop-user": "{{doc-apihelp-paramvalue|query+watchlist|prop|user}}",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "{{doc-apihelp-paramvalue|query+watchlist|prop|userid}}",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "{{doc-apihelp-paramvalue|query+watchlist|prop|comment}}",
+ "apihelp-query+watchlist-paramvalue-prop-parsedcomment": "{{doc-apihelp-paramvalue|query+watchlist|prop|parsedcomment}}",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "{{doc-apihelp-paramvalue|query+watchlist|prop|timestamp}}",
+ "apihelp-query+watchlist-paramvalue-prop-patrol": "{{doc-apihelp-paramvalue|query+watchlist|prop|patrol}}",
+ "apihelp-query+watchlist-paramvalue-prop-sizes": "{{doc-apihelp-paramvalue|query+watchlist|prop|sizes}}",
+ "apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "{{doc-apihelp-paramvalue|query+watchlist|prop|notificationtimestamp}}",
+ "apihelp-query+watchlist-paramvalue-prop-loginfo": "{{doc-apihelp-paramvalue|query+watchlist|prop|loginfo}}",
"apihelp-query+watchlist-param-show": "{{doc-apihelp-param|query+watchlist|show}}",
"apihelp-query+watchlist-param-type": "{{doc-apihelp-param|query+watchlist|type}}",
"apihelp-query+watchlist-param-owner": "{{doc-apihelp-param|query+watchlist|owner}}",
@@ -888,10 +1131,13 @@
"apihelp-query+watchlistraw-description": "{{doc-apihelp-description|query+watchlistraw}}",
"apihelp-query+watchlistraw-param-namespace": "{{doc-apihelp-param|query+watchlistraw|namespace}}",
"apihelp-query+watchlistraw-param-limit": "{{doc-apihelp-param|query+watchlistraw|limit}}",
- "apihelp-query+watchlistraw-param-prop": "{{doc-apihelp-param|query+watchlistraw|prop}}",
+ "apihelp-query+watchlistraw-param-prop": "{{doc-apihelp-param|query+watchlistraw|prop|paramvalues=1}}",
+ "apihelp-query+watchlistraw-paramvalue-prop-changed": "{{doc-apihelp-paramvalue|query+watchlistraw|prop|changed}}",
"apihelp-query+watchlistraw-param-show": "{{doc-apihelp-param|query+watchlistraw|show}}",
"apihelp-query+watchlistraw-param-owner": "{{doc-apihelp-param|query+watchlistraw|owner}}",
"apihelp-query+watchlistraw-param-token": "{{doc-apihelp-param|query+watchlistraw|token}}",
+ "apihelp-query+watchlistraw-param-fromtitle": "{{doc-apihelp-param|query+watchlistraw|fromtitle}}",
+ "apihelp-query+watchlistraw-param-totitle": "{{doc-apihelp-param|query+watchlistraw|totitle}}",
"apihelp-query+watchlistraw-example-simple": "{{doc-apihelp-example|query+watchlistraw}}",
"apihelp-query+watchlistraw-example-generator": "{{doc-apihelp-example|query+watchlistraw}}",
"apihelp-revisiondelete-description": "{{doc-apihelp-description|revisiondelete}}",
@@ -924,6 +1170,14 @@
"apihelp-setnotificationtimestamp-example-page": "{{doc-apihelp-example|setnotificationtimestamp}}",
"apihelp-setnotificationtimestamp-example-pagetimestamp": "{{doc-apihelp-example|setnotificationtimestamp}}",
"apihelp-setnotificationtimestamp-example-allpages": "{{doc-apihelp-example|setnotificationtimestamp}}",
+ "apihelp-stashedit-description": "{{apihelp-description|stashedit}}",
+ "apihelp-stashedit-param-title": "{{apihelp-param|stashedit|title}}",
+ "apihelp-stashedit-param-section": "{{apihelp-param|stashedit|section}}",
+ "apihelp-stashedit-param-sectiontitle": "{{apihelp-param|stashedit|sectiontitle}}",
+ "apihelp-stashedit-param-text": "{{apihelp-param|stashedit|text}}",
+ "apihelp-stashedit-param-contentmodel": "{{apihelp-param|stashedit|contentmodel}}",
+ "apihelp-stashedit-param-contentformat": "{{apihelp-param|stashedit|contentformat}}",
+ "apihelp-stashedit-param-baserevid": "{{apihelp-param|stashedit|baserevid}}",
"apihelp-tag-description": "{{doc-apihelp-description|tag}}",
"apihelp-tag-param-rcid": "{{doc-apihelp-param|tag|rcid}}",
"apihelp-tag-param-revid": "{{doc-apihelp-param|tag|revid}}",
@@ -990,8 +1244,6 @@
"apihelp-format-example-generic": "{{doc-apihelp-example|format|params=* $1 - Format name|paramstart=2|noseealso=1}}",
"apihelp-dbg-description": "{{doc-apihelp-description|dbg|seealso=* {{msg-mw|apihelp-dbgfm-description}}}}",
"apihelp-dbgfm-description": "{{doc-apihelp-description|dbgfm|seealso=* {{msg-mw|apihelp-dbg-description}}}}",
- "apihelp-dump-description": "{{doc-apihelp-description|dump|seealso=* {{msg-mw|apihelp-dumpfm-description}}}}",
- "apihelp-dumpfm-description": "{{doc-apihelp-description|dumpfm|seealso=* {{msg-mw|apihelp-dump-description}}}}",
"apihelp-json-description": "{{doc-apihelp-description|json|seealso=* {{msg-mw|apihelp-jsonfm-description}}}}",
"apihelp-json-param-callback": "{{doc-apihelp-param|json|callback}}",
"apihelp-json-param-utf8": "{{doc-apihelp-param|json|utf8}}",
@@ -1005,8 +1257,6 @@
"apihelp-rawfm-description": "{{doc-apihelp-description|rawfm|seealso=* {{msg-mw|apihelp-raw-description}}}}",
"apihelp-txt-description": "{{doc-apihelp-description|txt|seealso=* {{msg-mw|apihelp-txtfm-description}}}}",
"apihelp-txtfm-description": "{{doc-apihelp-description|txtfm|seealso=* {{msg-mw|apihelp-txt-description}}}}",
- "apihelp-wddx-description": "{{doc-apihelp-description|wddx|seealso=* {{msg-mw|apihelp-wddxfm-description}}}}",
- "apihelp-wddxfm-description": "{{doc-apihelp-description|wddxfm|seealso=* {{msg-mw|apihelp-wddx-description}}}}",
"apihelp-xml-description": "{{doc-apihelp-description|xml|seealso=* {{msg-mw|apihelp-xmlfm-description}}}}",
"apihelp-xml-param-xslt": "{{doc-apihelp-param|xml|xslt}}",
"apihelp-xml-param-includexmlnamespace": "{{doc-apihelp-param|xml|includexmlnamespace}}",
@@ -1015,6 +1265,7 @@
"apihelp-yamlfm-description": "{{doc-apihelp-description|yamlfm|seealso=* {{msg-mw|apihelp-yaml-description}}}}",
"api-format-title": "{{technical}}\nPage title when API output is pretty-printed in HTML.",
"api-format-prettyprint-header": "{{technical}} Displayed as a header when API output is pretty-printed in HTML.\n\nParameters:\n* $1 - Format name\n* $2 - Non-pretty-printing module name",
+ "api-format-prettyprint-header-only-html": "{{technical}} Displayed as a header when API output is pretty-printed in HTML, but there is no non-html module.\n\nParameters:\n* $1 - Format name",
"api-orm-param-props": "{{doc-apihelp-param|orm|props|description=the \"props\" parameter in subclasses of ApiQueryORM}}",
"api-orm-param-limit": "{{doc-apihelp-param|orm|limit|description=the \"limit\" parameter in subclasses of ApiQueryORM}}",
"api-pageset-param-titles": "{{doc-apihelp-param|pageset|titles|description=the \"titles\" parameter in pageset-using modules}}",
@@ -1030,17 +1281,30 @@
"api-help-fallback-description": "{{notranslate}}",
"api-help-fallback-parameter": "{{notranslate}}",
"api-help-fallback-example": "{{notranslate}}",
- "api-help-flags": "{{optional}} Label for the API help flags box\n\nParameters:\n* $1 - Number of flags to be displayed",
+ "api-help-flags": "{{ignored}} Label for the API help flags box\n\nParameters:\n* $1 - Number of flags to be displayed",
"api-help-flag-deprecated": "Flag displayed for an API module that is deprecated",
"api-help-flag-internal": "Flag displayed for an API module that is considered internal or unstable",
"api-help-flag-readrights": "Flag displayed for an API module that requires read rights",
"api-help-flag-writerights": "Flag displayed for an API module that requires write rights",
"api-help-flag-mustbeposted": "Flag displayed for an API module that only accepts POST requests",
"api-help-flag-generator": "Flag displayed for an API module that can be used as a generator",
- "api-help-help-urls": "{{optional}} Label for the API help urls section\n\nParameters:\n* $1 - Number of urls to be displayed",
+ "api-help-source": "Displayed in the flags box to indicate the source of an API module.\n\nParameters:\n* $1 - Possibly-localised extension name, or \"MediaWiki\" if it's a core module\n* $2 - Non-localised extension name.\n\nSee also:\n* {{msg-mw|api-help-source-unknown}}",
+ "api-help-source-unknown": "Displayed in the flags box to indicate that the source of an API module is not known.\n\nSee also:\n* {{msg-mw|api-help-source}}",
+ "api-help-license": "Displayed in the flags box to indicate the license of an API module.\n\nParameters:\n* $1 - Page to link to display the full license text\n* $2 - Display text for the link\n\nSee also:\n* {{msg-mw|api-help-license-noname}}\n* {{msg-mw|api-help-license-unknown}}",
+ "api-help-license-noname": "Displayed in the flags box to indicate the license of an API module, when the tag for the license is not known.\n\nParameters:\n* $1 - Page to link to display the full license text\n\nSee also:\n* {{msg-mw|api-help-license}}\n* {{msg-mw|api-help-license-unknown}}",
+ "api-help-license-unknown": "Displayed in the flags box to indicate that the license of the API module is not known.\n\nSee also:\n* {{msg-mw|api-help-license}}\n* {{msg-mw|api-help-license-noname}}",
+ "api-help-help-urls": "{{ignored}} Label for the API help urls section\n\nParameters:\n* $1 - Number of urls to be displayed",
"api-help-parameters": "Label for the API help parameters section\n\nParameters:\n* $1 - Number of parameters to be displayed\n{{Identical|Parameter}}",
"api-help-param-deprecated": "Displayed in the API help for any deprecated parameter\n{{Identical|Deprecated}}",
"api-help-param-required": "Displayed in the API help for any required parameter",
+ "api-help-datatypes-header": "Header for the data type section in the API help output",
+ "api-help-datatypes": "{{technical}} {{doc-important|Do not translate or reformat dates inside &lt;kbd%gt; tags}} Documentation of certain API data types\nSee also:\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
+ "api-help-param-type-limit": "{{technical}} {{doc-important|Do not translate text inside &lt;kbd%gt; tags}} Used to indicate that a parameter is a \"limit\" type. Parameters:\n* $1 - Always 1.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
+ "api-help-param-type-integer": "{{technical}} Used to indicate that a parameter is an integer or list of integers. Parameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes a list of values.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
+ "api-help-param-type-boolean": "{{technical}} {{doc-important|Do not translate <code>Special:ApiHelp</code> in this message.}} Used to indicate that a parameter is a boolean. Parameters:\n* $1 - Always 1.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
+ "api-help-param-type-password": "{{ignored}}{{technical}} Used to indicate that a parameter is a password or list of passwords. Parameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes a list of values.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
+ "api-help-param-type-timestamp": "{{technical}} {{doc-important|Do not translate <code>Special:ApiHelp</code> in this message.}} Used to indicate that a parameter is a timestamp or list of timestamps. Parameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes a list of values.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
+ "api-help-param-type-user": "{{technical}} Used to indicate that a parameter is a username or list of usernames. Parameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes a list of values.\nSee also:\n* {{msg-mw|api-help-datatypes}}\n* [[Special:PrefixIndex/MediaWiki:api-help-param-type]]",
"api-help-param-list": "Used to display the possible values for a parameter taking a list of values\n\nParameters:\n* $1 - 1 if the parameter takes one value, 2 if the parameter takes any number of values\n* $2 - Comma-separated list of values, possibly formatted using {{msg-mw|api-help-param-list-can-be-empty}}\n{{Identical|Value}}",
"api-help-param-list-can-be-empty": "Used to indicate that one of the possible values in the list is the empty string.\n\nParameters:\n* $1 - Number of items in the rest of the list; may be 0\n* $2 - Remainder of the list as a comma-separated string",
"api-help-param-limit": "Used to display the maximum value of a limit parameter\n\nParameters:\n* $1 - Maximum value",
diff --git a/includes/api/i18n/ru.json b/includes/api/i18n/ru.json
index e533d799..56b3f5b4 100644
--- a/includes/api/i18n/ru.json
+++ b/includes/api/i18n/ru.json
@@ -4,14 +4,19 @@
"Mahairod",
"Okras",
"Eakarpov",
- "Kaganer"
+ "Kaganer",
+ "Mariya",
+ "Дмитрий",
+ "WindEwriX",
+ "Ochilov",
+ "Nzeemin"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Документация]]\n* [[mw:API:FAQ|ЧаВО]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Почтовая рассылка]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Новости API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Ошибки и запросы]\n</div>\n<strong>Статус:</strong> Все отображаемые на этой странице функции должны работать, однако API находится в статусе активной разработки, и может измениться в любой момент. Подпишитесь на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ почтовую рассылку mediawiki-api-announce], чтобы быть в курсе обновлений.\n\n<strong>Ошибочные запросы:</strong> Если API получает запрос с ошибкой, вернётся заголовок HTTP с ключом \"MediaWiki-API-Error\", после чего значение заголовка и код ошибки будут отправлены обратно и установлены в то же значение. Более подробную информацию см. [[mw:API:Errors_and_warnings|API: Ошибки и предупреждения]].",
"apihelp-main-param-action": "Действие, которое следует выполнить.",
"apihelp-main-param-format": "Формат вывода.",
- "apihelp-main-param-smaxage": "Устанавливает заголовок <code>s-maxage</code> в заданное число секунд. Ошибки никогда не кэшируются.",
- "apihelp-main-param-maxage": "Устанавливает заголовок <code>max-age</code> в заданное число секунд. Ошибки никогда не кэшируются.",
+ "apihelp-main-param-smaxage": "Устанавливает значение HTTP-заголовка Cache-Control <code>s-maxage</code> в заданное число секунд. Ошибки никогда не кэшируются.",
+ "apihelp-main-param-maxage": "Устанавливает значение HTTP-заголовка Cache-Control <code>s-maxage</code> в заданное число секунд. Ошибки никогда не кэшируются.",
"apihelp-main-param-assert": "Удостовериться, что пользователь авторизован, если задано <kbd>user</kbd>, или что имеет права бота, если задано <kbd>bot</kbd>.",
"apihelp-main-param-requestid": "Любое заданное здесь значение будет включено в ответ. Может быть использовано для различения запросов.",
"apihelp-main-param-servedby": "Включить в результаты имя хоста, обработавшего запрос.",
@@ -20,36 +25,222 @@
"apihelp-block-description": "Блокировка участника.",
"apihelp-block-param-user": "Имя участника, IP-адрес или диапазон IP-адресов, которые вы хотите заблокировать.",
"apihelp-block-param-reason": "Причина блокировки.",
+ "apihelp-block-param-anononly": "Блокировать только анонимных пользователей (т. е. запретить анонимные правки для этого IP-адреса).",
"apihelp-block-param-nocreate": "Запретить создание учётных записей.",
+ "apihelp-block-param-watchuser": "Следить за страницей пользователя или IP-участника и страницей обсуждения.",
+ "apihelp-checktoken-param-type": "Тип маркера проходит тестирование.",
+ "apihelp-checktoken-param-token": "токен для проверки",
+ "apihelp-checktoken-param-maxtokenage": "Максимально допустимый возраст токена (в секундах).",
+ "apihelp-checktoken-example-simple": "Проверить годность <kbd>csrf</kbd>-токена.",
+ "apihelp-clearhasmsg-description": "Очищает флаг <code>hasmsg</code> для текущего участника.",
+ "apihelp-clearhasmsg-example-1": "Очистить флаг <code>hasmsg</code> для текущего участника.",
+ "apihelp-compare-param-fromtitle": "Первый заголовок для сравнения.",
+ "apihelp-compare-param-fromid": "Первый идентификатор страницы для сравнения.",
+ "apihelp-compare-param-fromrev": "Первая редакция для сравнения.",
+ "apihelp-compare-param-totitle": "Второй заголовок для сравнения.",
+ "apihelp-compare-param-toid": "Второй идентификатор страницы для сравнения",
+ "apihelp-compare-param-torev": "Вторая версия для сравнения",
+ "apihelp-compare-example-1": "Создание различий между версиями 1 и 2.",
+ "apihelp-createaccount-description": "Создайте новую учетную запись Пользователя.",
"apihelp-createaccount-param-name": "Имя участника.",
+ "apihelp-createaccount-param-password": "Пароль (ignored if <var>$1mailpassword</var> is set).",
+ "apihelp-createaccount-param-domain": "Домен для внешней аутентификации (дополнительно).",
+ "apihelp-createaccount-param-token": "Создание учетной записи токена, полученные в первом запросе.",
+ "apihelp-createaccount-param-email": "Адрес электронной почты пользователя (дополнительно).",
+ "apihelp-createaccount-param-realname": "Настоящее имя пользователя (дополнительно).",
+ "apihelp-createaccount-param-mailpassword": "Если установлено любое значение, случайный пароль будет выслан пользователю.",
+ "apihelp-createaccount-param-reason": "Дополнительная причина создания учетной записи для записи в журнал.",
+ "apihelp-createaccount-param-language": "Установить код языка по умолчанию для пользователя (необязательный, по умолчанию используется язык содержимого).",
+ "apihelp-createaccount-example-pass": "Создать пользователя <kbd>testuser</kbd> с паролем <kbd>test123</kbd>.",
+ "apihelp-createaccount-example-mail": "Создать пользователя <kbd>testmailuser</kbd> и адрес электронной почты, сгенерировать случайный пароль.",
"apihelp-delete-description": "Удалить страницу.",
+ "apihelp-delete-param-title": "Заголовок страницы удалить. Совместное использование с <var>$1страницы</var> невозможно.",
"apihelp-delete-param-watch": "Добавить страницу к текущему списку наблюдения пользователя.",
+ "apihelp-delete-param-unwatch": "Удалить страницу из списка наблюдения текущего пользователя.",
+ "apihelp-delete-example-simple": "удалить <kbd>Main Page</kbd>.",
+ "apihelp-delete-example-reason": "Удалить <kbd>Main Page</kbd> причина <kbd>Preparing for move</kbd>.",
"apihelp-disabled-description": "Этот модуль был отключен.",
+ "apihelp-edit-description": "Создать и отредактировать страницы.",
"apihelp-edit-param-sectiontitle": "Заголовок для нового раздела.",
"apihelp-edit-param-text": "Содержание страницы.",
"apihelp-edit-param-minor": "Незначительное изменение (малая правка).",
"apihelp-edit-param-notminor": "Значительное изменение (обычная, не «малая», правка).",
"apihelp-edit-param-bot": "Пометить правку как сделанную ботом.",
+ "apihelp-edit-param-createonly": "Не редактировать страницу, если она уже существует.",
+ "apihelp-edit-param-nocreate": "Выбрасывать ошибку, если страницы не существует.",
"apihelp-edit-param-watch": "Добавить страницу к текущему списку наблюдения пользователя.",
+ "apihelp-edit-param-unwatch": "Удалить страницу из списка наблюдения текущего пользователя.",
+ "apihelp-edit-param-redirect": "Автоматически разрешать редиректы.",
+ "apihelp-edit-param-contentformat": "Формат сериализации содержимого, используемый для ввода текста.",
"apihelp-edit-example-edit": "Редактировать страницу",
+ "apihelp-emailuser-description": "Письмо участнику",
+ "apihelp-emailuser-param-target": "Адресат электронного письма",
+ "apihelp-emailuser-param-subject": "Заголовок темы.",
+ "apihelp-emailuser-param-text": "Содержание письма",
+ "apihelp-emailuser-param-ccme": "Отправить копию этого сообщения мне.",
+ "apihelp-emailuser-example-email": "Отправить письмо пользователю <kbd>WikiSysop</kbd> с текстом <kbd>контентом</kbd>.",
+ "apihelp-expandtemplates-description": "Разворачивает все шаблоны в wikitext.",
"apihelp-expandtemplates-param-title": "Заголовок страницы.",
+ "apihelp-expandtemplates-param-text": "Викитекст для конвертирования",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "Расширенный викитекст",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "Дерево разбора XML входных данных.",
+ "apihelp-feedcontributions-param-year": "От года (и ранее).",
+ "apihelp-feedcontributions-param-month": "От месяца (и ранее).",
+ "apihelp-feedcontributions-param-newonly": "Показывать только правки, являющиеся созданием страниц.",
+ "apihelp-feedcontributions-param-showsizediff": "Показать размер различия между версиями.",
+ "apihelp-feedrecentchanges-param-limit": "Максимальное число возвращаемых результатов.",
+ "apihelp-feedrecentchanges-param-from": "Показать изменения с тех пор.",
+ "apihelp-feedrecentchanges-param-hideminor": "Скрыть малые правки.",
+ "apihelp-feedrecentchanges-param-hidebots": "Скрыть правки ботов.",
+ "apihelp-feedrecentchanges-param-hideanons": "Скрыть изменения, внесённые анонимными участниками.",
+ "apihelp-feedrecentchanges-param-hidepatrolled": "Скрыть отпатруллированные правки.",
+ "apihelp-feedrecentchanges-param-hidemyself": "Скрыть изменения, сделанные текущим участником.",
+ "apihelp-feedrecentchanges-param-tagfilter": "Фильтр по тегам.",
+ "apihelp-feedrecentchanges-example-simple": "Список последних изменений.",
+ "apihelp-feedrecentchanges-example-30days": "Показать последние изменения в течение 30 дней.",
+ "apihelp-filerevert-param-comment": "Загрузить комментарий.",
+ "apihelp-help-example-main": "Помощь по главному модулю.",
+ "apihelp-help-example-recursive": "Вся справка в одном разделе.",
+ "apihelp-imagerotate-description": "Поворот одного или нескольких изображений.",
+ "apihelp-imagerotate-param-rotation": "На сколько градусов по часовой стрелке повернуть изображение.",
+ "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-param-summary": "Импорт итога",
"apihelp-import-param-xml": "Загруженный XML-файл.",
"apihelp-login-param-name": "Имя участника.",
"apihelp-login-param-password": "Пароль.",
"apihelp-login-param-domain": "Домен (необязательно).",
"apihelp-login-example-login": "Войти",
"apihelp-logout-description": "Выйти и очистить данные сессии.",
+ "apihelp-move-description": "Переместить страницу.",
+ "apihelp-move-param-reason": "Причина переименования.",
+ "apihelp-move-param-movetalk": "Переименовать страницу обсуждения, если она есть.",
+ "apihelp-move-param-movesubpages": "Переименовать подстраницы, если это применимо.",
+ "apihelp-move-param-noredirect": "Не создавать перенаправление.",
+ "apihelp-move-param-ignorewarnings": "Игнорировать предупреждения",
+ "apihelp-opensearch-param-search": "Строка поиска.",
+ "apihelp-opensearch-param-limit": "Максимальное число возвращаемых результатов.",
+ "apihelp-opensearch-param-namespace": "Пространства имён для поиска.",
+ "apihelp-options-example-reset": "Сбросить все настройки.",
+ "apihelp-paraminfo-param-helpformat": "Формат строк справки.",
+ "apihelp-parse-example-page": "анализ страницы",
+ "apihelp-parse-example-text": "Анализ wikitext.",
+ "apihelp-protect-example-protect": "Защитить страницу.",
+ "apihelp-purge-param-forcelinkupdate": "Обновление связей таблиц.",
+ "apihelp-query-param-list": "Какие списки использовать",
+ "apihelp-query-param-meta": "Какие метаданные использовать",
+ "apihelp-query+allcategories-description": "Перечислить все категории.",
+ "apihelp-query+allcategories-param-limit": "Сколько категорий вернуть.",
+ "apihelp-query+allcategories-param-prop": "Какие свойства получить:",
"apihelp-query+alllinks-example-unique-generator": "Получить все названия-ссылки, выделяя пропущенные.",
+ "apihelp-query+blocks-example-simple": "Список блоков.",
+ "apihelp-query+categories-param-limit": "Сколько категорий на возврат.",
+ "apihelp-query+categorymembers-param-sort": "Свойство для сортировки.",
+ "apihelp-query+categorymembers-param-startsortkey": "Использовать $1starthexsortkey вместо.",
+ "apihelp-query+categorymembers-param-endsortkey": "Использовать $1endhexsortkey вместо.",
"apihelp-query+duplicatefiles-example-generated": "Поиск дубликатов всех файлов.",
+ "apihelp-query+logevents-description": "Получать события из журналов.",
+ "apihelp-query+logevents-example-simple": "Список последних зарегистрированных событий.",
+ "apihelp-query+pagepropnames-example-simple": "Получить первые 10 имен свойств.",
+ "apihelp-query+pageswithprop-param-limit": "Максимальное количество страниц для возврата",
+ "apihelp-query+pageswithprop-param-dir": "В каком направлении сортировать",
+ "apihelp-query+prefixsearch-param-search": "Строка поиска.",
+ "apihelp-query+prefixsearch-param-offset": "Количество результатов для пропуска",
+ "apihelp-query+protectedtitles-example-simple": "Список защищенных заголовков",
+ "apihelp-query+querypage-param-limit": "Количество возвращаемых результатов.",
+ "apihelp-query+recentchanges-param-limit": "Какое общее количество возвращать",
+ "apihelp-query+recentchanges-param-type": "Какие типы изменений показать.",
"apihelp-query+recentchanges-example-simple": "Список последних изменений.",
+ "apihelp-query+redirects-param-limit": "Сколько перенаправлений вернуть.",
+ "apihelp-query+revisions-example-last5": "Получить последние 5 версий <kbd>Main Page</kbd>.",
+ "apihelp-query+revisions-example-first5": "Получить 5 первых версий <kbd>Main Page</kbd>.",
+ "apihelp-query+revisions-example-first5-after": "Получить 5 первых версий <kbd>Main Page</kbd> созданных после 2006-05-01.",
+ "apihelp-query+revisions-example-first5-not-localhost": "Получить 5 первых версий <kbd>Main Page</kbd> которые не созданы анонимными пользователями <kbd>127.0.0.1</kbd>.",
+ "apihelp-query+revisions-example-first5-user": "Получить 5 первых версий <kbd>Main Page</kbd> которые созданы пользователями <kbd>MediaWiki default</kbd>.",
+ "apihelp-query+revisions+base-param-limit": "Ограничение на количество версий которое будут вовзращено",
+ "apihelp-query+search-description": "Выполнить полнотекстовый поиск.",
+ "apihelp-query+tags-description": "Список изменерий тегов.",
+ "apihelp-query+tags-example-simple": "Лист доступных тегов",
+ "apihelp-query+templates-param-namespace": "Показывать шаблоны только из данного списка имен",
+ "apihelp-query+templates-param-limit": "Как много шаблонов для возврата",
+ "apihelp-query+transcludedin-param-limit": "Сколько возвращать",
+ "apihelp-query+usercontribs-description": "Получить все правки пользователя",
+ "apihelp-revisiondelete-description": "удалить и восстановить редакции",
+ "apihelp-unblock-description": "Разблокировать пользователя.",
+ "apihelp-unblock-param-reason": "Причина разблокировки",
+ "apihelp-unblock-example-id": "Разблокировать блок с идентификатором #<kbd>105</kbd>.",
+ "apihelp-unblock-example-user": "Разблокировать пользователя <kbd>Bob</kbd> по причине <kbd>Sorry Bob</kbd>.",
+ "apihelp-undelete-param-title": "Заголовок страницы для восстановления.",
+ "apihelp-undelete-param-reason": "Причины восстановления.",
+ "apihelp-undelete-example-page": "Восстановить страницу <kbd>Main Page</kbd>.",
+ "apihelp-undelete-example-revisions": "Восстановить две версии страницы <kbd>Main Page</kbd>.",
+ "apihelp-upload-param-filename": "целевое название файла",
+ "apihelp-upload-param-text": "Первоначальный текст страницы для новых файлов.",
+ "apihelp-upload-param-watch": "Наблюдать за этой страницей",
+ "apihelp-upload-param-ignorewarnings": "Игнорируйте любые предупреждения.",
+ "apihelp-upload-param-file": "Содержимое файла.",
+ "apihelp-upload-param-url": "URL-Адрес для извлечения файла из.",
+ "apihelp-upload-param-offset": "Смещение блока в байтах.",
+ "apihelp-upload-param-chunk": "Кусок содержимого.",
+ "apihelp-upload-param-asyncdownload": "Сделать извлечение URL-адреса асинхронно",
"apihelp-upload-example-url": "Загрузить через URL",
+ "apihelp-userrights-description": "Изменить членство в группе пользователей.",
+ "apihelp-userrights-param-user": "Имя пользователя",
+ "apihelp-userrights-param-userid": "Идентификатор пользователя.",
+ "apihelp-userrights-param-add": "Добавить пользователя в эти группы.",
+ "apihelp-userrights-param-remove": "Удалить пользователя из этих групп.",
+ "apihelp-userrights-param-reason": "Причина изменений",
+ "apihelp-watch-example-watch": "Следить за страницей <kbd>Main Page</kbd>.",
+ "apihelp-watch-example-unwatch": "Не следить за страницей <kbd>Main Page</kbd>.",
+ "apihelp-json-description": "Выходные данные в формате json.",
+ "apihelp-jsonfm-description": "Выходные данные в JSON формате (pretty-print in HTML).",
+ "apihelp-none-description": "Нечего выводить",
+ "apihelp-php-description": "Выходные данные в сериализованном формате PHP.",
+ "apihelp-phpfm-description": "Выходные данные в сериализованном формате PHP (pretty-print in HTML).",
+ "apihelp-xml-description": "Выходные данные в формате XML.",
+ "apihelp-yaml-description": "Выходные данные в формате yaml.",
+ "api-format-title": "Результат MediaWiki API",
+ "api-orm-param-props": "Поля для запроса.",
+ "api-orm-param-limit": "Максимальное количество возвращаемых строк.",
+ "api-pageset-param-titles": "Список заголовков для работы.",
+ "api-pageset-param-pageids": "Список страниц идентификаторов для работы.",
+ "api-pageset-param-revids": "Список идентификаторов версий для работы.",
+ "api-help-title": "Справка MediaWiki API",
"api-help-main-header": "Главный модуль",
+ "api-help-flag-deprecated": "Этот модуль является устаревшим.",
+ "api-help-flag-readrights": "Этот модуль требует прав на чтение.",
+ "api-help-flag-writerights": "Этот модуль требует права на запись.",
+ "api-help-flag-mustbeposted": "Этот модуль принимает только Post-запросы.",
+ "api-help-flag-generator": "Этот модуль может быть использован в качестве генератора.",
+ "api-help-source": "Источник: $1",
+ "api-help-source-unknown": "Источник: <span class=\"apihelp-unknown\">unknown</span>",
+ "api-help-license": "Лицензия: [[$1|$2]]",
+ "api-help-license-noname": "Лицензия: [[$1|See link]]",
+ "api-help-license-unknown": "Лицензия: <span class=\"apihelp-unknown\">unknown</span>",
"api-help-parameters": "Параметр{{PLURAL:$1||ы}}:",
"api-help-param-deprecated": "Устаревший.",
"api-help-param-required": "Этот параметр является обязательным.",
+ "api-help-datatypes-header": "Типы данных",
+ "api-help-param-type-limit": "Тип: целое число или <kbd>max</kbd>",
+ "api-help-param-type-integer": "Тип: {{PLURAL:$1|1=integer|2=list of integers}}",
+ "api-help-param-type-boolean": "Тип: двоичный ([[Special:ApiHelp/main#main/datatypes|details]])",
+ "api-help-param-type-timestamp": "Тип: {{PLURAL:$1|1=timestamp|2=list of timestamps}} ([[Special:ApiHelp/main#main/datatypes|allowed formats]])",
+ "api-help-param-type-user": "Тип: {{PLURAL:$1|1=user name|2=list of user names}}",
+ "api-help-param-list": "{{PLURAL:$1|1=One value|2=Values (separate with <kbd>{{!}}</kbd>)}}: $2",
+ "api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Должен быть пустым|может быть пустым, или $2}}",
+ "api-help-param-limit": "Не более чем $1 разрешено.",
+ "api-help-param-limit2": "Разрешено не более чем $1 ($2 для ботов).",
+ "api-help-param-integer-min": "{{PLURAL:$1|1=value|2=values}} должен быть не меньше чем $2.",
+ "api-help-param-integer-max": "{{PLURAL:$1|1=value|2=values}} должен быть не больше чем $3.",
+ "api-help-param-integer-minmax": "{{PLURAL:$1|1=value|2=values}} должен быть между $2 и $3.",
+ "api-help-param-multi-separate": "Разделяйте значения с помощью <kbd>|</kbd>.",
+ "api-help-param-multi-max": "Максимальное количество значений должно быть {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} для ботов).",
"api-help-param-default": "По умолчанию: $1",
"api-help-param-default-empty": "По умолчанию: <span class=\"apihelp-empty\">(пусто)</span>",
+ "api-help-param-continue": "Когда доступно больше результатов, использовать этот чтобы продолжить.",
"api-help-param-no-description": "<span class=\"apihelp-empty\">(описание отсутствует)</span>",
"api-help-examples": "Пример{{PLURAL:$1||ы}}:",
+ "api-help-permissions": "{{PLURAL:$1|Permission|Permissions}}:",
+ "api-help-permissions-granted-to": "{{PLURAL:$1|Granted to}}: $2",
"api-credits-header": "Создатели"
}
diff --git a/includes/api/i18n/shn.json b/includes/api/i18n/shn.json
new file mode 100644
index 00000000..a5804f6c
--- /dev/null
+++ b/includes/api/i18n/shn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Saosukham"
+ ]
+ },
+ "apihelp-feedrecentchanges-param-hidecategorization": "သိူင်ႇပၢႆး ၽူႈၶဝ်ႈၸုမ်းလႅၵ်ႈလၢႆႈ"
+}
diff --git a/includes/api/i18n/si.json b/includes/api/i18n/si.json
index a075a49f..6c30d8b7 100644
--- a/includes/api/i18n/si.json
+++ b/includes/api/i18n/si.json
@@ -17,6 +17,7 @@
"apihelp-help-example-main": "ප්‍රධාන ඒකකය සදහා උදවු කරන්න",
"apihelp-help-example-recursive": "සියලුම උදවු එක පිටුවක් තුල",
"apihelp-help-example-query": "සැකසහිත අනුඒකක සදහා උදවු කරන්න",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "මෙම පිටුව සඳහා වූ JavaScript වින්‍යාස විචල්‍යයන් ලබා දෙයි.",
"apihelp-format-example-generic": "$1 ආකෘතියේ ඇති සැක සහිත ප්‍රථිපල පරිවර්තනය කරන්න",
"apihelp-dbg-description": "ප්‍රතිදාන දත්ත PHP හි var_export() ආකෘතියෙන් පවතී.",
"apihelp-dbgfm-description": "ප්‍රතිදාන දත්ත PHP හි var_export() ආකෘතියෙන් පවතී (හොදම පිටපත HTML භාෂාවෙනි).",
diff --git a/includes/api/i18n/sq.json b/includes/api/i18n/sq.json
new file mode 100644
index 00000000..34d55afd
--- /dev/null
+++ b/includes/api/i18n/sq.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ammartivari"
+ ]
+ },
+ "apihelp-block-param-reason": "Arsyeja për bllokim.",
+ "apihelp-move-param-reason": "Arsyeja për riemërtim.",
+ "apihelp-tag-param-reason": "Arsyeja për ndërrimin.",
+ "apihelp-unblock-description": "Zhblloko një përdorues.",
+ "apihelp-userrights-description": "Ndërro anëtarësinë e grupit e një përdoruesit."
+}
diff --git a/includes/api/i18n/sv.json b/includes/api/i18n/sv.json
index aa88484f..83f4d808 100644
--- a/includes/api/i18n/sv.json
+++ b/includes/api/i18n/sv.json
@@ -11,7 +11,9 @@
"Boom",
"Jenniesarina",
"Marfuas",
- "VickyC"
+ "VickyC",
+ "Josve05a",
+ "Rockyfelle"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Dokumentation]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-postlista]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-aviseringar]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R|Buggar & förslag]\n</div>\n<strong>Status:</strong> Alla funktioner som visas på denna sida borde fungera. API:et är dock fortfarande under aktiv utveckling och kan ändras när som helst. Prenumerera på [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/mediawiki-api-announce e-postlistan] för att få aviseringar om uppdateringar.\n\n<strong>Felaktiga förfrågningar:</strong> När felaktiga förfrågningar skickas till API:et skickas en HTTP-header med nyckeln \"MediaWiki-API-Error\" och sedan sätts både värdet på headern och den felkoden som returneras till samma värde. För mer information läs [[mw:API:Errors_and_warnings|API: Fel och varningar]].",
@@ -19,7 +21,7 @@
"apihelp-main-param-format": "Formatet för utdata.",
"apihelp-main-param-smaxage": "Ange headervärdet <code>s-maxage</code> till så här många sekunder. Fel cachelagras aldrig.",
"apihelp-main-param-maxage": "Ange headervärdet <code>max-age</code> till så här många sekunder. Fel cachelagras aldrig.",
- "apihelp-main-param-assert": "Bekräftar att användaren är inloggad om satt till <kbd>user</kbd>, eller har bot-användarrättigheter om satt till <kbd>bot</kbd>.",
+ "apihelp-main-param-assert": "Bekräfta att användaren är inloggad om satt till <kbd>user</kbd>, eller har bot-användarrättigheter om satt till <kbd>bot</kbd>.",
"apihelp-main-param-requestid": "Alla värde som anges här kommer att inkluderas i svaret. Kan användas för att särskilja förfrågningar.",
"apihelp-main-param-servedby": "Inkludera det värdnamn som besvarade förfrågan i resultatet.",
"apihelp-main-param-curtimestamp": "Inkludera den aktuella tidsstämpeln i resultatet.",
@@ -39,6 +41,10 @@
"apihelp-block-param-watchuser": "Bevaka användarens eller IP-adressens användarsida och diskussionssida",
"apihelp-block-example-ip-simple": "Blockera IP-adressen <kbd>192.0.2.5</kbd> i tre dagar med motivationen <kbd>First strike</kbd>",
"apihelp-block-example-user-complex": "Blockera användare <kbd>Vandal</kbd> på obegränsad tid med motivationen <kbd>Vandalism</kbd>, och förhindra kontoskapande och e-post.",
+ "apihelp-checktoken-param-type": "Typ av token som testas.",
+ "apihelp-checktoken-param-token": "Token att testa.",
+ "apihelp-checktoken-param-maxtokenage": "Högsta tillåtna åldern för token, i sekunder.",
+ "apihelp-checktoken-example-simple": "Testa giltigheten av en <kbd>csrf</kbd>-token.",
"apihelp-clearhasmsg-description": "Rensa <code>hasmsg</code>-flaggan för den aktuella användaren.",
"apihelp-clearhasmsg-example-1": "Rensa <code>hasmsg</code>-flaggan för den aktuella användaren",
"apihelp-compare-description": "Hämta skillnaden mellan två sidor.\n\nEtt versionsnummer, en sidtitel, eller ett sid-Id för både \"from\" och \"to\" måste skickas.",
@@ -79,6 +85,7 @@
"apihelp-edit-param-sectiontitle": "Rubriken för ett nytt avsnitt.",
"apihelp-edit-param-text": "Sidans innehåll.",
"apihelp-edit-param-summary": "Redigeringssammanfattning. Även avsnittets rubrik när $1section=new och $1sectiontitle inte anges.",
+ "apihelp-edit-param-tags": "Ändra taggar till att gälla för revideringen.",
"apihelp-edit-param-minor": "Mindre redigering.",
"apihelp-edit-param-notminor": "Icke-mindre redigering.",
"apihelp-edit-param-bot": "Markera denna redigering som robotredigering.",
@@ -93,11 +100,14 @@
"apihelp-edit-param-md5": "MD5-hash för $1text-parametern, eller $1prependtext- och $1appendtext-parametrarna sammanfogade.",
"apihelp-edit-param-prependtext": "Lägg till denna text i början på sidan. Ersätter $1text.",
"apihelp-edit-param-appendtext": "Lägg till denna text i slutet på sidan. Ersätter $1text.\n\nAnvänd $1section=new för att lägga till en ny sektion, hellre än denna parameter.",
+ "apihelp-edit-param-undo": "Ångra denna sidversion. Skriver över $1text, $1prependtext och $1appendtext.",
+ "apihelp-edit-param-undoafter": "Ångra alla sidversioner från $1undo till denna. Om inte, ångra endast en sidversion.",
"apihelp-edit-param-redirect": "Åtgärda automatiskt omdirigeringar.",
"apihelp-edit-param-contentformat": "Det serialiseringsformat som används för indatatexten.",
"apihelp-edit-param-contentmodel": "Det nya innehållets innehållsmodell.",
"apihelp-edit-param-token": "Token ska alltid skickas som sista parameter, eller åtminstone efter $1text-parametern",
"apihelp-edit-example-edit": "Redigera en sida",
+ "apihelp-edit-example-undo": "Ångra sidversioner 13579 till 13585 med automatisk sammanfattning.",
"apihelp-emailuser-description": "Skicka e-post till en användare.",
"apihelp-emailuser-param-target": "Användare att skicka e-post till.",
"apihelp-emailuser-param-subject": "Ämnesrubrik.",
@@ -108,6 +118,7 @@
"apihelp-expandtemplates-param-title": "Sidans rubrik.",
"apihelp-expandtemplates-param-text": "Wikitext att konvertera.",
"apihelp-expandtemplates-param-revid": "Revision ID, för <nowiki>{{REVISIONID}}</nowiki> och liknande variabler.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "Den expanderade wikitexten.",
"apihelp-expandtemplates-param-includecomments": "Om HTML-kommentarer skall inkluderas i utdata.",
"apihelp-expandtemplates-param-generatexml": "Generera ett XML tolknings träd (ersatt av $1prop=parsetree).",
"apihelp-expandtemplates-example-simple": "Expandera wikitexten <kbd><nowiki>{{Projekt:Sandbox}}</nowiki></kbd>.",
@@ -162,6 +173,7 @@
"apihelp-help-example-main": "Hjälp för huvudmodul",
"apihelp-help-example-recursive": "All hjälp på en sida",
"apihelp-help-example-help": "Hjälp för själva hjälpmodulen",
+ "apihelp-help-example-query": "Hjälp för två frågeundermoduler.",
"apihelp-imagerotate-description": "Rotera en eller flera bilder.",
"apihelp-imagerotate-param-rotation": "Grader att rotera bild medurs.",
"apihelp-imagerotate-example-simple": "Rotera <kbd>File:Example.png</kbd> med <kbd>90</kbd> grader",
@@ -173,9 +185,9 @@
"apihelp-import-param-interwikipage": "För interwiki-importer: sidan som du vill importera.",
"apihelp-import-param-fullhistory": "För interwiki-importer: importera hela historiken, inte bara den aktuella versionen.",
"apihelp-import-param-templates": "För interwiki-importer: importera även alla mallar som ingår.",
- "apihelp-import-param-namespace": "För interwiki-importer: importera till denna namnrymd.",
- "apihelp-import-param-rootpage": "Importera som undersida till denna sida.",
- "apihelp-import-example-import": "Importera [[meta:Help:Parserfunktioner]] till namnrymd 100 med full historik.",
+ "apihelp-import-param-namespace": "Importera till denna namnrymd. Kan inte användas tillsammans med <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Importera som undersida till denna sida. Kan inte användas tillsammans med <var>$1namespace</var>.",
+ "apihelp-import-example-import": "Importera [[meta:Help:ParserFunctions]] till namnrymd 100 med full historik.",
"apihelp-login-description": "Logga in och hämta autentiserings-cookies.\n\nOm inloggningen lyckas, finns de cookies som krävs med i HTTP-svarshuvuden. Om inloggningen misslyckas kan ytterligare försök per tidsenhet begränsas, som ett sätt att försöka minska risken för automatiserade lösenordsgissningar.",
"apihelp-login-param-name": "Användarnamn.",
"apihelp-login-param-password": "Lösenord.",
@@ -222,6 +234,8 @@
"apihelp-parse-param-summary": "Sammanfattning att tolka.",
"apihelp-parse-param-page": "Tolka innehållet av denna sida. Kan inte användas tillsammans med <var>$1text</var> och <var>$1title</var>.",
"apihelp-parse-param-pageid": "Tolka innehållet på denna sida. Åsidosätter <var>$1sidan</var>.",
+ "apihelp-parse-param-prop": "Vilka bitar av information att få:",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Ger HTML-version av kategorierna.",
"apihelp-parse-param-preview": "Tolka i preview-läget.",
"apihelp-parse-example-page": "Tolka en sida.",
"apihelp-parse-example-text": "Tolka wikitext.",
@@ -235,6 +249,8 @@
"apihelp-protect-example-protect": "Skydda en sida",
"apihelp-query-param-list": "Vilka listor att hämta.",
"apihelp-query-param-meta": "Vilka metadata att hämta.",
+ "apihelp-query-example-allpages": "Hämta sidversioner av sidor som börjar med <kbd>API/</kbd>.",
+ "apihelp-query+allcategories-param-prefix": "Sök efter alla kategorititlar som börjar med detta värde.",
"apihelp-query+allcategories-param-dir": "Riktning att sortera mot.",
"apihelp-query+allcategories-param-min": "Returnera endast kategorier med minst så här många medlemmar.",
"apihelp-query+allcategories-param-max": "Returnera endast kategorier med som mest så här många medlemmar.",
@@ -249,6 +265,7 @@
"apihelp-query+alldeletedrevisions-param-user": "Lista bara revideringar av denna användaren.",
"apihelp-query+alldeletedrevisions-param-excludeuser": "Lista inte revideringar av denna användaren.",
"apihelp-query+alldeletedrevisions-param-namespace": "Lista bara sidor i denna namnrymd.",
+ "apihelp-query+alldeletedrevisions-example-user": "List de senaste 50 raderade bidragen av användaren <kbd>Example<kbd>.",
"apihelp-query+alldeletedrevisions-example-ns-main": "Lista dem första 50 revideringarna i huvud-namnrymden",
"apihelp-query+allfileusages-description": "Lista all fil användningsområden, inklusive icke-existerande.",
"apihelp-query+allfileusages-param-prefix": "Sök för all fil-titlar som börjar med detta värde.",
@@ -300,9 +317,15 @@
"apihelp-query+allpages-param-limit": "Hur många sidor att returnera totalt.",
"apihelp-query+allpages-param-dir": "Riktningen att lista mot.",
"apihelp-query+allpages-example-B": "Visa en lista över sidor som börjar på bokstaven <kbd>B</kbd>.",
+ "apihelp-query+allpages-example-generator": "Visa information om fyra sidor som börjar på bokstaven <kbd>T</kbd>.",
+ "apihelp-query+allredirects-description": "Lista alla omdirigeringar till en namnrymd.",
"apihelp-query+allredirects-param-dir": "Riktningen att lista mot.",
"apihelp-query+allredirects-example-unique-generator": "Hämtar alla målsidor, markerar de som saknas.",
+ "apihelp-query+alltransclusions-description": "Lista alla mallinkluderingar (sidor inbäddade med &#123;&#123;x&#125;&#125;), inklusive icke-befintliga.",
+ "apihelp-query+alltransclusions-param-limit": "Hur många objekt att returnera.",
"apihelp-query+alltransclusions-param-dir": "Riktningen att lista mot.",
+ "apihelp-query+alltransclusions-example-unique": "Lista unika mallinkluderade titlar.",
+ "apihelp-query+alltransclusions-example-unique-generator": "Hämtar alla mallinkluderade titlar, markerar de som saknas.",
"apihelp-query+allusers-param-prefix": "Sök för alla användare som börjar med detta värde.",
"apihelp-query+allusers-param-dir": "Riktning att sortera i.",
"apihelp-query+allusers-param-group": "Inkludera bara användare i de givna grupperna.",
@@ -314,17 +337,57 @@
"apihelp-query+allusers-example-Y": "Lista användare som börjar på <kbd>Y</kbd>.",
"apihelp-query+backlinks-description": "Hitta alla sidor som länkar till den givna sidan.",
"apihelp-query+backlinks-param-dir": "Riktningen att lista mot.",
+ "apihelp-query+backlinks-example-simple": "Visa länkar till <kbd>huvudsidan<kbd>.",
+ "apihelp-query+blocks-description": "Lista alla blockerade användare och IP-adresser.",
+ "apihelp-query+blocks-param-prop": "Vilka egenskaper att hämta.",
+ "apihelp-query+blocks-paramvalue-prop-id": "Lägger till ID på blocket.",
+ "apihelp-query+blocks-paramvalue-prop-user": "Lägger till användarnamn för den blockerade användaren.",
+ "apihelp-query+blocks-paramvalue-prop-userid": "Lägger till användar-ID för den blockerade användaren.",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "Lägger till en tidsstämpel för när blockeringen gavs.",
+ "apihelp-query+blocks-paramvalue-prop-expiry": "Lägger till en tidsstämpel för när blockeringen går ut.",
+ "apihelp-query+blocks-paramvalue-prop-reason": "Lägger till de skäl som angetts för blockeringen.",
+ "apihelp-query+blocks-paramvalue-prop-range": "Lägger till intervallet av IP-adresser som berörs av blockeringen.",
+ "apihelp-query+blocks-example-simple": "Lista blockeringar.",
+ "apihelp-query+blocks-example-users": "Lista blockeringar av användarna <kbd>Alice</kbd> och <kbd>Bob</kbd>.",
+ "apihelp-query+categories-description": "Lista alla kategorier sidorna tillhör.",
+ "apihelp-query+categories-param-show": "Vilka sorters kategorier att visa.",
+ "apihelp-query+categories-param-limit": "Hur många kategorier att returnera.",
"apihelp-query+categories-param-dir": "Riktningen att lista mot.",
+ "apihelp-query+categories-example-simple": "Hämta en lista över kategorier som sidan <kbd>Albert Einstein</kbd> tillhör.",
+ "apihelp-query+categories-example-generator": "Hämta information om alla kategorier som används på sidan <kbd>Albert Einstein</kbd>.",
+ "apihelp-query+categoryinfo-description": "Returnerar information om angivna kategorier.",
+ "apihelp-query+categoryinfo-example-simple": "Hämta information om <kbd>Category:Foo</kbd> och <kbd>Category:Bar</kbd>.",
+ "apihelp-query+categorymembers-description": "Lista alla sidor i en angiven kategori.",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "Lägger till sid-ID.",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "Lägger till titeln och namnrymds-ID för sidan.",
+ "apihelp-query+categorymembers-param-dir": "I vilken riktning att sortera.",
+ "apihelp-query+categorymembers-param-startsortkey": "Använd $1starthexsortkey istället.",
+ "apihelp-query+categorymembers-param-endsortkey": "Använd $1endhexsortkey istället.",
+ "apihelp-query+categorymembers-example-simple": "Hämta de tio första sidorna i <kbd>Category:Physics</kbd>.",
+ "apihelp-query+categorymembers-example-generator": "Hämta sidinformation om de tio första sidorna i <kbd>Category:Physics</kbd>.",
+ "apihelp-query+contributors-description": "Hämta listan över inloggade bidragsgivare och antalet anonyma bidragsgivare för en sida.",
+ "apihelp-query+contributors-param-limit": "Hur många bidragsgivare att returnera.",
+ "apihelp-query+deletedrevisions-param-user": "Lista endast sidversioner av denna användare.",
+ "apihelp-query+deletedrevisions-param-excludeuser": "Lista inte sidversioner av denna användare.",
+ "apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|Läge|Lägen}}: $2",
+ "apihelp-query+deletedrevs-param-from": "Börja lista vid denna titel.",
+ "apihelp-query+deletedrevs-param-to": "Sluta lista vid denna titel.",
"apihelp-query+duplicatefiles-param-dir": "Riktningen att lista mot.",
"apihelp-query+duplicatefiles-example-generated": "Leta efter kopior av alla filer.",
"apihelp-query+embeddedin-param-dir": "Riktningen att lista mot.",
"apihelp-query+embeddedin-param-limit": "Hur många sidor att returnera totalt.",
"apihelp-query+filearchive-param-dir": "Riktningen att lista mot.",
+ "apihelp-query+filearchive-paramvalue-prop-timestamp": "Lägger till tidsstämpel för den uppladdade versionen.",
+ "apihelp-query+filearchive-paramvalue-prop-user": "Lägger till användaren som laddade upp bildversionen.",
"apihelp-query+filearchive-example-simple": "Visa en lista över alla borttagna filer.",
+ "apihelp-query+fileusage-paramvalue-prop-title": "Titel för varje sida.",
+ "apihelp-query+fileusage-paramvalue-prop-redirect": "Flagga om sidan är en omdirigering.",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "Lägg till det användar-ID som laddade upp varje filversion.",
"apihelp-query+images-param-dir": "Riktningen att lista mot.",
"apihelp-query+imageusage-param-dir": "Riktningen att lista mot.",
"apihelp-query+imageusage-example-simple": "Visa sidor med hjälp av [[:File:Albert Einstein Head.jpg]].",
"apihelp-query+imageusage-example-generator": "Hämta information om sidor med hjälp av [[:File:Albert Einstein Head.jpg]].",
+ "apihelp-query+info-description": "Få grundläggande sidinformation.",
"apihelp-query+iwbacklinks-param-limit": "Hur många sidor att returnera totalt.",
"apihelp-query+iwbacklinks-param-dir": "Riktningen att lista mot.",
"apihelp-query+iwlinks-param-dir": "Riktningen att lista mot.",
@@ -365,7 +428,7 @@
"api-help-parameters": "{{PLURAL:$1|Parameter|Parametrar}}:",
"api-help-param-deprecated": "Föråldrad.",
"api-help-param-required": "Denna parameter är obligatorisk.",
- "api-help-param-list": "{{PLURAL:$1|1=ett värde|2=värden (separade med \"{{!}}\")}}: $2",
+ "api-help-param-list": "{{PLURAL:$1|1=Ett värde|2=Värden (separerade med <kbd>{{!}}</kbd>)}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Måste vara tom|Kan vara tom, eller $2}}",
"api-help-param-limit": "Inte mer än $1 tillåts.",
"api-help-param-limit2": "Inte mer än $1 ($2 för robotar) tillåts."
diff --git a/includes/api/i18n/ta.json b/includes/api/i18n/ta.json
new file mode 100644
index 00000000..04e9a432
--- /dev/null
+++ b/includes/api/i18n/ta.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "AntanO",
+ "கலைவாணன்"
+ ]
+ },
+ "apihelp-import-param-namespace": "இதனைப் பெயர்வெளிக்கு இறக்குமதி செய்யவும். <kbd>$1rootpage</kbd> அளவுருவை மீறச்செய்யும்.",
+ "apihelp-import-param-rootpage": "இப்பக்கத்தின் துணைப்பக்கமாக இறக்குமதி செய்யவும். <kbd>$1namespace</kbd> அளவுரு வழங்கப்பட்டிருந்தால் இது புறக்கணிக்கப்படும்.",
+ "api-help-source": "மூலம்: $1",
+ "api-help-license": "அனுமதி: [[$1|$2]]",
+ "api-help-license-noname": "அனுமதி: [[$1|இணைப்பைப் பார்]]"
+}
diff --git a/includes/api/i18n/tr.json b/includes/api/i18n/tr.json
index 3a9ff258..4b610857 100644
--- a/includes/api/i18n/tr.json
+++ b/includes/api/i18n/tr.json
@@ -1,9 +1,17 @@
{
"@metadata": {
"authors": [
- "Sayginer"
+ "Sayginer",
+ "Sadrettin",
+ "Uğurkent"
]
},
+ "apihelp-createaccount-param-name": "Kullanıcı adı.",
+ "apihelp-createaccount-param-password": "Parola (ignored if <var>$1mailpassword</var> is set).",
+ "apihelp-createaccount-param-email": "Kullanıcının e-posta adresi (isteğe bağlı).",
+ "apihelp-createaccount-param-realname": "Kullanıcının gerçek adı (isteğe bağlı).",
+ "apihelp-delete-description": "Sayfayı sil.",
+ "apihelp-edit-description": "Sayfa oluştur ve düzenle.",
"apihelp-edit-param-text": "Sayfa içeriği.",
"apihelp-edit-param-minor": "Küçük değişiklik.",
"apihelp-edit-param-nocreate": "Sayfa mevcut değilse hata oluştur.",
@@ -27,6 +35,8 @@
"apihelp-feedrecentchanges-example-simple": "Son değişiklikleri göster",
"apihelp-feedrecentchanges-example-30days": "Son 30 gündeki değişiklikleri göster",
"apihelp-filerevert-description": "Bir dosyayı eski bir sürümüne geri döndür.",
+ "apihelp-login-param-name": "Kullanıcı adı.",
+ "apihelp-login-param-password": "Parola.",
"apihelp-move-description": "Bir sayfayı taşı.",
"apihelp-move-param-from": "Taşımak istediğiniz sayfanın başlığı. $1fromid ile birlikte kullanılamaz.",
"apihelp-move-param-noredirect": "Yönlendirme oluşturmayın.",
diff --git a/includes/api/i18n/uk.json b/includes/api/i18n/uk.json
index 13ce4907..194e10ff 100644
--- a/includes/api/i18n/uk.json
+++ b/includes/api/i18n/uk.json
@@ -2,18 +2,105 @@
"@metadata": {
"authors": [
"Ата",
- "A1"
+ "A1",
+ "Ahonc",
+ "Base",
+ "Dars",
+ "Umherirrender"
]
},
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Документація]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Список розсилки]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Оголошення API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Баґи і запити]\n</div>\n<strong>Статус:</strong> Усі функції, вказані на цій сторінці, мають працювати, але API далі перебуває в активній розробці і може змінитися у будь-який момент. Підпишіться на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ список розсилки mediawiki-api-announce], щоб помічати оновлення.\n\n<strong>Хибні запити:</strong> Коли до API надсилаються хибні запити, буде відіслано HTTP-шапку з ключем «MediaWiki-API-Error», а тоді і значення шапки, і код помилки, надіслані назад, будуть встановлені з тим же значенням. Більше інформації див. на [[mw:API:Errors_and_warnings|API: Errors and warnings]].",
"apihelp-main-param-action": "Яку дію виконати.",
"apihelp-main-param-format": "Формат виводу.",
+ "apihelp-main-param-maxlag": "Максимальна затримка може використовуватися, коли MediaWiki інстальовано на реплікований кластер бази даних. Щоб зберегти дії, які спричиняють більшу затримку реплікації, цей параметр може змусити клієнт почекати, поки затримка реплікації не буде меншою за вказане значення. У випадку непомірної затримки, видається код помилки <samp>maxlag</samp> з повідомленням на зразок <samp>Очікування на $host: $lag секунд(и) затримки</samp>.<br />Див. [[mw:Manual:Maxlag_parameter|Manual: Maxlag parameter]] для детальнішої інформації.",
+ "apihelp-main-param-smaxage": "Встановити <code>s-maxage</code> HTTP кеш-контроль заголовок на стільки секунд. Помилки ніколи не кешуються.",
+ "apihelp-main-param-maxage": "Встановити <code>max-age</code> HTTP кеш-контроль заголовок на стільки секунд. Помилки ніколи не кешуються.",
+ "apihelp-main-param-assert": "Перевірити, що користувач увійшов у систему, якщо задано <kbd>user</kbd>, або має права бота, якщо задано <kbd>bot</kbd>.",
+ "apihelp-main-param-requestid": "Будь-яке значення, вказане тут, буде включене у відповідь. Може використовуватися, щоб відрізняти запити.",
+ "apihelp-main-param-servedby": "Включити в результати ім'я хоста, який обробив запит.",
+ "apihelp-main-param-curtimestamp": "Включити в результат поточну мітку часу.",
+ "apihelp-main-param-origin": "При доступі до API з використанням крос-доменного AJAX-запиту (CORS), задайте параметру значення вихідного домена. Він має бути включений у будь-який попередній запит і таким чином мусить бути частиною запиту URI (не тіла POST). Він повинен точно співпадати з одним з виходів у заголовку <code>Origin</code>, тобто бути заданим чимось на зразок <kbd>https://uk.wikipedia.org</kbd> або <kbd>https://meta.wikimedia.org</kbd>. Якщо цей параметр не співпадає з заголовком <code>Origin</code>, повернеться помилка 403. Якщо цей параметр співпадає з заголовком <code>Origin</code> і вихід знаходиться у білому списку, буде встановлено заголовок <code>Access-Control-Allow-Origin</code>.",
+ "apihelp-main-param-uselang": "Мова, що використовується для перекладу повідомлень. Список кодів можна знайти на <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> з <kbd>siprop=languages</kbd> або вказати <kbd>user</kbd> на використання поточного налаштування мови користувача, або вказати <kbd>content</kbd> на використання мови вмісту цієї вікі.",
"apihelp-block-description": "Заблокувати користувача.",
"apihelp-block-param-user": "Ім'я користувача, IP-адреса або діапазон IP-адрес для блокування.",
+ "apihelp-block-param-expiry": "Закінчення часу. Може бути відносним (напр., <kbd>5 місяців</kbd> або <kbd>2 тижні</kbd>) чи абсолютним (напр., <kbd>2014-09-18T12:34:56Z</kbd>). Якщо вказано <kbd>infinite</kbd>, <kbd>indefinite</kbd> або <kbd>never</kbd>, блокування не закінчиться ніколи.",
"apihelp-block-param-reason": "Причина блокування.",
+ "apihelp-block-param-anononly": "Блокувати тільки анонімних користувачів (тобто відключити можливість анонімних редагувань з цієї IP-адреси).",
"apihelp-block-param-nocreate": "Заборонити створення облікових записів.",
+ "apihelp-block-param-autoblock": "Автоматично блокувати IP-адреси, які цей користувач використовував останніми, та будь-які наступні адреси, з яких він спробує зайти в систему.",
+ "apihelp-block-param-noemail": "Заборонити користувачеві надсилати електронні листи через вікі. (Вимагає права <code>blockemail</code>).",
+ "apihelp-block-param-hidename": "Приховати ім'я користувача з журналу блокувань. (Вимагає права <code>hideuser</code>).",
+ "apihelp-block-param-allowusertalk": "Дозволити користувачу редагувати власну сторінку обговорення (залежить від <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
+ "apihelp-block-param-reblock": "Якщо користувач уже заблокований, переписати наявне блокування.",
+ "apihelp-block-param-watchuser": "Спостерігати за сторінкою користувача чи IP-адреси і сторінкою обговорення.",
+ "apihelp-block-example-ip-simple": "Блокувати IP-адресу <kbd>192.0.2.5</kbd> на три дні з причиною <kbd>First strike</kbd>.",
+ "apihelp-block-example-user-complex": "Блокувати користувача<kbd>Vandal</kbd> на невизначений термін з причиною <kbd>Vandalism</kbd> і заборонити створення нових облікових записів та надсилання електронної пошти.",
+ "apihelp-checktoken-description": "Перевірити коректність токена з <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
+ "apihelp-checktoken-param-type": "Тип токена, який тестується.",
+ "apihelp-checktoken-param-token": "Токен для тесту.",
+ "apihelp-checktoken-param-maxtokenage": "Максимально допустимий вік токена (у секундах).",
+ "apihelp-checktoken-example-simple": "Перевірити дійсність токена <kbd>csrf</kbd>.",
+ "apihelp-clearhasmsg-description": "Очищає прапорець <code>hasmsg</code> для поточного користувача.",
+ "apihelp-clearhasmsg-example-1": "Очистити прапорець <code>hasmsg</code> для поточного користувача.",
+ "apihelp-compare-description": "Отримати порівняння двох сторінок.\n\nПовинні бути номер версії, назва сторінки або ID сторінки для «від» і «до».",
+ "apihelp-compare-param-fromtitle": "Перший заголовок для порівняння.",
+ "apihelp-compare-param-fromid": "Перший ID сторінки для порівняння.",
+ "apihelp-compare-param-fromrev": "Перша версія для порівняння.",
+ "apihelp-compare-param-totitle": "Другий заголовок для порівняння.",
+ "apihelp-compare-param-toid": "Другий ID сторінки для порівняння.",
+ "apihelp-compare-param-torev": "Друга версія для порівняння.",
+ "apihelp-compare-example-1": "Створити порівняння версій 1 і 2.",
+ "apihelp-createaccount-description": "Створити новий обліковий запис користувача.",
"apihelp-createaccount-param-name": "Ім'я користувача.",
"apihelp-createaccount-param-password": "Пароль (ігнорується, якщо встановлено <var>$1mailpassword</var>).",
"apihelp-createaccount-param-domain": "Домен для зовнішньої аутентифікації (опціонально).",
+ "apihelp-createaccount-param-token": "Токен створення облікового запису отримано у першому запиті.",
+ "apihelp-createaccount-param-email": "Адреса електронної пошти користувача (необов'язково).",
+ "apihelp-createaccount-param-realname": "Справжнє ім'я користувача (необов'язково).",
+ "apihelp-createaccount-param-mailpassword": "Якщо встановлено будь-яке значення, користувачеві буде надіслано випадковий пароль.",
+ "apihelp-createaccount-param-reason": "Необов'язкова причина для створення облікового запису, яка буде записана в журнал.",
+ "apihelp-createaccount-param-language": "Код мови для встановлення за замовчуванням для користувача (необов'язково, за замовчуванням — мова вмісту).",
+ "apihelp-createaccount-example-pass": "Створити користувача <kbd>testuser</kbd> з паролем <kbd>test123</kbd>.",
+ "apihelp-createaccount-example-mail": "Створити користувача <kbd>testmailuser</kbd> і надіслати на електронну пошту випадково-згенерований пароль.",
+ "apihelp-delete-description": "Вилучити сторінку.",
+ "apihelp-delete-param-title": "Назва сторінки для вилучення. Не можна використати разом з <var>$1pageid</var>.",
+ "apihelp-delete-param-pageid": "ID-сторінки на вилучення. Не можна використати разом з <var>$1title</var>.",
+ "apihelp-delete-param-reason": "Причина вилучення. Якщо не вказана, буде використано автоматично-згенеровану.",
+ "apihelp-delete-param-watch": "Додати сторінку у список спостереження поточного користувача.",
+ "apihelp-delete-param-watchlist": "Беззастережно додати або вилучити сторінку зі списку спостереження поточного користувача, використати налаштування або не змінювати спостереження.",
+ "apihelp-delete-param-unwatch": "Вилучити сторінку зі списку спостереження поточного користувача.",
+ "apihelp-delete-param-oldimage": "Назва старого зображення на вилучення, як вказано у [[Special:ApiHelp/query+imageinfo|action=query&prop=imageinfo&iiprop=archivename]].",
+ "apihelp-delete-example-simple": "Вилучити <kbd>Main Page</kbd>.",
+ "apihelp-delete-example-reason": "Вилучити <kbd>Main Page</kbd> з причиною <kbd>Preparing for move</kbd>.",
+ "apihelp-disabled-description": "Цей модуль було вимкнено.",
+ "apihelp-edit-description": "Створювати і редагувати сторінки.",
+ "apihelp-edit-param-title": "Назва сторінки для редагування. Не можна використати разом з <var>$1pageid</var>.",
+ "apihelp-edit-param-pageid": "ID-сторінки для редагування. Не можна використати разом з <var>$1title</var>.",
+ "apihelp-edit-param-section": "Номер розділу. <kbd>0</kbd> для вступного розділу, <kbd>new</kbd> для нового розділу.",
+ "apihelp-edit-param-sectiontitle": "Назва нового розділу.",
+ "apihelp-edit-param-text": "Вміст сторінки.",
+ "apihelp-edit-param-summary": "Опис редагування. Також заголовок розділу, коли $1section=new і коли $1sectiontitle не вказано.",
+ "apihelp-edit-param-tags": "Змінити теги для версії.",
+ "apihelp-edit-param-minor": "Незначне редагування.",
+ "apihelp-edit-param-notminor": "Не «незначне» редагування.",
+ "apihelp-edit-param-bot": "Помітити редагування як зроблене ботом.",
+ "apihelp-edit-param-basetimestamp": "Мітка часу для основної версії, використовується для виявлення конфлікту редагувань. Може бути отримана через [[Special:ApiHelp/query+revisions|action=query&prop=revisions&rvprop=timestamp]].",
+ "apihelp-edit-param-starttimestamp": "Мітка часу, з якого почався процес редагування, використовується для виявлення конфліктів редагувань. Відповідне значення можна отримати з допомогою <var>[[Special:ApiHelp/main|curtimestamp]]</var> на початку процесу редагування (напр., коли завантажується вміст сторінки для редагування).",
+ "apihelp-edit-param-recreate": "Відкинути будь-які помилки щодо цієї сторінки, вилучені нещодавно.",
+ "apihelp-edit-param-createonly": "Не редагувати сторінку, якщо вона вже існує.",
+ "apihelp-edit-param-nocreate": "Видати помилку, якщо сторінка не існує.",
+ "apihelp-edit-param-watch": "Додати сторінку у список спостереження поточного користувача.",
+ "apihelp-edit-param-unwatch": "Вилучити сторінку зі списку спостереження поточного користувача.",
+ "apihelp-edit-param-watchlist": "Беззастережно додати або вилучити сторінку зі списку спостереження поточного користувача, використати налаштування або не змінювати спостереження.",
+ "apihelp-edit-param-md5": "MD5-хеш у параметрі $1text або параметрах $1prependtext і $1appendtext разом. Якщо вказано, редагування буде зроблене, лише якщо хеш правильний.",
+ "apihelp-edit-param-prependtext": "Додати цей текст на початок сторінки. Замінює $1text.",
+ "apihelp-edit-param-appendtext": "Додати цей текст у кінець сторінки. Замінює $1text.\n\nЩоб додати новий розділ, замість цього параметра використайте $1section=new.",
+ "apihelp-edit-param-undo": "Скасувати цю версію. Замінює $1text, $1prependtext та $1appendtext.",
+ "apihelp-edit-param-undoafter": "Скасувати усі версії від $1undo до цієї. Якщо не вказано, просто скасувати одну версію.",
+ "apihelp-edit-param-redirect": "Автоматично виправляти перенаправлення.",
+ "apihelp-edit-param-contentformat": "Формат серіалізації вмісту, використовуваний для введеного тексту.",
+ "apihelp-edit-param-contentmodel": "Модель вмісту нового вмісту.",
+ "apihelp-edit-param-token": "Токен завжди має надсилатися як останній параметр або хоча б після параметра $1text.",
"apihelp-edit-example-edit": "Редагувати сторінку",
"apihelp-edit-example-prepend": "Додати зміст на початок сторінки",
"apihelp-edit-example-undo": "Скасувати версії з 13579 по 13585 з автоматичним описом змін",
@@ -22,9 +109,1202 @@
"apihelp-emailuser-param-subject": "Заголовок теми.",
"apihelp-emailuser-param-text": "Тіло листа.",
"apihelp-emailuser-param-ccme": "Надіслати копію цього повідомлення мені.",
- "apihelp-emailuser-example-email": "Відправити листа користувачу \"WikiSysop\" з текстом \"Вміст\"",
+ "apihelp-emailuser-example-email": "Відправити листа користувачу <kbd>WikiSysop</kbd> з текстом <kbd>Вміст</kbd>.",
"apihelp-expandtemplates-description": "Розгортає усі шаблони у вікітекст.",
"apihelp-expandtemplates-param-title": "Заголовок сторінки.",
"apihelp-expandtemplates-param-text": "Вікітекст для перетворення.",
- "apihelp-move-param-ignorewarnings": "Ігнорувати всі попередження"
+ "apihelp-expandtemplates-param-revid": "ID версії, для <nowiki>{{REVISIONID}}</nowiki> і подібних змінних.",
+ "apihelp-expandtemplates-param-prop": "Яку інформацію отримувати.\n\nЗважте, що якщо не вибрано значень, результат міститиме вікітекст, але буде в застарілому форматі.",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "Розгорнений вікітекст.",
+ "apihelp-expandtemplates-paramvalue-prop-categories": "Будь-які категорії, наявні у джерелі, але не виведені у вікітексті результату.",
+ "apihelp-expandtemplates-paramvalue-prop-properties": "Властивості сторінки, визначені розгорненими магічними словами у вікітексті.",
+ "apihelp-expandtemplates-paramvalue-prop-volatile": "Чи результат тривкий і не повинен повторно використовуватись десь іще на сторінці.",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "Максимальний час, після якого кеш результату стане недійсним.",
+ "apihelp-expandtemplates-paramvalue-prop-modules": "Будь-які модулі ResourceLoader, які парсерні функції запитують на додання у результат. Або <kbd>jsconfigvars</kbd>, або <kbd>encodedjsconfigvars</kbd> має бути запитано разом з <kbd>modules</kbd>.",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "Дає конфігурації JavaScript змінні, притаманні для сторінки.",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "Дає конфігурації JavaScript змінні, притаманні для сторінки, як рядок JSON.",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "Дерево парсу XML вхідних даних.",
+ "apihelp-expandtemplates-param-includecomments": "Чи включати HTML-коментарі у результат.",
+ "apihelp-expandtemplates-param-generatexml": "Дерево парсу XML вхідних даних (замінене на $1prop=parsetree).",
+ "apihelp-expandtemplates-example-simple": "Розгорнути вікітекст <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
+ "apihelp-feedcontributions-description": "Повертає стрічку внеску користувача.",
+ "apihelp-feedcontributions-param-feedformat": "Формат стрічки.",
+ "apihelp-feedcontributions-param-user": "Для яких користувачів отримати внесок.",
+ "apihelp-feedcontributions-param-namespace": "За яким простором назв фільтрувати внески.",
+ "apihelp-feedcontributions-param-year": "Від року (і раніше).",
+ "apihelp-feedcontributions-param-month": "До місяця (і раніше).",
+ "apihelp-feedcontributions-param-tagfilter": "Відфільтрувати внесок, у якого є ці теґи.",
+ "apihelp-feedcontributions-param-deletedonly": "Показати лише вилучений внесок.",
+ "apihelp-feedcontributions-param-toponly": "Показати лише редагування, які є останніми версіями.",
+ "apihelp-feedcontributions-param-newonly": "Показати лише редагування, які є створеннями сторінок.",
+ "apihelp-feedcontributions-param-showsizediff": "Показати різницю розміру між версіями.",
+ "apihelp-feedcontributions-example-simple": "Вивести внесок для користувача <kbd>Example</kbd>.",
+ "apihelp-feedrecentchanges-description": "Видає стрічку нових редагувань.",
+ "apihelp-feedrecentchanges-param-feedformat": "Формат стрічки.",
+ "apihelp-feedrecentchanges-param-namespace": "Простір назв, до якого обмежити результати.",
+ "apihelp-feedrecentchanges-param-invert": "Усі простори назв, крім вибраного.",
+ "apihelp-feedrecentchanges-param-associated": "Включно з пов'язаним (обговорення чи головним) простором назв.",
+ "apihelp-feedrecentchanges-param-days": "Дні, до яких обмежити результати.",
+ "apihelp-feedrecentchanges-param-limit": "Максимальна кількість результатів для виведення.",
+ "apihelp-feedrecentchanges-param-from": "Показати зміни відтоді.",
+ "apihelp-feedrecentchanges-param-hideminor": "Приховати незначні редагування.",
+ "apihelp-feedrecentchanges-param-hidebots": "Приховати редагування ботів.",
+ "apihelp-feedrecentchanges-param-hideanons": "Приховати редагування анонімних користувачів.",
+ "apihelp-feedrecentchanges-param-hideliu": "Приховати редагування зареєстрованих користувачів.",
+ "apihelp-feedrecentchanges-param-hidepatrolled": "Приховати відпатрульовані редагування.",
+ "apihelp-feedrecentchanges-param-hidemyself": "Приховати редагування поточного користувача.",
+ "apihelp-feedrecentchanges-param-tagfilter": "Фільтрувати за теґом.",
+ "apihelp-feedrecentchanges-param-target": "Показати лише зміни на сторінках, на які посилається ця сторінка.",
+ "apihelp-feedrecentchanges-param-showlinkedto": "Показати натомість лише зміни на сторінках, які посилаються на цю сторінку.",
+ "apihelp-feedrecentchanges-example-simple": "Показати нещодавні зміни.",
+ "apihelp-feedrecentchanges-example-30days": "Показати нещодавні зміни за 30 днів.",
+ "apihelp-feedwatchlist-description": "Видає стрічку списку спостереження.",
+ "apihelp-feedwatchlist-param-feedformat": "Формат стрічки.",
+ "apihelp-feedwatchlist-param-hours": "Список сторінок, змінених за цю кількість годин від зараз.",
+ "apihelp-feedwatchlist-param-linktosections": "За можливості, посилатися безпосередньо на змінені розділи.",
+ "apihelp-feedwatchlist-example-default": "Показати стрічку списку спостереження.",
+ "apihelp-feedwatchlist-example-all6hrs": "Показати всі зміни до спостережуваних сторінок за останні 6 годин.",
+ "apihelp-filerevert-description": "Повернути файл до старої версії.",
+ "apihelp-filerevert-param-filename": "Цільова назва файлу, без префіксу File:.",
+ "apihelp-filerevert-param-comment": "Завантажити коментар.",
+ "apihelp-filerevert-param-archivename": "Архівна назва версії, до якої повернути.",
+ "apihelp-filerevert-example-revert": "Повернути <kbd>Wiki.png</kbd> до версії <kbd>2011-03-05T15:27:40Z</kbd>.",
+ "apihelp-help-description": "Відображати довідку для зазначених модулів.",
+ "apihelp-help-param-modules": "Модулі, для яких відображати довідку (значення параметрів <var>action</var> і <var>format</var> або <kbd>main</kbd>). Можна вказати підмодулі через <kbd>+</kbd>.",
+ "apihelp-help-param-submodules": "Включити довідку для підмодулів вказаного модуля.",
+ "apihelp-help-param-recursivesubmodules": "Включити довідку для підмодулів рекурсивно.",
+ "apihelp-help-param-helpformat": "Формат результату довідки.",
+ "apihelp-help-param-wrap": "Помістити результат у стандартну структуру API-відповіді.",
+ "apihelp-help-param-toc": "Включити зміст у HTML-результат.",
+ "apihelp-help-example-main": "Довідка для головного модуля.",
+ "apihelp-help-example-recursive": "Уся довідка на одній сторінці.",
+ "apihelp-help-example-help": "Довідка для самого модуля довідки.",
+ "apihelp-help-example-query": "Довідка для двох підмодулів запитів.",
+ "apihelp-imagerotate-description": "Поворот одного або декількох зображень.",
+ "apihelp-imagerotate-param-rotation": "Градуси для повороту зображення за годинниковою стрілкою.",
+ "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-description": "Імпортувати сторінку з іншої вікі або з XML-файлу.\n\nЗважте, що HTTP POST має бути виконано як завантаження файлу (тобто з використанням даних різних частин/форм) під час надсилання файлу для параметра <var>xml</var>.",
+ "apihelp-import-param-summary": "Імпортувати підсумок.",
+ "apihelp-import-param-xml": "Завантажено XML-файл.",
+ "apihelp-import-param-interwikisource": "Для інтервікі-імпорту: вікі, з якої імпортувати.",
+ "apihelp-import-param-interwikipage": "Для інтервікі-імпорту: сторінки для імпорту.",
+ "apihelp-import-param-fullhistory": "Для інтервікі-імпорту: імпортувати повну історію, не лише поточну версію.",
+ "apihelp-import-param-templates": "Для інтервікі-імпорту: імпортувати також усі включені шаблони.",
+ "apihelp-import-param-namespace": "Імпортувати у цей простір назв. Не можна використати разом з <var>$1rootpage</var>.",
+ "apihelp-import-param-rootpage": "Імпортувати як підсторінку цієї сторінки. Не можна використати разом з <var>$1namespace</var>.",
+ "apihelp-import-example-import": "Імпортувати [[meta:Help:ParserFunctions]] у простір назв 100 з повною історією.",
+ "apihelp-login-description": "Увійти в систему й отримати куки автентифікації.\n\nУ випадку успішного входження в систему, потрібні куки буде включено в заголовки HTTP-відповіді. У разі невдалого входу, подальші спроби будуть обмежені до ліміту автоматичних спроб підбирання пароля.",
+ "apihelp-login-param-name": "Ім'я користувача.",
+ "apihelp-login-param-password": "Пароль.",
+ "apihelp-login-param-domain": "Домен (необов'язково).",
+ "apihelp-login-param-token": "Токен входу в систему, отриманий у першому запиті.",
+ "apihelp-login-example-gettoken": "Отримати токен входу в систему.",
+ "apihelp-login-example-login": "Увійти в систему.",
+ "apihelp-logout-description": "Вийти й очистити дані сесії.",
+ "apihelp-logout-example-logout": "Вийти з поточного облікового запису.",
+ "apihelp-managetags-description": "Виконати керівні завдання щодо зміни теґів.",
+ "apihelp-managetags-param-operation": "Яку операцію виконати:\n;create:Створити нову мітку редагування для використання вручну.\n;delete:Вилучити мітку редагування з бази даних, включно з вилученням її з усіх версій, записів нових редагувань та записів журналів, де вона використана.\n;activate:Активувати мітку редагування, дозволивши користувачам застосовувати її вручну.\n;deactivate:Деактивувати мітку редагування, заборонивши користувачам застосовувати її вручну.",
+ "apihelp-managetags-param-tag": "Мітка для створення, вилучення, активування чи деактивування. Для створення мітки, вона повинна не існувати. Для вилучення мітки, вона повинна існувати. Для активування мітки, вона повинна існувати і не використовуватися жодним розширенням. Для деактивування мітки, вона має бути жива і визначена вручну.",
+ "apihelp-managetags-param-reason": "Необов'язкова причина створення, вилучення, активування чи деактивування мітки.",
+ "apihelp-managetags-param-ignorewarnings": "Чи ігнорувати усі попередження, що з'являються під час операції.",
+ "apihelp-managetags-example-create": "Створити мітку з назвою <kbd>spam</kbd> з причиною <kbd>For use in edit patrolling</kbd>",
+ "apihelp-managetags-example-delete": "Вилучити мітку <kbd>vandlaism</kbd> з причиною <kbd>Misspelt</kbd>",
+ "apihelp-managetags-example-activate": "Активувати мітку з назвою <kbd>spam</kbd> з причиною <kbd>For use in edit patrolling</kbd>",
+ "apihelp-managetags-example-deactivate": "Деактивувати мітку з назвою <kbd>spam</kbd> з причиною <kbd>No longer required</kbd>",
+ "apihelp-move-description": "Перейменувати сторінку.",
+ "apihelp-move-param-from": "Назва сторінки для перейменування. Не можна використати разом з <var>$1fromid</var>.",
+ "apihelp-move-param-fromid": "ID сторінки для перейменування. Не можна використати разом з <var>$1from</var>.",
+ "apihelp-move-param-to": "Назва сторінки, на яку перейменувати.",
+ "apihelp-move-param-reason": "Причина перейменування.",
+ "apihelp-move-param-movetalk": "Перейменувати сторінку обговорення, якщо вона існує.",
+ "apihelp-move-param-movesubpages": "Перейменувати підсторінки, якщо можливо.",
+ "apihelp-move-param-noredirect": "Не створювати перенаправлення.",
+ "apihelp-move-param-watch": "Додати сторінку й перенаправлення у список спостереження поточного користувача.",
+ "apihelp-move-param-unwatch": "Вилучити сторінку й перенаправлення зі списку спостереження поточного користувача.",
+ "apihelp-move-param-watchlist": "Беззастережно додати або вилучити сторінку зі списку спостереження поточного користувача, використати налаштування або не змінювати спостереження.",
+ "apihelp-move-param-ignorewarnings": "Ігнорувати всі попередження",
+ "apihelp-move-example-move": "Перейменувати <kbd>Badtitle</kbd> на <kbd>Goodtitle</kbd> без збереження перенаправлення.",
+ "apihelp-opensearch-description": "Шукати у вікі з використанням протоколу OpenSearch.",
+ "apihelp-opensearch-param-search": "Рядок пошуку.",
+ "apihelp-opensearch-param-limit": "Максимальна кількість результатів для виведення.",
+ "apihelp-opensearch-param-namespace": "Простори назв, у яких шукати.",
+ "apihelp-opensearch-param-suggest": "Нічого не робити, якщо <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> хибний.",
+ "apihelp-opensearch-param-redirects": "Як обробляти перенаправлення:\n;return:Видати саме перенаправлення.\n;resolve:Видати цільову сторінку. Може видати менше, ніж $1limit результат{{PLURAL:$1limit||и|ів}}.\nЗ історичних причин, за замовчуванням стоїть «return» для $1format=json і «resolve» — для інших форматів.",
+ "apihelp-opensearch-param-format": "Формат виводу.",
+ "apihelp-opensearch-param-warningsaserror": "Якщо при <kbd>format=json</kbd> з'являються попередження, видати помилку API замість того, щоб їх ігнорувати.",
+ "apihelp-opensearch-example-te": "Знайти сторінки, що починаються з <kbd>Te</kbd>.",
+ "apihelp-options-description": "Змінити налаштування поточного користувача.\n\nМожна встановити лише опції, які зареєстровані у ядрі або в одному з інстальованих розширень, або опції з префіксом ключів <code>userjs-</code> (призначені для використання користувацькими скриптами).",
+ "apihelp-options-param-reset": "Встановлює налаштування сайту за замовчуванням.",
+ "apihelp-options-param-resetkinds": "Список типів опцій для перевстановлення, коли вказана опція <var>$1reset</var>.",
+ "apihelp-options-param-change": "Список змін, відформатованих як назва=значення (напр., skin=vector). Значення не може містити вертикальних рисок. Якщо значення не вказане (навіть немає знака рівності) , напр., optionname|otheroption|…, опцію буде перевстановлено до її значення за замовчуванням.",
+ "apihelp-options-param-optionname": "Назва опції, якій має бути присвоєне значення <var>$1optionvalue</var>.",
+ "apihelp-options-param-optionvalue": "Значення опції, вказане в <var>$1optionname</var>, може містити вертикальні риски.",
+ "apihelp-options-example-reset": "Скинути всі налаштування.",
+ "apihelp-options-example-change": "Змінити налаштування <kbd>skin</kbd> та <kbd>hideminor</kbd>.",
+ "apihelp-options-example-complex": "Скинути всі налаштування, потім встановити <kbd>skin</kbd> та <kbd>nickname</kbd>.",
+ "apihelp-paraminfo-description": "Отримати інформацію про модулі API.",
+ "apihelp-paraminfo-param-modules": "Список назв модулів (значення параметрів <var>action</var> і <var>format</var> або <kbd>main</kbd>). Можна вказати підмодулі через <kbd>+</kbd>.",
+ "apihelp-paraminfo-param-helpformat": "Формат рядків довідки.",
+ "apihelp-paraminfo-param-querymodules": "Список назв модулів запитів (значення параметра <var>prop</var>, <var>meta</var> або <var>list</var>). Використати <kbd>$1modules=query+foo</kbd> замість <kbd>$1querymodules=foo</kbd>.",
+ "apihelp-paraminfo-param-mainmodule": "Отримати інформацію також про основний модуль (топ-рівень). Використати натомість <kbd>$1modules=main</kbd>.",
+ "apihelp-paraminfo-param-pagesetmodule": "Отримати також інформацію про модуль pageset (з вказанням titles= і рідних).",
+ "apihelp-paraminfo-param-formatmodules": "Список назв модулів форматування (значення параметра <var>format</var>). Використати натомість <var>$1modules</var>.",
+ "apihelp-paraminfo-example-1": "Показати інформацію для <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>, <kbd>[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>, <kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd> та <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd>.",
+ "apihelp-parse-description": "Аналізує вміст і видає парсер виходу.\n\nДив. різні prop-модулі <kbd>[[Special:ApiHelp/query|action=query]]</kbd>, щоб отримати інформацію з поточної версії сторінки.\n\nЄ декілька способів вказати текст для аналізу:\n# Вказати сторінку або версію, використавши <var>$1page</var>, <var>$1pageid</var> або <var>$1oldid</var>.\n# Вказати безпосередньо, використавши <var>$1text</var>, <var>$1title</var> і <var>$1contentmodel</var>.\n# Вказати лише підсумок аналізу. <var>$1prop</var> повинен мати порожнє значення.",
+ "apihelp-parse-param-title": "Назва сторінки, якій належить текст. Якщо пропущена, має бути вказано <var>$1contentmodel</var>, а як назву буде вжито [[API]].",
+ "apihelp-parse-param-text": "Текст для аналізу. Використати <var>$1title</var> або <var>$1contentmodel</var> для контролю моделі вмісту.",
+ "apihelp-parse-param-summary": "Підсумок для аналізу.",
+ "apihelp-parse-param-page": "Аналізувати вміст цієї сторінки. Не можна використати разом з <var>$1text</var> і <var>$1title</var>.",
+ "apihelp-parse-param-pageid": "Аналізувати вміст цієї сторінки. Перевизначає <var>$1page</var>.",
+ "apihelp-parse-param-redirects": "Якщо <var>$1page</var> або <var>$1pageid</var> вказані як перенаправлення, виправити це.",
+ "apihelp-parse-param-oldid": "Аналізувати вміст цієї версії. Перевизначає <var>$1page</var> та <var>$1pageid</var>.",
+ "apihelp-parse-param-prop": "Яку інформацію отримати?",
+ "apihelp-parse-paramvalue-prop-text": "Дає текст-аналіз вікітексту.",
+ "apihelp-parse-paramvalue-prop-langlinks": "Дає мовні посилання в аналізованому вікітексті.",
+ "apihelp-parse-paramvalue-prop-categories": "Дає категорії в аналізованому вікітексті.",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "Дає HTML-версію категорій.",
+ "apihelp-parse-paramvalue-prop-links": "Дає зовнішні посилання в аналізованому вікітексті.",
+ "apihelp-parse-paramvalue-prop-templates": "Дає шаблони в аналізованому вікітексті.",
+ "apihelp-parse-paramvalue-prop-images": "Дає зображення в аналізованому вікітексті.",
+ "apihelp-parse-paramvalue-prop-externallinks": "Дає зовнішні посилання в аналізованому вікітексті.",
+ "apihelp-parse-paramvalue-prop-sections": "Дає розділи в аналізованому вікітексті.",
+ "apihelp-parse-paramvalue-prop-revid": "Додає ідентифікатор версії аналізованої сторінки.",
+ "apihelp-parse-paramvalue-prop-displaytitle": "Додає заголовок аналізованого вікітексту.",
+ "apihelp-parse-paramvalue-prop-headitems": "Дає елементи для вставки в <code>&lt;head&gt;</code> сторінки.",
+ "apihelp-parse-paramvalue-prop-headhtml": "Дає проаналізований <code>&lt;head&gt;</code> сторінки.",
+ "apihelp-parse-paramvalue-prop-modules": "Дає модулі ResourceLoader, використані на сторінці. Чи <kbd>jsconfigvars</kbd>, чи <kbd>encodedjsconfigvars</kbd> має бути запитано разом з <kbd>modules</kbd>.",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "Дає змінні конфігурації JavaScript, притаманні для сторінки.",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Дає змінні конфігурації JavaScript, притаманні для сторінки, як рядок JSON.",
+ "apihelp-parse-paramvalue-prop-indicators": "Дає HTML індикаторів стану сторінки, використаних на сторінці.",
+ "apihelp-parse-paramvalue-prop-iwlinks": "Дає інтервікі-посилання в аналізованому вікітексті.",
+ "apihelp-parse-paramvalue-prop-wikitext": "Дає вихідний вікітекст, який було аналізовано.",
+ "apihelp-parse-paramvalue-prop-properties": "Дає різні властивості, визначені в аналізованому вікітексті.",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "Дає звіт по обмеженнях у структурованому вигляді. Не видає даних, якщо встановлено <var>$1disablelimitreport</var>.",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "Дає HTML-версію звіту по обмеженнях. Не видає даних, якщо встановлено <var>$1disablelimitreport</var>.",
+ "apihelp-parse-paramvalue-prop-parsetree": "Синтаксичне дерево XML вмісту версії (передбачає модель вмісту <code>$1</code>)",
+ "apihelp-parse-param-pst": "Зробіть трансформацію вхідних даних перед збереженням і аналізом. Дійсне лише при використанні з текстом.",
+ "apihelp-parse-param-onlypst": "Зробіть трансформацію вхідних даних перед збереженням (PST), але не аналізуйте. Видає той самий вікітекст, після застосування PST. Дійсне лише у разі використання з <var>$1text</var>.",
+ "apihelp-parse-param-effectivelanglinks": "Включає мовні посилання, додані розширеннями (для використання з <kbd>$1prop=langlinks</kbd>).",
+ "apihelp-parse-param-section": "Видає вміст лише розділу з цим номером або при <kbd>new</kbd> створенні нового розділу.\n\n<kbd>new</kbd> розділ відзначається лише при вказанні тексту <var>text</var>.",
+ "apihelp-parse-param-sectiontitle": "Заголовок нового розділу, коли <var>section</var> має значення <kbd>new</kbd>.\n\nНа відміну від редагування сторінки, це не повертається до <var>summary</var>, якщо пропустити чи лишити порожнім.",
+ "apihelp-parse-param-disablelimitreport": "Пропустити звіт препроцесора («NewPP limit report») на виході аналізу.",
+ "apihelp-parse-param-disableeditsection": "Пропустити посилання на редагування розділів на виході аналізу.",
+ "apihelp-parse-param-generatexml": "Генерувати синтаксичне дерево XML (передбачає модель вмісту <code>$1</code>; замінено на <kbd>$2prop=parsetree</kbd>).",
+ "apihelp-parse-param-preview": "Аналізувати у режимі попереднього перегляду.",
+ "apihelp-parse-param-sectionpreview": "Аналізувати у режимі попереднього перегляду розділу (також вмикає попередній перегляд).",
+ "apihelp-parse-param-disabletoc": "Пропустити зміст на виході.",
+ "apihelp-parse-param-contentformat": "Формат серіалізації вмісту, використаний у вхідному тексті. Дійсний лише при використанні разом з $1text.",
+ "apihelp-parse-param-contentmodel": "Модель вмісту вхідного тексту. Якщо пропущено, має бути вказано $1title, і за замовчуванням буде модель вказаного заголовка. Дійсне лише при використанні з $1text.",
+ "apihelp-parse-example-page": "Аналізувати сторінку.",
+ "apihelp-parse-example-text": "Аналізувати вікітекст.",
+ "apihelp-parse-example-texttitle": "Аналізувати вікітекст, вказуючи назву сторінки.",
+ "apihelp-parse-example-summary": "Аналізувати опис.",
+ "apihelp-patrol-description": "Відпатрулювати сторінку чи версію.",
+ "apihelp-patrol-param-rcid": "ID нещодавніх змін для патрулювання.",
+ "apihelp-patrol-param-revid": "Ідентифікатор версії для патрулювання.",
+ "apihelp-patrol-example-rcid": "Відпатрулювати останню зміну.",
+ "apihelp-patrol-example-revid": "Відпатрулювати версію.",
+ "apihelp-protect-description": "Змінити рівень захисту сторінки.",
+ "apihelp-protect-param-title": "Заголовок сторінки для (зняття) захисту. Не може використовуватися разом із $1pageid.",
+ "apihelp-protect-param-pageid": "ID сторінки для (зняття) захисту. Не може використовуватися разом з $1title.",
+ "apihelp-protect-param-protections": "Список рівнів захисту у форматі <kbd>action=level</kbd> (напр., <kbd>edit=sysop</kbd>).\n\n<strong>Примітка:</strong> Обмеження на дії, яких нема в списку, буде знято.",
+ "apihelp-protect-param-expiry": "Часові мітки закінчення. Якщо встановлена лише одна мітка, її буде використано для усіх захистів. Для безстрокового захисту використовуйте <kbd>infinite</kbd>, <kbd>indefinite</kbd>, <kbd>infinity</kbd> або <kbd>never</kbd>.",
+ "apihelp-protect-param-reason": "Причина для (зняття) захисту.",
+ "apihelp-protect-param-cascade": "Увімкнути каскадний захист (тобто захистити включені шаблоні і зображення, використані на цій сторінці). Ігнорується, якщо жоден з вказаних рівнів захисту не підтримує каскадність.",
+ "apihelp-protect-param-watch": "Якщо вказано, додати сторінку, де додається/знімається захист, до списку спостереження поточного користувача.",
+ "apihelp-protect-param-watchlist": "Беззастережно додати або вилучити сторінку зі списку спостереження поточного користувача, використати налаштування або не змінювати спостереження.",
+ "apihelp-protect-example-protect": "Захистити сторінку.",
+ "apihelp-protect-example-unprotect": "Зняти захист зі сторінки, встановивши обмеження для <kbd>all</kbd>.",
+ "apihelp-protect-example-unprotect2": "Зняти захист з сторінки, встановивши відсутність обмежень.",
+ "apihelp-purge-description": "Очистити кеш для вказаних заголовків.\n\nВимагає запиту POST, якщо користувач не ввійшов у систему.",
+ "apihelp-purge-param-forcelinkupdate": "Оновити таблиці посилань.",
+ "apihelp-purge-param-forcerecursivelinkupdate": "Оновити таблицю посилань, і оновити таблиці посилань для кожної сторінки, що використовує цю сторінку як шаблон.",
+ "apihelp-purge-example-simple": "Очистити кеш <kbd>Main Page</kbd> і сторінки <kbd>API</kbd>.",
+ "apihelp-purge-example-generator": "Очистити кеш перших десяти сторінок у головному просторі назв.",
+ "apihelp-query-description": "Вибірка даних з і про MediaWiki.\n\nУсі зміни даних у першу чергу мають використовувати запит на отримання токена, щоб запобігти зловживанням зі шкідливих сайтів.",
+ "apihelp-query-param-prop": "Властивості, які потрібно отримати для запитуваних сторінок.",
+ "apihelp-query-param-list": "Які списки отримати.",
+ "apihelp-query-param-meta": "Які метадані отримати.",
+ "apihelp-query-param-indexpageids": "Включити додатковий розділ pageids зі списком усіх виданих ідентифікаторів сторінки.",
+ "apihelp-query-param-export": "Експортувати поточні версії усіх заданих або створюваних сторінок.",
+ "apihelp-query-param-exportnowrap": "Видати експорт XML без огортання його в XML-результат (той же формат, що й [[Special:Export]]). Може використовуватися лише з $1export.",
+ "apihelp-query-param-iwurl": "Чи отримувати повний URL, якщо назва є інтервікі-посиланням.",
+ "apihelp-query-param-rawcontinue": "Видати сирі дані <samp>query-continue</samp> для продовження.",
+ "apihelp-query-example-revisions": "Вибірка [[Special:ApiHelp/query+siteinfo|інформації про сайт]] та [[Special:ApiHelp/query+revisions|версій]] <kbd>Main Page</kbd>.",
+ "apihelp-query-example-allpages": "Вибрати версії сторінок, які починаються з <kbd>API/</kbd>.",
+ "apihelp-query+allcategories-description": "Перерахувати всі категорії.",
+ "apihelp-query+allcategories-param-from": "Категорія, з якої почати перелічувати.",
+ "apihelp-query+allcategories-param-to": "Категорія, на якій закінчити перелічувати.",
+ "apihelp-query+allcategories-param-prefix": "Шукати усі назви категорій, які починаються з цього значення.",
+ "apihelp-query+allcategories-param-dir": "Напрямок сортування.",
+ "apihelp-query+allcategories-param-min": "Видати лише категорії, які мають щонайменше стільки елементів.",
+ "apihelp-query+allcategories-param-max": "Видати лише категорії, які мають максимум стільки елементів.",
+ "apihelp-query+allcategories-param-limit": "Скільки категорій видати.",
+ "apihelp-query+allcategories-param-prop": "Які властивості отримати:",
+ "apihelp-query+allcategories-paramvalue-prop-size": "Додає номер сторінок у категорії.",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "Теґує категорії, приховані з <code>_&#95;HIDDENCAT_&#95;</code>.",
+ "apihelp-query+allcategories-example-size": "Перерахувати категорії з інформацією про кількість сторінок у кожній.",
+ "apihelp-query+allcategories-example-generator": "Отримати інформацію про саму сторінку категорії для категорій, що починаються з <kbd>List</kbd>.",
+ "apihelp-query+alldeletedrevisions-description": "Перерахувати усі вилучені версії за користувачем або у просторі назв.",
+ "apihelp-query+alldeletedrevisions-paraminfo-useronly": "Може використовуватися лише з <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "Не може використовуватися з <var>$3user</var>.",
+ "apihelp-query+alldeletedrevisions-param-start": "Часова мітка початку переліку.",
+ "apihelp-query+alldeletedrevisions-param-end": "Часова мітка закінчення переліку.",
+ "apihelp-query+alldeletedrevisions-param-from": "Почати перелік з цієї назви.",
+ "apihelp-query+alldeletedrevisions-param-to": "Закінчити перелік цією назвою.",
+ "apihelp-query+alldeletedrevisions-param-prefix": "Шукати усі назви сторінок, які починаються з цього значення.",
+ "apihelp-query+alldeletedrevisions-param-tag": "Перерахувати лише версії, помічені цим теґом.",
+ "apihelp-query+alldeletedrevisions-param-user": "Перерахувати лише версії цього користувача.",
+ "apihelp-query+alldeletedrevisions-param-excludeuser": "Не перераховувати версії цього користувача.",
+ "apihelp-query+alldeletedrevisions-param-namespace": "Перерахувати сторінки лише в цьому просторі назв.",
+ "apihelp-query+alldeletedrevisions-param-miser-user-namespace": "<strong>Примітка:</strong> через [[mw:Manual:$wgMiserMode|«скупий режим»]], використання <var>$1user</var> і <var>$1namespace</var> одночасно можуть вилитися у видачу результатів менше ніж <var>$1limit</var> перед продовженням; в особливих випадках можуть видаватися нульові результати.",
+ "apihelp-query+alldeletedrevisions-param-generatetitles": "Коли використовується як генератор, генерувати заголовки замість ідентифікаторів версій.",
+ "apihelp-query+alldeletedrevisions-example-user": "Перерахувати останні 50 вилучених редагувань користувача <kbd>Example<kbd>.",
+ "apihelp-query+alldeletedrevisions-example-ns-main": "Перерахувати останні 50 вилучених версій у головному просторі назв.",
+ "apihelp-query+allfileusages-description": "Перерахувати усі використання файлів, включно з тими, що не існують.",
+ "apihelp-query+allfileusages-param-from": "Назва файлу, з якої почати перераховувати.",
+ "apihelp-query+allfileusages-param-to": "Назва файлу, якою закінчувати перераховувати.",
+ "apihelp-query+allfileusages-param-prefix": "Шукати усі назви файлів, які починаються з цього значення.",
+ "apihelp-query+allfileusages-param-unique": "Показувати лише окремі назви файлів. Не може використовуватися разом з $1prop=ids.\nКоли використовується як генератор, видає цільові сторінки замість вихідних сторінок.",
+ "apihelp-query+allfileusages-param-prop": "Які відомості включати:",
+ "apihelp-query+allfileusages-paramvalue-prop-ids": "Додає ідентифікатори із використаних сторінок (не буде використовуватися, при єдиній $1).",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "Додає назву файлу.",
+ "apihelp-query+allfileusages-param-limit": "Скільки всього елементів виводити.",
+ "apihelp-query+allfileusages-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+allfileusages-example-B": "Перерахувати назви файлів, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
+ "apihelp-query+allfileusages-example-unique": "Перерахувати унікальні назви файлів.",
+ "apihelp-query+allfileusages-example-unique-generator": "Отримує всі назви файлів, позначаючи відсутні.",
+ "apihelp-query+allfileusages-example-generator": "Отримує сторінки, на яких є файли.",
+ "apihelp-query+allimages-description": "Перерахувати усі зображення послідовно.",
+ "apihelp-query+allimages-param-sort": "Властивість, за якою сортувати.",
+ "apihelp-query+allimages-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+allimages-param-from": "Назва зображення, з якої почати перерахунок. Можна використати лише з $1sort=name.",
+ "apihelp-query+allimages-param-to": "Назва зображення, якою закінчити перерахунок. Можна використати лише з $1sort=name.",
+ "apihelp-query+allimages-param-start": "Часова мітка, з якої почати перерахунок. Можна використати лише з $1sort=timestamp.",
+ "apihelp-query+allimages-param-end": "Часова мітка, якою закінчити перерахунок. Можна використати лише з $1sort=timestamp.",
+ "apihelp-query+allimages-param-prefix": "Шукати усі назви зображень, що починаються цим значенням. Можна використати лише разом з $1sort=name.",
+ "apihelp-query+allimages-param-minsize": "Обмежити до зображень, які мають щонайменше стільки байтів.",
+ "apihelp-query+allimages-param-maxsize": "Обмежити до зображень, які мають максимум стільки байтів.",
+ "apihelp-query+allimages-param-sha1": "SHA1-хеш зображення. Перевизначає $1sha1base36.",
+ "apihelp-query+allimages-param-sha1base36": "SHA1-хеш зображення у base 36 (використано в MediaWiki).",
+ "apihelp-query+allimages-param-user": "Видати лише файли, завантажені цим користувачем. Можна використати лише з $1sort=timestamp. Не можна використати разом з $1filterbots.",
+ "apihelp-query+allimages-param-filterbots": "Як фільтрувати файли, завантажені ботами. Можна використати лише з $1sort=timestamp. Не можна використати разом з $1user.",
+ "apihelp-query+allimages-param-mime": "Які MIME-типи шукати, напр., <kbd>image/jpeg</kbd>.",
+ "apihelp-query+allimages-param-limit": "Скільки всього зображень видати.",
+ "apihelp-query+allimages-example-B": "Показати список файлів, які починаються на літеру <kbd>B</kbd>.",
+ "apihelp-query+allimages-example-recent": "Показати список нещодавно завантажених файлів, подібно до [[Special:NewFiles]].",
+ "apihelp-query+allimages-example-mimetypes": "Показати список файлів з MIME-типом <kbd>image/png</kbd> або <kbd>image/gif</kbd>",
+ "apihelp-query+allimages-example-generator": "Показати інформацію про 4 файли, що починаються на літеру <kbd>T</kbd>.",
+ "apihelp-query+alllinks-description": "Перераховувати всі посилання, які вказують на заданий простір назв.",
+ "apihelp-query+alllinks-param-from": "Назва посилання, з якої почати перераховувати.",
+ "apihelp-query+alllinks-param-to": "Назва посилання, якою закінчити перераховувати.",
+ "apihelp-query+alllinks-param-prefix": "Шукати усі пов'язані назви, які починаються з цього значення.",
+ "apihelp-query+alllinks-param-unique": "Показувати лише окремі пов'язані назви. Не може використовуватися з <kbd>$1prop=ids</kbd>.\nКоли використовується як генератор, видає цільові сторінки замість вихідних сторінок.",
+ "apihelp-query+alllinks-param-prop": "Які відомості включати:",
+ "apihelp-query+alllinks-paramvalue-prop-ids": "Додає ідентифікатори сторінок, що має посилання (не можна використати разом з <var>$1unique</var>).",
+ "apihelp-query+alllinks-paramvalue-prop-title": "Додає назву посилання.",
+ "apihelp-query+alllinks-param-namespace": "Простір назв для переліку.",
+ "apihelp-query+alllinks-param-limit": "Скільки всього елементів виводити.",
+ "apihelp-query+alllinks-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+alllinks-example-B": "Перерахувати пов'язані назви, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
+ "apihelp-query+alllinks-example-unique": "Перерахувати унікальні назви з посиланнями.",
+ "apihelp-query+alllinks-example-unique-generator": "Отримує всі назви з посиланнями, позначаючи відсутні.",
+ "apihelp-query+alllinks-example-generator": "Отримує сторінки, на яких є посилання.",
+ "apihelp-query+allmessages-description": "Видати повідомлення від цього сайту.",
+ "apihelp-query+allmessages-param-messages": "Які повідомлення виводити. <kbd>*</kbd> (за замовчуванням) означає усі повідомлення.",
+ "apihelp-query+allmessages-param-prop": "Які властивості отримати.",
+ "apihelp-query+allmessages-param-enableparser": "Встановити увімкнення парсеру, це попередньо обробить вікітекст повідомлення (підставити магічні слова, розкрити шаблони тощо).",
+ "apihelp-query+allmessages-param-nocontent": "Якщо вказано, не включати повідомлення вміст повідомлення у результат.",
+ "apihelp-query+allmessages-param-includelocal": "Також включити локальні повідомлення, тобто повідомлення, що не існують у програмному забезпеченні, але існують як сторінка MediaWiki:.\nЦе видає список усіх сторінок MediaWiki:, так що у ньому будуть сторінки, які насправді не є повідомленнями, як-то [[MediaWiki:Common.js|Common.js]].",
+ "apihelp-query+allmessages-param-args": "Аргументи будуть підставлятися в повідомлення.",
+ "apihelp-query+allmessages-param-filter": "Видати лише повідомлення з назвами, що місять цей рядок.",
+ "apihelp-query+allmessages-param-customised": "Видати лише повідомлення у цьому стані налаштувань.",
+ "apihelp-query+allmessages-param-lang": "Видає повідомлення цією мовою.",
+ "apihelp-query+allmessages-param-from": "Видає повідомлення, починаючи з цього повідомлення.",
+ "apihelp-query+allmessages-param-to": "Видає повідомлення, закінчуючи цим повідомленням.",
+ "apihelp-query+allmessages-param-title": "Назва сторінки для використання як контекст при аналізі повідомлення (для опції $1enableparser).",
+ "apihelp-query+allmessages-param-prefix": "Видати повідомлення з цим префіксом.",
+ "apihelp-query+allmessages-example-ipb": "Показати повідомлення, які починаються на <kbd>ipb-</kbd>.",
+ "apihelp-query+allmessages-example-de": "Показати повідомлення <kbd>august</kbd> і <kbd>mainpage</kbd> німецькою.",
+ "apihelp-query+allpages-description": "Перераховувати всі сторінки послідовно в заданому просторі назв.",
+ "apihelp-query+allpages-param-from": "Заголовок сторінки, з якого почати перелічувати.",
+ "apihelp-query+allpages-param-to": "Заголовок сторінки, яким закінчувати перелічувати.",
+ "apihelp-query+allpages-param-prefix": "Шукати усі назви сторінок, які починаються з цього значення.",
+ "apihelp-query+allpages-param-namespace": "Простір назв для переліку.",
+ "apihelp-query+allpages-param-filterredir": "Які сторінки перерахувати.",
+ "apihelp-query+allpages-param-minsize": "Обмежити до сторінок, які мають щонайменше стільки байтів.",
+ "apihelp-query+allpages-param-maxsize": "Обмежити до сторінок, які мають максимум стільки байтів.",
+ "apihelp-query+allpages-param-prtype": "Обмежити до захищених сторінок.",
+ "apihelp-query+allpages-param-prlevel": "Фільтрувати захисти залежно від рівня (мусить використовуватися з $1prtype= parameter).",
+ "apihelp-query+allpages-param-prfiltercascade": "Фільтрувати захисти залежно від каскадності (ігнорується, коли $1prtype не вказано).",
+ "apihelp-query+allpages-param-limit": "Скільки всього сторінок виводити.",
+ "apihelp-query+allpages-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+allpages-param-filterlanglinks": "Фільтрувати залежно від наявності у сторінки мовних посилань. Зауважте, що це може не врахувати мовні посилання, додані розширеннями.",
+ "apihelp-query+allpages-param-prexpiry": "За якою тривалістю захисту фільтрувати сторінку:\n;indefinite:Отримати лише сторінки з нескінченним захистом.\n;definite:Отримати лише сторінки з визначеним терміном захисту.\n;all:Отримати сторінки з будь-яким терміном захисту.",
+ "apihelp-query+allpages-example-B": "Показати список сторінок, які починаються на літеру <kbd>B</kbd>.",
+ "apihelp-query+allpages-example-generator": "Показати інформацію про 4 сторінки, що починаються на літеру <kbd>T</kbd>.",
+ "apihelp-query+allpages-example-generator-revisions": "Показати вміст перших двох сторінок, що не є перенаправленнями і починаються на <kbd>Re</kbd>.",
+ "apihelp-query+allredirects-description": "Перерахувати усі перенаправлення на простір назв.",
+ "apihelp-query+allredirects-param-from": "Назва перенаправлення, з якої почати перераховувати.",
+ "apihelp-query+allredirects-param-to": "Назва перенаправлення, якою закінчувати перераховувати.",
+ "apihelp-query+allredirects-param-prefix": "Шукати усі цільові сторінки, які починаються з цього значення.",
+ "apihelp-query+allredirects-param-unique": "Показувати лише окремі цільові сторінки. Не може використовуватися разом з $1prop=ids|fragment|interwiki.\nКоли використовується як генератор, видає цільові сторінки замість вихідних сторінок.",
+ "apihelp-query+allredirects-param-prop": "Які відомості включити:",
+ "apihelp-query+allredirects-paramvalue-prop-ids": "Додає ID сторінки-перенаправлення (не можна використати разом з <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-title": "Додає заголовок перенаправлення.",
+ "apihelp-query+allredirects-paramvalue-prop-fragment": "Додає фрагмент з перенаправлення, якщо він є (не можна використати разом з <var>$1unique</var>).",
+ "apihelp-query+allredirects-paramvalue-prop-interwiki": "Додає інтервікі-префікс з перенаправлення, якщо він є (не можна використати разом з <var>$1unique</var>).",
+ "apihelp-query+allredirects-param-namespace": "Простір назв для переліку.",
+ "apihelp-query+allredirects-param-limit": "Скільки всього елементів виводити.",
+ "apihelp-query+allredirects-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+allredirects-example-B": "Перерахувати цільові сторінки, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
+ "apihelp-query+allredirects-example-unique": "Перерахувати унікальні цільові сторінки.",
+ "apihelp-query+allredirects-example-unique-generator": "Отримує всі цільові сторінки, позначаючи відсутні.",
+ "apihelp-query+allredirects-example-generator": "Отримує сторінки, які містять перенаправлення.",
+ "apihelp-query+alltransclusions-description": "Список усіх включень (сторінки, вставлені з використанням &#123;&#123;x&#125;&#125;), включно з неіснуючими.",
+ "apihelp-query+alltransclusions-param-from": "Назва включення, з якої почати перераховувати.",
+ "apihelp-query+alltransclusions-param-to": "Назва включення, якою закінчити перераховувати.",
+ "apihelp-query+alltransclusions-param-prefix": "Шукати усі включені назви, які починаються з цього значення.",
+ "apihelp-query+alltransclusions-param-unique": "Показувати лише окремі включені назви. Не може використовуватися разом з $1prop=ids.\nКоли використовується як генератор, видає цільові сторінки замість вихідних сторінок.",
+ "apihelp-query+alltransclusions-param-prop": "Які відомості включати:",
+ "apihelp-query+alltransclusions-paramvalue-prop-ids": "Додає ідентифікатор сторінки включення (не можна використати разом з $1unique).",
+ "apihelp-query+alltransclusions-paramvalue-prop-title": "Додає назву включення.",
+ "apihelp-query+alltransclusions-param-namespace": "Простір назв для переліку.",
+ "apihelp-query+alltransclusions-param-limit": "Скільки всього елементів виводити.",
+ "apihelp-query+alltransclusions-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+alltransclusions-example-B": "Перерахувати включені назви, включно з відсутніми, з ідентифікаторами сторінок, на яких вони використані, починаючи з <kbd>B</kbd>.",
+ "apihelp-query+alltransclusions-example-unique": "Перерахувати унікальні включені назв.",
+ "apihelp-query+alltransclusions-example-unique-generator": "Отримує всі включені назви, позначаючи відсутні.",
+ "apihelp-query+alltransclusions-example-generator": "Отримує сторінки, на яких є включення.",
+ "apihelp-query+allusers-description": "Перерахувати усіх зареєстрованих користувачів.",
+ "apihelp-query+allusers-param-from": "Ім'я користувача, з якого почати перелічувати.",
+ "apihelp-query+allusers-param-to": "Ім'я користувача, на якому закінчити перелічувати.",
+ "apihelp-query+allusers-param-prefix": "Шукати усіх користувачів, які починаються з цього значення.",
+ "apihelp-query+allusers-param-dir": "Напрямок сортування.",
+ "apihelp-query+allusers-param-group": "Включати лише користувачів з даних груп.",
+ "apihelp-query+allusers-param-excludegroup": "Виключити користувачів у даних групах.",
+ "apihelp-query+allusers-param-rights": "Включати лише користувачів з даними правами. Не включає права, надані безумовними або автоматичними групами на зразок *, користувач або автопідтверджені.",
+ "apihelp-query+allusers-param-prop": "Які саме відомості включати:",
+ "apihelp-query+allusers-paramvalue-prop-blockinfo": "Додає інформацію про поточне блокування користувача.",
+ "apihelp-query+allusers-paramvalue-prop-groups": "Перераховує групи, до яких користувач належить. Це використовує більше ресурсів сервера і може видати менше результатів, ніж ліміт.",
+ "apihelp-query+allusers-paramvalue-prop-implicitgroups": "Перераховує усіх групи, до яких користувач належить автоматично.",
+ "apihelp-query+allusers-paramvalue-prop-rights": "Перераховує права, які користувач має.",
+ "apihelp-query+allusers-paramvalue-prop-editcount": "Додає кількість редагувань користувача.",
+ "apihelp-query+allusers-paramvalue-prop-registration": "Додає часову мітку, коли користувач зареєструвався, якщо доступно (може бути пустою).",
+ "apihelp-query+allusers-param-limit": "Скільки всього виводити імен користувачів.",
+ "apihelp-query+allusers-param-witheditsonly": "Перерахувати лише користувачів, що зробили редагування.",
+ "apihelp-query+allusers-param-activeusers": "Перерахувати лише користувачів, що були активні $1 {{PLURAL:$1|останній день|останні дні|останніх днів}}.",
+ "apihelp-query+allusers-example-Y": "Перерахувати користувачів, починаючи з <kbd>Y</kbd>.",
+ "apihelp-query+backlinks-description": "Знайти усі сторінки, що посилаються на подану сторінку.",
+ "apihelp-query+backlinks-param-title": "Назва для пошуку. Не можна використати разом з <var>$1pageid</var>.",
+ "apihelp-query+backlinks-param-pageid": "ID сторінки для пошуку. Не можна використати разом з <var>$1title</var>.",
+ "apihelp-query+backlinks-param-namespace": "Простір назв для переліку.",
+ "apihelp-query+backlinks-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+backlinks-param-filterredir": "Як відфільтрувати перенаправлення. Якщо встановлено <kbd>nonredirects</kbd> при увімкненому <var>$1redirect</var>, це застосовується лише до другого рівня.",
+ "apihelp-query+backlinks-param-limit": "Скільки всього виводити сторінок. Якщо увімкнено <var>$1redirect</var>, ліміт застосовується до кожного рівня окремо (це означає, що може бути видано до 2 * <var>$1limit</var> результатів).",
+ "apihelp-query+backlinks-param-redirect": "Якщо сторінка, яка посилається, є перенаправленням, знайти всі сторінки, які посилаються на це перенаправлення, теж. Максимальний ліміт зменшується наполовину.",
+ "apihelp-query+backlinks-example-simple": "Показати посилання на <kbd>Main page<kbd>.",
+ "apihelp-query+backlinks-example-generator": "Отримати інформацію про сторінки, що посилаються на <kbd>Main page<kbd>.",
+ "apihelp-query+blocks-description": "Перерахувати усіх заблокованих користувачів і IP-адреси.",
+ "apihelp-query+blocks-param-start": "Часова мітка, з якої почати перелік.",
+ "apihelp-query+blocks-param-end": "Часова мітка закінчення переліку.",
+ "apihelp-query+blocks-param-ids": "Вивести список заблокованих ID (необов'язково).",
+ "apihelp-query+blocks-param-users": "Список користувачів для пошуку (необов'язково).",
+ "apihelp-query+blocks-param-ip": "Отримати всі блокування, що стосуються цієї IP-адреси або CIDR-діапазону, включно з блокуваннями діапазонів. Не може бути використано разом з <var>$3users</var>. CIDR-діапазони, ширші, ніж IPv4/$1 чи IPv6/$2, не приймаються.",
+ "apihelp-query+blocks-param-limit": "Максимальна кількість блокувань у списку.",
+ "apihelp-query+blocks-param-prop": "Які властивості отримати:",
+ "apihelp-query+blocks-paramvalue-prop-id": "Додає ID блокування.",
+ "apihelp-query+blocks-paramvalue-prop-user": "Додає ім'я заблокованого користувача.",
+ "apihelp-query+blocks-paramvalue-prop-userid": "Додає ID заблокованого користувача.",
+ "apihelp-query+blocks-paramvalue-prop-by": "Додає ім'я користувача, який заблокував.",
+ "apihelp-query+blocks-paramvalue-prop-byid": "Додає ID користувача, який заблокував.",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "Додає часову мітку здійснення блокування.",
+ "apihelp-query+blocks-paramvalue-prop-expiry": "Додає часову мітку закінчення терміну блокування.",
+ "apihelp-query+blocks-paramvalue-prop-reason": "Додає причину, вказану при блокуванні.",
+ "apihelp-query+blocks-paramvalue-prop-range": "Додає діапазон IP-адрес, на які поширюється блокування.",
+ "apihelp-query+blocks-paramvalue-prop-flags": "Мітки бану (автоблокування, лише анонім тощо).",
+ "apihelp-query+blocks-param-show": "Показувати лише елементи, які відповідають цим критеріям.\nНаприклад, щоб побачити лише незалежні блокування IP-адрес, встановіть <kbd>$1show=ip|!temp</kbd>.",
+ "apihelp-query+blocks-example-simple": "Вивести список блокувань.",
+ "apihelp-query+blocks-example-users": "Вивести список блокувань користувачів <kbd>Alice</kbd> та <kbd>Bob</kbd>.",
+ "apihelp-query+categories-description": "Перерахувати категорії, до яких сторінки належать.",
+ "apihelp-query+categories-param-prop": "Які додаткові властивості отримати для кожної категорії:",
+ "apihelp-query+categories-paramvalue-prop-sortkey": "Додає ключ сортування (шістнадцятковий рядок) і префікс ключа сортування (людиночитна частина) для категорії.",
+ "apihelp-query+categories-paramvalue-prop-timestamp": "Додає мітку часу, коли категорію було додано.",
+ "apihelp-query+categories-paramvalue-prop-hidden": "Тегує приховані категорії з допомогою <code>_&#95;HIDDENCAT_&#95;</code>.",
+ "apihelp-query+categories-param-show": "Який тип категорій показувати.",
+ "apihelp-query+categories-param-limit": "Скільки категорій видати.",
+ "apihelp-query+categories-param-categories": "Перерахувати лише ці категорії. Корисно для перевірки, чи певна сторінка є в певній категорії.",
+ "apihelp-query+categories-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+categories-example-simple": "Отримати список категорій, до яких належить сторінка <kbd>Albert Einstein</kbd>.",
+ "apihelp-query+categories-example-generator": "Отримати інформацію про усі категорії, використані на сторінці <kbd>Albert Einstein</kbd>.",
+ "apihelp-query+categoryinfo-description": "Видає інформацію про подані категорії.",
+ "apihelp-query+categoryinfo-example-simple": "Отримати інформацію про <kbd>Category:Foo</kbd> і <kbd>Category:Bar</kbd>.",
+ "apihelp-query+categorymembers-description": "Перерахувати усі сторінки у поданій категорії.",
+ "apihelp-query+categorymembers-param-title": "Яку категорію вивести (обов'язково). Мусить включати префікс <kbd>{{ns:category}}:</kbd>. Не можна використати разом з <var>$1pageid</var>.",
+ "apihelp-query+categorymembers-param-pageid": "ID сторінки категорії для виведення. Не можна використати разом з <var>$1title</var>.",
+ "apihelp-query+categorymembers-param-prop": "Які відомості включати:",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "Додає ID сторінки.",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "Додає назву й ID простору назв сторінки.",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkey": "Додає ключ сортування, використаний для сортування у категорії (шістнадцятковий рядок).",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "Додає ключ сортування, використаний для сортування у категорії (людиночитна частина).",
+ "apihelp-query+categorymembers-paramvalue-prop-type": "Додає тип, за яким категоризується сторінка (сторінка, підкатегорія або файл).",
+ "apihelp-query+categorymembers-paramvalue-prop-timestamp": "Додає мітку часу, коли сторінка була включена.",
+ "apihelp-query+categorymembers-param-namespace": "Включати лише сторінки у цих просторах назв. Зверніть увагу, що <kbd>$1type=subcat</kbd> чи <kbd>$1type=file</kbd> можна використовувати замість <kbd>$1namespace=14</kbd> чи <kbd>6</kbd>.",
+ "apihelp-query+categorymembers-param-type": "Який тип елементів категорії включати. Ігнорується, коли вказано <kbd>$1sort=timestamp</kbd>.",
+ "apihelp-query+categorymembers-param-limit": "Максимальна кількість сторінок для виведення.",
+ "apihelp-query+categorymembers-param-sort": "Властивість, за якою сортувати.",
+ "apihelp-query+categorymembers-param-dir": "У якому напрямку сортувати.",
+ "apihelp-query+categorymembers-param-start": "Часова мітка, з якої почати список. Можна використати лише разом з <kbd>$1sort=timestamp</kbd>.",
+ "apihelp-query+categorymembers-param-end": "Часова мітка, якою закінчити список. Можна використати лише разом з <kbd>$1sort=timestamp</kbd>.",
+ "apihelp-query+categorymembers-param-starthexsortkey": "Ключ сортування, з якого почати список, як видає <kbd>$1prop=sortkey</kbd>. Можна використати лише разом з <kbd>$1sort=sortkey</kbd>.",
+ "apihelp-query+categorymembers-param-endhexsortkey": "Ключ сортування, з якого почати список, як видає <kbd>$1prop=sortkey</kbd>. Можна використати лише разом з <kbd>$1sort=sortkey</kbd>.",
+ "apihelp-query+categorymembers-param-startsortkeyprefix": "Префікс ключа сортування, з якого почати список. Можна використати лише разом з <kbd>$1sort=sortkey</kbd>. Перевизначає <var>$1starthexsortkey</var>.",
+ "apihelp-query+categorymembers-param-endsortkeyprefix": "Префікс ключа сортування, <strong>перед</strong> яким закінчити список (не <strong>на</strong>; якщо це значення зустрінеться, його не буде включено!). Можна використати лише разом з $1sort=sortkey. Перевизначає $1endhexsortkey.",
+ "apihelp-query+categorymembers-param-startsortkey": "Використати натомість $1starthexsortkey.",
+ "apihelp-query+categorymembers-param-endsortkey": "Використати натомість $1endhexsortkey.",
+ "apihelp-query+categorymembers-example-simple": "Отримати перші 10 сторінок у <kbd>Category:Physics</kbd>.",
+ "apihelp-query+categorymembers-example-generator": "Отримати інформацію про перші 10 сторінок у <kbd>Category:Physics</kbd>.",
+ "apihelp-query+contributors-description": "Отримати список залогінених дописувачів і кількість анонімних дописувачів до сторінки.",
+ "apihelp-query+contributors-param-group": "Включати лише користувачів з даних груп. Не включає безумовні або автоматичні групи на зразок *, користувач або автопідтверджені.",
+ "apihelp-query+contributors-param-excludegroup": "Виключати користувачів з даних груп. Не включає безумовні або автоматичні групи на зразок *, користувач або автопідтверджені.",
+ "apihelp-query+contributors-param-rights": "Включати лише користувачів з даними правами. Не включає права, надані безумовними або автоматичними групами на зразок *, користувач або автопідтверджені.",
+ "apihelp-query+contributors-param-excluderights": "Виключати користувачів з даними правами. Не включає права, надані безумовними або автоматичними групами на зразок *, користувач або автопідтверджені.",
+ "apihelp-query+contributors-param-limit": "Скільки дописувачів виводити.",
+ "apihelp-query+contributors-example-simple": "Показати дописувачів до сторінки <kbd>Main Page</kbd>.",
+ "apihelp-query+deletedrevisions-description": "Отримати інформацію про вилучену версію.\n\nМожна використати кількома способами:\n# Отримати вилучені версії набору сторінок, вказавши заголовки або ідентифікатори сторінок. Сортується за назвою і часовою міткою.\n# Отримати дані про набір вилучених версій, вказавши їх ID з ідентифікаторами версій. Сортується за ID версії.",
+ "apihelp-query+deletedrevisions-param-start": "Мітка часу, з якої почати перелік. Ігнорується, якщо обробляється список ідентифікаторів версій.",
+ "apihelp-query+deletedrevisions-param-end": "Мітка часу, якою закінчити перелік. Ігнорується, якщо обробляється список ідентифікаторів версій.",
+ "apihelp-query+deletedrevisions-param-tag": "Перерахувати лише версії, помічені цим теґом.",
+ "apihelp-query+deletedrevisions-param-user": "Перерахувати лише версії цього користувача.",
+ "apihelp-query+deletedrevisions-param-excludeuser": "Не перераховувати версії цього користувача.",
+ "apihelp-query+deletedrevisions-example-titles": "Перерахувати вилучені версії сторінок <kbd>Main Page</kbd> і <kbd>Talk:Main Page</kbd>, з вмістом.",
+ "apihelp-query+deletedrevisions-example-revids": "Вивести інформацію вилученої версії <kbd>123456</kbd>.",
+ "apihelp-query+deletedrevs-description": "Перелічити вилучені версії.\n\nПрацює у трьох режимах:\n# Перелічити вилучені версії поданих назв, відсортованих за часовою міткою.\n# Перелічити вилучений внесок поданого користувача, відсортований за часовою міткою (без вказання заголовків).\n# Перелічити усі вилучені версії у поданому просторі назв, відсортовані за назвою та часовою міткою (без вказання заголовків, $1user не вказаний).\n\nОкремі параметри можуть застосовуватися в одному режимі й ігноруватися в іншому.",
+ "apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|Режим|Режими}}: $2",
+ "apihelp-query+deletedrevs-param-start": "Часова мітка початку переліку.",
+ "apihelp-query+deletedrevs-param-end": "Часова мітка закінчення переліку.",
+ "apihelp-query+deletedrevs-param-from": "Почати перелік з цієї назви.",
+ "apihelp-query+deletedrevs-param-to": "Закінчити перелік цією назвою.",
+ "apihelp-query+deletedrevs-param-prefix": "Шукати усі назви сторінок, які починаються з цього значення.",
+ "apihelp-query+deletedrevs-param-unique": "Вивести лише одну версію кожної сторінки.",
+ "apihelp-query+deletedrevs-param-tag": "Перерахувати лише версії, помічені цим теґом.",
+ "apihelp-query+deletedrevs-param-user": "Перерахувати лише версії цього користувача.",
+ "apihelp-query+deletedrevs-param-excludeuser": "Не перераховувати версії цього користувача.",
+ "apihelp-query+deletedrevs-param-namespace": "Перерахувати сторінки лише в цьому просторі назв.",
+ "apihelp-query+deletedrevs-param-limit": "Максимальна кількість версій для переліку.",
+ "apihelp-query+deletedrevs-param-prop": "Які властивості отримати:\n;revid:Додає ID вилученої версії.\n;parentid:Додає ID попередньої версії сторінки.\n;user:Додає користувача, який створив версію.\n;userid:Додає ID користувача, який створив версію.\n;comment:Додає коментар до версії.\n;parsedcomment:Додає проаналізований коментар до версії.\n;minor:Позначає, якщо версія створена незначним редагуванням.\n;len:Додає довжину (байти) версії.\n;sha1:Додає SHA-1 (base 16) версії.\n;content:Додає вміст версії.\n;token:<span class=\"apihelp-deprecated\">Застаріло.</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+deletedrevs-example-mode3-talk": "Перерахувати перші 50 вилучених сторінок у просторі назв {{ns:talk}} (режим 3).",
+ "apihelp-query+disabled-description": "Цей модуль запитів було вимкнено.",
+ "apihelp-query+duplicatefiles-description": "Перерахувати усі файли, які є дублікатами поданих файлів з огляду на значення хешу.",
+ "apihelp-query+duplicatefiles-param-limit": "Скільки файлів-дублікатів виводити.",
+ "apihelp-query+duplicatefiles-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+duplicatefiles-param-localonly": "Шукати лише файли у локальному репозиторії.",
+ "apihelp-query+duplicatefiles-example-simple": "Шукати дублікати [[:File:Albert Einstein Head.jpg]].",
+ "apihelp-query+duplicatefiles-example-generated": "Шукати дублікати усіх файлів.",
+ "apihelp-query+embeddedin-description": "Знайти всі сторінки, які вбудовують (включають) подану назву.",
+ "apihelp-query+embeddedin-param-title": "Назва для пошуку. Не можна використати разом з $1pageid.",
+ "apihelp-query+embeddedin-param-pageid": "ID сторінки для пошуку. Не можна використати разом з $1title.",
+ "apihelp-query+embeddedin-param-namespace": "Простір назв для переліку.",
+ "apihelp-query+embeddedin-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+embeddedin-param-filterredir": "Як фільтрувати перенаправлення.",
+ "apihelp-query+embeddedin-param-limit": "Скільки всього сторінок виводити.",
+ "apihelp-query+embeddedin-example-simple": "Показати сторінки, які включають <kbd>Template:Stub</kbd>.",
+ "apihelp-query+embeddedin-example-generator": "Отримати інформацію про сторінки, які включають <kbd>Template:Stub</kbd>.",
+ "apihelp-query+extlinks-description": "Видати усі зовнішні URL (не інтервікі) з поданих сторінок.",
+ "apihelp-query+extlinks-param-limit": "Скільки посилань виводити.",
+ "apihelp-query+extlinks-param-protocol": "Протокол URL. Якщо пусто і вказано <var>$1query</var>, протокол <kbd>http</kbd>. Залиште пустими і це, і <var>$1query</var>, щоб перелічити усі зовнішні посилання.",
+ "apihelp-query+extlinks-param-query": "Шукати рядок без протоколу. Корисно для перевірки, чи містить певна сторінка певне зовнішнє посилання.",
+ "apihelp-query+extlinks-param-expandurl": "Розгорнути протокол-залежні URL за канонічним протоколом.",
+ "apihelp-query+extlinks-example-simple": "Отримати список зовнішніх посилань на <kbd>Main Page<kbd>.",
+ "apihelp-query+exturlusage-description": "Перерахувати сторінки, які містять поданий URL.",
+ "apihelp-query+exturlusage-param-prop": "Які відомості включати:",
+ "apihelp-query+exturlusage-paramvalue-prop-ids": "Додає ID сторінки.",
+ "apihelp-query+exturlusage-paramvalue-prop-title": "Додає заголовок і ID простору назв сторінки.",
+ "apihelp-query+exturlusage-paramvalue-prop-url": "Додає URL, використаний на сторінці.",
+ "apihelp-query+exturlusage-param-protocol": "Протокол URL. Якщо пусто і вказано <var>$1query</var>, протокол <kbd>http</kbd>. Залиште пустими і це, і <var>$1query</var>, щоб перелічити усі зовнішні посилання.",
+ "apihelp-query+exturlusage-param-query": "Шукати рядок без протоколу. Див. [[Special:LinkSearch]]. Залиште пустим, щоб вивести усі зовнішні посилання.",
+ "apihelp-query+exturlusage-param-namespace": "Простори назв для переліку.",
+ "apihelp-query+exturlusage-param-limit": "Скільки сторінок виводити.",
+ "apihelp-query+exturlusage-param-expandurl": "Розгорнути протокол-залежні URL за канонічним протоколом.",
+ "apihelp-query+exturlusage-example-simple": "Показати сторінки, які посилаються на <kbd>http://www.mediawiki.org</kbd>.",
+ "apihelp-query+filearchive-description": "Перерахувати всі вилучені файли послідовно.",
+ "apihelp-query+filearchive-param-from": "Назва зображення, з якої почати перелічувати.",
+ "apihelp-query+filearchive-param-to": "Назва зображення, якою закінчити перелічувати.",
+ "apihelp-query+filearchive-param-prefix": "Шукати усі назви зображень, які починаються з цього значення.",
+ "apihelp-query+filearchive-param-limit": "Скільки всього зображень виводити.",
+ "apihelp-query+filearchive-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+filearchive-param-sha1": "SHA1-хеш зображення. Перевизначає $1sha1base36.",
+ "apihelp-query+filearchive-param-sha1base36": "SHA1-хеш зображення у base 36 (використано в MediaWiki).",
+ "apihelp-query+filearchive-param-prop": "Which image information to get:",
+ "apihelp-query+filearchive-paramvalue-prop-sha1": "Додає хеш SHA-1 до зображення.",
+ "apihelp-query+filearchive-paramvalue-prop-timestamp": "Додає часову мітку завантаженої версії.",
+ "apihelp-query+filearchive-paramvalue-prop-user": "Додає користувача, який завантажив версію зображення.",
+ "apihelp-query+filearchive-paramvalue-prop-size": "Додає розмір зображення у байтах, а також висоту, ширину і кількість сторінок (якщо є).",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "Аліас розміру.",
+ "apihelp-query+filearchive-paramvalue-prop-description": "Додає опис версії зображення.",
+ "apihelp-query+filearchive-paramvalue-prop-parseddescription": "Аналіз опису зображення.",
+ "apihelp-query+filearchive-paramvalue-prop-mime": "Додає MIME-тип зображення.",
+ "apihelp-query+filearchive-paramvalue-prop-mediatype": "Додає медіатип зображення.",
+ "apihelp-query+filearchive-paramvalue-prop-metadata": "Вилає Exif-метадані версії зображення.",
+ "apihelp-query+filearchive-paramvalue-prop-bitdepth": "Додає бітну глибину версії.",
+ "apihelp-query+filearchive-paramvalue-prop-archivename": "Додає до імені версію архіву для неостаточного варіанту файлу.",
+ "apihelp-query+filearchive-example-simple": "Показати список усіх вилучених файлів.",
+ "apihelp-query+filerepoinfo-description": "Видати мета-інформацію про репозиторії зображень, налаштовані на вікі.",
+ "apihelp-query+filerepoinfo-param-prop": "Які властивості репозиторію отримати (на деяких вікі може бути більше):\n;apiurl:URL до репозиторію API — корисне для отримання інформації про зображення з хосту.\n;name:Ключ репозиторію — використано в e.g. <var>[[mw:Manual:$wgForeignFileRepos|$wgForeignFileRepos]]</var> і значення [[Special:ApiHelp/query+imageinfo|imageinfo]].\n;displayname:Людиночита назва репозиторію вікі.\n;rooturl:Корінний URL для шляху зображення.\n;local:Чи репозиторій локальний, чи ні.",
+ "apihelp-query+filerepoinfo-example-simple": "Отримати інформацію про репозиторії файлів.",
+ "apihelp-query+fileusage-description": "Знайти всі сторінки, що використовують дані файли.",
+ "apihelp-query+fileusage-param-prop": "Які властивості отримати:",
+ "apihelp-query+fileusage-paramvalue-prop-pageid": "ID кожної сторінки.",
+ "apihelp-query+fileusage-paramvalue-prop-title": "Назва кожної сторінки.",
+ "apihelp-query+fileusage-paramvalue-prop-redirect": "Помітка, якщо сторінка є перенаправленням.",
+ "apihelp-query+fileusage-param-namespace": "Включати сторінки лише в цих просторах назв.",
+ "apihelp-query+fileusage-param-limit": "Скільки результатів виводити.",
+ "apihelp-query+fileusage-param-show": "Показати лише елементи, що відповідають цим критеріям:\n;redirect:Показати лише перенаправлення.\n;!redirect:Показати лише не перенаправлення.",
+ "apihelp-query+fileusage-example-simple": "Отримати список сторінок, які використовують [[:File:Example.jpg]].",
+ "apihelp-query+fileusage-example-generator": "Отримати інформацію про сторінки, які використовують [[:File:Example.jpg]].",
+ "apihelp-query+imageinfo-description": "Видає інформацію про файл й історію завантаження.",
+ "apihelp-query+imageinfo-param-prop": "Яку інформацію отримати:",
+ "apihelp-query+imageinfo-paramvalue-prop-timestamp": "Додає мітку часу для завантаженої версії.",
+ "apihelp-query+imageinfo-paramvalue-prop-user": "Додає користувача, який завантажив кожну версію файлу.",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "Додати ідентифікатор користувача, який завантажив кожну версію файлу.",
+ "apihelp-query+imageinfo-paramvalue-prop-comment": "Коментар до версії.",
+ "apihelp-query+imageinfo-paramvalue-prop-parsedcomment": "Аналізований коментар версії.",
+ "apihelp-query+imageinfo-paramvalue-prop-canonicaltitle": "Додає канонічну назву файлу.",
+ "apihelp-query+imageinfo-paramvalue-prop-url": "Дає посилання на файл і сторінку опису.",
+ "apihelp-query+imageinfo-paramvalue-prop-size": "Додає розмір файлу в байтах, а також висоту, ширину і кількість сторінок (якщо це можливо).",
+ "apihelp-query+imageinfo-paramvalue-prop-dimensions": "Псевдонім для розміру.",
+ "apihelp-query+imageinfo-paramvalue-prop-sha1": "Додає SHA-1 хеш файлу.",
+ "apihelp-query+imageinfo-paramvalue-prop-mime": "Додає MIME-тип файлу.",
+ "apihelp-query+imageinfo-paramvalue-prop-thumbmime": "Додає MIME-мініатюри зображення (передбачає url і параметр $1urlwidth).",
+ "apihelp-query+imageinfo-paramvalue-prop-mediatype": "Додає медіатип файлу.",
+ "apihelp-query+imageinfo-paramvalue-prop-metadata": "Перелічує Exif-метадані версії файлу.",
+ "apihelp-query+imageinfo-paramvalue-prop-commonmetadata": "Перелічує метадані формату версії файлу.",
+ "apihelp-query+imageinfo-paramvalue-prop-extmetadata": "Перелічує форматовані метадані, поєднані з кількох джерел. Результати у форматі HTML.",
+ "apihelp-query+imageinfo-paramvalue-prop-archivename": "Додає назву файлу архівної версії для неостанніх версій.",
+ "apihelp-query+imageinfo-paramvalue-prop-bitdepth": "Додає бітну глибину версії.",
+ "apihelp-query+imageinfo-paramvalue-prop-uploadwarning": "Використовується на Special:Upload page для отримання інформації про наявний файл. Не призначено для використання поза ядром MediaWiki.",
+ "apihelp-query+imageinfo-param-limit": "Скільки виводити версій кожного файлу.",
+ "apihelp-query+imageinfo-param-start": "Часова мітка, з якої почати список.",
+ "apihelp-query+imageinfo-param-end": "Часова мітка, на якій закінчити список.",
+ "apihelp-query+imageinfo-param-urlwidth": "Якщо вказано $2prop=url, буде видано URL на масштабоване до цього розміру зображення.\nДля підвищення продуктивності, якщо використовується ця опція, не буде видано більше, ніж $1 {{PLURAL:$1|масштабоване зображення|масштабовані зображення|масштабованих зображень}}.",
+ "apihelp-query+imageinfo-param-urlheight": "Аналогічно до $1urlwidth.",
+ "apihelp-query+imageinfo-param-metadataversion": "Версія метаданих, яку використати. Якщо вказано <kbd>latest</kbd>, використати останню версію. За замовчуванням — <kbd>1</kbd> для зворотної сумісності.",
+ "apihelp-query+imageinfo-param-extmetadatalanguage": "Якою мовою вибирати метадані. Це стосується і того, який переклад вибирати, якщо є різні, і як форматувати різні числа та значення.",
+ "apihelp-query+imageinfo-param-extmetadatamultilang": "Якщо переклади властивості extmetadata доступні, вибрати їх усі.",
+ "apihelp-query+imageinfo-param-extmetadatafilter": "Якщо вказано і не порожньо, буде видано лише ці ключі для $1prop=extmetadata.",
+ "apihelp-query+imageinfo-param-urlparam": "Рядок окремого параметра. Наприклад, PDF-ки можуть використовувати <kbd>page15-100px</kbd>. <var>$1urlwidth</var> повинно використовуватись і бути сумісним з <var>$1urlparam</var>.",
+ "apihelp-query+imageinfo-param-localonly": "Шукати лише файли у локальному репозиторії.",
+ "apihelp-query+imageinfo-example-simple": "Вибрати інформацію про поточну версію [[:File:Albert Einstein Head.jpg]].",
+ "apihelp-query+imageinfo-example-dated": "Вибрати інформацію про версії [[:File:Test.jpg]] від 2008 і раніше.",
+ "apihelp-query+images-description": "Видає усі файли, які містяться на вказаних сторінках.",
+ "apihelp-query+images-param-limit": "Скільки файлів виводити.",
+ "apihelp-query+images-param-images": "Перерахувати лише ці файли. Корисно для перевірки, чи певна сторінка має певний файл.",
+ "apihelp-query+images-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+images-example-simple": "Отримати список файлів, використаних на [[Main Page]].",
+ "apihelp-query+images-example-generator": "Отримати інформацію про всі файли, використані на [[Main Page]].",
+ "apihelp-query+imageusage-description": "Знайти всі сторінки, що використовують дану назву зображення.",
+ "apihelp-query+imageusage-param-title": "Назва для пошуку. Не можна використати разом з $1pageid.",
+ "apihelp-query+imageusage-param-pageid": "ID сторінки для пошуку. Не можна використати разом з $1title.",
+ "apihelp-query+imageusage-param-namespace": "Простір назв для переліку.",
+ "apihelp-query+imageusage-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+imageusage-param-filterredir": "Як відфільтрувати перенаправлення. Якщо встановлено для неперенаправлень при увімкненому $1redirect, це застосовується лише до другого рівня.",
+ "apihelp-query+imageusage-param-limit": "Скільки всього виводити сторінок. Якщо увімкнено <var>$1redirect</var>, ліміт застосовується до кожного рівня окремо (це означає, що може бути видано до 2 * <var>$1limit</var> результатів).",
+ "apihelp-query+imageusage-param-redirect": "Якщо сторінка, яка посилається, є перенаправленням, знайти всі сторінки, які посилаються на це перенаправлення, теж. Максимальний ліміт зменшується наполовину.",
+ "apihelp-query+imageusage-example-simple": "Показати сторінки, які використовують [[:File:Albert Einstein Head.jpg]].",
+ "apihelp-query+imageusage-example-generator": "Отримати інформацію про сторінки, які використовують [[:File:Albert Einstein Head.jpg]].",
+ "apihelp-query+info-description": "Отримати основні відомості про сторінку.",
+ "apihelp-query+info-param-prop": "Які додаткові властивості отримати:",
+ "apihelp-query+info-paramvalue-prop-protection": "Вивести рівень захисту кожної сторінки.",
+ "apihelp-query+info-paramvalue-prop-talkid": "Ідентифікатор сторінки обговорення для кожної сторінки, що не є обговоренням.",
+ "apihelp-query+info-paramvalue-prop-watched": "Вивести статус спостереженості кожної сторінки.",
+ "apihelp-query+info-paramvalue-prop-watchers": "Кількість спостерігачів, якщо це дозволено.",
+ "apihelp-query+info-paramvalue-prop-notificationtimestamp": "Часова мітка сповіщення списку спостереження кожної сторінки.",
+ "apihelp-query+info-paramvalue-prop-subjectid": "Ідентифікатор батьківської сторінки для кожної сторінки обговорення.",
+ "apihelp-query+info-paramvalue-prop-url": "Дає повний URL, URL редагування та канонічний URL для кожної сторінки.",
+ "apihelp-query+info-paramvalue-prop-readable": "Чи користувач може редагувати цю сторінку.",
+ "apihelp-query+info-paramvalue-prop-preload": "Дає текст, виданий EditFormPreloadText.",
+ "apihelp-query+info-paramvalue-prop-displaytitle": "Дає спосіб, у який відображається назва сторінки.",
+ "apihelp-query+info-param-testactions": "Перевірити, чи поточний користувач може виконувати певні дії на сторінці.",
+ "apihelp-query+info-param-token": "Використати натомість [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
+ "apihelp-query+info-example-simple": "Отримати інформацію про сторінку <kbd>Main Page</kbd>.",
+ "apihelp-query+info-example-protection": "Отримати загальну інформацію і дані про захист сторінки <kbd>Main Page</kbd>.",
+ "apihelp-query+iwbacklinks-description": "Знайти всі сторінки, які посилаються на дане інтервікі-посилання.\n\nМоже використовуватися, щоб знайти всі посилання з префіксом або всі посилання на назву (з даним префіксом). Без використання жодного параметра це, по суті, «всі інтервікі-посилання».",
+ "apihelp-query+iwbacklinks-param-prefix": "Префікс для інтервікі.",
+ "apihelp-query+iwbacklinks-param-title": "Інтервікі-посилання для пошуку. Повинно використовуватися з <var>$1blprefix</var>.",
+ "apihelp-query+iwbacklinks-param-limit": "Скільки всього сторінок виводити.",
+ "apihelp-query+iwbacklinks-param-prop": "Які властивості отримати:",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Додає префікс інтервікі.",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Додає назву інтервікі.",
+ "apihelp-query+iwbacklinks-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+iwbacklinks-example-simple": "Отримати сторінки, що посилаються на [[wikibooks:Test]].",
+ "apihelp-query+iwbacklinks-example-generator": "Отримати інформацію про сторінки, що посилаються на [[wikibooks:Test]].",
+ "apihelp-query+iwlinks-description": "Видає усі інтервікі-посилання із вказаних сторінок.",
+ "apihelp-query+iwlinks-param-url": "Чи отримувати повну URL-адресу (не може використовуватися з $1prop).",
+ "apihelp-query+iwlinks-param-prop": "Які додаткові властивості отримати для кожного міжмовного посилання:",
+ "apihelp-query+iwlinks-paramvalue-prop-url": "Додає повну URL-адресу.",
+ "apihelp-query+iwlinks-param-limit": "Скільки інтервікі-посилання виводити.",
+ "apihelp-query+iwlinks-param-prefix": "Видавати інтервікі-посилання лише з цим префіксом.",
+ "apihelp-query+iwlinks-param-title": "Інтервікі-посилання для пошуку. Повинно використовуватися з <var>$1prefix</var>.",
+ "apihelp-query+iwlinks-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+iwlinks-example-simple": "Отримати інтервікі-посилання зі сторінки <kbd>Main Page</kbd>.",
+ "apihelp-query+langbacklinks-description": "Знайти всі сторінки, які посилаються на дане мовне посилання.\n\nМоже бути використано для пошуку всіх посилань з кодом мови або всіх посилань на назву (з урахуванням мови). \nБез жодного параметра це «усі мовні посилання».\n\nЗверніть увагу, що це може не розглядати мовні посилання, додані розширеннями.",
+ "apihelp-query+langbacklinks-param-lang": "Мова мовного посилання.",
+ "apihelp-query+langbacklinks-param-title": "Мовне посилання для пошуку. Мусить бути використане з $1lang.",
+ "apihelp-query+langbacklinks-param-limit": "Скільки всього сторінок виводити.",
+ "apihelp-query+langbacklinks-param-prop": "Які властивості для отримання:",
+ "apihelp-query+langbacklinks-paramvalue-prop-lllang": "Додає код мови мовного посилання.",
+ "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Додає назву мовного посилання.",
+ "apihelp-query+langbacklinks-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+langbacklinks-example-simple": "Отримати сторінки, що посилаються на [[:fr:Test]].",
+ "apihelp-query+langbacklinks-example-generator": "Отримати інформацію про сторінки, що посилаються на [[:fr:Test]].",
+ "apihelp-query+langlinks-description": "Видає усі міжмовні посилання із вказаних сторінок.",
+ "apihelp-query+langlinks-param-limit": "Скільки мовних посилань виводити.",
+ "apihelp-query+langlinks-param-url": "Чи отримувати повну URL-адресу (не може використовуватися з <var>$1prop</var>).",
+ "apihelp-query+langlinks-param-prop": "Які додаткові властивості для отримання кожного із міжмовного посилання:",
+ "apihelp-query+langlinks-paramvalue-prop-url": "Додає повну URL-адресу.",
+ "apihelp-query+langlinks-paramvalue-prop-langname": "Додає локалізовану назву мови (найкращий варіант). Використайте <var>$1inlanguagecode</var> для контролю мови.",
+ "apihelp-query+langlinks-paramvalue-prop-autonym": "Додає самоназву мови.",
+ "apihelp-query+langlinks-param-lang": "Видавати лише мовні посилання з кодом мови.",
+ "apihelp-query+langlinks-param-title": "Посилання для пошуку. Повинно використовуватися з <var>$1lang</var>.",
+ "apihelp-query+langlinks-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+langlinks-param-inlanguagecode": "Код мови для локалізованих назв мов.",
+ "apihelp-query+langlinks-example-simple": "Отримати міжмовні посилання зі сторінки <kbd>Main Page</kbd>.",
+ "apihelp-query+links-description": "Видає усі посилання із вказаних сторінок.",
+ "apihelp-query+links-param-namespace": "Показати посилання лише у цих просторах назв.",
+ "apihelp-query+links-param-limit": "Скільки посилань виводити.",
+ "apihelp-query+links-param-titles": "Перерахувати лише посилання на ці назви. Корисно для перевірки, чи певна сторінка посилається на певну назву.",
+ "apihelp-query+links-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+links-example-simple": "Отримати посилання зі сторінки <kbd>Main Page</kbd>.",
+ "apihelp-query+links-example-generator": "Отримати інформацію про сторінки посилань на сторінці <kbd>Main Page</kbd>.",
+ "apihelp-query+links-example-namespaces": "Отримати посилання зі сторінки <kbd>Main Page</kbd> у просторах назв {{ns:user}} і {{ns:template}}.",
+ "apihelp-query+linkshere-description": "Знайти усі сторінки, що посилаються на подані сторінки.",
+ "apihelp-query+linkshere-param-prop": "Які властивості отримати:",
+ "apihelp-query+linkshere-paramvalue-prop-pageid": "ID кожної сторінки.",
+ "apihelp-query+linkshere-paramvalue-prop-title": "Назва кожної сторінки.",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "Відзначити, якщо сторінка є перенаправленням.",
+ "apihelp-query+linkshere-param-namespace": "Включати сторінки лише в цих просторах назв.",
+ "apihelp-query+linkshere-param-limit": "Скільки результатів виводити.",
+ "apihelp-query+linkshere-param-show": "Показати лише елементи, що відповідають цим критеріям:\n;redirect:Показати лише перенаправлення.\n;!redirect:Показати лише не перенаправлення.",
+ "apihelp-query+linkshere-example-simple": "Отримати список сторінок, що посилаються на [[Main Page]].",
+ "apihelp-query+linkshere-example-generator": "Отримати інформацію про сторінки, що посилаються на [[Main Page]].",
+ "apihelp-query+logevents-description": "Отримати події з журналів.",
+ "apihelp-query+logevents-param-prop": "Які властивості отримати:",
+ "apihelp-query+logevents-paramvalue-prop-ids": "Додає ID події в журналі.",
+ "apihelp-query+logevents-paramvalue-prop-title": "Додає назву сторінки події в журналі.",
+ "apihelp-query+logevents-paramvalue-prop-type": "Додає тип події в журналі.",
+ "apihelp-query+logevents-paramvalue-prop-user": "Додає користувача, відповідального за подію в журналі.",
+ "apihelp-query+logevents-paramvalue-prop-userid": "Додає ID користувача, відповідального за подію в журналі.",
+ "apihelp-query+logevents-paramvalue-prop-timestamp": "Додає часову мітку події.",
+ "apihelp-query+logevents-paramvalue-prop-comment": "Додає коментар події.",
+ "apihelp-query+logevents-paramvalue-prop-parsedcomment": "Додає проаналізований коментар події.",
+ "apihelp-query+logevents-paramvalue-prop-details": "Виводить додаткові деталі щодо події.",
+ "apihelp-query+logevents-paramvalue-prop-tags": "Виводить мітки події.",
+ "apihelp-query+logevents-param-type": "Відфільтрувати записи журналу лише цього типу.",
+ "apihelp-query+logevents-param-action": "Відфільтрувати дії журналу до лише цієї дії. Перезаписує <var>$1type</var>. Джокери на зразок <kbd>action/*</kbd> дозволяють вказати будь-який рядок замість астеріска.",
+ "apihelp-query+logevents-param-start": "Часова мітка початку переліку.",
+ "apihelp-query+logevents-param-end": "Часова мітка завершення переліку.",
+ "apihelp-query+logevents-param-user": "Відфільтрувати серед записів зроблені поданим користувачем.",
+ "apihelp-query+logevents-param-title": "Відфільтрувати серед записів пов'язані зі сторінкою.",
+ "apihelp-query+logevents-param-namespace": "Відфільтрувати до записів у поданому просторі назв.",
+ "apihelp-query+logevents-param-prefix": "Відфільтрувати до записів, що починаються з цього префікса.",
+ "apihelp-query+logevents-param-tag": "Перерахувати лише записи подій, помічені цим теґом.",
+ "apihelp-query+logevents-param-limit": "Скільки всього виводити записів подій.",
+ "apihelp-query+logevents-example-simple": "Перелічити останні подій в журналі.",
+ "apihelp-query+pagepropnames-description": "Перелічити усі назви властивостей сторінки, що використовуються у вікі.",
+ "apihelp-query+pagepropnames-param-limit": "Максимальна кількість назв для виведення.",
+ "apihelp-query+pagepropnames-example-simple": "Отримати перші 10 назв властивостей.",
+ "apihelp-query+pageprops-description": "Дає різні властивості, визначені у вмісті сторінки.",
+ "apihelp-query+pageprops-param-prop": "Перерахувати лише ці властивості. Корисно для перевірки, чи певна сторінка використовує певну властивість сторінки.",
+ "apihelp-query+pageprops-example-simple": "Отримати властивості для сторінок <kbd>Main Page</kbd> і <kbd>MediaWiki</kbd>.",
+ "apihelp-query+pageswithprop-description": "Перелічити усі сторінки, що використовують подану властивість сторінки.",
+ "apihelp-query+pageswithprop-param-propname": "Властивість сторі́нки, для якої перелічити сторінки́.",
+ "apihelp-query+pageswithprop-param-prop": "Які відомості включати:",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "Додає ID сторінки.",
+ "apihelp-query+pageswithprop-paramvalue-prop-title": "Додає заголовок і ID простору назв сторінки.",
+ "apihelp-query+pageswithprop-paramvalue-prop-value": "Додає значення властивості сторінки.",
+ "apihelp-query+pageswithprop-param-limit": "Максимальна кількість сторінок для виведення.",
+ "apihelp-query+pageswithprop-param-dir": "У якому напрямку сортувати.",
+ "apihelp-query+pageswithprop-example-simple": "Перелічити перші 10, що використовують <code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code>.",
+ "apihelp-query+pageswithprop-example-generator": "Отримати додаткову інформацію про перші 10 сторінок, що використовують <code>_&#95;NOTOC_&#95;</code>.",
+ "apihelp-query+prefixsearch-description": "Виконати пошук назв сторінок по префіксу.",
+ "apihelp-query+prefixsearch-param-search": "Рядок пошуку.",
+ "apihelp-query+prefixsearch-param-namespace": "Простори назв, у яких шукати.",
+ "apihelp-query+prefixsearch-param-limit": "Максимальна кількість результатів для виведення.",
+ "apihelp-query+prefixsearch-param-offset": "Кількість результатів, які пропустити.",
+ "apihelp-query+prefixsearch-example-simple": "Шукати назви сторінок, які починаються з <kbd>meaning</kbd>.",
+ "apihelp-query+protectedtitles-description": "Вивести список усіх назв, захищених від створення.",
+ "apihelp-query+protectedtitles-param-namespace": "Перерахувати назви лише в цих просторах назв.",
+ "apihelp-query+protectedtitles-param-level": "Перерахувати лише назви з цими рівням захисту.",
+ "apihelp-query+protectedtitles-param-limit": "Скільки всього сторінок виводити.",
+ "apihelp-query+protectedtitles-param-start": "Почати список з цієї часової мітки захисту.",
+ "apihelp-query+protectedtitles-param-end": "Закінчити список цією часовою міткою захисту.",
+ "apihelp-query+protectedtitles-param-prop": "Які властивості отримати:",
+ "apihelp-query+protectedtitles-paramvalue-prop-timestamp": "Додає часову мітку встановлення захисту.",
+ "apihelp-query+protectedtitles-paramvalue-prop-user": "Додає користувача, який встановив захист.",
+ "apihelp-query+protectedtitles-paramvalue-prop-userid": "Додає ID користувача, який встановив захист.",
+ "apihelp-query+protectedtitles-paramvalue-prop-comment": "Додає коментар захисту.",
+ "apihelp-query+protectedtitles-paramvalue-prop-parsedcomment": "Додає проаналізований коментар захисту.",
+ "apihelp-query+protectedtitles-paramvalue-prop-expiry": "Додає часову мітку закінчення захисту.",
+ "apihelp-query+protectedtitles-paramvalue-prop-level": "Додає рівень захисту.",
+ "apihelp-query+protectedtitles-example-simple": "Вивести список захищених назв.",
+ "apihelp-query+protectedtitles-example-generator": "Знайти посилання на захищені назви в основному просторі назв.",
+ "apihelp-query+querypage-description": "Отримати список, кий дає спеціальна сторінка на базі QueryPage.",
+ "apihelp-query+querypage-param-page": "Назва спеціальної сторінки. Зважте, що чутлива до регістру.",
+ "apihelp-query+querypage-param-limit": "Кількість результатів, які виводити.",
+ "apihelp-query+querypage-example-ancientpages": "Видати результати з [[Special:Ancientpages]].",
+ "apihelp-query+random-description": "Отримати набір випадкових сторінок.\n\nСторінки перелічені у певній послідовності, лише початкова точка рандомна. Це означає, що якщо, наприклад, <samp>Main Page</samp> є першою випадковою сторінкою у списку, <samp>List of fictional monkeys</samp> <em>завжди</em> буде другою, <samp>List of people on stamps of Vanuatu</samp> — третьою, і т. д.\n\nЯкщо кількість сторінок у просторі назв менша, ніж <var>$1limit</var>, буде показано менше сторінок. Та сама сторінка не виводиться двічі.",
+ "apihelp-query+random-param-namespace": "Вивести сторінки лише у цих просторах назв.",
+ "apihelp-query+random-param-limit": "Обмежити кількість випадкових сторінок, які буде видано.",
+ "apihelp-query+random-param-redirect": "Завантажити випадкове перенаправлення замість випадкової сторінки.",
+ "apihelp-query+random-example-simple": "Отримати дві випадкові сторінки з основного простору назв.",
+ "apihelp-query+random-example-generator": "Видати інформацію про дві випадкові сторінки з основного простору назв.",
+ "apihelp-query+recentchanges-description": "Перерахувати нещодавні зміни.",
+ "apihelp-query+recentchanges-param-start": "Часова мітка початку переліку.",
+ "apihelp-query+recentchanges-param-end": "Часова мітка завершення переліку.",
+ "apihelp-query+recentchanges-param-namespace": "Відфільтрувати до змін лише у цих просторах назв.",
+ "apihelp-query+recentchanges-param-user": "Перерахувати лише зміни, зроблені цим користувачем.",
+ "apihelp-query+recentchanges-param-excludeuser": "Не перераховувати зміни, зроблені цим користувачем.",
+ "apihelp-query+recentchanges-param-tag": "Перерахувати лише зміни, помічені цим теґом.",
+ "apihelp-query+recentchanges-param-prop": "Включити додаткові відомості:",
+ "apihelp-query+recentchanges-paramvalue-prop-user": "Додає користувача, відповідального за редагування і мітки, якщо він IP.",
+ "apihelp-query+recentchanges-paramvalue-prop-userid": "Додає ID користувача, відповідального за редагування.",
+ "apihelp-query+recentchanges-paramvalue-prop-comment": "Додає коментар редагування.",
+ "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "Додає проаналізований коментар редагування.",
+ "apihelp-query+recentchanges-paramvalue-prop-flags": "Додає прапорці редагування.",
+ "apihelp-query+recentchanges-paramvalue-prop-timestamp": "Додає часову мітку редагування.",
+ "apihelp-query+recentchanges-paramvalue-prop-title": "Додає назву сторінки, де було редагування.",
+ "apihelp-query+recentchanges-paramvalue-prop-ids": "Додає ID сторінки, ID нещодавніх змін, а також ID нової і старої версій.",
+ "apihelp-query+recentchanges-paramvalue-prop-sizes": "Додає нову і стару довжину сторінки в байтах.",
+ "apihelp-query+recentchanges-paramvalue-prop-redirect": "Помічає редагування, якщо сторінка є перенаправленням.",
+ "apihelp-query+recentchanges-paramvalue-prop-patrolled": "Помічає редагування як відпатрульвані чи невідпатрульовані.",
+ "apihelp-query+recentchanges-paramvalue-prop-loginfo": "Додає інформацію журналу (ID журналу, тип журналу тощо) до записів журналу.",
+ "apihelp-query+recentchanges-paramvalue-prop-tags": "Виводить мітки запису.",
+ "apihelp-query+recentchanges-paramvalue-prop-sha1": "Додає контрольну суму вмісту для записів, пов'язаних з версією.",
+ "apihelp-query+recentchanges-param-token": "Використати натомість <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
+ "apihelp-query+recentchanges-param-show": "Показати лише елементи, що задовільняють ці критерії. Наприклад, для перегляду лише незначних змін, здійснених користувачами, що увійшли до системи, вкажіть $1show=minor|!anon.",
+ "apihelp-query+recentchanges-param-limit": "Скільки всього змін виводити.",
+ "apihelp-query+recentchanges-param-type": "Які типи змін показувати.",
+ "apihelp-query+recentchanges-param-toponly": "Виводити лише зміни, які є останньою версією.",
+ "apihelp-query+recentchanges-example-simple": "Вивести нещодавні зміни.",
+ "apihelp-query+recentchanges-example-generator": "Отримати інформацію про сторінки з недавніми невідпатрульованими змінами.",
+ "apihelp-query+redirects-description": "Видає усі перенаправлення на дані сторінки.",
+ "apihelp-query+redirects-param-prop": "Які властивості отримати:",
+ "apihelp-query+redirects-paramvalue-prop-pageid": "Ідентифікатор сторінки кожного перенаправлення.",
+ "apihelp-query+redirects-paramvalue-prop-title": "Назва кожного перенаправлення.",
+ "apihelp-query+redirects-paramvalue-prop-fragment": "Фрагмент кожного перенаправлення, якщо є.",
+ "apihelp-query+redirects-param-namespace": "Включати сторінки лише в цих просторах назв.",
+ "apihelp-query+redirects-param-limit": "Скільки перенаправлень виводити.",
+ "apihelp-query+redirects-param-show": "Показати лише елементи, які відповідають цим критеріям:\n;fragment:Показати лише перенаправлення з фрагментом.\n;!fragment:Показати лише перенаправлення без фрагмента.",
+ "apihelp-query+redirects-example-simple": "Отримати список перенаправлень на [[Main Page]].",
+ "apihelp-query+redirects-example-generator": "Отримати інформацію про всі перенаправлення на [[Main Page]].",
+ "apihelp-query+revisions-description": "Отримати інформацію про версію.\n\nМоже бути використано кількома способами:\n# Отримати дані про набір сторінок (останні версії), вказавши назви або ідентифікатори сторінок.\n# Отримати версії для однієї вказаної сторінки, використавши назви або ідентифікатори і початок, кінець чи ліміт.\n# Отримати дані про набір версій, встановивши їх ID й ідентифікатори версій.",
+ "apihelp-query+revisions-paraminfo-singlepageonly": "Може використовуватися тільки з однією сторінкою (режим #2).",
+ "apihelp-query+revisions-param-startid": "З якого ID версії почати перелік.",
+ "apihelp-query+revisions-param-endid": "Зупинити перелік версій на цьому ID версії.",
+ "apihelp-query+revisions-param-start": "З якої часової мітки версії почати перелік.",
+ "apihelp-query+revisions-param-end": "Перелічувати до цієї часової мітки.",
+ "apihelp-query+revisions-param-user": "Включати лише версій, зроблені цим користувачем.",
+ "apihelp-query+revisions-param-excludeuser": "Виключити версії, зроблені цим користувачем.",
+ "apihelp-query+revisions-param-tag": "Перелічити лише версії, позначені цією міткою.",
+ "apihelp-query+revisions-param-token": "Які токени отримати для кожної версії.",
+ "apihelp-query+revisions-example-content": "Отримати дані з вмістом останньої версії для заголовків <kbd>API</kbd> та <kbd>Main Page</kbd>.",
+ "apihelp-query+revisions-example-last5": "Отримати 5 останніх версії <kbd>Main Page</kbd>.",
+ "apihelp-query+revisions-example-first5": "Отримати 5 перших версій <kbd>Main Page</kbd>.",
+ "apihelp-query+revisions-example-first5-after": "Отримати 5 перших версій <kbd>Main Page</kbd>, зроблених після 2006-05-01.",
+ "apihelp-query+revisions-example-first5-not-localhost": "Отримати 5 перших версій <kbd>Main Page</kbd>, що не були зроблені анонімним користувачем <kbd>127.0.0.1</kbd>.",
+ "apihelp-query+revisions-example-first5-user": "Отримати 5 перших версій <kbd>Main Page</kbd>, що були зроблені користувачем <kbd>MediaWiki default</kbd>.",
+ "apihelp-query+revisions+base-param-prop": "Які властивості отримати для кожної версії:",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "ID версії.",
+ "apihelp-query+revisions+base-paramvalue-prop-flags": "Позначки версії (незначні).",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "Часова мітка версії.",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "Користувач, який створив версію.",
+ "apihelp-query+revisions+base-paramvalue-prop-userid": "ID користувача, який створив версію.",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "Довжина версії (в байтах).",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "SHA-1 (base 16) версії.",
+ "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "ID моделі вмісту версії.",
+ "apihelp-query+revisions+base-paramvalue-prop-comment": "Коментар користувача до версії.",
+ "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": "Синтаксичне дерево XML вмісту версії (передбачає модель вмісту <code>$1</code>).",
+ "apihelp-query+revisions+base-param-limit": "Обмежити кількість версій, які буде видано.",
+ "apihelp-query+revisions+base-param-expandtemplates": "Розгорнути шаблони у вмісті версії (передбачає $1prop=content).",
+ "apihelp-query+revisions+base-param-generatexml": "Генерувати синтаксичне дерево XML для вмісту версії (передбачає $1prop=content; замінено на <kbd>$1prop=parsetree</kbd>).",
+ "apihelp-query+revisions+base-param-parse": "Аналізувати вміст версії (передбачає $1prop=content). З причин продуктивності, якщо використовується ця опція, $1limit встановлюється як 1.",
+ "apihelp-query+revisions+base-param-section": "Витягнути вміст лише розділу з цим номером.",
+ "apihelp-query+revisions+base-param-diffto": "ID версії, з якою порівняти кожну версію. Використайте <kbd>prev</kbd>, <kbd>next</kbd> і <kbd>cur</kbd> для попередньої, наступної та поточної версій відповідно.",
+ "apihelp-query+revisions+base-param-difftotext": "Текст, з яким порівняти кожну версію. Порівнює лише обмежену кількість версій. Перевизначає <var>$1diffto</var>. Якщо вказано <var>$1section</var>, лише ця версія буде порівняна з цим текстом.",
+ "apihelp-query+revisions+base-param-contentformat": "Формат серіалізації, використаний для <var>$1difftotext</var> й очікуваний для контенту-результату.",
+ "apihelp-query+search-description": "Виконати повнотекстовий пошук.",
+ "apihelp-query+search-param-search": "Шукати назви сторінок або вміст, що співпадає з цим значенням. Ви можете використати рядок пошуку для виклику спеціальних функцій пошуку, залежно від внутрішніх установок пошуку у вікі.",
+ "apihelp-query+search-param-namespace": "Шукати лише в межах цих просторів назв.",
+ "apihelp-query+search-param-what": "Який тип пошуку виконати.",
+ "apihelp-query+search-param-info": "Які метадані отримати.",
+ "apihelp-query+search-param-prop": "Які властивості для виведення:",
+ "apihelp-query+search-paramvalue-prop-size": "Додає розмір сторінки в байтах.",
+ "apihelp-query+search-paramvalue-prop-wordcount": "Додає кількість слів на сторінці.",
+ "apihelp-query+search-paramvalue-prop-timestamp": "Додає часову мітку останнього редагування сторінки.",
+ "apihelp-query+search-paramvalue-prop-snippet": "Додає проаналізований уривок сторінки.",
+ "apihelp-query+search-paramvalue-prop-titlesnippet": "Додає проаналізований уривок заголовка сторінки.",
+ "apihelp-query+search-paramvalue-prop-redirectsnippet": "Додає проаналізований уривок перенаправлення.",
+ "apihelp-query+search-paramvalue-prop-redirecttitle": "Додає заголовок відповідного перенаправлення.",
+ "apihelp-query+search-paramvalue-prop-sectionsnippet": "Додає проаналізований уривок заголовка відповідного розділу.",
+ "apihelp-query+search-paramvalue-prop-sectiontitle": "Додає заголовок відповідного розділу.",
+ "apihelp-query+search-paramvalue-prop-categorysnippet": "Додає проаналізований уривок відповідної категорії.",
+ "apihelp-query+search-paramvalue-prop-isfilematch": "Додає перемикач, який показує, є пошук знайшов вміст файлу.",
+ "apihelp-query+search-paramvalue-prop-score": "<span class=\"apihelp-deprecated\">Застаріло й інгорується.</span>",
+ "apihelp-query+search-paramvalue-prop-hasrelated": "<span class=\"apihelp-deprecated\">Застаріло й інгорується.</span>",
+ "apihelp-query+search-param-limit": "Скільки всього сторінок виводити.",
+ "apihelp-query+search-param-interwiki": "Включати інтервікі в результатах пошуку, якщо доступно.",
+ "apihelp-query+search-param-backend": "Який бекенд пошуку використовувати, якщо не за замовчуванням.",
+ "apihelp-query+search-example-simple": "Шукати <kbd>meaning</kbd>.",
+ "apihelp-query+search-example-text": "Шукати в текстах <kbd>meaning</kbd>.",
+ "apihelp-query+search-example-generator": "Отримати інформацію про сторінки, на яких знайдено <kbd>meaning</kbd>.",
+ "apihelp-query+siteinfo-description": "Видати загальну інформацію про сайт.",
+ "apihelp-query+siteinfo-param-prop": "Яку інформацію отримати:",
+ "apihelp-query+siteinfo-paramvalue-prop-general": "Загальна системна інформація.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespaces": "Список зареєстрованих просторів назв та їхні канонічні назви.",
+ "apihelp-query+siteinfo-paramvalue-prop-namespacealiases": "Список зареєстрованого простору прізвиськ.",
+ "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "Список аліасів спеціальної сторінки.",
+ "apihelp-query+siteinfo-paramvalue-prop-magicwords": "Список магічних слів та їх аліасів.",
+ "apihelp-query+siteinfo-paramvalue-prop-statistics": "Видає статистику сайту.",
+ "apihelp-query+siteinfo-paramvalue-prop-interwikimap": "Видає карту інтервікі (за бажанням, фільтровану, за бажанням локалізовану з використанням <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-dbrepllag": "Видає сервер бази даних з найбільшою затримкою відповіді.",
+ "apihelp-query+siteinfo-paramvalue-prop-usergroups": "Видає групи користувачів і пов'язані дозволи.",
+ "apihelp-query+siteinfo-paramvalue-prop-libraries": "Видає бібліотеки, встановлені у вікі.",
+ "apihelp-query+siteinfo-paramvalue-prop-extensions": "Видає розширення, встановлені у вікі.",
+ "apihelp-query+siteinfo-paramvalue-prop-fileextensions": "Видає список розширень файлів, які дозволено завантажувати.",
+ "apihelp-query+siteinfo-paramvalue-prop-rightsinfo": "Видає інформацію щодо прав (ліцензії) вікі, якщо наявна.",
+ "apihelp-query+siteinfo-paramvalue-prop-restrictions": "Видає інформацію про наявні типи обмежень (захисту).",
+ "apihelp-query+siteinfo-paramvalue-prop-languages": "Видає список мов, які підтримує MediaWiki (за бажанням локалізовані через <var>$1inlanguagecode</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-skins": "Видає список усіх доступних тем оформлення (опціонально локалізовані з використанням <var>$1inlanguagecode</var>, в іншому разі — мовою вмісту).",
+ "apihelp-query+siteinfo-paramvalue-prop-extensiontags": "Видає список теґів розширення парсеру.",
+ "apihelp-query+siteinfo-paramvalue-prop-functionhooks": "Видає список гуків парсерних функцій.",
+ "apihelp-query+siteinfo-paramvalue-prop-showhooks": "Видає список усіх підписаних гуків (вміст <var>[[mw:Manual:$wgHooks|$wgHooks]]</var>).",
+ "apihelp-query+siteinfo-paramvalue-prop-variables": "Видає список змінних ID.",
+ "apihelp-query+siteinfo-paramvalue-prop-protocols": "Видає список протоколів, дозволених у зовнішніх посиланнях.",
+ "apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "Видає значення налаштувань користувача за замовчуванням.",
+ "apihelp-query+siteinfo-param-filteriw": "Видати лише локальні або лише нелокальні елементи карти інтервікі.",
+ "apihelp-query+siteinfo-param-showalldb": "Перелічити усі сервери баз даних, а не лише той, який робить найбільшу затримку.",
+ "apihelp-query+siteinfo-param-numberingroup": "Перераховує кількість користувачів у групах користувачів.",
+ "apihelp-query+siteinfo-param-inlanguagecode": "Код мови для локалізованих назв мов (найкращий варіант) і назв тем оформлення.",
+ "apihelp-query+siteinfo-example-simple": "Вибрати інформацію про сайт.",
+ "apihelp-query+siteinfo-example-interwiki": "Отримати список локальних інтервікі-префіксів.",
+ "apihelp-query+siteinfo-example-replag": "Перевірити поточне відставання реплікації.",
+ "apihelp-query+stashimageinfo-description": "Видає інформацію про приховані файли.",
+ "apihelp-query+stashimageinfo-param-filekey": "Ключ, який ідентифікує попереднє завантаження, що було тимчасово приховане.",
+ "apihelp-query+stashimageinfo-param-sessionkey": "Аліас для $1filekey, для зворотної сумісності.",
+ "apihelp-query+stashimageinfo-example-simple": "Видає інформацію про прихований файл.",
+ "apihelp-query+stashimageinfo-example-params": "Видає мініатюри для двох прихованих файлів.",
+ "apihelp-query+tags-description": "Перелічити мітки змін.",
+ "apihelp-query+tags-param-limit": "Максимальна кількість міток у списку.",
+ "apihelp-query+tags-param-prop": "Які властивості отримати:",
+ "apihelp-query+tags-paramvalue-prop-name": "Додає назву мітки.",
+ "apihelp-query+tags-paramvalue-prop-displayname": "Додає системне повідомлення для мітки.",
+ "apihelp-query+tags-paramvalue-prop-description": "Додає опис мітки.",
+ "apihelp-query+tags-paramvalue-prop-hitcount": "Додає кількість версій та записів журналу, які мають цю мітку.",
+ "apihelp-query+tags-paramvalue-prop-defined": "Показує, чи мітка визначена.",
+ "apihelp-query+tags-paramvalue-prop-source": "Отримує джерела мітки, що може включати <samp>extension</samp> для визначених розширеннями міток і <samp>manual</samp> для міток, які користувачі можуть застосовувати вручну.",
+ "apihelp-query+tags-paramvalue-prop-active": "І все ж позначка досі задіяна.",
+ "apihelp-query+tags-example-simple": "Перелічити доступні мітки.",
+ "apihelp-query+templates-description": "Видає усі сторінки, які включені на вказаних сторінках.",
+ "apihelp-query+templates-param-namespace": "Показати шаблони лише у цьому просторі назв.",
+ "apihelp-query+templates-param-limit": "Скільки шаблонів виводити.",
+ "apihelp-query+templates-param-templates": "Перерахувати лише ці шаблони. Корисно для перевірки, чи певна сторінка використовує певний шаблон.",
+ "apihelp-query+templates-param-dir": "Напрямок, у якому перелічити.",
+ "apihelp-query+templates-example-simple": "Отримати шаблони, використані на сторінці <kbd>Main Page</kbd>.",
+ "apihelp-query+templates-example-generator": "Отримати інформацію про сторінки шаблонів, використаних на сторінці <kbd>Main Page</kbd>.",
+ "apihelp-query+templates-example-namespaces": "Отримати сторінки у просторах назв {{ns:user}} і {{ns:template}}, які включені на сторінці <kbd>Main Page</kbd>.",
+ "apihelp-query+tokens-description": "Отримує токени для дій, що змінюють дані.",
+ "apihelp-query+tokens-param-type": "Типи токена для запиту.",
+ "apihelp-query+tokens-example-simple": "Отримати csrf-токен (за замовчуванням).",
+ "apihelp-query+tokens-example-types": "Отримати токен спостереження і токен патрулювання.",
+ "apihelp-query+transcludedin-description": "Знайти усі сторінки, що включають подані сторінки.",
+ "apihelp-query+transcludedin-param-prop": "Які властивості отримати:",
+ "apihelp-query+transcludedin-paramvalue-prop-pageid": "ID кожної сторінки.",
+ "apihelp-query+transcludedin-paramvalue-prop-title": "Назва кожної сторінки.",
+ "apihelp-query+transcludedin-paramvalue-prop-redirect": "Помітка, якщо сторінка є перенаправленням.",
+ "apihelp-query+transcludedin-param-namespace": "Включати сторінки лише в цих просторах назв.",
+ "apihelp-query+transcludedin-param-limit": "Скільки результатів виводити.",
+ "apihelp-query+transcludedin-param-show": "Показати лише елементи, що відповідають цим критеріям:\n;redirect:Показати лише перенаправлення.\n;!redirect:Показати лише не перенаправлення.",
+ "apihelp-query+transcludedin-example-simple": "Отримати список сторінок, що включають <kbd>Main Page</kbd>.",
+ "apihelp-query+transcludedin-example-generator": "Отримати інформацію про сторінки, які включають <kbd>Main Page</kbd>.",
+ "apihelp-query+usercontribs-description": "Отримати всі редагування користувача.",
+ "apihelp-query+usercontribs-param-limit": "Максимальна кількість елементів внеску для виведення.",
+ "apihelp-query+usercontribs-param-start": "З якої часової мітки виводити.",
+ "apihelp-query+usercontribs-param-end": "До якої часової мітки виводити.",
+ "apihelp-query+usercontribs-param-user": "Користувачі, для яких отримати внесок.",
+ "apihelp-query+usercontribs-param-userprefix": "Отримати внесок усіх користувачів, чиї імена починаються цим значенням. Перевизначає $1user.",
+ "apihelp-query+usercontribs-param-namespace": "Перерахувати записи внеску лише в цих просторах назв.",
+ "apihelp-query+usercontribs-param-prop": "Включити додаткові відомомсті:",
+ "apihelp-query+usercontribs-paramvalue-prop-ids": "Додає ID сторінки й ID версії.",
+ "apihelp-query+usercontribs-paramvalue-prop-title": "Додає назву й ID простору назв сторінки.",
+ "apihelp-query+usercontribs-paramvalue-prop-timestamp": "Додає часову мітку редагування.",
+ "apihelp-query+usercontribs-paramvalue-prop-comment": "Додає коментар редагування.",
+ "apihelp-query+usercontribs-paramvalue-prop-parsedcomment": "Додає проаналізований коментар редагування.",
+ "apihelp-query+usercontribs-paramvalue-prop-size": "Додає новий розмір редагування.",
+ "apihelp-query+usercontribs-paramvalue-prop-sizediff": "Додає зміну розміру порівняно з попереднім редагуванням.",
+ "apihelp-query+usercontribs-paramvalue-prop-flags": "Додає прапорці редагування.",
+ "apihelp-query+usercontribs-paramvalue-prop-patrolled": "Відзначає патрульовані редагування.",
+ "apihelp-query+usercontribs-paramvalue-prop-tags": "Перелічує мітки редагування.",
+ "apihelp-query+usercontribs-param-show": "Показати лише елементи, що відповідають цим критеріям, наприклад, лише не незначні редагування: <kbd>$2show=!minor</kbd>.\n\nЯкщо вказано <kbd>$2show=patrolled</kbd> або <kbd>$2show=!patrolled</kbd>, версії, старіші ніж <var>[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|секунда|секунди|секунд}}) не будуть показуватися.",
+ "apihelp-query+usercontribs-param-tag": "Перерахувати лише версії, помічені цим теґом.",
+ "apihelp-query+usercontribs-param-toponly": "Виводити лише зміни, які є останньою версією.",
+ "apihelp-query+usercontribs-example-user": "Показати внесок користувача <kbd>Example</kbd>.",
+ "apihelp-query+usercontribs-example-ipprefix": "Показати внесок з усіх IP-адрес з префіксом <kbd>192.0.2.</kbd>.",
+ "apihelp-query+userinfo-description": "Отримати інформацію про поточного користувача.",
+ "apihelp-query+userinfo-param-prop": "Які саме відомості включати:",
+ "apihelp-query+userinfo-paramvalue-prop-blockinfo": "Позначає, чи поточний користувач заблокований, ким, з якої причини.",
+ "apihelp-query+userinfo-paramvalue-prop-hasmsg": "Додає мітку <samp>messages</samp>, якщо у користувача є непроглянуті повідомлення.",
+ "apihelp-query+userinfo-paramvalue-prop-groups": "Перелічує усі групи, до яких належить поточний користувач.",
+ "apihelp-query+userinfo-paramvalue-prop-implicitgroups": "Перелічує усі групи, до яких поточний користувач належить автоматично.",
+ "apihelp-query+userinfo-paramvalue-prop-rights": "Перелічує усі права, які має поточний користувач.",
+ "apihelp-query+userinfo-paramvalue-prop-changeablegroups": "Перелічує групи, у які користувач може додавати і з яких вилучати.",
+ "apihelp-query+userinfo-paramvalue-prop-options": "Перелічує усі налаштування, які поточний користувач встановив.",
+ "apihelp-query+userinfo-paramvalue-prop-preferencestoken": "<span class=\"apihelp-deprecated\">Застаріле.</span> Отримати знак для зміни налаштувань поточного користувача.",
+ "apihelp-query+userinfo-paramvalue-prop-editcount": "Додає кількість редагувань поточного користувача.",
+ "apihelp-query+userinfo-paramvalue-prop-ratelimits": "Перелічує усі ліміти оцінок, застосовні до поточного користувача.",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "Додає справжнє ім'я користувача.",
+ "apihelp-query+userinfo-paramvalue-prop-email": "Додає електронну пошту користувача та дату її підтвердження.",
+ "apihelp-query+userinfo-paramvalue-prop-acceptlang": "Дублює шапку <code>Accept-Language</code>, надіслану клієнтом у структурованому форматі.",
+ "apihelp-query+userinfo-paramvalue-prop-registrationdate": "ДОдає дату реєстрації користувача.",
+ "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Додає кількість непрочитаних сторінок у списку спостереження користувача (максимально $1; видає «<samp>$2</samp>», якщо більше).",
+ "apihelp-query+userinfo-example-simple": "Отримати інформацію про поточного користувача.",
+ "apihelp-query+userinfo-example-data": "Отримати додаткову інформацію про поточного користувача.",
+ "apihelp-query+users-description": "Отримати інформацію про список користувачів.",
+ "apihelp-query+users-param-prop": "Яку інформацію включити:",
+ "apihelp-query+users-paramvalue-prop-blockinfo": "Мітки про те чи є користувач заблокованим, ким, і з якою причиною.",
+ "apihelp-query+users-paramvalue-prop-groups": "Перелічує всі групи, до яких належить кожен з користувачів.",
+ "apihelp-query+users-paramvalue-prop-implicitgroups": "Перелічує всі групи, членом яких користувач є автоматично.",
+ "apihelp-query+users-paramvalue-prop-rights": "Перелічує всі права, які має кожен з користувачів.",
+ "apihelp-query+users-paramvalue-prop-editcount": "Додає лічильник редагувань користувача.",
+ "apihelp-query+users-paramvalue-prop-registration": "Додає часову мітку реєстрації користувача.",
+ "apihelp-query+users-paramvalue-prop-emailable": "Помічає чи хоче користувач отримувати електронну пошту через [[Special:Emailuser]].",
+ "apihelp-query+users-paramvalue-prop-gender": "Помічає стать користувача. Повертає \"male\", \"female\", або \"unknown\".",
+ "apihelp-query+users-param-users": "Список користувачів, для яких отримати інформацію.",
+ "apihelp-query+users-param-token": "Використати натомість <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
+ "apihelp-query+users-example-simple": "Вивести інформацію для користувача <kbd>Example</kbd>.",
+ "apihelp-query+watchlist-description": "Отримати нещодавні зміни сторінок у списку спостереження поточного користувача.",
+ "apihelp-query+watchlist-param-allrev": "Включити декілька версій тієї з сторінки у поданому часовому діапазоні.",
+ "apihelp-query+watchlist-param-start": "Часова мітка, з якої почати перелік.",
+ "apihelp-query+watchlist-param-end": "Часова мітка завершення переліку.",
+ "apihelp-query+watchlist-param-namespace": "Відфільтрувати до змін лише у поданих просторах назв.",
+ "apihelp-query+watchlist-param-user": "Перерахувати лише зміни, зроблені цим користувачем.",
+ "apihelp-query+watchlist-param-excludeuser": "Не перераховувати зміни, зроблені цим користувачем.",
+ "apihelp-query+watchlist-param-limit": "Скільки всього видати результатів за один запит.",
+ "apihelp-query+watchlist-param-prop": "Які додаткові властивості отримати:",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "Додає ID версій та ID сторінок.",
+ "apihelp-query+watchlist-paramvalue-prop-title": "Додає заголовок сторінки.",
+ "apihelp-query+watchlist-paramvalue-prop-flags": "Додає прапорці редагування.",
+ "apihelp-query+watchlist-paramvalue-prop-user": "Додає користувача, який зробив редагування.",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "Додає ідентифікатор користувача, який зробив редагування.",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "Додає коментар редагування.",
+ "apihelp-query+watchlist-paramvalue-prop-parsedcomment": "Додає проаналізований коментар редагування.",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "Додає часову мітку редагування.",
+ "apihelp-query+watchlist-paramvalue-prop-patrol": "Позначає відпатрульовані редагування.",
+ "apihelp-query+watchlist-paramvalue-prop-sizes": "Додає стару і нову довжину сторінки.",
+ "apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "Додає мітку часу, коли користувач був востаннє сповіщений про редагування.",
+ "apihelp-query+watchlist-paramvalue-prop-loginfo": "Додає інформацію журналу, де це доречно.",
+ "apihelp-query+watchlist-param-show": "Показати лише елементи, що задовільняють ці критерії. Наприклад, для перегляду лише незначних змін, здійснених користувачами, що увійшли до системи, вкажіть $1show=minor|!anon.",
+ "apihelp-query+watchlist-param-type": "Які типи змін показувати:\n;edit:Звичайні редагування сторінки.\n;external:Зовнішні зміни.\n;new:Створення сторінок.\n;log:Записи журналу.",
+ "apihelp-query+watchlist-param-owner": "Використовується разом з $1token для доступу до списку спостереження різних користувачів.",
+ "apihelp-query+watchlist-param-token": "Токен безпеки (доступний у [[Special:Preferences#mw-prefsection-watchlist|налаштуваннях]] користувача) для отримання доступу до списку спостереження іншого користувача.",
+ "apihelp-query+watchlist-example-simple": "Перелічити верхні версії для нещодавно змінених сторінок у списку спостереження поточного користувача.",
+ "apihelp-query+watchlist-example-props": "Вибрати додаткову інформацію про верхню версію нещодавно змінених сторінок у списку спостереження поточного користувача.",
+ "apihelp-query+watchlist-example-allrev": "Вибрати інформацію про усі нещодавні зміни на сторінках у списку спостереження поточного користувача.",
+ "apihelp-query+watchlist-example-generator": "Видати інформацію про сторінку для нещодавно змінених сторінок у списку спостереження поточного користувача.",
+ "apihelp-query+watchlist-example-generator-rev": "Вибрати інформацію про версію для усіх нещодавніх змін на сторінках у списку спостереження поточного користувача.",
+ "apihelp-query+watchlist-example-wlowner": "Перелічити верхні версії для нещодавно змінених сторінок у списку спостереження користувача <kbd>Example</kbd>.",
+ "apihelp-query+watchlistraw-description": "Отримати усі сторінки у списку спостереження поточного користувача.",
+ "apihelp-query+watchlistraw-param-namespace": "Перерахувати сторінки лише в поданих просторах назв.",
+ "apihelp-query+watchlistraw-param-limit": "Скільки всього видати результатів за один запит.",
+ "apihelp-query+watchlistraw-param-prop": "Які додаткові властивості отримати:",
+ "apihelp-query+watchlistraw-paramvalue-prop-changed": "Додає мітку часу, коли користувач був востаннє сповіщений про редагування.",
+ "apihelp-query+watchlistraw-param-show": "Перелічити лише елементи, які відповідають цим критеріям.",
+ "apihelp-query+watchlistraw-param-owner": "Використовується разом з $1token для доступу до списку спостереження різних користувачів.",
+ "apihelp-query+watchlistraw-param-token": "Токен безпеки (доступний у [[Special:Preferences#mw-prefsection-watchlist|налаштуваннях]] користувача) для отримання доступу до списку спостереження іншого користувача.",
+ "apihelp-query+watchlistraw-param-fromtitle": "Назва (з префіксом простору назв), з якої почати перерахування.",
+ "apihelp-query+watchlistraw-param-totitle": "Назва (з префіксом простору назв), якою закінчити перерахування.",
+ "apihelp-query+watchlistraw-example-simple": "Перелічити сторінки у списку спостереження поточного користувача.",
+ "apihelp-query+watchlistraw-example-generator": "Вибрати інформацію про сторінку для сторінок у списку спостереження поточного користувача.",
+ "apihelp-revisiondelete-description": "Вилучити або відновити версії.",
+ "apihelp-revisiondelete-param-type": "Тип здійснюваного вилучення версії.",
+ "apihelp-revisiondelete-param-target": "Назва сторінки, версію якої вилучити, якщо вимагається для цього типу.",
+ "apihelp-revisiondelete-param-ids": "Ідентифікатори версій, які слід вилучити.",
+ "apihelp-revisiondelete-param-hide": "Що приховати у кожній з версій.",
+ "apihelp-revisiondelete-param-show": "Що показати у кожній з версії.",
+ "apihelp-revisiondelete-param-suppress": "Чи приховати дані від адміністраторів так само як від усіх інших.",
+ "apihelp-revisiondelete-param-reason": "Причина вилучення або відновлення.",
+ "apihelp-revisiondelete-example-revision": "Приховати вміст версії <kbd>12345</kbd> сторінки <kbd>Main Page</kbd>.",
+ "apihelp-revisiondelete-example-log": "Приховати всі дані у записі журналу <kbd>67890</kbd> з причиною <kbd>BLP violation</kbd>.",
+ "apihelp-rollback-description": "Скасувати останнє редагування цієї сторінки.\n\nЯкщо користувач, який редагував сторінку, зробив декілька редагувань підряд, їх усі буде відкочено.",
+ "apihelp-rollback-param-title": "Назва сторінки, у якій здійснити відкіт. Не може використовуватись разом з <var>$1pageid</var>.",
+ "apihelp-rollback-param-pageid": "Ідентифікатор сторінки у якій здійснити відкіт. Не може використовуватись разом з <var>$1title</var>.",
+ "apihelp-rollback-param-user": "Ім'я користувача чиї редагування слід відкотити.",
+ "apihelp-rollback-param-summary": "Нестандартний опис редагування. Якщо порожній, буде використано опис редагування за замовчуванням.",
+ "apihelp-rollback-param-markbot": "Позначити відкинуті редагування та відкіт як редагування бота.",
+ "apihelp-rollback-param-watchlist": "Безумовно додати або вилучити сторінку із списку спостереження поточного користувача, використати налаштування, або не змінювати статус (не)спостереження.",
+ "apihelp-rollback-example-simple": "Відкинути останні редагування сторінки <kbd>Main Page</kbd> здійснені користувачем <kbd>Example</kbd>.",
+ "apihelp-rollback-example-summary": "Відкинути останні редагування сторінки <kbd>Main Page</kbd> здійснені IP-користувачем <kbd>192.0.2.5</kbd> з причиною <kbd>Reverting vandalism</kbd>, та позначити ці редагування та відкіт як редагування бота.",
+ "apihelp-rsd-description": "Експортувати як схему RSD (Really Simple Discovery).",
+ "apihelp-rsd-example-simple": "Експортувати RSD-схему.",
+ "apihelp-setnotificationtimestamp-description": "Оновити часову мітку сповіщень для сторінок, що спостерігаються.\n\nЦе зачепить підсвічування змінених сторінок у списку спостереження та історії, а також надсилання електронного листа якщо опція налаштувань «{{int:tog-enotifwatchlistpages}}» увімкнена.",
+ "apihelp-setnotificationtimestamp-param-entirewatchlist": "Опрацювати всі сторінки, що спостерігаються.",
+ "apihelp-setnotificationtimestamp-param-timestamp": "Часова мітка, яку вказати у якості часової мітки сповіщень.",
+ "apihelp-setnotificationtimestamp-param-torevid": "Версія до якої вказати часову мітку сповіщень (лише одна сторінка).",
+ "apihelp-setnotificationtimestamp-param-newerthanrevid": "Версія, до новішої від якої вказати часову мітку сповіщень (лише одна сторінка).",
+ "apihelp-setnotificationtimestamp-example-all": "Стерти статус сповіщень для всього списку спостереження.",
+ "apihelp-setnotificationtimestamp-example-page": "Стерти статус сповіщень для <kbd>Main page</kbd>.",
+ "apihelp-setnotificationtimestamp-example-pagetimestamp": "Встановити часову мітку сповіщень для <kbd>Main page</kbd> так, що всі редагування після 1 січня 2012 будуть виглядати як не переглянуті.",
+ "apihelp-setnotificationtimestamp-example-allpages": "Стерти статус сповіщень для сторінок у просторі назв <kbd>{{ns:user}}</kbd>.",
+ "apihelp-tag-description": "Додати або вилучити зміни міток з окремих версій або записів журналу.",
+ "apihelp-tag-param-rcid": "Один або більше ідентифікаторів останніх змін, до яких додати або вилучити мітки.",
+ "apihelp-tag-param-revid": "Один або більше ідентифікатор з якого додати або вилучити мітку.",
+ "apihelp-tag-param-logid": "Один або більше ідентифікатор запису журналу з якого вилучити або додати мітку.",
+ "apihelp-tag-param-add": "Мітки, які слід додати. Лише визначені вручну мітки може бути додано.",
+ "apihelp-tag-param-remove": "Мітки, які слід вилучити. Лише мітки, які було визначено вручну, або взагалі не визначено, можуть бути вилучені.",
+ "apihelp-tag-param-reason": "Причина зміни.",
+ "apihelp-tag-example-rev": "Додати мітку <kbd>vandalism</kbd> до версії з ідентифікатором 123 без вказання причини",
+ "apihelp-tag-example-log": "Вилучити мітку <kbd>spam</kbd> з запису журналу з ідентифікатором 123 з причиною <kbd>Wrongly applied</kbd>",
+ "apihelp-tokens-description": "Отримати жетони для дій пов'язаних зі зміною даних.\n\nЦей модуль застарів на користь [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
+ "apihelp-tokens-param-type": "Які типи жетонів запитати.",
+ "apihelp-tokens-example-edit": "Отримати жетон редагування (за замовчуванням).",
+ "apihelp-tokens-example-emailmove": "Отримати жетон електронної пошти та жетон перейменування.",
+ "apihelp-unblock-description": "Розблокувати користувача.",
+ "apihelp-unblock-param-id": "Ідентифікатор блоку чи розблокування (отриманий через <kbd>list=blocks</kbd>). Не може бути використано разом з <var>$1user</var>.",
+ "apihelp-unblock-param-user": "Ім'я користувача, IP-адреса чи IP-діапазон до розблокування. Не може бути використано разом з <var>$1id</var>.",
+ "apihelp-unblock-param-reason": "Причина розблокування.",
+ "apihelp-unblock-example-id": "Зняти блокування з ідентифікатором #<kbd>105</kbd>.",
+ "apihelp-unblock-example-user": "Розблокувати користувача <kbd>Bob</kbd> з причиною <kbd>Sorry Bob</kbd>.",
+ "apihelp-undelete-description": "Відновити версії вилученої сторінки.\n\nСписок вилучених версій (включено з часовими мітками) може бути отримано через [[Special:ApiHelp/query+deletedrevs|list=deletedrevs]], а список ідентифікаторів вилучених файлів може бути отримано через [[Special:ApiHelp/query+filearchive|list=filearchive]].",
+ "apihelp-undelete-param-title": "Назва сторінки, яку слід відновити.",
+ "apihelp-undelete-param-reason": "Причина відновлення.",
+ "apihelp-undelete-param-timestamps": "Часові мітки версій, які слід відновити. Якщо і <var>$1timestamps</var>, і <var>$1fileids</var> порожні, буде відновлено всі версії.",
+ "apihelp-undelete-param-fileids": "Ідентифікатори версій файлів, які слід відновити. Якщо і <var>$1timestamps</var>, і <var>$1fileids</var> порожні, буде відновлено всі версії.",
+ "apihelp-undelete-param-watchlist": "Безумовно додати або вилучити сторінку із списку спостереження поточного користувача, використати налаштування, або не змінювати статус (не)спостереження.",
+ "apihelp-undelete-example-page": "Відновити сторінку <kbd>Main Page</kbd>.",
+ "apihelp-undelete-example-revisions": "Відновити дві версії сторінки <kbd>Main Page</kbd>.",
+ "apihelp-upload-description": "Завантажити файл, або отримати статус завантажень у процесі.\n\nДоступні декілька методів:\n* Завантажити вміст файлу напряму, використовуючи параметр <var>$1file</var>.\n* Завантажити файл шматками, використовуючи параметри <var>$1filesize</var>, <var>$1chunk</var>, та <var>$1offset</var>.\n* Змусити сервер Медіавікі отримати файл за URL, використовуючи параметр <var>$1url</var>.\n* Завершити раніше розпочате завантаження, яке не вдалось через попередження, використовуючи параметр <var>$1filekey</var>.\nЗауважте, що HTTP POST повинен бути здійснений як завантаження файлу (наприклад, використовуючи <code>multipart/form-data</code>)",
+ "apihelp-upload-param-filename": "Цільова назва файлу.",
+ "apihelp-upload-param-comment": "Коментар завантаження. Також використовується як початковий текст сторінок для нових файлів, якщо <var>$1text</var> не вказано.",
+ "apihelp-upload-param-text": "Початковий текст сторінок для нових файлів.",
+ "apihelp-upload-param-watch": "Спостерігати за сторінкою.",
+ "apihelp-upload-param-watchlist": "Безумовно додати або вилучити сторінку із списку спостереження поточного користувача, використати налаштування, або не змінювати статус (не)спостереження.",
+ "apihelp-upload-param-ignorewarnings": "Ігнорувати всі попередження.",
+ "apihelp-upload-param-file": "Вміст файлу.",
+ "apihelp-upload-param-url": "URL з якого отримати файл.",
+ "apihelp-upload-param-filekey": "Ключ, що ідентифікує попереднє завантаження яке було відкладено тимчасово",
+ "apihelp-upload-param-sessionkey": "Те ж саме, що $1filekey, підтримується для зворотної сумісності.",
+ "apihelp-upload-param-stash": "Якщо вказано, сервер тимчасово відкладе файл замість додати його до репозиторію.",
+ "apihelp-upload-param-filesize": "Розмір файлу цілого завантаження.",
+ "apihelp-upload-param-offset": "Зміщення шматка в байтах.",
+ "apihelp-upload-param-chunk": "Шматок вмісту.",
+ "apihelp-upload-param-async": "Зробити операції з потенційно великими файлами асинхронними коли можливо.",
+ "apihelp-upload-param-asyncdownload": "Зробити отримання за URL асинхронним.",
+ "apihelp-upload-param-leavemessage": "Якщо використовується asyncdownload, залишити повідомлення на сторінці обговорення користувача при закінченні.",
+ "apihelp-upload-param-statuskey": "Отримати статус завантаження для цього ключа файлу (завантаження за URL)",
+ "apihelp-upload-param-checkstatus": "Отримувати статус завантаження лише для даного ключа файлу.",
+ "apihelp-upload-example-url": "Завантаження з URL.",
+ "apihelp-upload-example-filekey": "Завершити завантаження, що не вдалось через попередження.",
+ "apihelp-userrights-description": "Змінити членство користувача у групах.",
+ "apihelp-userrights-param-user": "Ім'я користувача.",
+ "apihelp-userrights-param-userid": "Ідентифікатор користувача.",
+ "apihelp-userrights-param-add": "Додати користувача до цих груп.",
+ "apihelp-userrights-param-remove": "Вилучити користувача із цих груп.",
+ "apihelp-userrights-param-reason": "Причина зміни.",
+ "apihelp-userrights-example-user": "Додати користувача <kbd>FooBot</kbd> до групи <kbd>bot</kbd> та вилучити із груп <kbd>sysop</kbd> та <kbd>bureaucrat</kbd>.",
+ "apihelp-userrights-example-userid": "Додати користувача з ідентифікатором <kbd>123</kbd> до групи <kbd>bot</kbd> та вилучити із груп <kbd>sysop</kbd> та <kbd>bureaucrat</kbd>.",
+ "apihelp-watch-description": "Додати або вилучити сторінки з списку спостереження поточного користувача.",
+ "apihelp-watch-param-title": "Сторінки до додання/вилучення. Використовуйте <var>$1titles</var> натомість.",
+ "apihelp-watch-param-unwatch": "Якщо вказано, сторінку буде вилучено зі списку спостереження замість додання до нього.",
+ "apihelp-watch-example-watch": "Спостерігати за сторінкою <kbd>Головна сторінка</kbd>.",
+ "apihelp-watch-example-unwatch": "Вилучити сторінку <kbd>Головна сторінка</kbd> зі списку спостереження.",
+ "apihelp-watch-example-generator": "Додати перші декілька сторінок основного простору назв до списку спостереження.",
+ "apihelp-format-example-generic": "Повернути результат запиту у форматі $1.",
+ "apihelp-dbg-description": "Вивести дані у форматі PHP <code>var_export()</code>.",
+ "apihelp-dbgfm-description": "Вивести дані у форматі PHP <code>var_export()</code> (вивід відформатованого коду за допомогою HTML).",
+ "apihelp-json-description": "Вивести дані у форматі JSON.",
+ "apihelp-json-param-callback": "Якщо вказано, огортає вивід викликом даної функції. З міркувань безпеки, усі специфічні до користувача дані буде утримано.",
+ "apihelp-json-param-utf8": "Якщо вказано, кодує більшість (але не всі) не-ASCII символів як UTF-8, замість заміни їх шістнадцятковими екрануючими послідовностями. За замовчуванням коли <var>formatversion</var> не є <kbd>1</kbd>.",
+ "apihelp-json-param-ascii": "Якщо вказано, кодує всі не-ASCII використовуючи шістнадцяткові екрануючі послідовності. За замовчуванням коли <var>formatversion</var> є <kbd>1</kbd>.",
+ "apihelp-json-param-formatversion": "Форматування виводу:\n;1:Формат зворотної сумісності (булеви XML-стилю, <samp>*</samp> ключі для вузлів вмісту тощо).\n;2:Експериментальний сучасний формат. Деталі можуть змінюватись.\n;latest:Використовувати найостанніший формат (наразі <kbd>2</kbd>). Може змінюватись без попередження.",
+ "apihelp-jsonfm-description": "Вивести дані у форматі JSON (вивід відформатованого коду за допомогою HTML).",
+ "apihelp-none-description": "Нічого не виводити.",
+ "apihelp-php-description": "Виводити дані у форматі серіалізованого PHP.",
+ "apihelp-php-param-formatversion": "Форматування виводу:\n;1:Формат зворотної сумісності (булеви XML-стилю, <samp>*</samp> ключі для вузлів вмісту тощо).\n;2:Експериментальний сучасний формат. Деталі можуть змінюватись.\n;latest:Використовувати найостанніший формат (наразі <kbd>2</kbd>). Може змінюватись без попередження.",
+ "apihelp-phpfm-description": "Виводити дані у форматі серіалізованого PHP (вивід відформатованого коду за допомогою HTML).",
+ "apihelp-rawfm-description": "Виводити дані у форматі JSON разом з елементами налагодження (вивід відформатованого коду за допомогою HTML).",
+ "apihelp-txt-description": "Виводити дані у форматі PHP <code>print_r()</code>.",
+ "apihelp-txtfm-description": "Виводити дані у форматі PHP <code>print_r()</code> (вивід відформатованого коду за допомогою HTML).",
+ "apihelp-xml-description": "Виводити дані у форматі XML.",
+ "apihelp-xml-param-xslt": "Якщо вказано, додає названу сторінку як таблицю стилів XSL. Це значення повинне бути назвою у просторі назв {{ns:mediawiki}}, що закінчується на <code>.xsl</code>.",
+ "apihelp-xml-param-includexmlnamespace": "Якщо вказано, додає простір назв XML.",
+ "apihelp-xmlfm-description": "Вивести дані у форматі XML (вивід відформатованого коду за допомогою HTML).",
+ "apihelp-yaml-description": "Вивести дані у форматі YAML.",
+ "apihelp-yamlfm-description": "Вивести дані у форматі YAML (вивід відформатованого коду за допомогою HTML).",
+ "api-format-title": "Результат запиту до API MediaWiki",
+ "api-format-prettyprint-header": "Це HTML-представлення формату $1. HTML є гарним для налагодження, однак не придатний для прикладного використання.\n\nУкажіть значення для параметру <var>format</var>, для того щоб змінити формат. Для перегляду не-HTML-представлення формату, $1, вкажіть <kbd>format=$2</kbd>.\n\nДив. [[mw:API|повну документацію]], або [[Special:ApiHelp/main|довідку з API]] для детальнішої інформації.",
+ "api-format-prettyprint-header-only-html": "Це HTML-представлення призначене для налагодження, однак не придатне для прикладного використання.\n\nДив. [[mw:API|повну документацію]], або [[Special:ApiHelp/main|довідку з API]] для детальнішої інформації.",
+ "api-orm-param-props": "Поля до запиту.",
+ "api-orm-param-limit": "Яке максимальне число рядків повернути.",
+ "api-pageset-param-titles": "Список назв над якими працювати.",
+ "api-pageset-param-pageids": "Список ідентифікаторів сторінок над якими працювати.",
+ "api-pageset-param-revids": "Список ідентифікаторів версій над якими працювати.",
+ "api-pageset-param-generator": "Отримати список сторінок над якими працювати шляхом виконання вказаного модуля запиту.\n\n<strong>Примітка:</strong> Назви параметрів генератора повинні мати префікс «g», див. приклади.",
+ "api-pageset-param-redirects-generator": "Автоматично вирішувати перенаправлення у <var>$1titles</var>, <var>$1pageids</var>, і <var>$1revids</var>, та у сторінках, повернених <var>$1generator</var>.",
+ "api-pageset-param-redirects-nogenerator": "Автоматично вирішувати перенаправлення у <var>$1titles</var>, <var>$1pageids</var>, та <var>$1revids</var>.",
+ "api-pageset-param-converttitles": "Конвертувати назви в інші варіанти за необхідності. Працює лише для вікі, мова вмісту яких підтримує конвертування варіантів. Мовами, що підтримують конвертування варіантів є $1.",
+ "api-help-title": "Довідка API Медіавікі",
+ "api-help-lead": "Це автоматично генерована сторінка документації API Медіавікі.\n\nДокументація та приклади: https://www.mediawiki.org/wiki/API",
+ "api-help-main-header": "Головний модуль",
+ "api-help-flag-deprecated": "Цей модуль є застарілим.",
+ "api-help-flag-internal": "<strong>Цей модуль є внутрішнім або нестабільним.</strong> Його робота може бути змінена без сповіщення.",
+ "api-help-flag-readrights": "Цей модуль вимагає прав на читання.",
+ "api-help-flag-writerights": "Цей модуль вимагає прав на запис.",
+ "api-help-flag-mustbeposted": "Цей модуль приймає лише POST-запити.",
+ "api-help-flag-generator": "Цей модуль може бути використаний як генератор.",
+ "api-help-source": "Джерело: $1",
+ "api-help-source-unknown": "Джерело: <span class=\"apihelp-unknown\">невідоме</span>",
+ "api-help-license": "Ліцензія: [[$1|$2]]",
+ "api-help-license-noname": "Ліцензія: [[$1|див. посилання]]",
+ "api-help-license-unknown": "Ліцензія: <span class=\"apihelp-unknown\">невідома</span>",
+ "api-help-parameters": "{{PLURAL:$1|Параметр|Параметри}}:",
+ "api-help-param-deprecated": "Застарілий.",
+ "api-help-param-required": "Цей параметр є обов'язковим.",
+ "api-help-datatypes-header": "Типи даних",
+ "api-help-datatypes": "Деякі типи параметрів у запитах API потребують ширшого пояснення:\n;boolean\n:Логічні параметри працюють як галочки HTML: якщо параметр вказано, не залежно від значення, він вважається істинним. Щоб значення було хибним, пропустіть параметр зовсім.\n;timestamp\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:* Формат C ctime, <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>",
+ "api-help-param-type-limit": "Тип: ціле число або <kbd>max</kbd>",
+ "api-help-param-type-integer": "Тип: {{PLURAL:$1|1=ціле число|2=список цілих чисел}}",
+ "api-help-param-type-boolean": "Тип: логічний ([[Special:ApiHelp/main#main/datatypes|деталі]])",
+ "api-help-param-type-timestamp": "Тип: {{PLURAL:$1|1=часова мітка|2=список часових міток}} ([[Special:ApiHelp/main#main/datatypes|дозволені формати]])",
+ "api-help-param-type-user": "Тип: {{PLURAL:$1|1=ім'я користувача|2=список імен користувачів}}",
+ "api-help-param-list": "{{PLURAL:$1|1=Одне значення|2=Значення (розділені через <kbd>{{!}}</kbd>)}}: $2",
+ "api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Повинно бути пустим|Може бути пустим або $2}}",
+ "api-help-param-limit": "Дозволено не більше $1.",
+ "api-help-param-limit2": "Дозволено не більше $1 ($2 для ботів).",
+ "api-help-param-integer-min": "{{PLURAL:$1|1=Значення має бути|2=Значення мають бути}} не менше $2.",
+ "api-help-param-integer-max": "{{PLURAL:$1|1=Значення має бути|2=Значення мають бути}} не більше $3.",
+ "api-help-param-integer-minmax": "{{PLURAL:$1|1=Значення має бути|2=Значення мають бути}} між $2 і $3.",
+ "api-help-param-upload": "Повинно бути надіслано у формі надсилання файлу використовуючи multipart/form-data.",
+ "api-help-param-multi-separate": "Розділіть значення з допомогою <kbd>|</kbd>.",
+ "api-help-param-multi-max": "Максимальна кількість значень — {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} для ботів).",
+ "api-help-param-default": "За замовчуванням: $1",
+ "api-help-param-default-empty": "За замовчуванням: <span class=\"apihelp-empty\">(пусто)</span>",
+ "api-help-param-token": "Токен «$1» отримано з [[Special:ApiHelp/query+tokens|action=query&meta=tokens]]",
+ "api-help-param-token-webui": "Для сумісності, приймається також токен, використаний у користувацькому веб-інтерфейсі.",
+ "api-help-param-disabled-in-miser-mode": "Вимкнено через [[mw:Manual:$wgMiserMode|скупий режим]].",
+ "api-help-param-limited-in-miser-mode": "<strong>Примітка:</strong> через [[mw:Manual:$wgMiserMode|«скупий режим»]], використання цього може вилитися у видачу результатів менше ніж <var>$1limit</var> перед продовженням; в особливих випадках можуть видаватися нульові результати.",
+ "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-examples": "{{PLURAL:$1|Приклад|Приклади}}:",
+ "api-help-permissions": "{{PLURAL:$1|Дозвіл|Дозволи}}:",
+ "api-help-permissions-granted-to": "{{PLURAL:$1|Надано|Надані}}: $2",
+ "api-help-right-apihighlimits": "Використовувати вищі ліміти у запитах API (повільні запити: $1; швидкі запити: $2). Ліміти для повільних запитів також застосовуються до багатозначних параметрів.",
+ "api-credits-header": "Автор(и)",
+ "api-credits": "Розробники API:\n* Roan Kattouw (головний розробник вер. 2007–2009)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (творець, головний розробник вер. 2006 – вер. 2007)\n* Brad Jorsch (головний розробник 2013 – тепер)\n\nБудь ласка, надсилайте свої коментарі, пропозиції та запитання на mediawiki-api@lists.wikimedia.org\nабо зафайліть звіт про баґ на https://phabricator.wikimedia.org/."
}
diff --git a/includes/api/i18n/vi.json b/includes/api/i18n/vi.json
index a027d9d8..53bc4e81 100644
--- a/includes/api/i18n/vi.json
+++ b/includes/api/i18n/vi.json
@@ -8,10 +8,15 @@
},
"apihelp-main-param-action": "Tác vụ để thực hiện.",
"apihelp-main-param-format": "Định dạng của dữ liệu được cho ra.",
+ "apihelp-main-param-uselang": "Ngôn ngữ để sử dụng cho các phiên dịch thông điệp. Một danh sách các mã có thể được lấy từ <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> với <kbd>siprop=languages</kbd>, hoặc <kbd>user</kbd> cụ thể sử dụng ngôn ngữ tham khảo của người dùng hiện tại, hoặc <kbd>content</kbd> cụ thể để sử dụng ngôn ngữ nội dung của wiki này.",
"apihelp-block-description": "Cấm người dùng.",
"apihelp-block-param-user": "Tên truy nhập, địa chỉ IP hoặc dãi IP mà bạn muốn chặn.",
"apihelp-block-param-reason": "Lý do cấm.",
"apihelp-block-param-nocreate": "Cấm tạo tài khoản.",
+ "apihelp-block-param-reblock": "Nếu người dùng này đã bị khóa, ghi đè lên người này.",
+ "apihelp-checktoken-param-type": "Kiểu dấu hiệu được kiểm thử.",
+ "apihelp-checktoken-param-token": "Dấu hiệu để kiểm thử.",
+ "apihelp-checktoken-example-simple": "Kiểm thử dấu hiệu <kbd>csrf</kbd> có hợp lệ hay không.",
"apihelp-clearhasmsg-description": "Xóa cờ <code>hasmsg</code> cho người dùng hiện tại.",
"apihelp-clearhasmsg-example-1": "Xóa cờ <code>hasmsg</code> cho người dùng hiện tại",
"apihelp-compare-param-fromtitle": "So sánh tiêu đề đầu tiên.",
@@ -36,13 +41,13 @@
"apihelp-delete-description": "Xóa trang.",
"apihelp-delete-param-title": "Xóa tiêu đề của trang. Không thể sử dụng cùng với <var>$1pageid</var>.",
"apihelp-delete-param-pageid": "Xóa ID của trang. Không thể sử dụng cùng với <var>$1title</var>.",
- "apihelp-delete-param-watch": "Thêm trang vào danh sách theo dõi của bạn.",
- "apihelp-delete-param-unwatch": "Bỏ trang này khỏi danh sách theo dõi của bạn.",
- "apihelp-delete-example-simple": "Xóa Trang Chính",
- "apihelp-delete-example-reason": "Xóa Trang Chính với lý do “Chuẩn bị di chuyển”",
+ "apihelp-delete-param-watch": "Thêm trang vào danh sách theo dõi của người dùng hiện tại.",
+ "apihelp-delete-param-unwatch": "Bỏ trang này khỏi danh sách theo dõi của người dùng hiện tại.",
+ "apihelp-delete-example-simple": "Xóa <kbd>Trang Chính</kbd>.",
+ "apihelp-delete-example-reason": "Xóa <kbd>Trang Chính</kbd> với lý do <kbd>Chuẩn bị di chuyển</kbd>.",
"apihelp-disabled-description": "Mô đun này đã bị vô hiệu hóa.",
"apihelp-edit-description": "Tạo và sửa trang.",
- "apihelp-edit-param-section": "Số phần trang. 0 là phần đầu; “new” là phần mới.",
+ "apihelp-edit-param-section": "Số phần trang. <kbd>0</kbd> là phần đầu; <kbd>new</kbd> là phần mới.",
"apihelp-edit-param-sectiontitle": "Tên của phần mới.",
"apihelp-edit-param-text": "Nội dung trang.",
"apihelp-edit-param-summary": "Tóm lược sửa đổi. Cũng là tên phần khi $1section=new và $1sectiontitle không được đặt.",
@@ -51,8 +56,8 @@
"apihelp-edit-param-bot": "Đánh dấu sửa đổi này là do bot thực hiện.",
"apihelp-edit-param-createonly": "Không sửa đổi trang nếu nó đã tồn tại.",
"apihelp-edit-param-nocreate": "Gây lỗi nếu trang không tồn tại.",
- "apihelp-edit-param-watch": "Thêm trang vào danh sách theo dõi của bạn.",
- "apihelp-edit-param-unwatch": "Bỏ trang này khỏi danh sách theo dõi của bạn.",
+ "apihelp-edit-param-watch": "Thêm trang vào danh sách theo dõi của người dùng hiện tại.",
+ "apihelp-edit-param-unwatch": "Bỏ trang này khỏi danh sách theo dõi của người dùng hiện tại.",
"apihelp-edit-param-undo": "Hoàn tác sửa đổi này. Ghi đè $1text, $1prependtext và $ 1appendtext.",
"apihelp-edit-param-undoafter": "Hoàn tác tất cả các sửa đổi từ $1undo cho tới sửa đổi này. Nếu không được thiết lập, chỉ cần lùi lại một sửa đổi.",
"apihelp-edit-example-edit": "Sửa đổi trang",
@@ -63,10 +68,32 @@
"apihelp-emailuser-param-subject": "Tiêu đề bức thư.",
"apihelp-emailuser-param-text": "Nội dung bức thư.",
"apihelp-emailuser-param-ccme": "Gửi bản sao của thư này cho tôi.",
- "apihelp-emailuser-example-email": "Gửi thư điện tử cho thành viên “BQVWiki” với văn bản “Nội dung”",
+ "apihelp-emailuser-example-email": "Gửi thư điện tử cho thành viên <kbd>BQVWiki</kbd> với văn bản <kbd>Nội dung</kbd>.",
"apihelp-expandtemplates-description": "Bung tất cả bản mẫu trong văn bản wiki.",
"apihelp-expandtemplates-param-title": "Tên trang.",
"apihelp-expandtemplates-param-text": "Văn bản wiki để bung.",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "Cây phân tích XML của đầu vào.",
+ "apihelp-feedcontributions-description": "Trả về nguồn cấp đóng góp người dùng.",
+ "apihelp-feedcontributions-param-feedformat": "Định dạng nguồn cấp.",
+ "apihelp-feedcontributions-param-year": "Từ năm (trở về trước).",
+ "apihelp-feedcontributions-param-month": "Từ tháng (trở về trước).",
+ "apihelp-feedcontributions-param-deletedonly": "Chỉ hiện các đóng góp đã xóa.",
+ "apihelp-feedcontributions-param-toponly": "Chỉ hiện các phiên bản mới nhất.",
+ "apihelp-feedcontributions-param-newonly": "Chỉ hiện các sửa đổi tạo trang.",
+ "apihelp-feedcontributions-example-simple": "Trả về các đóng góp của người dùng <kbd>Ví dụ</kbd>.",
+ "apihelp-feedrecentchanges-description": "Trả về nguồn cấp thay đổi gần đây.",
+ "apihelp-feedrecentchanges-param-feedformat": "Định dạng nguồn cấp.",
+ "apihelp-feedrecentchanges-param-hideminor": "Ẩn thay đổi nhỏ.",
+ "apihelp-feedrecentchanges-param-hidebots": "Ẩn thay đổi do bot thực hiện.",
+ "apihelp-feedrecentchanges-param-hideanons": "Ẩn thay đổi do người dùng vô danh thực hiện.",
+ "apihelp-feedrecentchanges-param-hideliu": "Ẩn thay đổi do người dùng đăng nhập thực hiện.",
+ "apihelp-feedrecentchanges-param-hidepatrolled": "Ẩn thay đổi đã tuần tra.",
+ "apihelp-feedrecentchanges-param-hidemyself": "Ẩn thay đổi do người dùng hiện tại thực hiện.",
+ "apihelp-feedrecentchanges-param-tagfilter": "Lọc theo thẻ.",
+ "apihelp-feedrecentchanges-example-simple": "Xem thay đổi gần đây.",
+ "apihelp-feedwatchlist-description": "Trả về nguồn cấp danh sách theo dõi.",
+ "apihelp-feedwatchlist-param-feedformat": "Định dạng nguồn cấp.",
+ "apihelp-feedwatchlist-example-default": "Xem nguồn cấp danh sách theo dõi.",
"apihelp-filerevert-param-comment": "Tải lên bình luận.",
"apihelp-filerevert-param-archivename": "Tên lưu trữ của bản sửa đổi để trở lại .",
"apihelp-filerevert-example-revert": "Hoàn nguyên <kbd>Wiki.png</kbd> veef phiên bản 2011-03-05T15 : 27:40Z",
@@ -77,8 +104,8 @@
"apihelp-help-example-query": "Trợ giúp cho hai module con truy vấn",
"apihelp-imagerotate-description": "Xoay một hoặc nhiều hình ảnh.",
"apihelp-imagerotate-param-rotation": "Độ xoay hình ảnh theo chiều kim đồng hồ.",
- "apihelp-imagerotate-example-simple": "Xoay [[:Tập tin:Ví dụ.jpg]] 90 độ",
- "apihelp-imagerotate-example-generator": "Xoay tất cả các hình ảnh trong [[:Thể loại:Búng]] 180 độ",
+ "apihelp-imagerotate-example-simple": "Xoay <kbd>Tập tin:Ví dụ.jpg</kbd> <kbd>90</kbd> độ.",
+ "apihelp-imagerotate-example-generator": "Xoay tất cả các hình ảnh trong <kbd>Thể loại:Búng</kbd> <kbd>180</kbd> độ.",
"apihelp-login-param-name": "Tên người dùng.",
"apihelp-login-param-password": "Mật khẩu.",
"apihelp-login-param-domain": "Tên miền (tùy chọn).",
@@ -87,7 +114,7 @@
"apihelp-login-example-login": "Đăng nhập",
"apihelp-logout-example-logout": "Đăng xuất người dùng hiện tại",
"apihelp-move-description": "Di chuyển trang.",
- "apihelp-move-param-reason": "Lý do di chuyển.",
+ "apihelp-move-param-reason": "Lý do đổi tên.",
"apihelp-move-param-noredirect": "Không tạo trang đổi hướng.",
"apihelp-move-param-ignorewarnings": "Bỏ qua tất cả các cảnh báo.",
"apihelp-opensearch-description": "Tìm kiếm trong wiki qua giao thức OpenSearch.",
@@ -95,18 +122,18 @@
"apihelp-opensearch-param-limit": "Đa số kết quả để cho ra.",
"apihelp-opensearch-param-namespace": "Không gian tên để tìm kiếm.",
"apihelp-opensearch-param-format": "Định dạng kết quả được cho ra.",
- "apihelp-opensearch-example-te": "Tìm trang bắt đầu với “Te”",
+ "apihelp-opensearch-example-te": "Tìm trang bắt đầu với <kbd>Te</kbd>.",
"apihelp-options-example-reset": "Mặc định lại các tùy chọn",
"apihelp-paraminfo-param-helpformat": "Định dạng chuỗi trợ giúp.",
"apihelp-parse-param-summary": "Lời tóm lược để phân tích.",
- "apihelp-parse-param-section": "Chỉ truy xuất nội dung của số bộ phận này.",
- "apihelp-parse-param-disablepp": "Vô hiệu hóa phân tích cú pháp đầu ra của Báo cáo PP .",
+ "apihelp-parse-param-section": "Chỉ truy xuất nội dung của số phần này; nếu có <kbd>new</kbd> thì tạo phần mới.\n\nPhần <kbd>new</kbd> chỉ được chấp nhận khi định rõ <var>text</var>.",
+ "apihelp-parse-param-disablelimitreport": "Bỏ qua thông báo bộ tiền xử lý (“NewPP limit report”) khi cho ra kết quả bộ xử lý.",
"apihelp-parse-example-page": "Phân tích trang.",
"apihelp-parse-example-text": "Phân tích văn bản wiki.",
"apihelp-parse-example-texttitle": "Phân tích văn bản wiki theo tên trang.",
"apihelp-parse-example-summary": "Phân tích lời tóm lược.",
"apihelp-protect-example-protect": "Khóa trang.",
- "apihelp-protect-example-unprotect": "Mở khóa trang bằng cách đặt hạn chế thành “all”",
+ "apihelp-protect-example-unprotect": "Mở khóa trang bằng cách đặt hạn chế thành <kbd>all</kbd>.",
"apihelp-protect-example-unprotect2": "Mở khóa trang bằng cách không đặt hạn chế nào",
"apihelp-purge-param-forcelinkupdate": "Cập nhật các bảng liên kết.",
"apihelp-purge-example-generator": "Làm mới 10 trang đầu tiên trong không gian tên chính",
@@ -115,19 +142,15 @@
"apihelp-query-param-meta": "Siêu dữ liệu để lấy.",
"apihelp-query+allcategories-param-dir": "Hướng xếp loại.",
"apihelp-rollback-description": "Hoàn tác chỉnh sửa cuối cùng của trang này.\n\nNếu người dùng cuối cùng đã cỉnh sửa trang này nhiều lần, tất cả chúng sẽ được hoàn tác lại như ban đầu.",
- "apihelp-format-example-generic": "Định dạng kết quả truy vấn dưới dạng $1",
- "apihelp-dbg-description": "Cho ra dữ liệu dưới dạng var_export() của PHP.",
- "apihelp-dbgfm-description": "Cho ra dữ liệu dưới dạng var_export() của PHP (định dạng bằng HTML).",
- "apihelp-dump-description": "Cho ra dữ liệu dưới dạng var_dump() của PHP.",
- "apihelp-dumpfm-description": "Cho ra dữ liệu dưới dạng var_dump() của PHP (định dạng bằng HTML).",
+ "apihelp-format-example-generic": "Cho ra kết quả truy vấn dưới dạng $1.",
+ "apihelp-dbg-description": "Cho ra dữ liệu dưới dạng <code>var_export()</code> của PHP.",
+ "apihelp-dbgfm-description": "Cho ra dữ liệu dưới dạng <code>var_export()</code> của PHP (định dạng bằng HTML).",
"apihelp-json-description": "Cho ra dữ liệu dưới dạng JSON.",
"apihelp-jsonfm-description": "Cho ra dữ liệu dưới dạng JSON (định dạng bằng HTML).",
"apihelp-none-description": "Không cho ra gì.",
"apihelp-rawfm-description": "Cho ra dữ liệu với các phần tử gỡ lỗi dưới dạng JSON (định dạng bằng HTML).",
- "apihelp-txt-description": "Cho ra dữ liệu dưới dạng print_r() của PHP.",
- "apihelp-txtfm-description": "Cho ra dữ liệu dưới dạng print_r() của PHP (định dạng bằng HTML).",
- "apihelp-wddx-description": "Cho ra dữ liệu dưới dạng WDDX.",
- "apihelp-wddxfm-description": "Cho ra dữ liệu dưới dạng WDDX (định dạng bằng HTML).",
+ "apihelp-txt-description": "Cho ra dữ liệu dưới dạng <code>print_r()</code> của PHP.",
+ "apihelp-txtfm-description": "Cho ra dữ liệu dưới dạng <code>print_r()</code> của PHP (định dạng bằng HTML).",
"apihelp-xml-description": "Cho ra dữ liệu dưới dạng XML.",
"apihelp-xmlfm-description": "Cho ra dữ liệu dưới dạng XML (định dạng bằng HTML).",
"apihelp-yaml-description": "Cho ra dữ liệu dưới dạng YAML.",
@@ -142,11 +165,11 @@
"api-help-parameters": "{{PLURAL:$1|Tham số|Các tham số}}:",
"api-help-param-deprecated": "Bị phản đối.",
"api-help-param-required": "Tham số này là bắt buộc.",
- "api-help-param-list": "{{PLURAL:$1|1=Một giá trị|2=Các giá trị (phân tách bằng “{{!}}”)}}: $2",
+ "api-help-param-list": "{{PLURAL:$1|1=Một giá trị|2=Các giá trị (phân tách bằng <kbd>{{!}}</kbd>)}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Cần phải để trống|Cần phải để trống hoặc là $2}}",
"api-help-param-limit": "Không cho phép hơn $1.",
"api-help-param-limit2": "Không cho phép hơn $1 ($2 đối với các bot).",
- "api-help-param-multi-separate": "Phân tách các giá trị bằng “|”.",
+ "api-help-param-multi-separate": "Phân tách các giá trị bằng <kbd>|</kbd>.",
"api-help-param-default": "Mặc định: $1",
"api-help-param-default-empty": "Mặc định: <span class=\"apihelp-empty\">(trống)</span>",
"api-help-examples": "{{PLURAL:$1|Ví dụ|Các ví dụ}}:",
diff --git a/includes/api/i18n/wuu.json b/includes/api/i18n/wuu.json
new file mode 100644
index 00000000..7df8a48d
--- /dev/null
+++ b/includes/api/i18n/wuu.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "反共复国"
+ ]
+ },
+ "apihelp-main-param-action": "要执行个操作。"
+}
diff --git a/includes/api/i18n/yi.json b/includes/api/i18n/yi.json
new file mode 100644
index 00000000..c2acd421
--- /dev/null
+++ b/includes/api/i18n/yi.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "פוילישער"
+ ]
+ },
+ "apihelp-main-param-action": "וועלכע אקציע אויסצופירן.",
+ "apihelp-main-param-format": "פארמאט פונעם אויסגאב.",
+ "api-help-source": "מקור: $1"
+}
diff --git a/includes/api/i18n/zh-hans.json b/includes/api/i18n/zh-hans.json
index 722803bf..dd3fb8f3 100644
--- a/includes/api/i18n/zh-hans.json
+++ b/includes/api/i18n/zh-hans.json
@@ -11,15 +11,19 @@
"JuneAugsut",
"EagerLin",
"Simon xianyu",
- "Kuailong"
+ "Kuailong",
+ "Zhxy 519",
+ "御坂美琴",
+ "RyRubyy",
+ "Umherirrender"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|文档]]\n* [[mw:API:FAQ|常见问题]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 邮件列表]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R 程序错误与功能请求]\n</div>\n<strong>状态信息:</strong>本页所展示的所有特性都应正常工作,但是API仍在开发当中,将会随时变化。请订阅[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 邮件列表]以便获得更新通知。\n\n<strong>错误请求:</strong>当API收到错误请求时,HTTP header将会返回一个包含\"MediaWiki-API-Error\"的值,随后header的值与error code将会送回并设置为相同的值。详细信息请参阅[[mw:API:Errors_and_warnings|API: 错误与警告]]。",
"apihelp-main-param-action": "要执行的操作。",
"apihelp-main-param-format": "输出的格式。",
"apihelp-main-param-maxlag": "最大延迟可被用于MediaWiki安装于数据库复制集中。要保存导致更多网站复制延迟的操作,此参数可使客户端等待直到复制延迟少于指定值时。万一发生过多延迟,错误代码<samp>maxlag</samp>会返回消息,例如<samp>等待$host中:延迟$lag秒</samp>。<br />参见[[mw:Manual:Maxlag_parameter|Manual: Maxlag parameter]]以获取更多信息。",
- "apihelp-main-param-smaxage": "设置<code>s-maxage</code>页顶至这些秒。错误不会缓存。",
- "apihelp-main-param-maxage": "设置<code>max-age</code>页顶至这些秒。错误不会缓存。",
+ "apihelp-main-param-smaxage": "设置<code>s-maxage</code> HTTP缓存控制头至这些秒。错误不会缓存。",
+ "apihelp-main-param-maxage": "设置<code>max-age</code> HTTP缓存控制头至这些秒。错误不会缓存。",
"apihelp-main-param-assert": "如果设置为<kbd>user</kbd>就验证用户是否登录,或如果设置为<kbd>bot</kbd>就验证是否有机器人用户权限。",
"apihelp-main-param-requestid": "任何在此提供的值将包含在响应中。可能可以用以区别请求。",
"apihelp-main-param-servedby": "包含保存结果请求的主机名。",
@@ -29,7 +33,7 @@
"apihelp-block-description": "封禁一位用户。",
"apihelp-block-param-user": "您要封禁的用户、IP地址或IP地址段。",
"apihelp-block-param-expiry": "到期时间。可以是相对时间(例如<kbd>5 months</kbd>或<kbd>2 weeks</kbd>)或绝对时间(例如<kbd>2014-09-18T12:34:56Z</kbd>)。如果设置为<kbd>infinite</kbd>、<kbd>indefinite</kbd>或<kbd>never</kbd>,封禁将无限期。",
- "apihelp-block-param-reason": "封禁的原因",
+ "apihelp-block-param-reason": "封禁的原因。",
"apihelp-block-param-anononly": "只封禁匿名用户(也就是说禁止此 IP 地址的匿名编辑)。",
"apihelp-block-param-nocreate": "防止创建帐户。",
"apihelp-block-param-autoblock": "自动封禁最近使用的IP地址,以及以后他们尝试登陆使用的IP地址。",
@@ -47,16 +51,16 @@
"apihelp-checktoken-example-simple": "测试<kbd>csrf</kbd>令牌的有效性。",
"apihelp-clearhasmsg-description": "清除当前用户的<code>hasmsg</code>标记。",
"apihelp-clearhasmsg-example-1": "清除当前用户的<code>hasmsg</code>标记。",
- "apihelp-compare-description": "获得2个页面之间的差别。\n\n用于“from”和“to”的修订版本号、页面标题或页面 ID 必须获得通过。",
+ "apihelp-compare-description": "获取2个页面之间的差别。\n\n用于“from”和“to”的修订版本号、页面标题或页面 ID 必须获得通过。",
"apihelp-compare-param-fromtitle": "要比较的第一个标题。",
"apihelp-compare-param-fromid": "要比较的第一个页面 ID。",
"apihelp-compare-param-fromrev": "要比较的第一个修订版本。",
"apihelp-compare-param-totitle": "要比较的第二个标题。",
"apihelp-compare-param-toid": "要比较的第二个页面 ID。",
"apihelp-compare-param-torev": "要比较的第二个修订版本。",
- "apihelp-compare-example-1": "在版本1和2中创建差异",
+ "apihelp-compare-example-1": "在版本1和2中创建差异。",
"apihelp-createaccount-description": "创建一个新用户账户。",
- "apihelp-createaccount-param-name": "用户名",
+ "apihelp-createaccount-param-name": "用户名。",
"apihelp-createaccount-param-password": "密码(如果设置<var>$1mailpassword</var>则忽略)。",
"apihelp-createaccount-param-domain": "外部身份验证域 (可选)。",
"apihelp-createaccount-param-token": "在第一个请求中获得的帐户创建标记。",
@@ -85,6 +89,7 @@
"apihelp-edit-param-sectiontitle": "新小节的标题。",
"apihelp-edit-param-text": "页面内容。",
"apihelp-edit-param-summary": "编辑摘要。当$1section=new且未设置$1sectiontitle时,还包括小节标题。",
+ "apihelp-edit-param-tags": "更改标签以应用修订。",
"apihelp-edit-param-minor": "小编辑。",
"apihelp-edit-param-notminor": "不是小编辑。",
"apihelp-edit-param-bot": "标记此编辑为机器人编辑。",
@@ -101,13 +106,13 @@
"apihelp-edit-param-appendtext": "将该文本添加到该页面的结尾。覆盖$1text。\n\n采用$1section=new来添加一个新的章节,而不是这个参数。",
"apihelp-edit-param-undo": "撤销此次修订。覆盖$1text、$1prependtext和$1appendtext。",
"apihelp-edit-param-undoafter": "撤销从$1undo至此的所有修订。如果不设置就撤销一次修订。",
- "apihelp-edit-param-redirect": "自动解析重定向。",
+ "apihelp-edit-param-redirect": "自动解决重定向。",
"apihelp-edit-param-contentformat": "用于输入文本的内容串行化格式。",
"apihelp-edit-param-contentmodel": "新内容的内容模型。",
"apihelp-edit-param-token": "令牌应总是发送为最后参数,或至少在$1text参数之后。",
- "apihelp-edit-example-edit": "编辑一个页面",
- "apihelp-edit-example-prepend": "页面中预置<kbd>_&#95;NOTOC_&#95;</kbd>",
- "apihelp-edit-example-undo": "通过13585撤销修订版本13579并自动填写编辑摘要",
+ "apihelp-edit-example-edit": "编辑一个页面。",
+ "apihelp-edit-example-prepend": "页面中预置<kbd>_&#95;NOTOC_&#95;</kbd>。",
+ "apihelp-edit-example-undo": "通过13585撤销修订版本13579并自动填写编辑摘要。",
"apihelp-emailuser-description": "电子邮件联系一位用户。",
"apihelp-emailuser-param-target": "电子邮件的目标用户。",
"apihelp-emailuser-param-subject": "主题页眉。",
@@ -118,7 +123,15 @@
"apihelp-expandtemplates-param-title": "页面标题。",
"apihelp-expandtemplates-param-text": "要转换的wiki文本。",
"apihelp-expandtemplates-param-revid": "修订版本ID,用于<nowiki>{{REVISIONID}}</nowiki>和类似变体。",
- "apihelp-expandtemplates-param-prop": "要获取的那条信息:\n;wikitext:展开的wiki文本。\n;categories:任何在不代表wiki文本输出的输入框出现的分类。\n;properties:由wiki文本中扩充的魔术字定义的页面属性。\n;volatile:输出是否不稳定,并且不应在任何页面中再度使用。\n;ttl:结果的哪个缓存后等待最长时间应无效化。\n;parsetree:输入的XML解析树。\n注意如果没有选定值,结果将包含wiki文本,但将以弃用的格式显示。",
+ "apihelp-expandtemplates-param-prop": "要获取的那条信息。\n\n注意如果没有选定值,结果将包含wiki文本,但将以弃用的格式显示。",
+ "apihelp-expandtemplates-paramvalue-prop-wikitext": "扩充的wiki文本。",
+ "apihelp-expandtemplates-paramvalue-prop-properties": "由wiki文本中扩充的魔术字定义的页面属性。",
+ "apihelp-expandtemplates-paramvalue-prop-volatile": "无论输出是否常常变动,均不应被在页面中其他任何位置重用。",
+ "apihelp-expandtemplates-paramvalue-prop-ttl": "结果缓存应无效化后的最长时间。",
+ "apihelp-expandtemplates-paramvalue-prop-modules": "任何解析器函数请求添加至输出的ResourceLoader模块。无论<kbd>jsconfigvars</kbd>还是<kbd>encodedjsconfigvars</kbd>都必须与<kbd>modules</kbd>共同被请求。",
+ "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "针对页面提供JavaScript配置变量。",
+ "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "针对页面提供JavaScript配置变量为一个JSON字符串。",
+ "apihelp-expandtemplates-paramvalue-prop-parsetree": "输入的XML分析树。",
"apihelp-expandtemplates-param-includecomments": "输出时是否包含HTML摘要。",
"apihelp-expandtemplates-param-generatexml": "生成XML解析树(取代自$1prop=parsetree)。",
"apihelp-expandtemplates-example-simple": "展开wiki文本<kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>。",
@@ -151,13 +164,13 @@
"apihelp-feedrecentchanges-param-tagfilter": "按标签过滤。",
"apihelp-feedrecentchanges-param-target": "仅仅显示从该页面链出的那些页面的变更。",
"apihelp-feedrecentchanges-param-showlinkedto": "仅仅显示链入到该页面的那些页面的变更。",
- "apihelp-feedrecentchanges-example-simple": "显示最近更改",
- "apihelp-feedrecentchanges-example-30days": "显示最近30天的更改",
+ "apihelp-feedrecentchanges-example-simple": "显示最近更改。",
+ "apihelp-feedrecentchanges-example-30days": "显示最近30天的更改。",
"apihelp-feedwatchlist-description": "返回监视列表纲要。",
"apihelp-feedwatchlist-param-feedformat": "纲要的格式。",
"apihelp-feedwatchlist-param-hours": "列出从现在起数小时内修改的页面。",
"apihelp-feedwatchlist-param-linktosections": "如果可能的话,直接链接到已变更的小节。",
- "apihelp-feedwatchlist-example-default": "显示监视列表订阅",
+ "apihelp-feedwatchlist-example-default": "显示监视列表订阅。",
"apihelp-feedwatchlist-example-all6hrs": "显示过去6小时内受监视页面的所有更改。",
"apihelp-filerevert-description": "回退一个文件至某一旧版本。",
"apihelp-filerevert-param-filename": "目标文件名,不包含前缀“File:”。",
@@ -171,33 +184,33 @@
"apihelp-help-param-helpformat": "帮助的输出格式。",
"apihelp-help-param-wrap": "在一个标准API响应结构中包裹输出。",
"apihelp-help-param-toc": "在HTML输出中包括目录。",
- "apihelp-help-example-main": "主模块帮助",
- "apihelp-help-example-recursive": "一个页面中的所有帮助",
- "apihelp-help-example-help": "帮助模块本身的帮助",
- "apihelp-help-example-query": "两个查询子模块的帮助",
+ "apihelp-help-example-main": "主模块帮助。",
+ "apihelp-help-example-recursive": "一个页面中的所有帮助。",
+ "apihelp-help-example-help": "帮助模块本身的帮助。",
+ "apihelp-help-example-query": "两个查询子模块的帮助。",
"apihelp-imagerotate-description": "旋转一幅或多幅图像。",
"apihelp-imagerotate-param-rotation": "顺时针旋转图像的度数。",
"apihelp-imagerotate-example-simple": "<kbd>90</kbd>度旋转<kbd>File:Example.png</kbd>。",
"apihelp-imagerotate-example-generator": "将<kbd>Category:Flip</kbd>之中的所有图像旋转<kbd>180</kbd>度。",
- "apihelp-import-description": "从另一个wiki导入一个页面,或一个XML文件。\n\n注意当发送一个用于<var>xml</var>参数的文件时,HTTP POST必须作为一次文件上传完成(也就是使用multipart/form-data)。",
+ "apihelp-import-description": "从另一个wiki或从一个XML文件导入页面。\n\n注意当发送一个用于<var>xml</var>参数的文件时,HTTP POST必须作为一次文件上传完成(也就是使用multipart/form-data)。",
"apihelp-import-param-summary": "导入摘要。",
"apihelp-import-param-xml": "上传的XML文件。",
"apihelp-import-param-interwikisource": "用于跨wiki导入:导入的来源wiki。",
"apihelp-import-param-interwikipage": "用于跨wiki导入:导入的页面。",
"apihelp-import-param-fullhistory": "用于跨wiki导入:完整导入历史,而不只是最新版本。",
"apihelp-import-param-templates": "用于跨wiki导入:连带导入所有包含的模板。",
- "apihelp-import-param-namespace": "用于跨wiki导入:导入到此名字空间。",
- "apihelp-import-param-rootpage": "导入作为此页面的子页面。",
- "apihelp-import-example-import": "将页面[[meta:Help:Parserfunctions]]连带完整历史导入至100名字空间。",
+ "apihelp-import-param-namespace": "导入至此名字空间。不能与<var>$1rootpage</var>一起使用。",
+ "apihelp-import-param-rootpage": "作为此页面的子页面导入。不能与<var>$1namespace</var>一起使用。",
+ "apihelp-import-example-import": "将页面[[meta:Help:ParserFunctions]]连带完整历史导入至100名字空间。",
"apihelp-login-description": "登录并获得身份验证Cookie。\n\n在成功登录的情况下,所需的Cookie将包含在HTTP响应头中。在登录失败的情况下,进一步的尝试可能会被自动密码猜解攻击的限制所遏制。",
"apihelp-login-param-name": "用户名。",
"apihelp-login-param-password": "密码。",
"apihelp-login-param-domain": "域名(可选)。",
"apihelp-login-param-token": "在首个请求中获得的登录令牌。",
- "apihelp-login-example-gettoken": "检索登录令牌",
- "apihelp-login-example-login": "登录",
+ "apihelp-login-example-gettoken": "检索登录令牌。",
+ "apihelp-login-example-login": "登录。",
"apihelp-logout-description": "退出并清除会话数据。",
- "apihelp-logout-example-logout": "退出当前用户",
+ "apihelp-logout-example-logout": "退出当前用户。",
"apihelp-managetags-description": "执行有关更改标签的管理任务。",
"apihelp-managetags-param-operation": "要执行哪个操作:\n;create:创建一个新的更改标签供手动使用。\n;delete:从数据库中移除一个更改标签,包括移除已使用在所有修订版本、最近更改记录和日志记录上的该标签。\n;activate:激活一个更改标签,允许用户手动应用它。\n;deactivate:停用一个更改标签,阻止用户手动应用它。",
"apihelp-managetags-param-tag": "要创建、删除、激活或取消激活的标签。要创建标签,标签必须不存在。要删除标签,标签必须存在。要激活标签,标签必须存在,且不被任何扩展使用。要取消激活标签,标签必须当前处于激活状态,且被手动定义。",
@@ -219,7 +232,7 @@
"apihelp-move-param-unwatch": "从当前用户的监视列表中移除页面及重定向。",
"apihelp-move-param-watchlist": "无条件地将页面加入至当前用户的监视列表或将其移除,使用设置或不更改监视。",
"apihelp-move-param-ignorewarnings": "忽略任何警告。",
- "apihelp-move-example-move": "移动<kbd>坏标题</kbd>到<kbd>好标题</kbd>并且不留下重定向。",
+ "apihelp-move-example-move": "移动<kbd>Badtitle</kbd>到<kbd>Goodtitle</kbd>,不保留重定向。",
"apihelp-opensearch-description": "使用OpenSearch协议搜索本wiki。",
"apihelp-opensearch-param-search": "搜索字符串。",
"apihelp-opensearch-param-limit": "要返回的结果最大数。",
@@ -227,22 +240,23 @@
"apihelp-opensearch-param-suggest": "如果<var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var>设置为false则不做任何事情。",
"apihelp-opensearch-param-redirects": "如何处理重定向:\n;return:返回重定向本身。\n;resolve:返回目标页面。可能返回少于$1limit个结果。\n由于历史原因,$1format=json默认为\"return\",其他格式默认为\"resolve\"。",
"apihelp-opensearch-param-format": "输出格式。",
+ "apihelp-opensearch-param-warningsaserror": "如果警告通过<kbd>format=json</kbd>提升,返回一个API错误而不是忽略它们。",
"apihelp-opensearch-example-te": "查找以<kbd>Te</kbd>开头的页面。",
- "apihelp-options-description": "更改当前用户的偏好设置。\n\n只有注册在核心或者已安装扩展中的选项,或者具有\"userjs-\"键值前缀(旨在被用户脚本使用)的选项可被设置。",
+ "apihelp-options-description": "更改当前用户的偏好设置。\n\n只有注册在核心或者已安装扩展中的选项,或者具有<code>userjs-</code>键值前缀(旨在被用户脚本使用)的选项可被设置。",
"apihelp-options-param-reset": "重置偏好设置到网站默认设置。",
"apihelp-options-param-resetkinds": "当<var>$1reset</var>选项被设置时,要重置的选项类型列表。",
"apihelp-options-param-change": "更改列表,以name=value格式化(例如skin=vector)。值不能包含管道字符。如果没提供值(甚至没有等号),例如optionname|otheroption|...,选项将重置为默认值。",
"apihelp-options-param-optionname": "应设置为由<var>$1optionvalue</var>提供值的选项名称。",
- "apihelp-options-param-optionvalue": "使用<var>$1选项名</var>指定的选项值中,可以包含管道字符",
- "apihelp-options-example-reset": "重置所有用户设置",
+ "apihelp-options-param-optionvalue": "用于由<var>$1optionname</var>指定的选项的值,可以包含管道字符。",
+ "apihelp-options-example-reset": "重置所有用户设置。",
"apihelp-options-example-change": "更改<kbd>skin</kbd>和<kbd>hideminor</kbd>设置。",
- "apihelp-options-example-complex": "重置所有设置,然后设置<kbd>皮肤</kbd>和<kbd>昵称</kbd>。",
- "apihelp-paraminfo-description": "获取关于 API 模块的信息。",
+ "apihelp-options-example-complex": "重置所有设置,然后设置<kbd>skin</kbd>和<kbd>nickname</kbd>。",
+ "apihelp-paraminfo-description": "获得关于API模块的信息。",
"apihelp-paraminfo-param-modules": "模块名称(<var>action</var>和<var>format</var>参数值,或<kbd>main</kbd>)的列表。可通过<kbd>+</kbd>指定子模块。",
"apihelp-paraminfo-param-helpformat": "帮助字符串的格式。",
"apihelp-paraminfo-param-querymodules": "查询模块名称(<var>prop</var>、<var>meta</var>或<var>list</var>参数值)的列表。使用<kbd>$1modules=query+foo</kbd>而不是<kbd>$1querymodules=foo</kbd>。",
- "apihelp-paraminfo-param-mainmodule": "获得有关主要(最高级)模块的信息。也可使用<kbd>$1modules=main</kbd>。",
- "apihelp-paraminfo-param-pagesetmodule": "获得有关页面设置模块(提供titles=和朋友)的信息。",
+ "apihelp-paraminfo-param-mainmodule": "获取有关主要(最高级)模块的信息。也可使用<kbd>$1modules=main</kbd>。",
+ "apihelp-paraminfo-param-pagesetmodule": "获取有关页面设置模块(提供titles=和朋友)的信息。",
"apihelp-paraminfo-param-formatmodules": "格式模块名称(<var>format</var>参数的值)的列表。也可使用<var>$1modules</var>。",
"apihelp-paraminfo-example-1": "显示<kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>、<kbd>[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>、<kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd>和<kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd>的信息。",
"apihelp-parse-description": "解析内容并返回解析器输出。\n\n参见<kbd>[[Special:ApiHelp/query|action=query]]</kbd>的各种prop-module以从页面的当前版本获得信息。\n\n这里有几种方法可以指定解析的文本:\n# 指定一个页面或修订,使用<var>$1page</var>、<var>$1pageid</var>或<var>$1oldid</var>。\n# 明确指定内容,使用<var>$1text</var>、<var>$1title</var>和<var>$1contentmodel</var>。\n# 只指定一段摘要解析。<var>$1prop</var>应提供一个空值。",
@@ -253,103 +267,163 @@
"apihelp-parse-param-pageid": "解析此页的内容。覆盖<var>$1page</var>。",
"apihelp-parse-param-redirects": "如果<var>$1page</var>或<var>$1pageid</var>被设置为一个重定向,则解析它。",
"apihelp-parse-param-oldid": "解析该修订版本的内容。覆盖<var>$1page</var>和<var>$1pageid</var>。",
+ "apihelp-parse-param-prop": "要获取的信息束:",
+ "apihelp-parse-paramvalue-prop-text": "提供wiki文本中的被解析文本。",
+ "apihelp-parse-paramvalue-prop-langlinks": "在被解析的wiki文本中提供语言链接。",
+ "apihelp-parse-paramvalue-prop-categories": "在被解析的wiki文本中提供分类。",
+ "apihelp-parse-paramvalue-prop-categorieshtml": "提供HTML版本分类。",
+ "apihelp-parse-paramvalue-prop-links": "在被解析的wiki文本中提供内部链接。",
+ "apihelp-parse-paramvalue-prop-templates": "在被解析的wiki文本中提供模板。",
+ "apihelp-parse-paramvalue-prop-images": "在被解析的wiki文本中提供图片。",
+ "apihelp-parse-paramvalue-prop-externallinks": "在被解析的wiki文本中提供外部链接。",
+ "apihelp-parse-paramvalue-prop-sections": "在被解析的wiki文本中提供段落。",
+ "apihelp-parse-paramvalue-prop-revid": "添加被解析页面的修订ID。",
+ "apihelp-parse-paramvalue-prop-displaytitle": "为被解析的wiki文本添加标题。",
+ "apihelp-parse-paramvalue-prop-headitems": "提供项目以插入至页面的<code>&lt;head&gt;</code>。",
+ "apihelp-parse-paramvalue-prop-headhtml": "提供页面的被解析<code>&lt;head&gt;</code>。",
+ "apihelp-parse-paramvalue-prop-modules": "提供在页面中使用的ResourceLoader模块。无论<kbd>jsconfigvars</kbd>还是<kbd>encodedjsconfigvars</kbd>都必须与<kbd>modules</kbd>共同被请求。",
+ "apihelp-parse-paramvalue-prop-jsconfigvars": "针对页面提供JavaScript配置变量。",
+ "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "针对页面提供JavaScript配置变量为一个JSON字符串。",
+ "apihelp-parse-paramvalue-prop-indicators": "提供页面上使用的页面状态指示器的HTML。",
+ "apihelp-parse-paramvalue-prop-iwlinks": "在被解析的wiki文本中提供跨wiki链接。",
+ "apihelp-parse-paramvalue-prop-wikitext": "提供被解析的原始wiki文本。",
+ "apihelp-parse-paramvalue-prop-properties": "提供多种定义在被解析的wiki文本中的属性。",
+ "apihelp-parse-paramvalue-prop-limitreportdata": "以结构化的方式提供限制报告。如果<var>$1disablelimitreport</var>被设定则不提供数据。",
+ "apihelp-parse-paramvalue-prop-limitreporthtml": "提供限制报告的HTML版本。当<var>$1disablelimitreport</var>被设置时不会提供数据。",
+ "apihelp-parse-paramvalue-prop-parsetree": "修订内容的XML解析树(需要内容模型<code>$1</code>)",
"apihelp-parse-param-pst": "在解析输入前,对输入做一次保存前变换处理。仅当使用文本时有效。",
"apihelp-parse-param-effectivelanglinks": "包含由扩展提供的语言链接(用于与<kbd>$1prop=langlinks</kbd>一起使用)。",
"apihelp-parse-param-section": "只检索此段数的内容,或只当<kbd>new</kbd>生成新的段落时检索。\n\n<kbd>new</kbd>段落只当指定<var>text</var>时受尊重。",
"apihelp-parse-param-sectiontitle": "当<var>section</var>为<kbd>new</kbd>时新段落标题。\n\n不像页面编辑,当省略或为空时将不会备选为<var>summary</var>。",
- "apihelp-parse-param-disablepp": "从解析器输出中禁用PP报告。",
- "apihelp-parse-param-disableeditsection": "从解析器输出中禁用编辑段落链接。",
- "apihelp-parse-param-generatexml": "生成XML解析树(需要内容模型<code>$1</code>)。",
+ "apihelp-parse-param-disablelimitreport": "从解析器输出中省略限制报告(“NewPP limit report”)。",
+ "apihelp-parse-param-disablepp": "请改用<var>$1disablelimitreport</var>。",
+ "apihelp-parse-param-disableeditsection": "从解析器输出中省略编辑段落链接。",
+ "apihelp-parse-param-disabletidy": "不要在解析器输出中运行HTML清理(例如tidy)。",
+ "apihelp-parse-param-generatexml": "生成XML解析树(需要内容模型<code>$1</code>;被<kbd>$2prop=parsetree</kbd>所取代)。",
"apihelp-parse-param-preview": "在预览模式下解析。",
"apihelp-parse-param-sectionpreview": "在小节预览模式下解析 (同时要启用预览模式)。",
- "apihelp-parse-param-disabletoc": "在输出中禁用目录。",
+ "apihelp-parse-param-disabletoc": "在输出中省略目录。",
+ "apihelp-parse-param-contentformat": "用于输入文本的内容序列化格式。只当与$1text一起使用时有效。",
"apihelp-parse-example-page": "解析一个页面。",
"apihelp-parse-example-text": "解析wiki文本。",
- "apihelp-parse-example-texttitle": "解析维基文本,指定页面标题。",
+ "apihelp-parse-example-texttitle": "解析wiki文本,指定页面标题。",
"apihelp-parse-example-summary": "解析一个摘要。",
"apihelp-patrol-description": "巡查页面或修订版本。",
"apihelp-patrol-param-rcid": "所要巡查的最近变更 ID。",
"apihelp-patrol-param-revid": "要巡查的修订版本ID。",
- "apihelp-patrol-example-rcid": "巡查一次最近更改",
- "apihelp-patrol-example-revid": "巡查一次修订",
+ "apihelp-patrol-example-rcid": "巡查一次最近更改。",
+ "apihelp-patrol-example-revid": "巡查一次修订。",
"apihelp-protect-description": "更改页面的保护等级。",
"apihelp-protect-param-title": "要(解除)保护的页面标题。不能与$1pageid一起使用。",
"apihelp-protect-param-pageid": "要(解除)保护的页面ID。不能与$1title一起使用。",
"apihelp-protect-param-protections": "保护等级列表,格式:<kbd>action=level</kbd>(例如<kbd>edit=sysop</kbd>)。\n\n<strong>注意:</strong>未列出的操作将移除限制。",
"apihelp-protect-param-expiry": "到期时间戳。如果只有一个时间戳被设置,它将被用于所有保护。使用<kbd>infinite</kbd>、<kbd>indefinite</kbd>、<kbd>infinity</kbd>或<kbd>never</kbd>用于永不过期的保护。",
"apihelp-protect-param-reason": "(解除)保护的原因。",
- "apihelp-protect-param-cascade": "启用级联保护(也就是保护包含于此页面的页面)。如果所有提供的保护等级不支持级联,就将其忽略。",
+ "apihelp-protect-param-cascade": "启用连锁保护(也就是保护包含于此页面的页面)。如果所有提供的保护等级不支持连锁,就将其忽略。",
"apihelp-protect-param-watch": "如果设置,就加入已开始(解除)保护的页面至当前用户的监视列表。",
"apihelp-protect-param-watchlist": "无条件地将页面加入至当前用户的监视列表或将其移除,使用设置或不更改监视。",
- "apihelp-protect-example-protect": "保护一个页面",
+ "apihelp-protect-example-protect": "保护一个页面。",
"apihelp-protect-example-unprotect": "通过设置限制为<kbd>all</kbd>解除保护一个页面。",
- "apihelp-protect-example-unprotect2": "通过设置没有限制解除保护一个页面",
+ "apihelp-protect-example-unprotect2": "通过设置没有限制解除保护一个页面。",
"apihelp-purge-description": "为指定标题刷新缓存。\n\n如果用户尚未登录的话,就需要POST请求。",
"apihelp-purge-param-forcelinkupdate": "更新链接表。",
"apihelp-purge-param-forcerecursivelinkupdate": "更新链接表中,并更新任何使用此页作为模板的页面的链接表。",
"apihelp-purge-example-simple": "刷新<kbd>Main Page</kbd>和<kbd>API</kbd>页面。",
- "apihelp-purge-example-generator": "刷新主名字空间的前10个页面",
+ "apihelp-purge-example-generator": "刷新主名字空间的前10个页面。",
"apihelp-query-description": "获取来自和有关MediaWiki的数据。\n\n所有数据修改将首先要使用查询以获得令牌以阻止来自恶意网站的滥用破坏。",
"apihelp-query-param-prop": "要为已查询页面获取的属性。",
"apihelp-query-param-list": "要获取的列表。",
"apihelp-query-param-meta": "要获取的元数据。",
- "apihelp-query-param-rawcontinue": "目前被忽略。将来<var>$1continue</var>将成为默认,且这里将需要得到原始的<samp>query-continue</samp>数据。",
+ "apihelp-query-param-indexpageids": "包含一个额外的pageid段落,列举所有返回的页面ID。",
+ "apihelp-query-param-export": "导出所有指定或生成页面的当前修订。",
+ "apihelp-query-param-exportnowrap": "返回导出XML,不需要将其包裹在一个XML结果中(与[[Special:Export]]格式相同)。只能与$1export一起使用。",
+ "apihelp-query-param-iwurl": "如果标题是一个跨wiki链接的话,是否获取完整URL。",
+ "apihelp-query-param-rawcontinue": "为继续返回原始<samp>query-continue</samp>数据。",
"apihelp-query-example-revisions": "获取<kbd>Main Page</kbd>的[[Special:ApiHelp/query+siteinfo|网站信息]]和[[Special:ApiHelp/query+revisions|修订版本]]。",
- "apihelp-query-example-allpages": "获取以<kbd>API/</kbd>开头的页面的修订版本",
- "apihelp-query+allcategories-description": "枚举所有类别。",
+ "apihelp-query-example-allpages": "获取以<kbd>API/</kbd>开头的页面的修订版本。",
+ "apihelp-query+allcategories-description": "列举所有分类。",
"apihelp-query+allcategories-param-from": "要作为枚举起始点的类别。",
"apihelp-query+allcategories-param-to": "要作为枚举终止点的类别。",
- "apihelp-query+allcategories-param-prefix": "搜索此值开头的所有分类标题。",
+ "apihelp-query+allcategories-param-prefix": "搜索所有以此值开头的分类标题。",
"apihelp-query+allcategories-param-dir": "排序方向。",
"apihelp-query+allcategories-param-min": "只返回至少带这么多成员的分类。",
"apihelp-query+allcategories-param-max": "只返回最多带这么多成员的分类。",
"apihelp-query+allcategories-param-limit": "要返回多少个类别。",
- "apihelp-query+allcategories-param-prop": "要获取的属性:\n;size:在分类中添加页面数。\n;hidden:标记由_&#95;HIDDENCAT_&#95;隐藏的分类。",
+ "apihelp-query+allcategories-param-prop": "要获取的属性:",
+ "apihelp-query+allcategories-paramvalue-prop-size": "在分类中添加页面数。",
+ "apihelp-query+allcategories-paramvalue-prop-hidden": "标记由<code>_&#95;HIDDENCAT_&#95;</code>隐藏的分类。",
"apihelp-query+allcategories-example-size": "列出分类及其含有多少页面的信息。",
+ "apihelp-query+allcategories-example-generator": "为以<kbd>List</kbd>的分类检索有关分类页面本身的信息。",
+ "apihelp-query+alldeletedrevisions-description": "列举由一位用户或在一个名字空间中所有已删除的修订。",
"apihelp-query+alldeletedrevisions-paraminfo-useronly": "只可以与<var>$3user</var>一起使用。",
"apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "不能与<var>$3user</var>一起使用。",
"apihelp-query+alldeletedrevisions-param-start": "枚举的起始时间戳。",
"apihelp-query+alldeletedrevisions-param-end": "枚举的结束时间戳。",
"apihelp-query+alldeletedrevisions-param-from": "从此标题开始列出。",
"apihelp-query+alldeletedrevisions-param-to": "列出至此标题为止。",
+ "apihelp-query+alldeletedrevisions-param-prefix": "搜索所有以此值开头的页面标题。",
"apihelp-query+alldeletedrevisions-param-tag": "只列出被此标签标记的修订。",
"apihelp-query+alldeletedrevisions-param-user": "只列出此用户做出的修订。",
"apihelp-query+alldeletedrevisions-param-excludeuser": "不要列出此用户做出的修订。",
"apihelp-query+alldeletedrevisions-param-namespace": "只列出此名字空间的页面。",
"apihelp-query+alldeletedrevisions-param-miser-user-namespace": "<strong>注意:</strong>由于[[mw:Manual:$wgMiserMode|miser模式]],同时使用<var>$1user</var>和<var>$1namespace</var>将导致继续前返回少于<var>$1limit</var>个结果,在极端条件下可能不返回任何结果。",
+ "apihelp-query+alldeletedrevisions-param-generatetitles": "当作为生成器使用时,生成标题而不是修订ID。",
"apihelp-query+alldeletedrevisions-example-user": "列出由<kbd>Example<kbd>作出的最近50次已删除贡献。",
"apihelp-query+alldeletedrevisions-example-ns-main": "列出前50次已删除的主名字空间修订。",
"apihelp-query+allfileusages-description": "列出所有文件用途,包括不存在的。",
- "apihelp-query+allfileusages-param-from": "文件的标题开始枚举于.",
- "apihelp-query+allfileusages-param-prefix": "搜索此值开头的所有文件标题。",
- "apihelp-query+allfileusages-param-prop": "要包含的信息束:\n;ids:添加使用中的页面的页面ID(不能与$1unique一起使用)。\n;title:添加文件的标题。",
+ "apihelp-query+allfileusages-param-from": "要列举的起始文件标题。",
+ "apihelp-query+allfileusages-param-to": "要列举的最终文件标题。",
+ "apihelp-query+allfileusages-param-prefix": "搜索所有以此值开头的文件标题。",
+ "apihelp-query+allfileusages-param-unique": "只显示明显的文件标题。不能与$1prop=ids一起使用。\n当作为生成器使用时,产生目标页面而不是来源页面。",
+ "apihelp-query+allfileusages-param-prop": "要包含的信息束:",
+ "apihelp-query+allfileusages-paramvalue-prop-ids": "添加使用中的页面的页面ID(不能与$1unique一起使用)。",
+ "apihelp-query+allfileusages-paramvalue-prop-title": "添加文件的标题。",
"apihelp-query+allfileusages-param-limit": "要返回的总计项目。",
"apihelp-query+allfileusages-param-dir": "罗列所采用的方向。",
- "apihelp-query+allfileusages-example-unique": "列出唯一性的文件标题",
- "apihelp-query+allfileusages-example-unique-generator": "获取所有文件标题,并标记出缺失者",
- "apihelp-query+allfileusages-example-generator": "获取包含这些文件的页面",
+ "apihelp-query+allfileusages-example-B": "列举文件标题,包含丢失的文件、它们来自的页面ID,以<kbd>B</kbd>开头。",
+ "apihelp-query+allfileusages-example-unique": "列出唯一文件标题。",
+ "apihelp-query+allfileusages-example-unique-generator": "获取所有文件标题,并标记出缺失者。",
+ "apihelp-query+allfileusages-example-generator": "获取包含这些文件的页面。",
"apihelp-query+allimages-description": "按顺序枚举所有图像。",
"apihelp-query+allimages-param-sort": "要作为排序方式的属性。",
"apihelp-query+allimages-param-dir": "罗列所采用的方向。",
+ "apihelp-query+allimages-param-from": "要列举的起始图片标题。只能与$1sort=name一起使用。",
+ "apihelp-query+allimages-param-to": "要列举的最终图片标题。只能与$1sort=name一起使用。",
+ "apihelp-query+allimages-param-start": "要列举的起始时间戳。只能与$1sort=timestamp一起使用。",
+ "apihelp-query+allimages-param-end": "要列举的最终时间戳。只能与$1sort=timestamp一起使用。",
+ "apihelp-query+allimages-param-prefix": "搜索所有以此值开头的图像标题。只能与$1sort=name一起使用。",
"apihelp-query+allimages-param-minsize": "限于至少这么多字节的图像。",
"apihelp-query+allimages-param-maxsize": "限于顶多这么多字节的图像。",
"apihelp-query+allimages-param-sha1": "图像的 SHA1 哈希。覆盖$1sha1base36。",
"apihelp-query+allimages-param-sha1base36": "基于base 36的图片的SHA1哈希值(用于MediaWiki)。",
+ "apihelp-query+allimages-param-user": "只返回此用户上传的文件。只能与$1sort=timestamp一起使用。不能与$1filterbots一起使用。",
+ "apihelp-query+allimages-param-filterbots": "如何过滤由机器人上传的文件。只能与$1sort=timestamp一起使用。不能与$1user一起使用。",
"apihelp-query+allimages-param-mime": "要搜索的MIME类型,例如<kbd>image/jpeg</kbd>。",
"apihelp-query+allimages-param-limit": "共计要返回多少图像。",
"apihelp-query+allimages-example-B": "显示以字母<kbd>B</kbd>开始的文件列表。",
"apihelp-query+allimages-example-recent": "显示一个最近上传文件的列表,类似[[Special:NewFiles]]。",
"apihelp-query+allimages-example-mimetypes": "显示带MIME类型<kbd>image/png</kbd>或<kbd>image/gif</kbd>的文件列表",
"apihelp-query+allimages-example-generator": "显示有关4个以<kbd>T</kbd>开头的文件的信息。",
+ "apihelp-query+alllinks-description": "列举所有指向至指定名字空间的链接。",
+ "apihelp-query+alllinks-param-from": "要列举的起始标题链接。",
+ "apihelp-query+alllinks-param-to": "要列举的最终标题链接。",
+ "apihelp-query+alllinks-param-prefix": "搜索所有以此值开头的已链接标题。",
+ "apihelp-query+alllinks-param-unique": "只显示明显的链接标题。不能与<kbd>$1prop=ids</kbd>一起使用。\n当作为生成器使用时,产生目标页面而不是来源页面。",
+ "apihelp-query+alllinks-param-prop": "要包含的信息束:",
+ "apihelp-query+alllinks-paramvalue-prop-ids": "添加链接中的页面的页面ID(不能与<var>$1unique</var>一起使用)。",
+ "apihelp-query+alllinks-paramvalue-prop-title": "添加链接的标题。",
"apihelp-query+alllinks-param-namespace": "要列举的名字空间。",
"apihelp-query+alllinks-param-limit": "总共要返回多少个项目。",
"apihelp-query+alllinks-param-dir": "列出方向。",
- "apihelp-query+alllinks-example-unique": "列出唯一的链接标题",
- "apihelp-query+alllinks-example-unique-generator": "获得所有已链接的标题,标记缺少的。",
- "apihelp-query+alllinks-example-generator": "获取包含这些链接的页面",
+ "apihelp-query+alllinks-example-B": "列出链接的标题,包括丢失的,带它们来自的页面ID,以<kbd>B</kbd>开头。",
+ "apihelp-query+alllinks-example-unique": "列出唯一的链接标题。",
+ "apihelp-query+alllinks-example-unique-generator": "获取所有已链接的标题,标记缺少的。",
+ "apihelp-query+alllinks-example-generator": "获取包含这些链接的页面。",
"apihelp-query+allmessages-description": "返回来自该网站的消息。",
"apihelp-query+allmessages-param-messages": "要输出的消息。<kbd>*</kbd>(默认)表示所有消息。",
"apihelp-query+allmessages-param-prop": "要获取的属性。",
+ "apihelp-query+allmessages-param-args": "要替代进消息的参数。",
+ "apihelp-query+allmessages-param-filter": "只返回名称包含此字符串的消息。",
"apihelp-query+allmessages-param-customised": "只返回在此定制情形下的消息。",
"apihelp-query+allmessages-param-lang": "返回这种语言的信息。",
"apihelp-query+allmessages-param-from": "从此消息开始返回消息。",
@@ -357,56 +431,107 @@
"apihelp-query+allmessages-param-prefix": "返回带有该前缀的消息。",
"apihelp-query+allmessages-example-ipb": "显示以<kbd>ipb-</kbd>开始的消息。",
"apihelp-query+allmessages-example-de": "显示德语版的<kbd>august</kbd>和<kbd>mainpage</kbd>消息。",
+ "apihelp-query+allpages-description": "循序列举在指定名字空间中的所有页面。",
+ "apihelp-query+allpages-param-from": "枚举的起始页面标题。",
+ "apihelp-query+allpages-param-to": "枚举的结束页面标题。",
+ "apihelp-query+allpages-param-prefix": "搜索所有以此值开头的页面标题。",
"apihelp-query+allpages-param-namespace": "要列举的名字空间。",
"apihelp-query+allpages-param-filterredir": "要列出哪些页面。",
"apihelp-query+allpages-param-minsize": "限于至少这么多字节的页面。",
"apihelp-query+allpages-param-maxsize": "限于至多这么多字节的页面。",
"apihelp-query+allpages-param-prtype": "仅限于受保护页面。",
+ "apihelp-query+allpages-param-prfiltercascade": "过滤基于cascadingness的保护(当$1prtype未设置时忽略)。",
"apihelp-query+allpages-param-limit": "返回的总计页面数。",
+ "apihelp-query+allpages-param-dir": "罗列所采用的方向。",
+ "apihelp-query+allpages-param-filterlanglinks": "过滤基于页面是否有语言链接。注意这可能不考虑由扩展添加的语言链接。",
+ "apihelp-query+allpages-param-prexpiry": "要在页面上过滤的保护期限:\n;indefinite:只获取带无限期保护的页面。\n;definite:只获取带指定保护期限的页面。\n;all:获取任意保护期限的页面。",
"apihelp-query+allpages-example-B": "显示以字母<kbd>B</kbd>开头的页面的列表。",
"apihelp-query+allpages-example-generator": "显示有关4个以字母<kbd>T</kbd>开头的页面的信息。",
"apihelp-query+allpages-example-generator-revisions": "显示前2个以<kbd>Re</kbd>开头的非重定向页面的内容。",
"apihelp-query+allredirects-description": "列出至一个名字空间的重定向。",
+ "apihelp-query+allredirects-param-from": "要列举的起始重定向标题。",
+ "apihelp-query+allredirects-param-to": "要列举的最终重定向标题。",
+ "apihelp-query+allredirects-param-prefix": "搜索所有以此值开头的目标页面。",
+ "apihelp-query+allredirects-param-unique": "只显示明显的目标页面。不能与$1prop=ids|fragment|interwiki一起使用。\n当作为生成器使用时,产生目标页面而不是来源页面。",
+ "apihelp-query+allredirects-param-prop": "要包含的信息束:",
+ "apihelp-query+allredirects-paramvalue-prop-ids": "添加重定向页面的页面ID(不能与<var>$1unique</var>一起使用)。",
+ "apihelp-query+allredirects-paramvalue-prop-title": "添加重定向的标题。",
+ "apihelp-query+allredirects-paramvalue-prop-fragment": "添加来自重定向的碎片,如果有(不能与<var>$1unique</var>一起使用)。",
+ "apihelp-query+allredirects-paramvalue-prop-interwiki": "添加来自重定向的跨wiki前缀,如果有(不能与<var>$1unique</var>一起使用)。",
"apihelp-query+allredirects-param-namespace": "要列举的名字空间。",
"apihelp-query+allredirects-param-limit": "返回的总计项目数。",
"apihelp-query+allredirects-param-dir": "罗列所采用的方向。",
- "apihelp-query+allredirects-example-unique": "列出孤立目标页面",
- "apihelp-query+allredirects-example-unique-generator": "获得所有目标页面,标记丢失的",
- "apihelp-query+allredirects-example-generator": "获得包含重定向的页面",
+ "apihelp-query+allredirects-example-unique": "列出孤立目标页面。",
+ "apihelp-query+allredirects-example-unique-generator": "获取所有目标页面,标记丢失的。",
+ "apihelp-query+allredirects-example-generator": "获取包含重定向的页面。",
"apihelp-query+alltransclusions-description": "列出所有嵌入页面(使用&#123;&#123;x&#125;&#125;嵌入的页面),包括不存在的。",
+ "apihelp-query+alltransclusions-param-from": "要列举的起始嵌入标题。",
+ "apihelp-query+alltransclusions-param-to": "要列举的最终嵌入标题。",
+ "apihelp-query+alltransclusions-param-prefix": "搜索所有以此值开头的嵌入的标题。",
+ "apihelp-query+alltransclusions-param-unique": "只显示明显的被嵌入标题。不能与$1prop=ids一起使用。\n当作为生成器使用时,产生目标页面而不是来源页面。",
+ "apihelp-query+alltransclusions-param-prop": "要包含的信息束:",
+ "apihelp-query+alltransclusions-paramvalue-prop-ids": "添加嵌入中的页面的页面ID(不能与$1unique一起使用)。",
+ "apihelp-query+alltransclusions-paramvalue-prop-title": "添加嵌入的标题。",
"apihelp-query+alltransclusions-param-namespace": "要列举的名字空间。",
"apihelp-query+alltransclusions-param-limit": "要返回的总计项目。",
"apihelp-query+alltransclusions-param-dir": "罗列所采用的方向。",
+ "apihelp-query+alltransclusions-example-B": "列出嵌入的标题,包括丢失的,带有来自的页面ID,从<kbd>B</kbd>开始。",
"apihelp-query+alltransclusions-example-unique": "列出孤立嵌入标题",
+ "apihelp-query+alltransclusions-example-unique-generator": "获取所有嵌入的标题,并标记缺失的。",
"apihelp-query+alltransclusions-example-generator": "获得包含嵌入内容的页面。",
"apihelp-query+allusers-description": "列举所有注册用户。",
"apihelp-query+allusers-param-from": "枚举的起始用户名。",
"apihelp-query+allusers-param-to": "枚举的结束用户名。",
- "apihelp-query+allusers-param-prefix": "搜索以此值开始的所有用户。",
+ "apihelp-query+allusers-param-prefix": "搜索所有以此值开头的用户。",
"apihelp-query+allusers-param-dir": "排序方向。",
"apihelp-query+allusers-param-group": "只包含指定组中的用户。",
"apihelp-query+allusers-param-excludegroup": "排除指定组中的用户。",
"apihelp-query+allusers-param-rights": "仅列出有所选权限的用户。不包括隐性的或自动加入的用户组别(如*、用户或自动确认用户)所授予的权限。",
+ "apihelp-query+allusers-param-prop": "要包含的信息束:",
+ "apihelp-query+allusers-paramvalue-prop-blockinfo": "添加有关用户当前封禁的信息。",
+ "apihelp-query+allusers-paramvalue-prop-groups": "列举用户所在的组。这使用更多服务器资源,并可能返回少于限制的结果。",
+ "apihelp-query+allusers-paramvalue-prop-implicitgroups": "列出用户自动属于的所有组。",
+ "apihelp-query+allusers-paramvalue-prop-rights": "用户拥有的权限列表。",
+ "apihelp-query+allusers-paramvalue-prop-editcount": "添加用户的编辑计数。",
+ "apihelp-query+allusers-paramvalue-prop-registration": "如果可能,添加用户注册时的时间戳(可能为空白)。",
"apihelp-query+allusers-param-limit": "返回的总计用户数。",
"apihelp-query+allusers-param-witheditsonly": "只列出有编辑的用户。",
- "apihelp-query+allusers-param-activeusers": "只列出最近$1天内活跃的用户。",
+ "apihelp-query+allusers-param-activeusers": "只列出最近$1{{PLURAL:$1|天}}内活跃的用户。",
"apihelp-query+allusers-example-Y": "列出以<kbd>Y</kbd>开头的用户。",
"apihelp-query+backlinks-description": "查找所有链接至指定页面的页面。",
"apihelp-query+backlinks-param-title": "要搜索的标题。不能与<var>$1pageid</var>一起使用。",
"apihelp-query+backlinks-param-pageid": "要搜索的页面ID。不能与<var>$1title</var>一起使用。",
"apihelp-query+backlinks-param-namespace": "要列举的名字空间。",
"apihelp-query+backlinks-param-dir": "罗列所采用的方向。",
+ "apihelp-query+backlinks-param-filterredir": "如何过滤重定向。当<var>$1redirect</var>被启用时如果设置为<kbd>nonredirects</kbd>,这只会应用到第二级。",
"apihelp-query+backlinks-param-limit": "返回总计页面数。如果<var>$1redirect</var>被启用,则限定分别适用于每一等级(这意味着将返回多达2 * <var>$1limit</var>个结果)。",
+ "apihelp-query+backlinks-param-redirect": "如果链入页面是一个重定向,则寻找所有链接至此重定向的页面。最大限制减半。",
"apihelp-query+backlinks-example-simple": "显示至<kbd>Main page<kbd>的链接。",
- "apihelp-query+backlinks-example-generator": "获得关于链接至<kbd>Main page<kbd>的页面的信息。",
+ "apihelp-query+backlinks-example-generator": "获取关于链接至<kbd>Main page<kbd>的页面的信息。",
"apihelp-query+blocks-description": "列出所有被封禁的用户和IP地址。",
+ "apihelp-query+blocks-param-start": "枚举的起始时间戳。",
+ "apihelp-query+blocks-param-end": "枚举的结束时间戳。",
"apihelp-query+blocks-param-ids": "要列出的封禁ID列表(可选)。",
"apihelp-query+blocks-param-users": "要搜索的用户列表(可选)。",
- "apihelp-query+blocks-param-prop": "要获取的属性:\n;id:添加封禁ID。\n;user:添加被封禁用户的用户名。\n;userid:添加被封禁用户的用户ID。\n;by:添加执行封禁的用户的用户名。\n;byid:添加执行封禁的用户的用户ID。\n;timestamp:添加封禁生效时的时间戳。\n;expiry:添加封禁截止时的时间戳。\n;reason:添加封禁原因。\n;range:添加受封禁影响的IP地址段。\n;flags:标记编辑禁止(自动封禁、仅限匿名用户等)。",
- "apihelp-query+blocks-example-simple": "封禁列表",
+ "apihelp-query+blocks-param-limit": "封禁列表的最大数量。",
+ "apihelp-query+blocks-param-prop": "要获取的属性:",
+ "apihelp-query+blocks-paramvalue-prop-id": "添加封禁ID。",
+ "apihelp-query+blocks-paramvalue-prop-user": "添加被封禁用户的用户名。",
+ "apihelp-query+blocks-paramvalue-prop-userid": "添加被封禁用户的用户ID。",
+ "apihelp-query+blocks-paramvalue-prop-by": "添加执行封禁的用户的用户名。",
+ "apihelp-query+blocks-paramvalue-prop-byid": "添加执行封禁的用户的用户ID。",
+ "apihelp-query+blocks-paramvalue-prop-timestamp": "添加封禁生效时的时间戳。",
+ "apihelp-query+blocks-paramvalue-prop-expiry": "添加封禁截止时的时间戳。",
+ "apihelp-query+blocks-paramvalue-prop-reason": "添加封禁原因。",
+ "apihelp-query+blocks-paramvalue-prop-range": "添加受封禁影响的IP地址段。",
+ "apihelp-query+blocks-paramvalue-prop-flags": "标记编辑禁止(自动封禁、仅限匿名用户等)。",
+ "apihelp-query+blocks-example-simple": "封禁列表。",
"apihelp-query+blocks-example-users": "列出用户<kbd>Alice</kbd>和<kbd>Bob</kbd>的封禁。",
"apihelp-query+categories-description": "页面属于的所有分类列表。",
- "apihelp-query+categories-param-prop": "要为每个分类获取的额外属性:\n;sortkey:为每个分类添加关键词(十六进制字符串)和关键词前缀(人类可读部分)。\n;timestamp:添加分类添加时的时间戳。\n;hidden:标记由_&#95;HIDDENCAT_&#95;隐藏的分类。",
+ "apihelp-query+categories-param-prop": "要为每个分类获取的额外属性:",
+ "apihelp-query+categories-paramvalue-prop-sortkey": "为每个分类添加关键词(十六进制字符串)和关键词前缀(人类可读部分)。",
+ "apihelp-query+categories-paramvalue-prop-timestamp": "添加分类添加时的时间戳。",
+ "apihelp-query+categories-paramvalue-prop-hidden": "标记由<code>_&#95;HIDDENCAT_&#95;</code>隐藏的分类。",
"apihelp-query+categories-param-show": "显示何种分类。",
"apihelp-query+categories-param-limit": "返回多少分类。",
"apihelp-query+categories-param-dir": "罗列所采用的方向。",
@@ -417,6 +542,13 @@
"apihelp-query+categorymembers-description": "在指定的分类中列出所有页面。",
"apihelp-query+categorymembers-param-title": "要列举的分类(必需)。必须包括<kbd>{{ns:category}}:</kbd>前缀。不能与<var>$1pageid</var>一起使用。",
"apihelp-query+categorymembers-param-pageid": "要枚举的分类的页面 ID。不能与<var>$1title</var>一起使用。",
+ "apihelp-query+categorymembers-param-prop": "要包含的信息束:",
+ "apihelp-query+categorymembers-paramvalue-prop-ids": "添加页面ID。",
+ "apihelp-query+categorymembers-paramvalue-prop-title": "添加页面标题和名字空间ID。",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkey": "Adds the sortkey used for sorting in the category (hexadecimal string).",
+ "apihelp-query+categorymembers-paramvalue-prop-sortkeyprefix": "Adds the sortkey prefix used for sorting in the category (human-readable part of the sortkey).",
+ "apihelp-query+categorymembers-paramvalue-prop-type": "Adds the type that the page has been categorised as (page, subcat or file).",
+ "apihelp-query+categorymembers-paramvalue-prop-timestamp": "Adds the timestamp of when the page was included.",
"apihelp-query+categorymembers-param-namespace": "仅包含这些名字空间的页面。注意<kbd>$1type=subcat</kbd>或<kbd>$1type=file</kbd>可能被使用,而不是<kbd>$1namespace=14</kbd>或<kbd>6</kbd>。",
"apihelp-query+categorymembers-param-type": "包含的分类成员类型。当<kbd>$1sort=timestamp</kbd>被设置时会忽略。",
"apihelp-query+categorymembers-param-limit": "返回页面的最大数量。",
@@ -426,10 +558,11 @@
"apihelp-query+categorymembers-param-end": "列举的结尾时间戳。只能与<kbd>$1sort=timestamp</kbd>一起使用。",
"apihelp-query+categorymembers-param-starthexsortkey": "开始列举的关键词,由<kbd>$1prop=sortkey</kbd>返回。不能与<kbd>$1sort=sortkey</kbd>一起使用。",
"apihelp-query+categorymembers-param-endhexsortkey": "结束列举的关键词,由<kbd>$1prop=sortkey</kbd>返回。不能与<kbd>$1sort=sortkey</kbd>一起使用。",
+ "apihelp-query+categorymembers-param-startsortkeyprefix": "要开始列举的排序关键词前缀。只能与<kbd>$1sort=sortkey</kbd>一起使用。覆盖<var>$1starthexsortkey</var>。",
"apihelp-query+categorymembers-param-startsortkey": "请改用$1starthexsortkey。",
"apihelp-query+categorymembers-param-endsortkey": "请改用$1endhexsortkey。",
- "apihelp-query+categorymembers-example-simple": "获得<kbd>Category:Physics</kbd>中的前10个页面。",
- "apihelp-query+categorymembers-example-generator": "获得有关<kbd>Category:Physics</kbd>中的前10个页面的页面信息。",
+ "apihelp-query+categorymembers-example-simple": "获取<kbd>Category:Physics</kbd>中的前10个页面。",
+ "apihelp-query+categorymembers-example-generator": "获取有关<kbd>Category:Physics</kbd>中的前10个页面的页面信息。",
"apihelp-query+contributors-description": "获取对一个页面的登录贡献者列表和匿名贡献数。",
"apihelp-query+contributors-param-limit": "返回的贡献数。",
"apihelp-query+contributors-example-simple": "显示<kbd>Main Page</kbd>的贡献。",
@@ -437,26 +570,32 @@
"apihelp-query+deletedrevisions-param-tag": "只列出被此标签标记的修订。",
"apihelp-query+deletedrevisions-param-user": "只列出此用户做出的修订。",
"apihelp-query+deletedrevisions-param-excludeuser": "不要列出此用户做出的修订。",
- "apihelp-query+deletedrevisions-param-limit": "要列出的修订的最高数额。",
- "apihelp-query+deletedrevisions-param-prop": "要获取的属性:\n;revid:添加已删除修订的修订ID。\n;parentid:添加上一修订的修订ID至页面中。\n;user:添加做出修订的用户。\n;userid:添加做出修订的用户ID。\n;comment:添加修订的摘要。\n;parsedcomment:添加修订的解析摘要。\n;minor:如果修订为小修订则予以标记。\n;len:添加修订的长度(字节)。\n;sha1:添加修订的SHA-1(base 16)。\n;content:添加修订内容。\n;tags:用于修订的标签。",
"apihelp-query+deletedrevisions-example-titles": "列出页面<kbd>Main Page</kbd>和<kbd>Talk:Main Page</kbd>的已删除修订,包含内容。",
"apihelp-query+deletedrevisions-example-revids": "列出已删除修订<kbd>123456</kbd>的信息。",
+ "apihelp-query+deletedrevs-description": "列出被删除修订。\n\n操作于三种模式中:\n# 为指定标题列举已删除修订,按时间戳排列。\n# 为指定用户列举已删除贡献,按时间戳排列(未指定标题)。\n# 在指定名字空间中列举所有已删除修订,按标题和时间戳排列(无指定标题,未设置$1user)。\n\n任一参数只应用于一些模式,并忽略其他参数。",
"apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|模式}}:$2",
+ "apihelp-query+deletedrevs-param-start": "枚举的起始时间戳。",
+ "apihelp-query+deletedrevs-param-end": "枚举的结束时间戳。",
"apihelp-query+deletedrevs-param-from": "从此标题开始列出。",
"apihelp-query+deletedrevs-param-to": "列出至此标题为止。",
+ "apihelp-query+deletedrevs-param-prefix": "搜索所有以此值开头的页面标题。",
+ "apihelp-query+deletedrevs-param-unique": "每个页面只列出一个修订。",
+ "apihelp-query+deletedrevs-param-tag": "只列出被此标签标记的修订。",
"apihelp-query+deletedrevs-param-user": "只列出此用户做出的修订。",
"apihelp-query+deletedrevs-param-excludeuser": "不要列出此用户做出的修订。",
"apihelp-query+deletedrevs-param-namespace": "只列出此名字空间的页面。",
+ "apihelp-query+deletedrevs-param-prop": "要获取的属性:\n;revid:添加被删除修订的修订ID。\n;parentid:添加上一修订的修订ID至页面。\n;user:添加做出修订的用户。\n;userid:添加做出修订的用户ID。\n;comment:添加修订摘要。\n;parsedcomment:添加解析过的修订摘要。\n;minor:如果修订是小编辑则加标签。\n;len:添加修订长度(字节)。\n;sha1:添加修订的SHA-1(base 16)。\n;content:添加修订内容。\n;token:<span class=\"apihelp-deprecated\">已弃用。</span>提供编辑令牌。\n;tags:修订标签。",
"apihelp-query+deletedrevs-example-mode1": "列出最近已删除的对页面<kbd>Main Page</kbd>和<kbd>Talk:Main Page</kbd>的贡献,带内容(模式1)。",
"apihelp-query+deletedrevs-example-mode2": "列出由<kbd>Bob</kbd>作出的最近50次已删除贡献(模式2)。",
- "apihelp-query+deletedrevs-example-mode3-main": "列出前50次主名字空间已删除贡献(模式3)",
- "apihelp-query+deletedrevs-example-mode3-talk": "列出前50次{{ns:talk}}名字空间已删除页面(模式3):",
+ "apihelp-query+deletedrevs-example-mode3-main": "列出前50次主名字空间已删除贡献(模式3)。",
+ "apihelp-query+deletedrevs-example-mode3-talk": "列出前50次{{ns:talk}}名字空间已删除页面(模式3)。",
"apihelp-query+disabled-description": "此查询模块已被禁用。",
"apihelp-query+duplicatefiles-param-limit": "返回多少重复文件。",
"apihelp-query+duplicatefiles-param-dir": "罗列所采用的方向。",
"apihelp-query+duplicatefiles-param-localonly": "只看本地存储库的文件。",
- "apihelp-query+duplicatefiles-example-simple": "查找与[[:File:Albert Einstein Head.jpg]]重复的文件",
- "apihelp-query+duplicatefiles-example-generated": "查找所有文件的重复文件",
+ "apihelp-query+duplicatefiles-example-simple": "查找与[[:File:Albert Einstein Head.jpg]]重复的文件。",
+ "apihelp-query+duplicatefiles-example-generated": "查找所有文件的重复文件。",
+ "apihelp-query+embeddedin-description": "查找所有嵌入指定标题的页面。",
"apihelp-query+embeddedin-param-title": "要搜索的标题。不能与$1pageid一起使用。",
"apihelp-query+embeddedin-param-pageid": "要搜索的页面ID。不能与$1title一起使用。",
"apihelp-query+embeddedin-param-namespace": "列举的名字空间。",
@@ -464,14 +603,25 @@
"apihelp-query+embeddedin-param-filterredir": "如何过滤重定向。",
"apihelp-query+embeddedin-param-limit": "返回的总计页面数。",
"apihelp-query+embeddedin-example-simple": "显示嵌入<kbd>Template:Stub</kbd>的页面。",
- "apihelp-query+embeddedin-example-generator": "获得有关显示嵌入<kbd>Template:Stub</kbd>的页面的信息。",
+ "apihelp-query+embeddedin-example-generator": "获取有关显示嵌入<kbd>Template:Stub</kbd>的页面的信息。",
+ "apihelp-query+extlinks-description": "从指定页面返回所有外部URL(非跨wiki链接)。",
"apihelp-query+extlinks-param-limit": "返回多少链接。",
- "apihelp-query+extlinks-example-simple": "获取<kbd>首页</kbd>的外部链接列表。",
+ "apihelp-query+extlinks-param-protocol": "URL协议。如果为空并且<var>$1query</var>被设置,协议为<kbd>http</kbd>。将此和<var>$1query</var>都留空以列举所有外部链接。",
+ "apihelp-query+extlinks-param-query": "不使用协议搜索字符串。对于检查某一页面是否包含某一外部URL很有用。",
+ "apihelp-query+extlinks-param-expandurl": "扩展协议相对URL与规范协议。",
+ "apihelp-query+extlinks-example-simple": "获取<kbd>Main Page<kbd>的外部链接列表。",
+ "apihelp-query+exturlusage-description": "列举包含一个指定URL的页面。",
+ "apihelp-query+exturlusage-param-prop": "要包含的信息束:",
+ "apihelp-query+exturlusage-paramvalue-prop-ids": "添加页面ID。",
+ "apihelp-query+exturlusage-paramvalue-prop-title": "添加页面的标题和名字空间ID。",
+ "apihelp-query+exturlusage-paramvalue-prop-url": "添加页面中使用的URL。",
"apihelp-query+exturlusage-param-protocol": "URL协议。如果为空并且<var>$1query</var>被设置,协议为<kbd>http</kbd>。将此和<var>$1query</var>都留空以列举所有外部链接。",
"apihelp-query+exturlusage-param-query": "不包括协议的搜索字符串。参见[[Special:LinkSearch]]。留空以列出所有外部链接。",
"apihelp-query+exturlusage-param-namespace": "要列举的页面名字空间。",
"apihelp-query+exturlusage-param-limit": "返回多少页面。",
+ "apihelp-query+exturlusage-param-expandurl": "用标准协议展开协议相关URL。",
"apihelp-query+exturlusage-example-simple": "显示链接至<kbd>http://www.mediawiki.org</kbd>的页面。",
+ "apihelp-query+filearchive-description": "循序列举所有被删除的文件。",
"apihelp-query+filearchive-param-from": "枚举的起始图片标题。",
"apihelp-query+filearchive-param-to": "枚举的结束图片标题。",
"apihelp-query+filearchive-param-prefix": "搜索所有以此值开头的图像标题。",
@@ -479,58 +629,108 @@
"apihelp-query+filearchive-param-dir": "罗列所采用的方向。",
"apihelp-query+filearchive-param-sha1": "图片的SHA1哈希值。覆盖$1sha1base36。",
"apihelp-query+filearchive-param-sha1base36": "基于base 36的图片的SHA1哈希值(用于MediaWiki)。",
- "apihelp-query+filearchive-example-simple": "显示已删除文件列表",
+ "apihelp-query+filearchive-param-prop": "要获取的图片信息:",
+ "apihelp-query+filearchive-paramvalue-prop-sha1": "为文件加入SHA-1哈希值。",
+ "apihelp-query+filearchive-paramvalue-prop-timestamp": "为已上传版本添加时间戳。",
+ "apihelp-query+filearchive-paramvalue-prop-user": "添加上传了图片版本的用户。",
+ "apihelp-query+filearchive-paramvalue-prop-size": "添加图片大小(字节)及其高度、宽度和页面计数(如果可以)。",
+ "apihelp-query+filearchive-paramvalue-prop-dimensions": "用于大小的别名。",
+ "apihelp-query+filearchive-paramvalue-prop-description": "添加图片版本的说明。",
+ "apihelp-query+filearchive-paramvalue-prop-parseddescription": "解析版本的描述。",
+ "apihelp-query+filearchive-paramvalue-prop-mime": "添加图片的MIME。",
+ "apihelp-query+filearchive-paramvalue-prop-mediatype": "添加图片的媒体类型。",
+ "apihelp-query+filearchive-paramvalue-prop-metadata": "为图片版本列出Exif元数据。",
+ "apihelp-query+filearchive-paramvalue-prop-bitdepth": "添加版本的字节深度。",
+ "apihelp-query+filearchive-paramvalue-prop-archivename": "添加用于非最新版本的存档版本的文件名。",
+ "apihelp-query+filearchive-example-simple": "显示已删除文件列表。",
+ "apihelp-query+filerepoinfo-description": "返回有关wiki配置的图片存储库的元信息。",
"apihelp-query+filerepoinfo-example-simple": "获得有关文件存储库的信息。",
- "apihelp-query+fileusage-param-prop": "要获取的属性:\n;pageid:每个页面的页面ID。\n;title:每个页面的标题。\n;redirect:标记作为重定向的页面。",
+ "apihelp-query+fileusage-description": "查找所有使用指定文件的页面。",
+ "apihelp-query+fileusage-param-prop": "要获取的属性:",
+ "apihelp-query+fileusage-paramvalue-prop-pageid": "每个页面的页面ID。",
+ "apihelp-query+fileusage-paramvalue-prop-title": "每个页面的标题。",
+ "apihelp-query+fileusage-paramvalue-prop-redirect": "标记作为重定向的页面。",
"apihelp-query+fileusage-param-namespace": "只包括这些名字空间的页面。",
"apihelp-query+fileusage-param-limit": "返回多少。",
- "apihelp-query+fileusage-example-simple": "获取使用[[:File:Example.jpg]]的页面列表",
- "apihelp-query+fileusage-example-generator": "获取有关使用[[:File:Example.jpg]]的页面的信息",
+ "apihelp-query+fileusage-param-show": "只显示符合以下标准的项:\n;redirect:只显示重定向。\n;!redirect:只显示非重定向。",
+ "apihelp-query+fileusage-example-simple": "获取使用[[:File:Example.jpg]]的页面列表。",
+ "apihelp-query+fileusage-example-generator": "获取有关使用[[:File:Example.jpg]]的页面的信息。",
"apihelp-query+imageinfo-description": "返回文件信息和上传历史。",
"apihelp-query+imageinfo-param-prop": "要获取的文件信息:",
"apihelp-query+imageinfo-paramvalue-prop-timestamp": "添加时间戳至上传的版本。",
+ "apihelp-query+imageinfo-paramvalue-prop-user": "添加上传了每个文件版本的用户。",
+ "apihelp-query+imageinfo-paramvalue-prop-userid": "添加上传了每个文件版本的用户ID。",
"apihelp-query+imageinfo-paramvalue-prop-comment": "此版本的摘要。",
- "apihelp-query+imageinfo-paramvalue-prop-dimensions": "大小别名。",
+ "apihelp-query+imageinfo-paramvalue-prop-parsedcomment": "解析版本上的注释。",
+ "apihelp-query+imageinfo-paramvalue-prop-canonicaltitle": "添加文件的规范标题。",
+ "apihelp-query+imageinfo-paramvalue-prop-url": "为文件及其描述页面提供URL。",
+ "apihelp-query+imageinfo-paramvalue-prop-size": "添加文件大小(字节)及其高度、宽度和页面数(如果可以)。",
+ "apihelp-query+imageinfo-paramvalue-prop-dimensions": "用于大小的别名。",
"apihelp-query+imageinfo-paramvalue-prop-sha1": "为文件加入SHA-1哈希值。",
"apihelp-query+imageinfo-paramvalue-prop-mime": "添加文件的MIME类型。",
+ "apihelp-query+imageinfo-paramvalue-prop-thumbmime": "添加图片缩略图的MIME类型(需要url和参数$1urlwidth)。",
"apihelp-query+imageinfo-paramvalue-prop-mediatype": "添加文件媒体类型。",
+ "apihelp-query+imageinfo-paramvalue-prop-metadata": "列出这个版本的文件的EXIF元数据。",
+ "apihelp-query+imageinfo-paramvalue-prop-commonmetadata": "为文件的修订版本列出文件格式相关元数据。",
+ "apihelp-query+imageinfo-paramvalue-prop-extmetadata": "列出结合自多个来源的格式化的元数据。结果均依HTML格式化。",
+ "apihelp-query+imageinfo-paramvalue-prop-archivename": "添加用于非最新修订的存档修订的文件名。",
+ "apihelp-query+imageinfo-paramvalue-prop-bitdepth": "添加修订的字节深度。",
+ "apihelp-query+imageinfo-paramvalue-prop-uploadwarning": "由Special:Upload所使用,以获取关于现有文件的信息。不适用于MediaWiki核心以外代码。",
+ "apihelp-query+imageinfo-param-limit": "每个文件返回多少文件修订。",
"apihelp-query+imageinfo-param-start": "开始列举的时间戳。",
"apihelp-query+imageinfo-param-end": "列举的结束时间戳。",
+ "apihelp-query+imageinfo-param-urlwidth": "如果$2prop=url被设定,将返回至缩放到此宽度的一张图片的URL。\n由于性能原因,如果此消息被使用,将不会返回超过$1张被缩放的图片。",
"apihelp-query+imageinfo-param-urlheight": "与$1urlwidth类似。",
"apihelp-query+imageinfo-param-metadataversion": "要使用的元数据版本。如果<kbd>latest</kbd>被指定,则使用最新版本。默认为<kbd>1</kbd>以便向下兼容。",
+ "apihelp-query+imageinfo-param-extmetadatalanguage": "要取得extmetadata的语言。This affects both which translation to fetch, if multiple are available, as well as how things like numbers and various values are formatted.",
+ "apihelp-query+imageinfo-param-extmetadatamultilang": "如果用于extmetadata属性的翻译可用,则全部取得。",
+ "apihelp-query+imageinfo-param-extmetadatafilter": "如果指定且非空,则只为$1prop=extmetadata返回这些键。",
+ "apihelp-query+imageinfo-param-urlparam": "处理器特定的参数字符串。例如PDF可能使用<kbd>page15-100px</kbd>。<var>$1urlwidth</var>必须被使用,并与<var>$1urlparam</var>一致。",
"apihelp-query+imageinfo-param-localonly": "只看本地存储库的文件。",
- "apihelp-query+imageinfo-example-simple": "获取有关[[:File:Albert Einstein Head.jpg]]的当前版本的信息",
- "apihelp-query+imageinfo-example-dated": "获取有关[[:File:Albert Einstein Head.jpg]]自2008年以来版本的信息",
+ "apihelp-query+imageinfo-example-simple": "取得有关[[:File:Albert Einstein Head.jpg]]的当前版本的信息。",
+ "apihelp-query+imageinfo-example-dated": "取得有关[[:File:Test.jpg]]自2008年以来版本的信息。",
+ "apihelp-query+images-description": "返回指定页面上包含的所有文件。",
"apihelp-query+images-param-limit": "返回多少文件。",
"apihelp-query+images-param-dir": "罗列所采用的方向。",
- "apihelp-query+images-example-simple": "获取[[首页]]使用的文件列表",
- "apihelp-query+images-example-generator": "获取有关[[首页]]使用的文件的信息",
+ "apihelp-query+images-example-simple": "获取[[Main Page]]使用的文件列表。",
+ "apihelp-query+images-example-generator": "获取有关[[Main Page]]使用的文件的信息。",
"apihelp-query+imageusage-description": "查找所有使用指定图片标题的页面。",
"apihelp-query+imageusage-param-title": "要搜索的标题。不能与$1pageid一起使用。",
"apihelp-query+imageusage-param-pageid": "要搜索的页面ID。不能与$1title一起使用。",
"apihelp-query+imageusage-param-namespace": "要列举的名字空间。",
"apihelp-query+imageusage-param-dir": "罗列所采用的方向。",
- "apihelp-query+imageusage-example-simple": "显示使用[[:File:Albert Einstein Head.jpg]]的页面",
- "apihelp-query+imageusage-example-generator": "获取有关使用[[:File:Albert Einstein Head.jpg]]的页面的信息",
+ "apihelp-query+imageusage-example-simple": "显示使用[[:File:Albert Einstein Head.jpg]]的页面。",
+ "apihelp-query+imageusage-example-generator": "获取有关使用[[:File:Albert Einstein Head.jpg]]的页面的信息。",
"apihelp-query+info-description": "获取基本页面信息。",
"apihelp-query+info-param-prop": "要获取的额外属性:",
"apihelp-query+info-paramvalue-prop-protection": "列出每个页面的保护等级。",
+ "apihelp-query+info-paramvalue-prop-talkid": "每个非讨论页面的讨论页的页面ID。",
"apihelp-query+info-paramvalue-prop-watched": "列出每个页面的被监视状态。",
"apihelp-query+info-paramvalue-prop-watchers": "监视人员数,如果允许。",
+ "apihelp-query+info-paramvalue-prop-notificationtimestamp": "每个页面的监视列表通知时间戳。",
+ "apihelp-query+info-paramvalue-prop-subjectid": "每个讨论页的母页面的页面ID。",
+ "apihelp-query+info-paramvalue-prop-url": "为每个页面提供一个完整URL、一个编辑URL和规范URL。",
"apihelp-query+info-paramvalue-prop-readable": "用户是否可以阅读此页面。",
+ "apihelp-query+info-paramvalue-prop-preload": "提供由EditFormPreloadText返回的文本。",
+ "apihelp-query+info-paramvalue-prop-displaytitle": "在页面标题实际显示的地方提供方式。",
"apihelp-query+info-param-testactions": "测试当前用户是否可以在页面上执行某种操作。",
"apihelp-query+info-param-token": "请改用[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]。",
- "apihelp-query+info-example-simple": "获得有关页面<kbd>Main Page</kbd>的信息。",
- "apihelp-query+info-example-protection": "获取<kbd>首页</kbd>相关的常规和保护信息。",
+ "apihelp-query+info-example-simple": "获取有关页面<kbd>Main Page</kbd>的信息。",
+ "apihelp-query+info-example-protection": "获取<kbd>Main Page</kbd>相关的常规和保护信息。",
+ "apihelp-query+iwbacklinks-description": "查找所有链接至指定跨wiki链接的页面。\n\n可被用于查找带某一前缀的所有链接,或所有至某一标题的链接(带指定前缀)。两参数都不使用就意味着“所有跨wiki链接”。",
"apihelp-query+iwbacklinks-param-prefix": "跨维基前缀。",
"apihelp-query+iwbacklinks-param-title": "要搜索的跨wiki链接。必须与<var>$1blprefix</var>一起使用。",
"apihelp-query+iwbacklinks-param-limit": "返回的总计页面数。",
- "apihelp-query+iwbacklinks-param-prop": "要获取的属性:\n;iwprefix:加入跨wiki前缀。\n;iwtitle:加入跨wiki标题。",
+ "apihelp-query+iwbacklinks-param-prop": "要获取的属性:",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "加入跨wiki前缀。",
+ "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "加入跨wiki标题。",
"apihelp-query+iwbacklinks-param-dir": "罗列所采用的方向。",
- "apihelp-query+iwbacklinks-example-simple": "获得链接至[[wikibooks:Test]]的页面。",
- "apihelp-query+iwbacklinks-example-generator": "获得有关链接至[[wikibooks:Test]]的页面的信息。",
+ "apihelp-query+iwbacklinks-example-simple": "获取链接至[[wikibooks:Test]]的页面。",
+ "apihelp-query+iwbacklinks-example-generator": "获取有关链接至[[wikibooks:Test]]的页面的信息。",
"apihelp-query+iwlinks-description": "从指定页面返回所有跨wiki链接。",
"apihelp-query+iwlinks-param-url": "是否获取完整URL(不能与$1prop一起使用)。",
+ "apihelp-query+iwlinks-param-prop": "要为每个跨语言链接获取的额外属性:",
+ "apihelp-query+iwlinks-paramvalue-prop-url": "添加完整URL。",
"apihelp-query+iwlinks-param-limit": "返回多少跨wiki链接。",
"apihelp-query+iwlinks-param-prefix": "只返回此前缀的跨wiki链接。",
"apihelp-query+iwlinks-param-title": "用于搜索的跨wiki链接。必须与<var>$1prefix</var>一起使用。",
@@ -539,174 +739,415 @@
"apihelp-query+langbacklinks-param-lang": "用于语言链接的语言。",
"apihelp-query+langbacklinks-param-title": "要搜索的语言链接。必须与$1lang一起使用。",
"apihelp-query+langbacklinks-param-limit": "返回的总计页面数。",
- "apihelp-query+langbacklinks-param-prop": "要获得的属性:\n;lllang:添加语言链接的语言代码。\n;lltitle:添加语言链接的标题。",
+ "apihelp-query+langbacklinks-param-prop": "要获得的属性:",
+ "apihelp-query+langbacklinks-paramvalue-prop-lllang": "添加语言链接的语言代码。",
+ "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "添加语言链接的标题。",
"apihelp-query+langbacklinks-param-dir": "罗列所采用的方向。",
- "apihelp-query+langbacklinks-example-simple": "获取链接至[[:fr:Test]]的页面",
- "apihelp-query+langbacklinks-example-generator": "获取链接至[[:fr:Test]]的页面的信息",
+ "apihelp-query+langbacklinks-example-simple": "获取链接至[[:fr:Test]]的页面。",
+ "apihelp-query+langbacklinks-example-generator": "获取链接至[[:fr:Test]]的页面的信息。",
"apihelp-query+langlinks-description": "从指定页面返回所有跨语言链接。",
"apihelp-query+langlinks-param-limit": "返回多少语言链接。",
"apihelp-query+langlinks-param-url": "是否获取完整URL(不能与<var>$1prop</var>一起使用)。",
+ "apihelp-query+langlinks-param-prop": "要为每个跨语言链接获取的额外属性:",
+ "apihelp-query+langlinks-paramvalue-prop-url": "添加完整URL。",
+ "apihelp-query+langlinks-paramvalue-prop-langname": "添加本地化语言名(尽可能)。使用<var>$1inlanguagecode</var>以控制语言。",
+ "apihelp-query+langlinks-paramvalue-prop-autonym": "添加本地语言名。",
"apihelp-query+langlinks-param-lang": "只返回带此语言代码的语言链接。",
"apihelp-query+langlinks-param-title": "要搜索的链接。必须与<var>$1lang</var>一起使用。",
"apihelp-query+langlinks-param-dir": "罗列所采用的方向。",
"apihelp-query+langlinks-param-inlanguagecode": "本地化语言名称的语言代码。",
- "apihelp-query+langlinks-example-simple": "从页面<kbd>Main Page</kbd>获得跨语言链接。",
+ "apihelp-query+langlinks-example-simple": "从页面<kbd>Main Page</kbd>获取跨语言链接。",
"apihelp-query+links-description": "从指定页面返回所有链接。",
"apihelp-query+links-param-namespace": "只显示这些名字空间的链接。",
"apihelp-query+links-param-limit": "返回多少链接。",
"apihelp-query+links-param-dir": "罗列所采用的方向。",
- "apihelp-query+links-example-simple": "从页面<kbd>Main Page</kbd>获得链接",
- "apihelp-query+links-example-generator": "获得有关在页面<kbd>Main Page</kbd>中连接的页面的信息。",
- "apihelp-query+links-example-namespaces": "获得在{{ns:user}}和{{ns:template}}名字空间中来自页面<kbd>Main Page</kbd>的链接。",
+ "apihelp-query+links-example-simple": "从页面<kbd>Main Page</kbd>获取链接。",
+ "apihelp-query+links-example-generator": "获取有关在页面<kbd>Main Page</kbd>中连接的页面的信息。",
+ "apihelp-query+links-example-namespaces": "获取在{{ns:user}}和{{ns:template}}名字空间中来自页面<kbd>Main Page</kbd>的链接。",
"apihelp-query+linkshere-description": "查找所有链接至指定页面的页面。",
- "apihelp-query+linkshere-param-prop": "要获得的属性:\n;pageid:每个页面的页面ID。\n;title:每个页面的标题。\n;redirect:如果页面是一个重定向就标记。",
+ "apihelp-query+linkshere-param-prop": "要获取的属性:",
+ "apihelp-query+linkshere-paramvalue-prop-pageid": "每个页面的页面ID。",
+ "apihelp-query+linkshere-paramvalue-prop-title": "每个页面的标题。",
+ "apihelp-query+linkshere-paramvalue-prop-redirect": "如果页面是一个重定向就标记。",
"apihelp-query+linkshere-param-namespace": "只包括这些名字空间的页面。",
"apihelp-query+linkshere-param-limit": "返回多少。",
"apihelp-query+linkshere-param-show": "只显示符合以下标准的项:\n;redirect:只显示重定向。\n;!redirect:只显示非重定向。",
- "apihelp-query+linkshere-example-simple": "获取链接至[[首页]]的页面列表",
- "apihelp-query+linkshere-example-generator": "获取有关链接至[[首页]]的页面的信息",
+ "apihelp-query+linkshere-example-simple": "获取链接至[[Main Page]]的页面列表。",
+ "apihelp-query+linkshere-example-generator": "获取有关链接至[[Main Page]]的页面的信息。",
"apihelp-query+logevents-description": "从日志获取事件。",
+ "apihelp-query+logevents-param-prop": "要获取的属性:",
+ "apihelp-query+logevents-paramvalue-prop-ids": "添加日志活动的ID。",
+ "apihelp-query+logevents-paramvalue-prop-title": "为日志事件添加页面标题。",
+ "apihelp-query+logevents-paramvalue-prop-type": "添加日志活动的类型。",
+ "apihelp-query+logevents-paramvalue-prop-user": "为日志事件添加用户责任。",
+ "apihelp-query+logevents-paramvalue-prop-userid": "为日志事件添加对此负责的用户ID。",
+ "apihelp-query+logevents-paramvalue-prop-timestamp": "为日志活动添加时间戳。",
+ "apihelp-query+logevents-paramvalue-prop-comment": "添加日志活动的摘要。",
+ "apihelp-query+logevents-paramvalue-prop-parsedcomment": "添加被解析的日志活动的摘要。",
+ "apihelp-query+logevents-paramvalue-prop-details": "列举有关日志事件的额外详细信息。",
+ "apihelp-query+logevents-paramvalue-prop-tags": "列举用于日志活动的标签。",
+ "apihelp-query+logevents-param-type": "过滤日志记录至仅限此类型。",
+ "apihelp-query+logevents-param-action": "过滤日志操作为仅限此操作。覆盖<var>$1type</var>。在可用值列表中,带星号通配符的值例如<kbd>action/*</kbd>可在斜线(/)后拥有不同字符串。",
"apihelp-query+logevents-param-start": "枚举的起始时间戳。",
"apihelp-query+logevents-param-end": "枚举的结束时间戳。",
- "apihelp-query+logevents-example-simple": "列出最近日志活动",
+ "apihelp-query+logevents-param-user": "过滤记录为这些由指定用户做出的。",
+ "apihelp-query+logevents-param-title": "过滤记录至这些与页面相关的。",
+ "apihelp-query+logevents-param-namespace": "过滤事件为在这些指定的名字空间中。",
+ "apihelp-query+logevents-param-prefix": "过滤以此前缀开头的记录。",
+ "apihelp-query+logevents-param-tag": "只列举带此标签的事件日志记录。",
+ "apihelp-query+logevents-param-limit": "返回的事件日志记录总数。",
+ "apihelp-query+logevents-example-simple": "列出最近日志事件。",
"apihelp-query+pagepropnames-description": "列出wiki中所有使用中的页面属性名称。",
"apihelp-query+pagepropnames-param-limit": "返回名称的最大数量。",
"apihelp-query+pagepropnames-example-simple": "获取前10个属性名称。",
- "apihelp-query+pageprops-example-simple": "获得用于<kbd>Category:Foo</kbd>的属性。",
+ "apihelp-query+pageprops-description": "获取页面内容中定义的各种属性。",
+ "apihelp-query+pageprops-param-prop": "只列出这些组。在检查某一页面是否使用某一个页面属性时有用。",
+ "apihelp-query+pageprops-example-simple": "获取用于页面<kbd>Main Page</kbd>和<kbd>MediaWiki</kbd>的属性。",
"apihelp-query+pageswithprop-description": "列出所有使用指定页面属性的页面。",
+ "apihelp-query+pageswithprop-param-propname": "要用于列举页面的页面属性。",
+ "apihelp-query+pageswithprop-param-prop": "要包含的信息束:",
+ "apihelp-query+pageswithprop-paramvalue-prop-ids": "添加页面ID。",
+ "apihelp-query+pageswithprop-paramvalue-prop-title": "添加页面的标题和名字空间ID。",
+ "apihelp-query+pageswithprop-paramvalue-prop-value": "添加页面属性值。",
"apihelp-query+pageswithprop-param-limit": "返回页面的最大数量。",
"apihelp-query+pageswithprop-param-dir": "排序的方向。",
"apihelp-query+pageswithprop-example-simple": "列出前10个使用<code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code>的页面。",
- "apihelp-query+pageswithprop-example-generator": "获取有关前10个使用<code>_&#95;NOTOC_&#95;</code>的页面的信息。",
+ "apihelp-query+pageswithprop-example-generator": "获取有关前10个使用<code>_&#95;NOTOC_&#95;</code>的页面的额外信息。",
"apihelp-query+prefixsearch-param-search": "搜索字符串。",
"apihelp-query+prefixsearch-param-namespace": "搜索的名字空间。",
"apihelp-query+prefixsearch-param-limit": "要返回的结果最大数。",
"apihelp-query+prefixsearch-param-offset": "跳过的结果数。",
"apihelp-query+prefixsearch-example-simple": "搜索以<kbd>meaning</kbd>开头的页面标题。",
+ "apihelp-query+protectedtitles-description": "列出所有被限制创建的标题。",
"apihelp-query+protectedtitles-param-namespace": "只列出这些名字空间的标题。",
+ "apihelp-query+protectedtitles-param-level": "只列出带这些保护级别的标题。",
"apihelp-query+protectedtitles-param-limit": "返回的总计页面数。",
- "apihelp-query+protectedtitles-example-simple": "受保护标题列表",
+ "apihelp-query+protectedtitles-param-prop": "要获取的属性:",
+ "apihelp-query+protectedtitles-paramvalue-prop-timestamp": "添加保护被添加时的时间戳。",
+ "apihelp-query+protectedtitles-paramvalue-prop-user": "添加对页面添加保护的用户。",
+ "apihelp-query+protectedtitles-paramvalue-prop-userid": "添加对页面添加保护的用户ID。",
+ "apihelp-query+protectedtitles-paramvalue-prop-comment": "为保护添加摘要。",
+ "apihelp-query+protectedtitles-paramvalue-prop-parsedcomment": "为保护添加解析的摘要。",
+ "apihelp-query+protectedtitles-paramvalue-prop-expiry": "添加保护将被提升时的时间戳。",
+ "apihelp-query+protectedtitles-paramvalue-prop-level": "添加保护级别。",
+ "apihelp-query+protectedtitles-example-simple": "受保护标题列表。",
"apihelp-query+protectedtitles-example-generator": "找到主命名空间中已保护的标题的链接。",
"apihelp-query+querypage-param-limit": "返回的结果数。",
"apihelp-query+querypage-example-ancientpages": "返回[[Special:Ancientpages]]的结果。",
+ "apihelp-query+random-description": "获取一组随机页面。\n\n页面列举在一个固定序列中,只有起始点是随机的。这意味着如果<samp>Main Page</samp>是列表中第一个随机页面的话,<samp>List of fictional monkeys</samp>将<em>总是</em>第二个,<samp>List of people on stamps of Vanuatu</samp>是第三个等。",
"apihelp-query+random-param-namespace": "只返回这些名字空间的页面。",
"apihelp-query+random-param-limit": "限制返回多少随机页面。",
- "apihelp-query+random-param-redirect": "加载一个随机重定向而不是一个随机页面。",
+ "apihelp-query+random-param-redirect": "请改用<kbd>$1filterredir=redirects</kbd>。",
+ "apihelp-query+random-param-filterredir": "如何过滤重定向。",
"apihelp-query+random-example-simple": "从主名字空间返回两个随机页面。",
+ "apihelp-query+random-example-generator": "返回有关来自主名字空间的两个随机页面的页面信息。",
"apihelp-query+recentchanges-description": "枚举最近更改。",
"apihelp-query+recentchanges-param-start": "枚举的起始时间戳。",
"apihelp-query+recentchanges-param-end": "枚举的结束时间戳。",
+ "apihelp-query+recentchanges-param-namespace": "过滤更改为仅限这些名字空间。",
"apihelp-query+recentchanges-param-user": "只列出此用户的更改。",
"apihelp-query+recentchanges-param-excludeuser": "不要列出此用户的更改。",
"apihelp-query+recentchanges-param-tag": "只列出带此标签的更改。",
+ "apihelp-query+recentchanges-param-prop": "包含的额外信息束:",
+ "apihelp-query+recentchanges-paramvalue-prop-user": "Adds the user responsible for the edit and tags if they are an IP.",
+ "apihelp-query+recentchanges-paramvalue-prop-userid": "Adds the user ID responsible for the edit.",
+ "apihelp-query+recentchanges-paramvalue-prop-comment": "Adds the comment for the edit.",
+ "apihelp-query+recentchanges-paramvalue-prop-parsedcomment": "Adds the parsed comment for the edit.",
+ "apihelp-query+recentchanges-paramvalue-prop-flags": "为编辑添加标记。",
+ "apihelp-query+recentchanges-paramvalue-prop-timestamp": "添加编辑的时间戳。",
+ "apihelp-query+recentchanges-paramvalue-prop-title": "添加编辑的页面标题。",
+ "apihelp-query+recentchanges-paramvalue-prop-ids": "添加页面ID、最近更改ID和新旧修订的ID。",
+ "apihelp-query+recentchanges-paramvalue-prop-sizes": "Adds the new and old page length in bytes.",
+ "apihelp-query+recentchanges-paramvalue-prop-redirect": "Tags edit if page is a redirect.",
+ "apihelp-query+recentchanges-paramvalue-prop-patrolled": "Tags patrollable edits as being patrolled or unpatrolled.",
+ "apihelp-query+recentchanges-paramvalue-prop-loginfo": "Adds log information (log ID, log type, etc) to log entries.",
+ "apihelp-query+recentchanges-paramvalue-prop-tags": "Lists tags for the entry.",
+ "apihelp-query+recentchanges-paramvalue-prop-sha1": "Adds the content checksum for entries associated with a revision.",
"apihelp-query+recentchanges-param-token": "请改用<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>。",
"apihelp-query+recentchanges-param-limit": "返回总计更新数。",
"apihelp-query+recentchanges-param-type": "显示的更改类型。",
- "apihelp-query+recentchanges-example-simple": "最近更改列表",
+ "apihelp-query+recentchanges-example-simple": "最近更改列表。",
+ "apihelp-query+recentchanges-example-generator": "获取有关最近未巡查更改的页面信息。",
"apihelp-query+redirects-description": "返回至指定页面的所有重定向。",
+ "apihelp-query+redirects-param-prop": "要获取的属性:",
+ "apihelp-query+redirects-paramvalue-prop-pageid": "每个重定向的页面ID。",
+ "apihelp-query+redirects-paramvalue-prop-title": "每个重定向的标题。",
+ "apihelp-query+redirects-paramvalue-prop-fragment": "每个重定向的碎片,如果有。",
"apihelp-query+redirects-param-namespace": "只包含这些名字空间的页面。",
"apihelp-query+redirects-param-limit": "返回多少重定向。",
- "apihelp-query+redirects-example-simple": "获取至[[Project:首页]]的重定向列表",
- "apihelp-query+redirects-example-generator": "获取所有重定向至[[首页]]的信息",
- "apihelp-query+revisions-example-content": "获得带内容的数据,用于标题<kbd>API</kbd>和<kbd>Main Page</kbd>的最近修订。",
+ "apihelp-query+redirects-example-simple": "获取至[[Main Page]]的重定向列表。",
+ "apihelp-query+redirects-example-generator": "获取所有重定向至[[Main Page]]的信息。",
+ "apihelp-query+revisions-paraminfo-singlepageonly": "可能只能与单一页面使用(模式#2)。",
+ "apihelp-query+revisions-param-end": "列举直至此时间戳。",
+ "apihelp-query+revisions-example-content": "获取带内容的数据,用于标题<kbd>API</kbd>和<kbd>Main Page</kbd>的最近修订。",
"apihelp-query+revisions-example-last5": "获取<kbd>Main Page</kbd>的最近5次修订。",
"apihelp-query+revisions-example-first5": "获取<kbd>Main Page</kbd>的前5次修订。",
- "apihelp-query+revisions-example-first5-after": "获得<kbd>Main Page</kbd>于2006年05月01日之后做出的前5次修订版本。",
+ "apihelp-query+revisions-example-first5-after": "获取<kbd>Main Page</kbd>于2006年05月01日之后做出的前5次修订版本。",
"apihelp-query+revisions-example-first5-not-localhost": "获取<kbd>Main Page</kbd>的前5次不是由匿名用户<kbd>127.0.0.1</kbd>做出的修订。",
"apihelp-query+revisions-example-first5-user": "获取<kbd>Main Page</kbd>的前5次由用户<kbd>MediaWiki default</kbd>做出的修订。",
+ "apihelp-query+revisions+base-param-prop": "要为每个修订获取的属性:",
+ "apihelp-query+revisions+base-paramvalue-prop-ids": "修订ID。",
+ "apihelp-query+revisions+base-paramvalue-prop-flags": "修订标记(小编辑)。",
+ "apihelp-query+revisions+base-paramvalue-prop-timestamp": "修订的时间戳。",
+ "apihelp-query+revisions+base-paramvalue-prop-user": "做出修订的用户。",
+ "apihelp-query+revisions+base-paramvalue-prop-userid": "修订创建者的用户ID。",
+ "apihelp-query+revisions+base-paramvalue-prop-size": "修订的长度(字节)。",
+ "apihelp-query+revisions+base-paramvalue-prop-sha1": "修订的SHA-1(base 16)。",
+ "apihelp-query+revisions+base-paramvalue-prop-contentmodel": "修订的内容模型ID。",
+ "apihelp-query+revisions+base-paramvalue-prop-comment": "由用户对修订做出的摘要。",
+ "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": "修订内容的XML解析树(需要内容模型<code>$1</code>)。",
"apihelp-query+revisions+base-param-limit": "限制返回多少修订。",
- "apihelp-query+search-param-search": "搜索所有拥有此值的页面标题(或内容)。",
+ "apihelp-query+revisions+base-param-expandtemplates": "展开修订内容中的模板(需要$1prop=content)。",
+ "apihelp-query+revisions+base-param-generatexml": "生成用于修订内容的XML解析树(需要$1prop=content;被<kbd>$1prop=parsetree</kbd>所取代)。",
+ "apihelp-query+revisions+base-param-parse": "解析修订内容(需要$1prop=content)。由于性能原因,如果此选项被使用,$1limit会被强制为1。",
+ "apihelp-query+revisions+base-param-section": "只检索此段落数的内容。",
+ "apihelp-query+revisions+base-param-diffto": "要比较修订差异的修订ID。使用<kbd>prev</kbd>、<kbd>next</kbd>和<kbd>cur</kbd>分别用于上个、下个和当前修订。",
+ "apihelp-query+revisions+base-param-difftotext": "要比较修订差异的文本。只有修订的有限数字内的差异。覆盖<var>$1diffto</var>。如果<var>$1section</var>被设置,只有那个段落将与此文本之间比较差异",
+ "apihelp-query+revisions+base-param-contentformat": "序列化用于<var>$1difftotext</var>的格式并预估内容输出。",
+ "apihelp-query+search-description": "执行一次全文本搜索。",
+ "apihelp-query+search-param-search": "搜索所有匹配此值的页面标题或内容。根据wiki的搜索后端工具,您可以使用搜索字符串以调用特殊搜索功能。",
"apihelp-query+search-param-namespace": "只在这些名字空间搜索。",
+ "apihelp-query+search-param-what": "要执行的搜索类型。",
"apihelp-query+search-param-info": "要返回的元数据。",
+ "apihelp-query+search-param-prop": "要返回的属性:",
+ "apihelp-query+search-paramvalue-prop-size": "Adds the size of the page in bytes.",
+ "apihelp-query+search-paramvalue-prop-wordcount": "Adds the word count of the page.",
+ "apihelp-query+search-paramvalue-prop-timestamp": "Adds the timestamp of when the page was last edited.",
+ "apihelp-query+search-paramvalue-prop-snippet": "Adds a parsed snippet of the page.",
+ "apihelp-query+search-paramvalue-prop-titlesnippet": "Adds a parsed snippet of the page title.",
+ "apihelp-query+search-paramvalue-prop-redirectsnippet": "Adds a parsed snippet of the redirect title.",
+ "apihelp-query+search-paramvalue-prop-redirecttitle": "Adds the title of the matching redirect.",
+ "apihelp-query+search-paramvalue-prop-sectionsnippet": "Adds a parsed snippet of the matching section title.",
+ "apihelp-query+search-paramvalue-prop-sectiontitle": "Adds the title of the matching section.",
+ "apihelp-query+search-paramvalue-prop-categorysnippet": "Adds a parsed snippet of the matching category.",
+ "apihelp-query+search-paramvalue-prop-isfilematch": "Adds a boolean indicating if the search matched file content.",
+ "apihelp-query+search-paramvalue-prop-score": "<span class=\"apihelp-deprecated\">Deprecated and ignored.</span>",
+ "apihelp-query+search-paramvalue-prop-hasrelated": "<span class=\"apihelp-deprecated\">Deprecated and ignored.</span>",
"apihelp-query+search-param-limit": "返回的总计页面数。",
"apihelp-query+search-param-interwiki": "搜索结果中包含跨wiki结果,如果可用。",
"apihelp-query+search-example-simple": "搜索<kbd>meaning</kbd>。",
"apihelp-query+search-example-text": "搜索文本<kbd>meaning</kbd>。",
"apihelp-query+search-example-generator": "获得有关搜索<kbd>meaning</kbd>返回页面的页面信息。",
+ "apihelp-query+siteinfo-description": "返回有关网站的一般信息。",
+ "apihelp-query+siteinfo-param-prop": "要获取的信息:",
+ "apihelp-query+siteinfo-paramvalue-prop-general": "全部系统信息。",
+ "apihelp-query+siteinfo-paramvalue-prop-namespaces": "注册的名字空间及其规范名称列表。",
+ "apihelp-query+siteinfo-paramvalue-prop-namespacealiases": "注册的名字空间别名列表。",
+ "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "特殊页面别名列表。",
+ "apihelp-query+siteinfo-paramvalue-prop-magicwords": "魔术字及其别名列表。",
+ "apihelp-query+siteinfo-paramvalue-prop-statistics": "返回网站统计。",
+ "apihelp-query+siteinfo-paramvalue-prop-interwikimap": "返回跨wiki映射(可选过滤,可选择使用<var>$1inlanguagecode</var>本地化)。",
+ "apihelp-query+siteinfo-paramvalue-prop-dbrepllag": "返回数据库服务器与最高反应延迟。",
+ "apihelp-query+siteinfo-paramvalue-prop-usergroups": "返回用户组及其相关权限。",
+ "apihelp-query+siteinfo-paramvalue-prop-libraries": "返回wiki上安装的库。",
+ "apihelp-query+siteinfo-paramvalue-prop-extensions": "返回wiki上安装的扩展。",
+ "apihelp-query+siteinfo-paramvalue-prop-fileextensions": "返回允许上传的文件扩展名列表。",
+ "apihelp-query+siteinfo-paramvalue-prop-rightsinfo": "如果可用,返回wiki的版权信息。",
+ "apihelp-query+siteinfo-paramvalue-prop-restrictions": "返回可用的编辑限制(保护)类型信息。",
+ "apihelp-query+siteinfo-paramvalue-prop-languages": "返回MediaWiki支持的语言列表(可选择使用<var>$1inlanguagecode</var>本地化)。",
+ "apihelp-query+siteinfo-paramvalue-prop-skins": "返回所有启用的皮肤列表(可选择使用<var>$1inlanguagecode</var>本地化,否则是内容语言)。",
+ "apihelp-query+siteinfo-paramvalue-prop-extensiontags": "返回解析器扩展标签列表。",
+ "apihelp-query+siteinfo-paramvalue-prop-functionhooks": "返回解析器函数钩列表。",
+ "apihelp-query+siteinfo-paramvalue-prop-showhooks": "返回所有订阅的钩列表(<var>[[mw:Manual:$wgHooks|$wgHooks]]</var>的内容)。",
+ "apihelp-query+siteinfo-paramvalue-prop-variables": "返回变量ID列表。",
+ "apihelp-query+siteinfo-paramvalue-prop-protocols": "返回外部链接中允许的协议列表。",
+ "apihelp-query+siteinfo-paramvalue-prop-defaultoptions": "返回用户设置的默认值。",
+ "apihelp-query+siteinfo-param-filteriw": "只返回跨wiki地图中的本地或非本地记录。",
+ "apihelp-query+siteinfo-param-showalldb": "列出所有数据库服务器,不只是最落后的那个。",
"apihelp-query+siteinfo-param-numberingroup": "列出用户组中的用户数。",
- "apihelp-query+siteinfo-example-simple": "获取网站信息",
- "apihelp-query+siteinfo-example-interwiki": "获取本地跨wiki前缀列表",
+ "apihelp-query+siteinfo-param-inlanguagecode": "用于本地化语言名称(尽可能)和皮肤名称的语言代码。",
+ "apihelp-query+siteinfo-example-simple": "取得网站信息。",
+ "apihelp-query+siteinfo-example-interwiki": "取得本地跨wiki前缀列表。",
"apihelp-query+siteinfo-example-replag": "检查当前的响应延迟。",
+ "apihelp-query+stashimageinfo-description": "返回用于藏匿文件的文件信息。",
+ "apihelp-query+stashimageinfo-param-sessionkey": "$1filekey的别名,用于向后兼容。",
"apihelp-query+stashimageinfo-example-simple": "返回藏匿文件的信息。",
"apihelp-query+tags-description": "列出更改标签。",
"apihelp-query+tags-param-limit": "列出标签的最大数量。",
- "apihelp-query+tags-param-prop": "要获取哪个属性:\n;name:添加标签名称。\n;displayname:为标签添加系统消息。\n;description:为标签添加描述。\n;hitcount:已添加此标签的修订版本与日志数量。\n;defined:标识标签是否已定义。\n;source:获得标签来源,它可能包括用于扩展定义的标签的<samp>extension</samp>,以及用于可被用户手动应用的标签的<samp>manual</samp>。\n;active:标签是否仍可被应用。",
- "apihelp-query+tags-example-simple": "可用标签列表",
+ "apihelp-query+tags-param-prop": "要获取哪个属性:",
+ "apihelp-query+tags-paramvalue-prop-name": "添加标签名称。",
+ "apihelp-query+tags-paramvalue-prop-displayname": "为标签添加系统消息。",
+ "apihelp-query+tags-paramvalue-prop-description": "为标签添加描述。",
+ "apihelp-query+tags-paramvalue-prop-hitcount": "已添加此标签的修订版本与日志数量。",
+ "apihelp-query+tags-paramvalue-prop-defined": "标识标签是否已定义。",
+ "apihelp-query+tags-paramvalue-prop-source": "获得标签来源,它可能包括用于扩展定义的标签的<samp>extension</samp>,以及用于可被用户手动应用的标签的<samp>manual</samp>。",
+ "apihelp-query+tags-paramvalue-prop-active": "标签是否仍可被应用。",
+ "apihelp-query+tags-example-simple": "可用标签列表。",
+ "apihelp-query+templates-description": "返回指定页面上所有被嵌入的页面。",
"apihelp-query+templates-param-namespace": "只显示此名字空间的模板。",
- "apihelp-query+templates-param-limit": "返回多少模板。",
+ "apihelp-query+templates-param-limit": "返回的模板数量。",
"apihelp-query+templates-param-templates": "只列出这些模板。对于检查某一页面使用某一模板很有用。",
"apihelp-query+templates-param-dir": "罗列所采用的方向。",
- "apihelp-query+templates-example-simple": "获得在页面<kbd>Main Page</kbd>使用的模板。",
- "apihelp-query+templates-example-generator": "获得有关<kbd>Main Page</kbd>中使用的模板页面的信息。",
- "apihelp-query+templates-example-namespaces": "获得在{{ns:user}}和{{ns:template}}名字空间中,嵌入在<kbd>Main Page</kbd>页面的页面。",
+ "apihelp-query+templates-example-simple": "获取在页面<kbd>Main Page</kbd>使用的模板。",
+ "apihelp-query+templates-example-generator": "获取有关<kbd>Main Page</kbd>中使用的模板页面的信息。",
+ "apihelp-query+templates-example-namespaces": "获取在{{ns:user}}和{{ns:template}}名字空间中,嵌入在<kbd>Main Page</kbd>页面的页面。",
+ "apihelp-query+tokens-description": "获取可修改数据的操作的令牌。",
"apihelp-query+tokens-param-type": "要请求的令牌类型。",
+ "apihelp-query+tokens-example-simple": "检索一个csrf令牌(默认)。",
+ "apihelp-query+tokens-example-types": "检索一个监视令牌和一个巡查令牌。",
+ "apihelp-query+transcludedin-param-prop": "要获取的属性:",
+ "apihelp-query+transcludedin-paramvalue-prop-pageid": "每个页面的页面ID。",
+ "apihelp-query+transcludedin-paramvalue-prop-title": "每个页面的标题。",
+ "apihelp-query+transcludedin-paramvalue-prop-redirect": "标记作为重定向的页面。",
"apihelp-query+transcludedin-param-namespace": "至包含这些名字空间的页面。",
"apihelp-query+transcludedin-param-limit": "返回多少。",
- "apihelp-query+transcludedin-example-simple": "获得嵌入<kbd>Main Page</kbd>的页面列表。",
- "apihelp-query+transcludedin-example-generator": "获得有关嵌入<kbd>Main Page</kbd>的页面的信息。",
+ "apihelp-query+transcludedin-param-show": "只显示符合以下标准的项:\n;redirect:只显示重定向。\n;!redirect:只显示非重定向。",
+ "apihelp-query+transcludedin-example-simple": "获取嵌入<kbd>Main Page</kbd>的页面列表。",
+ "apihelp-query+transcludedin-example-generator": "获取有关嵌入<kbd>Main Page</kbd>的页面的信息。",
"apihelp-query+usercontribs-description": "获取一位用户的所有编辑。",
"apihelp-query+usercontribs-param-limit": "返回贡献的最大数量。",
"apihelp-query+usercontribs-param-start": "返回的起始时间戳。",
"apihelp-query+usercontribs-param-end": "返回的最终时间戳。",
+ "apihelp-query+usercontribs-param-user": "要检索贡献的用户。",
"apihelp-query+usercontribs-param-namespace": "只列出这些名字空间的贡献。",
+ "apihelp-query+usercontribs-param-prop": "包含额外的信息束:",
+ "apihelp-query+usercontribs-paramvalue-prop-ids": "添加页面ID和修订ID。",
+ "apihelp-query+usercontribs-paramvalue-prop-title": "添加页面标题及其名字空间ID。",
+ "apihelp-query+usercontribs-paramvalue-prop-timestamp": "添加编辑的时间戳。",
+ "apihelp-query+usercontribs-paramvalue-prop-comment": "添加编辑摘要。",
+ "apihelp-query+usercontribs-paramvalue-prop-parsedcomment": "添加被解析的编辑摘要。",
+ "apihelp-query+usercontribs-paramvalue-prop-size": "添加编辑的新大小。",
+ "apihelp-query+usercontribs-paramvalue-prop-sizediff": "添加与父编辑相比该编辑的大小变化。",
+ "apihelp-query+usercontribs-paramvalue-prop-flags": "添加编辑标记。",
+ "apihelp-query+usercontribs-paramvalue-prop-patrolled": "标记已巡查编辑。",
+ "apihelp-query+usercontribs-paramvalue-prop-tags": "列举用于编辑的标签。",
+ "apihelp-query+usercontribs-param-show": "只显示符合这些标准的项目,例如只显示不是小编辑的编辑:<kbd>$2show=!minor</kbd>。\n\n如果<kbd>$2show=patrolled</kbd>或<kbd>$2show=!patrolled</kbd>被设定,早于<var>[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var>($1秒)的修订不会被显示。",
"apihelp-query+usercontribs-example-user": "显示用户<kbd>Example</kbd>的贡献。",
"apihelp-query+usercontribs-example-ipprefix": "显示来自<kbd>192.0.2.</kbd>前缀所有 IP 地址的贡献。",
"apihelp-query+userinfo-description": "获取有关当前用户的信息。",
- "apihelp-query+userinfo-example-simple": "获取有关当前用户的信息",
- "apihelp-query+userinfo-example-data": "获取有关当前用户的额外信息",
+ "apihelp-query+userinfo-param-prop": "要包含的信息束:",
+ "apihelp-query+userinfo-paramvalue-prop-blockinfo": "如果当前用户被封禁就标记,并注明是谁封禁,以何种原因封禁的。",
+ "apihelp-query+userinfo-paramvalue-prop-hasmsg": "如果当前用户有等待中的消息的话,添加标签<samp>messages</samp>。",
+ "apihelp-query+userinfo-paramvalue-prop-groups": "Lists all the groups the current user belongs to.",
+ "apihelp-query+userinfo-paramvalue-prop-implicitgroups": "Lists all the groups the current user is automatically a member of.",
+ "apihelp-query+userinfo-paramvalue-prop-rights": "Lists all the rights the current user has.",
+ "apihelp-query+userinfo-paramvalue-prop-changeablegroups": "Lists the groups the current user can add to and remove from.",
+ "apihelp-query+userinfo-paramvalue-prop-options": "Lists all preferences the current user has set.",
+ "apihelp-query+userinfo-paramvalue-prop-preferencestoken": "<span class=\"apihelp-deprecated\">Deprecated.</span> Get a token to change current user's preferences.",
+ "apihelp-query+userinfo-paramvalue-prop-editcount": "Adds the current user's edit count.",
+ "apihelp-query+userinfo-paramvalue-prop-ratelimits": "Lists all rate limits applying to the current user.",
+ "apihelp-query+userinfo-paramvalue-prop-realname": "添加用户的真实姓名。",
+ "apihelp-query+userinfo-paramvalue-prop-email": "Adds the user's email address and email authentication date.",
+ "apihelp-query+userinfo-paramvalue-prop-acceptlang": "Echoes the <code>Accept-Language</code> header sent by the client in a structured format.",
+ "apihelp-query+userinfo-paramvalue-prop-registrationdate": "添加用户的注册时间。",
+ "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Adds the count of unread pages on the user's watchlist (maximum $1; returns <samp>$2</samp> if more).",
+ "apihelp-query+userinfo-example-simple": "获取有关当前用户的信息。",
+ "apihelp-query+userinfo-example-data": "获取有关当前用户的额外信息。",
"apihelp-query+users-description": "获取有关列出用户的信息。",
+ "apihelp-query+users-param-prop": "要包含的信息束:",
+ "apihelp-query+users-paramvalue-prop-blockinfo": "如果用户被封禁就标记,并注明是谁封禁,以何种原因封禁的。",
+ "apihelp-query+users-paramvalue-prop-groups": "列举每位用户属于的所有组。",
+ "apihelp-query+users-paramvalue-prop-implicitgroups": "Lists all the groups a user is automatically a member of.",
+ "apihelp-query+users-paramvalue-prop-rights": "Lists all the rights each user has.",
+ "apihelp-query+users-paramvalue-prop-editcount": "Adds the user's edit count.",
+ "apihelp-query+users-paramvalue-prop-registration": "Adds the user's registration timestamp.",
+ "apihelp-query+users-paramvalue-prop-emailable": "Tags if the user can and wants to receive email through [[Special:Emailuser]].",
+ "apihelp-query+users-paramvalue-prop-gender": "Tags the gender of the user. Returns \"male\", \"female\", or \"unknown\".",
"apihelp-query+users-param-token": "请改用<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>。",
"apihelp-query+users-example-simple": "返回用户<kbd>Example</kbd>的信息。",
+ "apihelp-query+watchlist-description": "在当前用户的监视列表中获取对页面的最近更改。",
"apihelp-query+watchlist-param-start": "枚举的起始时间戳。",
"apihelp-query+watchlist-param-end": "枚举的结束时间戳。",
"apihelp-query+watchlist-param-user": "只列出此用户的更改。",
"apihelp-query+watchlist-param-excludeuser": "不要列出此用户的更改。",
"apihelp-query+watchlist-param-limit": "根据结果返回的结果总数。",
+ "apihelp-query+watchlist-param-prop": "要获取的额外属性:",
+ "apihelp-query+watchlist-paramvalue-prop-ids": "添加修订ID和页面ID。",
+ "apihelp-query+watchlist-paramvalue-prop-title": "添加页面标题。",
+ "apihelp-query+watchlist-paramvalue-prop-flags": "为编辑添加标记。",
+ "apihelp-query+watchlist-paramvalue-prop-user": "添加做出编辑的用户。",
+ "apihelp-query+watchlist-paramvalue-prop-userid": "添加做出编辑的用户的ID。",
+ "apihelp-query+watchlist-paramvalue-prop-comment": "添加编辑摘要。",
+ "apihelp-query+watchlist-paramvalue-prop-parsedcomment": "添加解析过的编辑摘要。",
+ "apihelp-query+watchlist-paramvalue-prop-timestamp": "添加编辑时间戳。",
+ "apihelp-query+watchlist-paramvalue-prop-patrol": "将编辑标记为已巡查。",
+ "apihelp-query+watchlist-paramvalue-prop-sizes": "添加页面的旧有长度和新长度。",
+ "apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "添加最近被通知有关编辑的用户的时间戳。",
+ "apihelp-query+watchlist-paramvalue-prop-loginfo": "在适当位置添加日志信息。",
+ "apihelp-query+watchlist-param-type": "要显示的更改类型:\n;edit:定期页面编辑。\n;external:外部更改。\n;new:页面创建。\n;log:日志记录。",
"apihelp-query+watchlist-param-token": "允许访问其他用户监视列表的安全密钥(可通过用户的[[Special:Preferences#mw-prefsection-watchlist|参数设置]]找到)。",
+ "apihelp-query+watchlist-example-simple": "在当前用户的监视列表中列出用于最近更改页面的最新修订。",
+ "apihelp-query+watchlist-example-props": "在当前用户的监视列表中检索有关用于最近更改页面的最新修订的额外信息。",
+ "apihelp-query+watchlist-example-allrev": "在当前用户的监视列表中检索有关所有最近对页面的更改的信息。",
"apihelp-query+watchlist-example-generator": "在当前用户的监视列表中检索用于最近更改页面的页面信息。",
+ "apihelp-query+watchlist-example-generator-rev": "在当前用户的监视列表中检索用于对页面最近更改的修订信息。",
+ "apihelp-query+watchlist-example-wlowner": "在用户<kbd>Example</kbd>的监视列表中列出用于最近更改页面的最新修订。",
"apihelp-query+watchlistraw-description": "获得当前用户的监视列表上的所有页面。",
"apihelp-query+watchlistraw-param-namespace": "只列出指定名字空间的页面。",
"apihelp-query+watchlistraw-param-limit": "根据结果返回的结果总数。",
+ "apihelp-query+watchlistraw-param-prop": "要获取的额外属性:",
+ "apihelp-query+watchlistraw-paramvalue-prop-changed": "添加最近被通知有关编辑的用户的时间戳。",
"apihelp-query+watchlistraw-param-token": "允许访问其他用户监视列表的安全密钥(可通过用户的[[Special:Preferences#mw-prefsection-watchlist|参数设置]]找到)。",
+ "apihelp-query+watchlistraw-param-fromtitle": "要列举的起始标题(带名字空间前缀)。",
+ "apihelp-query+watchlistraw-param-totitle": "要列举的最终标题(带名字空间前缀)。",
"apihelp-query+watchlistraw-example-simple": "列出当前用户的监视列表中的页面。",
"apihelp-revisiondelete-description": "删除和恢复修订版本。",
+ "apihelp-revisiondelete-param-ids": "用于将被删除的修订的标识符。",
"apihelp-revisiondelete-param-hide": "每次修订要隐藏的东西。",
"apihelp-revisiondelete-param-show": "每次修订要恢复显示的东西。",
"apihelp-revisiondelete-param-reason": "删除或恢复的原因。",
"apihelp-revisiondelete-example-revision": "隐藏<kbd>首页</kbd>的修订版本<kbd>12345</kbd>的内容。",
+ "apihelp-revisiondelete-example-log": "隐藏日志记录<kbd>67890</kbd>上的所有数据,原因<kbd>BLP violation</kbd>。",
+ "apihelp-rollback-description": "撤销对页面的最近编辑。\n\n如果最近编辑页面的用户在一行中进行多次编辑,所有编辑将被回退。",
"apihelp-rollback-param-title": "要回退的页面标题。不能与<var>$1pageid</var>一起使用。",
"apihelp-rollback-param-pageid": "要回退的页面的页面 ID。不能与<var>$1title</var>一起使用。",
"apihelp-rollback-param-watchlist": "无条件地将页面加入至当前用户的监视列表或将其移除,使用设置或不更改监视。",
"apihelp-rollback-example-simple": "回退由用户<kbd>Example</kbd>对<kbd>Main Page</kbd>做出的最近编辑。",
"apihelp-rollback-example-summary": "回退由IP用户<kbd>192.0.2.5</kbd>对页面<kbd>Main Page</kbd>做出的最近编辑,带编辑摘要<kbd>Reverting vandalism</kbd>,并将这些编辑和回退标记为机器人编辑。",
- "apihelp-rsd-description": "导出一个RSD(Really Simple Discovery)架构",
- "apihelp-rsd-example-simple": "导出RSD架构",
+ "apihelp-rsd-description": "导出一个RSD(Really Simple Discovery)架构。",
+ "apihelp-rsd-example-simple": "导出RSD架构。",
+ "apihelp-setnotificationtimestamp-description": "更新用于监视页面的通知时间戳。\n\n这会影响监视列表和历史中已更改页面的高亮度,并且如果“{{int:tog-enotifwatchlistpages}}”设置被启用的话,也会影响电子邮件的发送。",
"apihelp-setnotificationtimestamp-param-entirewatchlist": "工作于所有已监视页面。",
+ "apihelp-setnotificationtimestamp-param-timestamp": "要设置通知时间戳的时间戳。",
+ "apihelp-setnotificationtimestamp-param-torevid": "要设置通知时间戳的修订(只限一个页面)。",
+ "apihelp-setnotificationtimestamp-param-newerthanrevid": "要设置通知时间戳的较新修订(只限一个页面)。",
"apihelp-setnotificationtimestamp-example-all": "重置整个监视列表的通知状态。",
+ "apihelp-setnotificationtimestamp-example-page": "重置用于<kbd>Main page</kbd>的通知状态。",
"apihelp-setnotificationtimestamp-example-pagetimestamp": "设置<kbd>Main page</kbd>的通知时间戳,这样所有从2012年1月1日起的编辑都会是未复核的。",
"apihelp-setnotificationtimestamp-example-allpages": "重置在<kbd>{{ns:user}}</kbd>名字空间中的页面的通知状态。",
+ "apihelp-tag-description": "从个别修订或日志记录中添加或移除更改标签。",
+ "apihelp-tag-param-rcid": "要添加或移除标签的一个或更多的最近更改ID。",
+ "apihelp-tag-param-revid": "要添加或移除标签的一个或更多的修订ID。",
+ "apihelp-tag-param-logid": "要添加或移除标签的一个或更多的日志记录ID。",
+ "apihelp-tag-param-add": "要添加的标签。只有手动定义的标签可以添加。",
+ "apihelp-tag-param-remove": "要移除的标签。只有手动定义或完全不明确的标签可以被移除。",
+ "apihelp-tag-param-reason": "更改原因。",
+ "apihelp-tag-example-rev": "将<kbd>vandalism</kbd>标签添加至修订ID 123,而不指定原因",
+ "apihelp-tag-example-log": "从日志记录ID 123移除<kbd>spam</kbd>标签,原因为<kbd>Wrongly applied</kbd>",
+ "apihelp-tokens-description": "获取可修改数据的操作的令牌。\n\n此模块被弃用以有利于[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]。",
"apihelp-tokens-param-type": "要请求的令牌类型。",
+ "apihelp-tokens-example-edit": "检索一个编辑令牌(默认)。",
+ "apihelp-tokens-example-emailmove": "检索一个电子邮件令牌和一个移动令牌。",
"apihelp-unblock-description": "解封一位用户。",
"apihelp-unblock-param-id": "解封时需要的封禁ID(通过<kbd>list=blocks</kbd>获得)。不能与<var>$1user</var>一起使用。",
"apihelp-unblock-param-user": "要解封的用户名、IP地址或IP段。不能与<var>$1id</var>一起使用。",
"apihelp-unblock-param-reason": "解封的原因。",
"apihelp-unblock-example-id": "解封封禁ID #<kbd>105</kbd>。",
"apihelp-unblock-example-user": "解封用户<kbd>Bob</kbd>,原因<kbd>Sorry Bob</kbd>。",
+ "apihelp-undelete-description": "恢复一个被删除页面的修订。\n\n被删除修订的列表(包括时间戳)可通过[[Special:ApiHelp/query+deletedrevs|list=deletedrevs]]检索到,并且被删除的文件ID列表可通过[[Special:ApiHelp/query+filearchive|list=filearchive]]检索到。",
"apihelp-undelete-param-title": "要恢复的页面标题。",
"apihelp-undelete-param-reason": "恢复的原因。",
+ "apihelp-undelete-param-timestamps": "要回复的修订的时间戳。如果<var>$1timestamps</var>和<var>$1fileids</var>都为空,所有将被恢复。",
"apihelp-undelete-param-fileids": "要恢复的文件修订ID。如果<var>$1timestamps</var>和<var>$1fileids</var>都为空,所有将被恢复。",
"apihelp-undelete-example-page": "恢复页面<kbd>Main Page</kbd>。",
- "apihelp-undelete-example-revisions": "恢复<kbd>首页</kbd>的两个修订。",
+ "apihelp-undelete-example-revisions": "恢复<kbd>Main Page</kbd>的两个修订。",
+ "apihelp-upload-description": "上传一个文件,或获取正在等待中的上传的状态。\n\n可以使用的几种方法:\n* 直接上传文件内容,使用<var>$1file</var>参数。\n* 成批上传文件,使用<var>$1filesize</var>、<var>$1chunk</var>和<var>$1offset</var>参数。\n* 有MediaWiki服务器从URL检索一个文件,使用<var>$1url</var>参数。\n* Complete an earlier upload that failed due to warnings, using the <var>$1filekey</var> parameter.\nNote that the HTTP POST must be done as a file upload (i.e. using <code>multipart/form-data</code>) when sending the <var>$1file</var>.",
"apihelp-upload-param-filename": "目标文件名。",
"apihelp-upload-param-comment": "上传注释。如果没有指定<var>$1text</var>,那么它也被用于新文件的初始页面文本。",
"apihelp-upload-param-watch": "监视页面。",
"apihelp-upload-param-watchlist": "无条件地将页面加入至当前用户的监视列表或将其移除,使用设置或不更改监视。",
"apihelp-upload-param-ignorewarnings": "忽略任何警告。",
"apihelp-upload-param-file": "文件内容。",
+ "apihelp-upload-param-url": "要检索文件来源的URL。",
"apihelp-upload-param-stash": "如果设置,服务器将临时藏匿文件而不是加入存储库。",
+ "apihelp-upload-param-filesize": "全部上传的文件大小。",
"apihelp-upload-param-offset": "块的偏移量(字节)。",
"apihelp-upload-param-chunk": "大块内容。",
- "apihelp-upload-example-url": "从URL上传",
+ "apihelp-upload-param-leavemessage": "如果asyncdownload被使用,当完成时,在用户讨论页留下一条消息。",
+ "apihelp-upload-example-url": "从URL上传。",
"apihelp-upload-example-filekey": "完成一次由于警告而失败的上传。",
"apihelp-userrights-description": "更改一位用户的组成员。",
"apihelp-userrights-param-user": "用户名。",
@@ -716,35 +1157,46 @@
"apihelp-userrights-param-reason": "更改原因。",
"apihelp-userrights-example-user": "将用户<kbd>FooBot</kbd>添加至<kbd>bot</kbd>用户组,并从<kbd>sysop</kbd>和<kbd>bureaucrat</kbd>组移除。",
"apihelp-userrights-example-userid": "将ID为<kbd>123</kbd>的用户加入至<kbd>机器人</kbd>组,并将其从<kbd>管理员</kbd>和<kbd>行政员</kbd>组移除。",
+ "apihelp-watch-description": "从当前用户的监视列表中添加或移除页面。",
"apihelp-watch-param-title": "要(取消)监视的页面。也可使用<var>$1titles</var>。",
+ "apihelp-watch-param-unwatch": "如果设置页面将被取消监视而不是被监视。",
"apihelp-watch-example-watch": "监视页面<kbd>Main Page</kbd>。",
- "apihelp-watch-example-unwatch": "取消监视页面<kbd>首页</kbd>。",
- "apihelp-format-example-generic": "格式化查询结果为$1格式。",
+ "apihelp-watch-example-unwatch": "取消监视页面<kbd>Main Page</kbd>。",
+ "apihelp-watch-example-generator": "监视主名字空间中的最少几个页面。",
+ "apihelp-format-example-generic": "返回查询结果为$1格式。",
"apihelp-dbg-description": "输出数据为PHP的<code>var_export()</code>格式。",
"apihelp-dbgfm-description": "输出数据为PHP的<code>var_export()</code>格式(HTML优质打印效果)。",
- "apihelp-dump-description": "输出数据为PHP的<code>var_dump()</code>格式。",
- "apihelp-dumpfm-description": "输出数据为PHP的<code>var_dump()</code>格式(HTML优质打印效果)。",
"apihelp-json-description": "输出数据为JSON格式。",
+ "apihelp-json-param-callback": "如果指定,将输出内容包裹在一个指定的函数调用中。出于安全考虑,所有用户相关的数据将被限制。",
+ "apihelp-json-param-utf8": "如果指定,使用十六进制转义序列将大多数(但不是全部)非ASCII的字符编码为UTF-8,而不是替换它们。默认当<var>formatversion</var>不是<kbd>1</kbd>时。",
+ "apihelp-json-param-ascii": "如果指定,使用十六进制转义序列将所有非ASCII编码。默认当<var>formatversion</var>为<kbd>1</kbd>时。",
+ "apihelp-json-param-formatversion": "输出格式:\n;1:向后兼容格式(XML样式布尔值、用于内容节点的<samp>*</samp>键等)。\n;2:实验现代格式。细节可以更改!\n;latest:使用最新格式(当前为<kbd>2</kbd>),可以在没有警告的情况下更改。",
"apihelp-jsonfm-description": "输出数据为JSON格式(HTML优质打印效果)。",
"apihelp-none-description": "不输出任何东西。",
"apihelp-php-description": "输出数据为序列化PHP格式。",
+ "apihelp-php-param-formatversion": "输出格式:\n;1:向后兼容格式(XML样式布尔值、用于内容节点的<samp>*</samp>键等)。\n;2:实验现代格式。细节可以更改!\n;latest:使用最新格式(当前为<kbd>2</kbd>),可以在没有警告的情况下更改。",
"apihelp-phpfm-description": "输出数据为序列化PHP格式(HTML优质打印效果)。",
"apihelp-rawfm-description": "输出数据为JSON格式,带调试元素(HTML优质打印效果)。",
"apihelp-txt-description": "输出数据为PHP的<code>print_r()</code>格式。",
"apihelp-txtfm-description": "输出数据为PHP的<code>print_r()</code>格式(HTML优质打印效果)。",
- "apihelp-wddx-description": "输出数据为WDDX格式。",
- "apihelp-wddxfm-description": "输出数据为WDDX格式(HTML优质打印效果)。",
"apihelp-xml-description": "输出数据为XML格式。",
"apihelp-xml-param-xslt": "如果指定,加入已命名的页面作为一个XSL样式表。值必须是在{{ns:mediawiki}}名字空间以<code>.xsl</code>为结尾的标题。",
+ "apihelp-xml-param-includexmlnamespace": "如果指定,添加一个XML名字空间。",
"apihelp-xmlfm-description": "输出数据为XML格式(HTML优质打印效果)。",
"apihelp-yaml-description": "输出数据为YAML格式。",
"apihelp-yamlfm-description": "输出数据为YAML格式(HTML优质打印效果)。",
"api-format-title": "MediaWiki API 结果",
"api-format-prettyprint-header": "这是$1格式的HTML表示。HTML对调试很有用,但不适合应用程序使用。\n\n指定<var>format</var>参数以更改输出格式。要查看$1格式的非HTML表示,设置<kbd>format=$2</kbd>。\n\n参见[[mw:API|完整文档]],或[[Special:ApiHelp/main|API 帮助]]以获取更多信息。",
+ "api-format-prettyprint-header-only-html": "这是用来调试的HTML表现,不适合实际使用。\n\n参见[[mw:API|完整文档]],或[[Special:ApiHelp/main|API帮助]]以获取更多信息。",
"api-orm-param-props": "要查询的字段。",
"api-orm-param-limit": "返回的总行数。",
+ "api-pageset-param-titles": "要工作的标题列表。",
+ "api-pageset-param-pageids": "要工作的页面ID列表。",
+ "api-pageset-param-revids": "要工作的修订ID列表。",
"api-pageset-param-generator": "通过执行指定查询模块获得页面列表以工作。\n\n<strong>注意:</strong>发生器参数名称必须以“g”开头,参见例子。",
+ "api-pageset-param-redirects-generator": "自动解决在<var>$1titles</var>、<var>$1pageids</var>和<var>$1revids</var>,以及在由<var>$1generator</var>返回的页面中的重定向。",
"api-pageset-param-redirects-nogenerator": "自动解决<var>$1titles</var>、<var>$1pageids</var>和<var>$1revids</var>中的重定向。",
+ "api-pageset-param-converttitles": "如有需要,将标题转换为其他变体。只有当wiki的内容语言支持变体转换时才能工作。支持变体转换的语言包括$1。",
"api-help-title": "MediaWiki API 帮助",
"api-help-lead": "这是自动生成的MediaWiki API文档页面。\n\n文档和例子:https://www.mediawiki.org/wiki/API:Main_page/zh",
"api-help-main-header": "主模块",
@@ -754,21 +1206,35 @@
"api-help-flag-writerights": "此模块需要写入权限。",
"api-help-flag-mustbeposted": "此模块只允许POST请求。",
"api-help-flag-generator": "此模块可作为发生器使用。",
+ "api-help-source": "来源:$1",
+ "api-help-source-unknown": "来源:<span class=\"apihelp-unknown\">未知</span>",
+ "api-help-license": "许可协议:[[$1|$2]]",
+ "api-help-license-noname": "许可协议:[[$1|参见链接]]",
+ "api-help-license-unknown": "许可协议:<span class=\"apihelp-unknown\">未知</span>",
"api-help-parameters": "{{PLURAL:$1|参数}}:",
"api-help-param-deprecated": "不推荐使用。",
"api-help-param-required": "这个参数是必须的。",
- "api-help-param-list": "{{PLURAL:$1|1=一个值|2=值(以<kbd>{{!}}</kbd>分隔)}}:$2",
+ "api-help-datatypes-header": "数据类型",
+ "api-help-datatypes": "一些在API请求中的参数类型需要更进一步解释:\n;boolean\n:布尔参数就像HTML复选框一样工作:如果指定参数,无论何值都被认为是真。如果要假值,则可完全忽略参数。\n;timestamp\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:* C ctime格式,<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>",
+ "api-help-param-type-limit": "类型:整数或<kbd>max</kbd>",
+ "api-help-param-type-integer": "类型:{{PLURAL:$1|1=整数|2=整数列表}}",
+ "api-help-param-type-boolean": "类型:布尔值([[Special:ApiHelp/main#main/datatypes|详细信息]])",
+ "api-help-param-type-timestamp": "类型:{{PLURAL:$1|1=时间戳|2=时间戳列表}}([[Special:ApiHelp/main#main/datatypes|允许格式]])",
+ "api-help-param-type-user": "类型:{{PLURAL:$1|1=用户名|2=用户名列表}}",
+ "api-help-param-list": "{{PLURAL:$1|1=以下值中的一个|2=值(以<kbd>{{!}}</kbd>分隔)}}:$2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=必须为空|可以为空,或$2}}",
"api-help-param-limit": "不允许超过$1。",
"api-help-param-limit2": "不允许超过$1个(对于机器人则是$2个)。",
"api-help-param-integer-min": "{{PLURAL:$1|值}}必须不少于$2。",
"api-help-param-integer-max": "{{PLURAL:$1|值}}必须不大于$3。",
"api-help-param-integer-minmax": "{{PLURAL:$1|值}}必须介于$2和$3之间。",
+ "api-help-param-upload": "必须被公布为使用multipart/form-data的一次文件上传。",
"api-help-param-multi-separate": "通过“<kbd>|</kbd>”隔开各值。",
"api-help-param-multi-max": "值的最高数字是{{PLURAL:$1|$1}}(对于机器人则是{{PLURAL:$2|$2}})。",
"api-help-param-default": "默认:$1",
"api-help-param-default-empty": "默认:<span class=\"apihelp-empty\">(空)</span>",
"api-help-param-token": "从[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]取回的“$1”令牌",
+ "api-help-param-token-webui": "出于兼容性考虑,web UI中使用的令牌也被接受。",
"api-help-param-disabled-in-miser-mode": "由于[[mw:Manual:$wgMiserMode|miser模式]]而禁用。",
"api-help-param-limited-in-miser-mode": "<strong>注意:</strong>由于[[mw:Manual:$wgMiserMode|miser模式]],使用这个可能导致继续前返回少于<var>$1limit</var>个结果;极端情况下可能不会返回任何结果。",
"api-help-param-direction": "列举的方向:\n;newer:最早的优先。注意:$1start应早于$1end。\n;older:最新的优先(默认)。注意:$1start应晚于$1end。",
@@ -777,6 +1243,7 @@
"api-help-examples": "{{PLURAL:$1|例子}}:",
"api-help-permissions": "{{PLURAL:$1|权限}}:",
"api-help-permissions-granted-to": "{{PLURAL:$1|授予}}:$2",
+ "api-help-right-apihighlimits": "在API查询中使用更高的上限(慢查询:$1;快查询:$2)。慢查询的限制也适用于多值参数。",
"api-credits-header": "制作人员",
"api-credits": "API 开发人员:\n* Roan Kattouw(2007年9月~2009年的开发组领导)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan(创建者,2006年9月~2007年9月的开发组领导)\n* Brad Jorsch(2013年至今的开发组领导)\n\n请将您的评论、建议和问题发送至mediawiki-api@lists.wikimedia.org,或提交错误请求在https://phabricator.wikimedia.org/。"
}
diff --git a/includes/api/i18n/zh-hant.json b/includes/api/i18n/zh-hant.json
index dc3cc2d8..b1e6d953 100644
--- a/includes/api/i18n/zh-hant.json
+++ b/includes/api/i18n/zh-hant.json
@@ -4,7 +4,8 @@
"Cwlin0416",
"Liuxinyu970226",
"LNDDYL",
- "EagerLin"
+ "EagerLin",
+ "Zhxy 519"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|文件]]\n* [[mw:API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 郵件清單]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bug與請求]\n</div>\n<strong>狀態資訊:</strong>本頁所展示的所有功能都應正常工作,但是 API 仍在開發當中,將會隨時變化。請訂閱[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 郵件清單]以便得到更新通知。\n\n<strong>錯誤請求:</strong>當 API 收到錯誤請求時, HTTP header 將會返回一個包含「MediaWiki-API-Error」的值,隨後 header 的值與錯誤碼將會送回並設定為相同的值。詳細資訊請參閱[[mw:API:Errors_and_warnings|API: 錯誤與警告]]。",
@@ -42,7 +43,7 @@
"apihelp-createaccount-param-name": "使用者名稱。",
"apihelp-createaccount-param-password": "密碼 (若有設定 <var>$1mailpassword</var> 則可略過)。",
"apihelp-createaccount-param-domain": "外部認証使用的網域 (選填)。",
- "apihelp-createaccount-param-token": "已取得帳號建立密鑰於第一次請求。",
+ "apihelp-createaccount-param-token": "在第一次請求時已取得的帳號建立金鑰。",
"apihelp-createaccount-param-email": "使用者的電子郵件地址 (選填) 。",
"apihelp-createaccount-param-realname": "使用者的真實姓名 (選填)。",
"apihelp-createaccount-param-mailpassword": "若設為其他值,將會以電子郵件寄送隨機密碼給使用者。",
@@ -86,6 +87,8 @@
"apihelp-expandtemplates-description": "展開所有於 wikitext 中模板。",
"apihelp-expandtemplates-param-title": "頁面標題。",
"apihelp-expandtemplates-param-text": "要轉換的 Wikitext。",
+ "apihelp-feedcontributions-description": "回傳使用者貢獻 Feed。",
+ "apihelp-feedcontributions-param-feedformat": "Feed 的格式。",
"apihelp-feedcontributions-param-showsizediff": "顯示修訂版本之間的差異大小。",
"apihelp-feedcontributions-example-simple": "返回使用者<kbd>Example</kbd>的貢獻。",
"apihelp-feedrecentchanges-description": "返回近期邊更摘要。",
@@ -134,7 +137,23 @@
"apihelp-opensearch-param-limit": "回傳的結果數量上限。",
"apihelp-opensearch-param-namespace": "搜尋的命名空間。",
"apihelp-opensearch-param-format": "輸出的格式。",
+ "apihelp-options-param-reset": "重設偏好設定為網站預設值。",
"apihelp-options-example-reset": "重設所有偏好設定",
+ "apihelp-parse-example-page": "解析一個頁面。",
+ "apihelp-parse-example-text": "解析 wikitext。",
+ "apihelp-parse-example-texttitle": "解析 wikitext,指定頁面標題。",
+ "apihelp-parse-example-summary": "解析一個摘要。",
+ "apihelp-patrol-description": "巡查一個頁面或修訂。",
+ "apihelp-patrol-param-rcid": "要巡查的近期變更 ID。",
+ "apihelp-patrol-param-revid": "要巡查的修訂 ID。",
+ "apihelp-patrol-example-rcid": "巡查一個近期變更。",
+ "apihelp-patrol-example-revid": "巡查一個修訂。",
+ "apihelp-protect-description": "變更頁面的保護層級。",
+ "apihelp-protect-param-title": "要(解除)保護頁面的標題。 不能與 $1pageid 一起使用。",
+ "apihelp-protect-param-pageid": "要(解除)保護頁面的 ID。 不能與 $1title 一起使用。",
+ "apihelp-protect-param-protections": "保護層級清單,格式為 <kbd>action=level</kbd> (例如 <kbd>edit=sysop</kbd>)。\n\n<strong>注意:</strong> 任何未列入清單項目的限制將會被移除。",
+ "apihelp-protect-param-expiry": "期限時間戳記,若只設定一個時間戳記,該時間戳記將會套用至所有的保護層級。 使用 <kbd>infinite</kbd>、<kbd>indefinite</kbd>、<kbd>infinity</kbd> 或 <kbd>never</kbd> 來設定保護層級期限為永遠。",
+ "apihelp-protect-param-reason": "(解除)保護的原因。",
"apihelp-query+allcategories-param-limit": "要回傳的分類數量。",
"apihelp-query+allfileusages-param-limit": "要回傳的項目總數。",
"apihelp-query+allimages-param-limit": "要回傳的圖片總數。",
@@ -143,19 +162,26 @@
"apihelp-query+allredirects-param-limit": "要回傳的項目總數。",
"apihelp-query+alltransclusions-param-limit": "要回傳的項目總數。",
"apihelp-query+categories-param-limit": "要回傳的分類數量。",
+ "apihelp-query+categoryinfo-description": "回傳有關指定分類的資訊。",
"apihelp-query+categorymembers-param-limit": "回傳的頁面數量上限。",
"apihelp-query+contributors-param-limit": "要回傳的貢獻人員數量。",
"apihelp-query+duplicatefiles-param-limit": "要回傳的重複檔案數量。",
"apihelp-query+embeddedin-param-limit": "要回傳的頁面總數。",
+ "apihelp-query+extlinks-description": "回傳所有指定頁面的外部 URL (非 interwiki)。",
"apihelp-query+extlinks-param-limit": "要回傳的連結數量。",
"apihelp-query+exturlusage-param-limit": "要回傳的頁面數量。",
"apihelp-query+filearchive-param-limit": "要回傳的圖片總數。",
"apihelp-query+fileusage-param-limit": "要回傳的數量。",
+ "apihelp-query+imageinfo-description": "回傳檔案資訊與上傳日誌。",
"apihelp-query+imageinfo-param-limit": "每個檔案要回傳的檔案修訂數量。",
+ "apihelp-query+images-description": "回傳指定頁面中包含的所有檔案。",
"apihelp-query+images-param-limit": "要回傳的檔案數量。",
+ "apihelp-query+iwlinks-description": "回傳指定頁面的所有 interwiki 連結。",
"apihelp-query+iwlinks-param-limit": "要回傳的跨 Wiki 連結數量。",
"apihelp-query+langbacklinks-param-limit": "要回傳的頁面總數。",
+ "apihelp-query+langlinks-description": "回傳指定頁面的所有跨語言連結。",
"apihelp-query+langlinks-param-limit": "要回傳的 langlinks 數量。",
+ "apihelp-query+links-description": "回傳指定頁面的所有連結。",
"apihelp-query+links-param-limit": "要回傳的連結數量。",
"apihelp-query+linkshere-param-limit": "要回傳的數量。",
"apihelp-query+logevents-param-limit": "要回傳的事件項目總數。",
@@ -167,10 +193,14 @@
"apihelp-query+recentchanges-description": "列舉出近期變動。",
"apihelp-query+recentchanges-param-limit": "要回傳變更總數。",
"apihelp-query+recentchanges-example-simple": "近期變動清單",
+ "apihelp-query+redirects-description": "回傳連結至指定頁面的所有重新導向。",
"apihelp-query+redirects-param-limit": "要回傳的重新導向數量。",
"apihelp-query+search-param-limit": "要回傳的頁面總數。",
- "apihelp-query+templates-param-limit": "要回傳的樣板數量。",
- "apihelp-query+tokens-param-type": "要請求的密鑰類型。",
+ "apihelp-query+stashimageinfo-description": "回傳多筆儲藏檔案的檔案資訊。",
+ "apihelp-query+stashimageinfo-example-simple": "回傳儲藏檔案的檔案資訊。",
+ "apihelp-query+templates-description": "回傳指定頁面中所有引用的頁面。",
+ "apihelp-query+templates-param-limit": "要回傳的模板數量。",
+ "apihelp-query+tokens-param-type": "請求的密鑰類型。",
"apihelp-query+tokens-example-simple": "接收 csrf 密鑰 (預設)。",
"apihelp-query+tokens-example-types": "接收監視密鑰以及巡邏密鑰。",
"apihelp-query+transcludedin-param-limit": "回傳的數量。",
@@ -190,8 +220,6 @@
"apihelp-format-example-generic": "格式化查詢結果為 $1 格式",
"apihelp-dbg-description": "使用 PHP 的 <code>var_export()</code> 格式輸出資料。",
"apihelp-dbgfm-description": "使用 PHP 的 <code>var_export()</code> 格式輸出資料 (使用 HTML 格式顯示)。",
- "apihelp-dump-description": "使用 PHP 的 <code>var_dump()</code> 格式輸出資料。",
- "apihelp-dumpfm-description": "使用 PHP 的 <code>var_dump()</code> 格式輸出資料 (使用 HTML 格式顯示)。",
"apihelp-json-description": "使用 JSON 格式輸出資料。",
"apihelp-jsonfm-description": "使用 JSON 格式輸出資料 (使用 HTML 格式顯示)。",
"apihelp-none-description": "不輸出。",
@@ -200,8 +228,6 @@
"apihelp-rawfm-description": "使用 JSON 格式的除錯元素輸出資料 (使用 HTML 格式顯示)。",
"apihelp-txt-description": "使用 PHP 的 <code>print_r()</code> 格式輸出資料。",
"apihelp-txtfm-description": "使用 PHP 的 <code>print_r()</code> 格式輸出資料 (使用 HTML 格式顯示)。",
- "apihelp-wddx-description": "使用 WDDX 格式輸出資料。",
- "apihelp-wddxfm-description": "使用 WDDX 格式輸出資料 (使用 HTML 格式顯示)。",
"apihelp-xml-description": "使用 XML 格式輸出資料。",
"apihelp-xmlfm-description": "使用 XML 格式輸出資料 (使用 HTML 格式顯示)。",
"apihelp-yaml-description": "使用 YAML 格式輸出資料。",
diff --git a/includes/cache/BacklinkCache.php b/includes/cache/BacklinkCache.php
index 10b4fb00..1296c136 100644
--- a/includes/cache/BacklinkCache.php
+++ b/includes/cache/BacklinkCache.php
@@ -157,7 +157,7 @@ class BacklinkCache {
* @param string $table
* @param int|bool $startId
* @param int|bool $endId
- * @param int|INF $max
+ * @param int $max
* @return TitleArrayFromResult
*/
public function getLinks( $table, $startId = false, $endId = false, $max = INF ) {
@@ -169,7 +169,7 @@ class BacklinkCache {
* @param string $table
* @param int|bool $startId
* @param int|bool $endId
- * @param int|INF $max
+ * @param int $max
* @param string $select 'all' or 'ids'
* @return ResultWrapper
*/
@@ -319,7 +319,7 @@ class BacklinkCache {
/**
* Get the approximate number of backlinks
* @param string $table
- * @param int|INF $max Only count up to this many backlinks
+ * @param int $max Only count up to this many backlinks
* @return int
*/
public function getNumLinks( $table, $max = INF ) {
diff --git a/includes/cache/CacheDependency.php b/includes/cache/CacheDependency.php
index 517f3798..2abcabdc 100644
--- a/includes/cache/CacheDependency.php
+++ b/includes/cache/CacheDependency.php
@@ -181,11 +181,11 @@ class FileDependency extends CacheDependency {
function loadDependencyValues() {
if ( is_null( $this->timestamp ) ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
# Dependency on a non-existent file stores "false"
# This is a valid concept!
$this->timestamp = filemtime( $this->filename );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
}
@@ -193,9 +193,9 @@ class FileDependency extends CacheDependency {
* @return bool
*/
function isExpired() {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$lastmod = filemtime( $this->filename );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $lastmod === false ) {
if ( $this->timestamp === false ) {
# Still nonexistent
diff --git a/includes/cache/FileCacheBase.php b/includes/cache/FileCacheBase.php
index 4bf36114..5632596a 100644
--- a/includes/cache/FileCacheBase.php
+++ b/includes/cache/FileCacheBase.php
@@ -185,9 +185,9 @@ abstract class FileCacheBase {
* @return void
*/
public function clearCache() {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
unlink( $this->cachePath() );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
$this->mCached = false;
}
diff --git a/includes/cache/HTMLFileCache.php b/includes/cache/HTMLFileCache.php
index c07032bf..483eaa57 100644
--- a/includes/cache/HTMLFileCache.php
+++ b/includes/cache/HTMLFileCache.php
@@ -48,6 +48,7 @@ class HTMLFileCache extends FileCacheBase {
* @throws MWException
*/
public function __construct( $title, $action ) {
+ parent::__construct();
$allowedTypes = self::cacheablePageActions();
if ( !in_array( $action, $allowedTypes ) ) {
throw new MWException( 'Invalid file cache type given.' );
diff --git a/includes/cache/LCStoreStaticArray.php b/includes/cache/LCStoreStaticArray.php
new file mode 100644
index 00000000..fff9bab2
--- /dev/null
+++ b/includes/cache/LCStoreStaticArray.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Localisation cache storage based on PHP files and static arrays.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @since 1.26
+ */
+class LCStoreStaticArray implements LCStore {
+ /** @var string|null Current language code. */
+ private $currentLang = null;
+
+ /** @var array Localisation data. */
+ private $data = array();
+
+ /** @var string File name. */
+ private $fname = null;
+
+ /** @var string Directory for cache files. */
+ private $directory;
+
+ public function __construct( $conf = array() ) {
+ global $wgCacheDirectory;
+
+ if ( isset( $conf['directory'] ) ) {
+ $this->directory = $conf['directory'];
+ } else {
+ $this->directory = $wgCacheDirectory;
+ }
+ }
+
+ public function startWrite( $code ) {
+ $this->currentLang = $code;
+ $this->fname = $this->directory . '/' . $code . '.l10n.php';
+ $this->data[$code] = array();
+ if ( file_exists( $this->fname ) ) {
+ $this->data[$code] = require $this->fname;
+ }
+ }
+
+ public function set( $key, $value ) {
+ $this->data[$this->currentLang][$key] = self::encode( $value );
+ }
+
+ /**
+ * Encodes a value into an array format
+ *
+ * @param mixed $value
+ * @return array
+ * @throws RuntimeException
+ */
+ public static function encode( $value ) {
+ if ( is_scalar( $value ) || $value === null ) {
+ // [V]alue
+ return array( 'v', $value );
+ }
+ if ( is_object( $value ) ) {
+ // [S]erialized
+ return array( 's', serialize( $value ) );
+ }
+ if ( is_array( $value ) ) {
+ // [A]rray
+ return array( 'a', array_map( function ( $v ) {
+ return LCStoreStaticArray::encode( $v );
+ }, $value ) );
+ }
+
+ throw new RuntimeException( 'Cannot encode ' . var_export( $value, true ) );
+ }
+
+ /**
+ * Decode something that was encoded with encode
+ *
+ * @param array $encoded
+ * @return array|mixed
+ * @throws RuntimeException
+ */
+ public static function decode( array $encoded ) {
+ $type = $encoded[0];
+ $data = $encoded[1];
+
+ switch ( $type ) {
+ case 'v':
+ return $data;
+ case 's':
+ return unserialize( $data );
+ case 'a':
+ return array_map( function ( $v ) {
+ return LCStoreStaticArray::decode( $v );
+ }, $data );
+ default:
+ throw new RuntimeException(
+ 'Unable to decode ' . var_export( $encoded, true ) );
+ }
+ }
+
+ public function finishWrite() {
+ file_put_contents(
+ $this->fname,
+ "<?php\n" .
+ "// Generated by LCStoreStaticArray.php -- do not edit!\n" .
+ "return " .
+ var_export( $this->data[$this->currentLang], true ) . ';'
+ );
+ $this->currentLang = null;
+ $this->fname = null;
+ }
+
+ public function get( $code, $key ) {
+ if ( !array_key_exists( $code, $this->data ) ) {
+ $fname = $this->directory . '/' . $code . '.l10n.php';
+ if ( !file_exists( $fname ) ) {
+ return null;
+ }
+ $this->data[$code] = require $fname;
+ }
+ $data = $this->data[$code];
+ if ( array_key_exists( $key, $data ) ) {
+ return self::decode( $data[$key] );
+ }
+ return null;
+ }
+}
diff --git a/includes/cache/LinkBatch.php b/includes/cache/LinkBatch.php
index 77e4d490..698b3046 100644
--- a/includes/cache/LinkBatch.php
+++ b/includes/cache/LinkBatch.php
@@ -78,7 +78,7 @@ class LinkBatch {
$this->data[$ns] = array();
}
- $this->data[$ns][str_replace( ' ', '_', $dbkey )] = 1;
+ $this->data[$ns][strtr( $dbkey, ' ', '_' )] = 1;
}
/**
diff --git a/includes/cache/LinkCache.php b/includes/cache/LinkCache.php
index eace1eea..56c92569 100644
--- a/includes/cache/LinkCache.php
+++ b/includes/cache/LinkCache.php
@@ -29,18 +29,34 @@
class LinkCache {
// Increment $mClassVer whenever old serialized versions of this class
// becomes incompatible with the new version.
- private $mClassVer = 4;
+ private $mClassVer = 5;
- private $mGoodLinks = array();
- private $mGoodLinkFields = array();
- private $mBadLinks = array();
+ /**
+ * @var MapCacheLRU
+ */
+ private $mGoodLinks;
+ /**
+ * @var MapCacheLRU
+ */
+ private $mBadLinks;
private $mForUpdate = false;
/**
+ * How many Titles to store. There are two caches, so the amount actually
+ * stored in memory can be up to twice this.
+ */
+ const MAX_SIZE = 10000;
+
+ /**
* @var LinkCache
*/
protected static $instance;
+ public function __construct() {
+ $this->mGoodLinks = new MapCacheLRU( self::MAX_SIZE );
+ $this->mBadLinks = new MapCacheLRU( self::MAX_SIZE );
+ }
+
/**
* Get an instance of this class.
*
@@ -90,8 +106,9 @@ class LinkCache {
* @return int
*/
public function getGoodLinkID( $title ) {
- if ( array_key_exists( $title, $this->mGoodLinks ) ) {
- return $this->mGoodLinks[$title];
+ if ( $this->mGoodLinks->has( $title ) ) {
+ $info = $this->mGoodLinks->get( $title );
+ return $info['id'];
} else {
return 0;
}
@@ -106,8 +123,9 @@ class LinkCache {
*/
public function getGoodLinkFieldObj( $title, $field ) {
$dbkey = $title->getPrefixedDBkey();
- if ( array_key_exists( $dbkey, $this->mGoodLinkFields ) ) {
- return $this->mGoodLinkFields[$dbkey][$field];
+ if ( $this->mGoodLinks->has( $dbkey ) ) {
+ $info = $this->mGoodLinks->get( $dbkey );
+ return $info[$field];
} else {
return null;
}
@@ -118,7 +136,8 @@ class LinkCache {
* @return bool
*/
public function isBadLink( $title ) {
- return array_key_exists( $title, $this->mBadLinks );
+ // We need to use get here since has will not call ping.
+ return $this->mBadLinks->get( $title ) !== null;
}
/**
@@ -135,13 +154,13 @@ class LinkCache {
$revision = 0, $model = null
) {
$dbkey = $title->getPrefixedDBkey();
- $this->mGoodLinks[$dbkey] = (int)$id;
- $this->mGoodLinkFields[$dbkey] = array(
+ $this->mGoodLinks->set( $dbkey, array(
+ 'id' => (int)$id,
'length' => (int)$len,
'redirect' => (int)$redir,
'revision' => (int)$revision,
'model' => $model ? (string)$model : null,
- );
+ ) );
}
/**
@@ -153,13 +172,13 @@ class LinkCache {
*/
public function addGoodLinkObjFromRow( $title, $row ) {
$dbkey = $title->getPrefixedDBkey();
- $this->mGoodLinks[$dbkey] = intval( $row->page_id );
- $this->mGoodLinkFields[$dbkey] = array(
+ $this->mGoodLinks->set( $dbkey, array(
+ 'id' => intval( $row->page_id ),
'length' => intval( $row->page_len ),
'redirect' => intval( $row->page_is_redirect ),
'revision' => intval( $row->page_latest ),
'model' => !empty( $row->page_content_model ) ? strval( $row->page_content_model ) : null,
- );
+ ) );
}
/**
@@ -168,12 +187,12 @@ class LinkCache {
public function addBadLinkObj( $title ) {
$dbkey = $title->getPrefixedDBkey();
if ( !$this->isBadLink( $dbkey ) ) {
- $this->mBadLinks[$dbkey] = 1;
+ $this->mBadLinks->set( $dbkey, 1 );
}
}
public function clearBadLink( $title ) {
- unset( $this->mBadLinks[$title] );
+ $this->mBadLinks->clear( array( $title ) );
}
/**
@@ -181,17 +200,33 @@ class LinkCache {
*/
public function clearLink( $title ) {
$dbkey = $title->getPrefixedDBkey();
- unset( $this->mBadLinks[$dbkey] );
- unset( $this->mGoodLinks[$dbkey] );
- unset( $this->mGoodLinkFields[$dbkey] );
+ $this->mBadLinks->clear( array( $dbkey ) );
+ $this->mGoodLinks->clear( array( $dbkey ) );
}
+
+ /**
+ * @deprecated since 1.26
+ * @return array
+ */
public function getGoodLinks() {
- return $this->mGoodLinks;
+ wfDeprecated( __METHOD__, '1.26' );
+ $links = array();
+ foreach ( $this->mGoodLinks->getAllKeys() as $key ) {
+ $info = $this->mGoodLinks->get( $key );
+ $links[$key] = $info['id'];
+ }
+
+ return $links;
}
+ /**
+ * @deprecated since 1.26
+ * @return array
+ */
public function getBadLinks() {
- return array_keys( $this->mBadLinks );
+ wfDeprecated( __METHOD__, '1.26' );
+ return $this->mBadLinks->getAllKeys();
}
/**
@@ -220,17 +255,14 @@ class LinkCache {
$key = $nt->getPrefixedDBkey();
if ( $this->isBadLink( $key ) || $nt->isExternal() ) {
-
return 0;
}
$id = $this->getGoodLinkID( $key );
if ( $id != 0 ) {
-
return $id;
}
if ( $key === '' ) {
-
return 0;
}
@@ -265,8 +297,7 @@ class LinkCache {
* Clears cache
*/
public function clear() {
- $this->mGoodLinks = array();
- $this->mGoodLinkFields = array();
- $this->mBadLinks = array();
+ $this->mGoodLinks->clear();
+ $this->mBadLinks->clear();
}
}
diff --git a/includes/cache/LocalisationCache.php b/includes/cache/LocalisationCache.php
index dc5a2eb6..276e84aa 100644
--- a/includes/cache/LocalisationCache.php
+++ b/includes/cache/LocalisationCache.php
@@ -204,6 +204,9 @@ class LocalisationCache {
case 'db':
$storeClass = 'LCStoreDB';
break;
+ case 'array':
+ $storeClass = 'LCStoreStaticArray';
+ break;
case 'detect':
$storeClass = $wgCacheDirectory ? 'LCStoreCDB' : 'LCStoreDB';
break;
@@ -506,15 +509,15 @@ class LocalisationCache {
*/
protected function readPHPFile( $_fileName, $_fileType ) {
// Disable APC caching
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$_apcEnabled = ini_set( 'apc.cache_by_default', '0' );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
include $_fileName;
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
ini_set( 'apc.cache_by_default', $_apcEnabled );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $_fileType == 'core' || $_fileType == 'extension' ) {
$data = compact( self::$allKeys );
@@ -536,13 +539,11 @@ class LocalisationCache {
public function readJSONFile( $fileName ) {
if ( !is_readable( $fileName ) ) {
-
return array();
}
$json = file_get_contents( $fileName );
if ( $json === false ) {
-
return array();
}
diff --git a/includes/MessageBlobStore.php b/includes/cache/MessageBlobStore.php
index 011cae66..19349b2d 100644
--- a/includes/MessageBlobStore.php
+++ b/includes/cache/MessageBlobStore.php
@@ -33,6 +33,15 @@
*/
class MessageBlobStore {
/**
+ * In-process cache for message blobs.
+ *
+ * Keyed by language code, then module name.
+ *
+ * @var array
+ */
+ protected $blobCache = array();
+
+ /**
* Get the singleton instance
*
* @since 1.24
@@ -56,18 +65,40 @@ class MessageBlobStore {
if ( !count( $modules ) ) {
return array();
}
- // Try getting from the DB first
- $blobs = $this->getFromDB( $resourceLoader, array_keys( $modules ), $lang );
- // Generate blobs for any missing modules and store them in the DB
- $missing = array_diff( array_keys( $modules ), array_keys( $blobs ) );
- foreach ( $missing as $name ) {
+ $blobs = array();
+
+ // Try in-process cache
+ $missingFromCache = array();
+ foreach ( $modules as $name => $module ) {
+ if ( isset( $this->blobCache[$lang][$name] ) ) {
+ $blobs[$name] = $this->blobCache[$lang][$name];
+ } else {
+ $missingFromCache[] = $name;
+ }
+ }
+
+ // Try DB cache
+ if ( $missingFromCache ) {
+ $blobs += $this->getFromDB( $resourceLoader, $missingFromCache, $lang );
+ }
+
+ // Generate new blobs for any remaining modules and store in DB
+ $missingFromDb = array_diff( array_keys( $modules ), array_keys( $blobs ) );
+ foreach ( $missingFromDb as $name ) {
$blob = $this->insertMessageBlob( $name, $modules[$name], $lang );
if ( $blob ) {
$blobs[$name] = $blob;
}
}
+ // Update in-process cache
+ if ( isset( $this->blobCache[$lang] ) ) {
+ $this->blobCache[$lang] += $blobs;
+ } else {
+ $this->blobCache[$lang] = $blobs;
+ }
+
return $blobs;
}
@@ -339,6 +370,10 @@ class MessageBlobStore {
* @return array Array mapping module names to blobs
*/
private function getFromDB( ResourceLoader $resourceLoader, $modules, $lang ) {
+ if ( !count( $modules ) ) {
+ return array();
+ }
+
$config = $resourceLoader->getConfig();
$retval = array();
$dbr = wfGetDB( DB_SLAVE );
diff --git a/includes/cache/MessageCache.php b/includes/cache/MessageCache.php
index a55e25a3..f22c860a 100644
--- a/includes/cache/MessageCache.php
+++ b/includes/cache/MessageCache.php
@@ -25,24 +25,7 @@
* MediaWiki message cache structure version.
* Bump this whenever the message cache format has changed.
*/
-define( 'MSG_CACHE_VERSION', 1 );
-
-/**
- * Memcached timeout when loading a key.
- * See MessageCache::load()
- */
-define( 'MSG_LOAD_TIMEOUT', 60 );
-
-/**
- * Memcached timeout when locking a key for a writing operation.
- * See MessageCache::lock()
- */
-define( 'MSG_LOCK_TIMEOUT', 30 );
-/**
- * Number of times we will try to acquire a lock from Memcached.
- * This comes in addition to MSG_LOCK_TIMEOUT.
- */
-define( 'MSG_WAIT_TIMEOUT', 30 );
+define( 'MSG_CACHE_VERSION', 2 );
/**
* Message cache
@@ -50,12 +33,20 @@ define( 'MSG_WAIT_TIMEOUT', 30 );
* @ingroup Cache
*/
class MessageCache {
+ const FOR_UPDATE = 1; // force message reload
+
+ /** How long to wait for memcached locks */
+ const WAIT_SEC = 15;
+ /** How long memcached locks last */
+ const LOCK_TTL = 30;
+
/**
* Process local cache of loaded messages that are defined in
* MediaWiki namespace. First array level is a language code,
* second level is message key and the values are either message
* content prefixed with space, or !NONEXISTENT for negative
* caching.
+ * @var array $mCache
*/
protected $mCache;
@@ -84,6 +75,16 @@ class MessageCache {
protected $mLoadedLanguages = array();
/**
+ * @var bool $mInParser
+ */
+ protected $mInParser = false;
+
+ /** @var BagOStuff */
+ protected $mMemc;
+ /** @var WANObjectCache */
+ protected $wanCache;
+
+ /**
* Singleton instance
*
* @var MessageCache $instance
@@ -91,11 +92,6 @@ class MessageCache {
private static $instance;
/**
- * @var bool $mInParser
- */
- protected $mInParser = false;
-
- /**
* Get the signleton instance of this class
*
* @since 1.18
@@ -124,11 +120,31 @@ class MessageCache {
}
/**
+ * Normalize message key input
+ *
+ * @param string $key Input message key to be normalized
+ * @return string Normalized message key
+ */
+ public static function normalizeKey( $key ) {
+ global $wgContLang;
+ $lckey = strtr( $key, ' ', '_' );
+ if ( ord( $lckey ) < 128 ) {
+ $lckey[0] = strtolower( $lckey[0] );
+ } else {
+ $lckey = $wgContLang->lcfirst( $lckey );
+ }
+
+ return $lckey;
+ }
+
+ /**
* @param BagOStuff $memCached A cache instance. If none, fall back to CACHE_NONE.
* @param bool $useDB
* @param int $expiry Lifetime for cache. @see $mExpiry.
*/
function __construct( $memCached, $useDB, $expiry ) {
+ global $wgUseLocalMessageCache;
+
if ( !$memCached ) {
$memCached = wfGetCache( CACHE_NONE );
}
@@ -136,6 +152,14 @@ class MessageCache {
$this->mMemc = $memCached;
$this->mDisable = !$useDB;
$this->mExpiry = $expiry;
+
+ if ( $wgUseLocalMessageCache ) {
+ $this->localCache = ObjectCache::newAccelerator( CACHE_NONE );
+ } else {
+ $this->localCache = wfGetCache( CACHE_NONE );
+ }
+
+ $this->wanCache = ObjectCache::getMainWANInstance();
}
/**
@@ -153,70 +177,26 @@ class MessageCache {
}
/**
- * Try to load the cache from a local file.
+ * Try to load the cache from APC.
*
- * @param string $hash The hash of contents, to check validity.
* @param string $code Optional language code, see documenation of load().
- * @return array The cache array
+ * @return array|bool The cache array, or false if not in cache.
*/
- function getLocalCache( $hash, $code ) {
- global $wgCacheDirectory;
-
- $filename = "$wgCacheDirectory/messages-" . wfWikiID() . "-$code";
-
- # Check file existence
- wfSuppressWarnings();
- $file = fopen( $filename, 'r' );
- wfRestoreWarnings();
- if ( !$file ) {
- return false; // No cache file
- }
-
- // Check to see if the file has the hash specified
- $localHash = fread( $file, 32 );
- if ( $hash === $localHash ) {
- // All good, get the rest of it
- $serialized = '';
- while ( !feof( $file ) ) {
- $serialized .= fread( $file, 100000 );
- }
- fclose( $file );
-
- return unserialize( $serialized );
- } else {
- fclose( $file );
+ protected function getLocalCache( $code ) {
+ $cacheKey = wfMemcKey( __CLASS__, $code );
- return false; // Wrong hash
- }
+ return $this->localCache->get( $cacheKey );
}
/**
- * Save the cache to a local file.
- * @param string $serialized
- * @param string $hash
+ * Save the cache to APC.
+ *
* @param string $code
+ * @param array $cache The cache array
*/
- function saveToLocal( $serialized, $hash, $code ) {
- global $wgCacheDirectory;
-
- $filename = "$wgCacheDirectory/messages-" . wfWikiID() . "-$code";
- wfMkdirParents( $wgCacheDirectory, null, __METHOD__ ); // might fail
-
- wfSuppressWarnings();
- $file = fopen( $filename, 'w' );
- wfRestoreWarnings();
-
- if ( !$file ) {
- wfDebug( "Unable to open local cache file for writing\n" );
-
- return;
- }
-
- fwrite( $file, $hash . $serialized );
- fclose( $file );
- wfSuppressWarnings();
- chmod( $filename, 0666 );
- wfRestoreWarnings();
+ protected function saveToLocalCache( $code, $cache ) {
+ $cacheKey = wfMemcKey( __CLASS__, $code );
+ $this->localCache->set( $cacheKey, $cache );
}
/**
@@ -236,12 +216,11 @@ class MessageCache {
* is disabled.
*
* @param bool|string $code Language to which load messages
+ * @param integer $mode Use MessageCache::FOR_UPDATE to skip process cache
* @throws MWException
* @return bool
*/
- function load( $code = false ) {
- global $wgUseLocalMessageCache;
-
+ function load( $code = false, $mode = null ) {
if ( !is_string( $code ) ) {
# This isn't really nice, so at least make a note about it and try to
# fall back
@@ -250,7 +229,7 @@ class MessageCache {
}
# Don't do double loading...
- if ( isset( $this->mLoadedLanguages[$code] ) ) {
+ if ( isset( $this->mLoadedLanguages[$code] ) && $mode != self::FOR_UPDATE ) {
return true;
}
@@ -269,45 +248,60 @@ class MessageCache {
$success = false; # Keep track of success
$staleCache = false; # a cache array with expired data, or false if none has been loaded
$where = array(); # Debug info, delayed to avoid spamming debug log too much
- $cacheKey = wfMemcKey( 'messages', $code ); # Key in memc for messages
- # Local cache
- # Hash of the contents is stored in memcache, to detect if local cache goes
- # out of date (e.g. due to replace() on some other server)
- if ( $wgUseLocalMessageCache ) {
-
- $hash = $this->mMemc->get( wfMemcKey( 'messages', $code, 'hash' ) );
- if ( $hash ) {
- $cache = $this->getLocalCache( $hash, $code );
- if ( !$cache ) {
- $where[] = 'local cache is empty or has the wrong hash';
- } elseif ( $this->isCacheExpired( $cache ) ) {
- $where[] = 'local cache is expired';
- $staleCache = $cache;
- } else {
- $where[] = 'got from local cache';
- $success = true;
- $this->mCache[$code] = $cache;
- }
- }
+ # Hash of the contents is stored in memcache, to detect if data-center cache
+ # or local cache goes out of date (e.g. due to replace() on some other server)
+ list( $hash, $hashVolatile ) = $this->getValidationHash( $code );
+
+ # Try the local cache and check against the cluster hash key...
+ $cache = $this->getLocalCache( $code );
+ if ( !$cache ) {
+ $where[] = 'local cache is empty';
+ } elseif ( !isset( $cache['HASH'] ) || $cache['HASH'] !== $hash ) {
+ $where[] = 'local cache has the wrong hash';
+ $staleCache = $cache;
+ } elseif ( $this->isCacheExpired( $cache ) ) {
+ $where[] = 'local cache is expired';
+ $staleCache = $cache;
+ } elseif ( $hashVolatile ) {
+ $where[] = 'local cache validation key is expired/volatile';
+ $staleCache = $cache;
+ } else {
+ $where[] = 'got from local cache';
+ $success = true;
+ $this->mCache[$code] = $cache;
}
if ( !$success ) {
+ $cacheKey = wfMemcKey( 'messages', $code ); # Key in memc for messages
# Try the global cache. If it is empty, try to acquire a lock. If
# the lock can't be acquired, wait for the other thread to finish
# and then try the global cache a second time.
- for ( $failedAttempts = 0; $failedAttempts < 2; $failedAttempts++ ) {
- $cache = $this->mMemc->get( $cacheKey );
- if ( !$cache ) {
- $where[] = 'global cache is empty';
- } elseif ( $this->isCacheExpired( $cache ) ) {
- $where[] = 'global cache is expired';
- $staleCache = $cache;
+ for ( $failedAttempts = 0; $failedAttempts <= 1; $failedAttempts++ ) {
+ if ( $hashVolatile && $staleCache ) {
+ # Do not bother fetching the whole cache blob to avoid I/O.
+ # Instead, just try to get the non-blocking $statusKey lock
+ # below, and use the local stale value if it was not acquired.
+ $where[] = 'global cache is presumed expired';
} else {
- $where[] = 'got from global cache';
- $this->mCache[$code] = $cache;
- $this->saveToCaches( $cache, 'local-only', $code );
- $success = true;
+ $cache = $this->mMemc->get( $cacheKey );
+ if ( !$cache ) {
+ $where[] = 'global cache is empty';
+ } elseif ( $this->isCacheExpired( $cache ) ) {
+ $where[] = 'global cache is expired';
+ $staleCache = $cache;
+ } elseif ( $hashVolatile ) {
+ # DB results are slave lag prone until the holdoff TTL passes.
+ # By then, updates should be reflected in loadFromDBWithLock().
+ # One thread renerates the cache while others use old values.
+ $where[] = 'global cache is expired/volatile';
+ $staleCache = $cache;
+ } else {
+ $where[] = 'got from global cache';
+ $this->mCache[$code] = $cache;
+ $this->saveToCaches( $cache, 'local-only', $code );
+ $success = true;
+ }
}
if ( $success ) {
@@ -315,68 +309,12 @@ class MessageCache {
break;
}
- # We need to call loadFromDB. Limit the concurrency to a single
- # process. This prevents the site from going down when the cache
- # expires.
- $statusKey = wfMemcKey( 'messages', $code, 'status' );
- $acquired = $this->mMemc->add( $statusKey, 'loading', MSG_LOAD_TIMEOUT );
- if ( $acquired ) {
- # Unlock the status key if there is an exception
- $that = $this;
- $statusUnlocker = new ScopedCallback( function () use ( $that, $statusKey ) {
- $that->mMemc->delete( $statusKey );
- } );
-
- # Now let's regenerate
- $where[] = 'loading from database';
-
- # Lock the cache to prevent conflicting writes
- # If this lock fails, it doesn't really matter, it just means the
- # write is potentially non-atomic, e.g. the results of a replace()
- # may be discarded.
- if ( $this->lock( $cacheKey ) ) {
- $mainUnlocker = new ScopedCallback( function () use ( $that, $cacheKey ) {
- $that->unlock( $cacheKey );
- } );
- } else {
- $mainUnlocker = null;
- $where[] = 'could not acquire main lock';
- }
-
- $cache = $this->loadFromDB( $code );
- $this->mCache[$code] = $cache;
+ # We need to call loadFromDB. Limit the concurrency to one process.
+ # This prevents the site from going down when the cache expires.
+ # Note that the DB slam protection lock here is non-blocking.
+ $loadStatus = $this->loadFromDBWithLock( $code, $where, $mode );
+ if ( $loadStatus === true ) {
$success = true;
- $saveSuccess = $this->saveToCaches( $cache, 'all', $code );
-
- # Unlock
- ScopedCallback::consume( $mainUnlocker );
- ScopedCallback::consume( $statusUnlocker );
-
- if ( !$saveSuccess ) {
- # Cache save has failed.
- # There are two main scenarios where this could be a problem:
- #
- # - The cache is more than the maximum size (typically
- # 1MB compressed).
- #
- # - Memcached has no space remaining in the relevant slab
- # class. This is unlikely with recent versions of
- # memcached.
- #
- # Either way, if there is a local cache, nothing bad will
- # happen. If there is no local cache, disabling the message
- # cache for all requests avoids incurring a loadFromDB()
- # overhead on every request, and thus saves the wiki from
- # complete downtime under moderate traffic conditions.
- if ( !$wgUseLocalMessageCache ) {
- $this->mMemc->set( $statusKey, 'error', 60 * 5 );
- $where[] = 'could not save cache, disabled globally for 5 minutes';
- } else {
- $where[] = "could not save global cache";
- }
- }
-
- # Load from DB complete, no need to retry
break;
} elseif ( $staleCache ) {
# Use the stale cache while some other thread constructs the new one
@@ -385,22 +323,19 @@ class MessageCache {
$success = true;
break;
} elseif ( $failedAttempts > 0 ) {
- # Already retried once, still failed, so don't do another lock/unlock cycle
+ # Already blocked once, so avoid another lock/unlock cycle.
# This case will typically be hit if memcached is down, or if
- # loadFromDB() takes longer than MSG_WAIT_TIMEOUT
+ # loadFromDB() takes longer than LOCK_WAIT.
$where[] = "could not acquire status key.";
break;
+ } elseif ( $loadStatus === 'cantacquire' ) {
+ # Wait for the other thread to finish, then retry. Normally,
+ # the memcached get() will then yeild the other thread's result.
+ $where[] = 'waited for other thread to complete';
+ $this->getReentrantScopedLock( $cacheKey );
} else {
- $status = $this->mMemc->get( $statusKey );
- if ( $status === 'error' ) {
- # Disable cache
- break;
- } else {
- # Wait for the other thread to finish, then retry
- $where[] = 'waited for other thread to complete';
- $this->lock( $cacheKey );
- $this->unlock( $cacheKey );
- }
+ # Disable cache; $loadStatus is 'disabled'
+ break;
}
}
}
@@ -415,6 +350,7 @@ class MessageCache {
# All good, just record the success
$this->mLoadedLanguages[$code] = true;
}
+
$info = implode( ', ', $where );
wfDebugLog( 'MessageCache', __METHOD__ . ": Loading $code... $info\n" );
@@ -422,16 +358,82 @@ class MessageCache {
}
/**
+ * @param string $code
+ * @param array $where List of wfDebug() comments
+ * @param integer $mode Use MessageCache::FOR_UPDATE to use DB_MASTER
+ * @return bool|string True on success or one of ("cantacquire", "disabled")
+ */
+ protected function loadFromDBWithLock( $code, array &$where, $mode = null ) {
+ global $wgUseLocalMessageCache;
+
+ # If cache updates on all levels fail, give up on message overrides.
+ # This is to avoid easy site outages; see $saveSuccess comments below.
+ $statusKey = wfMemcKey( 'messages', $code, 'status' );
+ $status = $this->mMemc->get( $statusKey );
+ if ( $status === 'error' ) {
+ $where[] = "could not load; method is still globally disabled";
+ return 'disabled';
+ }
+
+ # Now let's regenerate
+ $where[] = 'loading from database';
+
+ # Lock the cache to prevent conflicting writes.
+ # This lock is non-blocking so stale cache can quickly be used.
+ # Note that load() will call a blocking getReentrantScopedLock()
+ # after this if it really need to wait for any current thread.
+ $cacheKey = wfMemcKey( 'messages', $code );
+ $scopedLock = $this->getReentrantScopedLock( $cacheKey, 0 );
+ if ( !$scopedLock ) {
+ $where[] = 'could not acquire main lock';
+ return 'cantacquire';
+ }
+
+ $cache = $this->loadFromDB( $code, $mode );
+ $this->mCache[$code] = $cache;
+ $saveSuccess = $this->saveToCaches( $cache, 'all', $code );
+
+ if ( !$saveSuccess ) {
+ # Cache save has failed.
+ # There are two main scenarios where this could be a problem:
+ #
+ # - The cache is more than the maximum size (typically
+ # 1MB compressed).
+ #
+ # - Memcached has no space remaining in the relevant slab
+ # class. This is unlikely with recent versions of
+ # memcached.
+ #
+ # Either way, if there is a local cache, nothing bad will
+ # happen. If there is no local cache, disabling the message
+ # cache for all requests avoids incurring a loadFromDB()
+ # overhead on every request, and thus saves the wiki from
+ # complete downtime under moderate traffic conditions.
+ if ( !$wgUseLocalMessageCache ) {
+ $this->mMemc->set( $statusKey, 'error', 60 * 5 );
+ $where[] = 'could not save cache, disabled globally for 5 minutes';
+ } else {
+ $where[] = "could not save global cache";
+ }
+ }
+
+ return true;
+ }
+
+ /**
* Loads cacheable messages from the database. Messages bigger than
* $wgMaxMsgCacheEntrySize are assigned a special value, and are loaded
* on-demand from the database later.
*
- * @param string $code Language code.
- * @return array Loaded messages for storing in caches.
+ * @param string $code Language code
+ * @param integer $mode Use MessageCache::FOR_UPDATE to skip process cache
+ * @return array Loaded messages for storing in caches
*/
- function loadFromDB( $code ) {
+ function loadFromDB( $code, $mode = null ) {
global $wgMaxMsgCacheEntrySize, $wgLanguageCode, $wgAdaptiveMessageCache;
- $dbr = wfGetDB( DB_SLAVE );
+
+ $dbr = wfGetDB( ( $mode == self::FOR_UPDATE ) ? DB_MASTER : DB_SLAVE );
+
$cache = array();
# Common conditions
@@ -502,6 +504,8 @@ class MessageCache {
}
$cache['VERSION'] = MSG_CACHE_VERSION;
+ ksort( $cache );
+ $cache['HASH'] = md5( serialize( $cache ) );
$cache['EXPIRY'] = wfTimestamp( TS_MW, time() + $this->mExpiry );
return $cache;
@@ -510,41 +514,57 @@ class MessageCache {
/**
* Updates cache as necessary when message page is changed
*
- * @param string $title Name of the page changed.
+ * @param string|bool $title Name of the page changed (false if deleted)
* @param mixed $text New contents of the page.
*/
public function replace( $title, $text ) {
- global $wgMaxMsgCacheEntrySize;
+ global $wgMaxMsgCacheEntrySize, $wgContLang, $wgLanguageCode;
if ( $this->mDisable ) {
-
return;
}
list( $msg, $code ) = $this->figureMessage( $title );
+ if ( strpos( $title, '/' ) !== false && $code === $wgLanguageCode ) {
+ // Content language overrides do not use the /<code> suffix
+ return;
+ }
+ // Note that if the cache is volatile, load() may trigger a DB fetch.
+ // In that case we reenter/reuse the existing cache key lock to avoid
+ // a self-deadlock. This is safe as no reads happen *directly* in this
+ // method between getReentrantScopedLock() and load() below. There is
+ // no risk of data "changing under our feet" for replace().
$cacheKey = wfMemcKey( 'messages', $code );
- $this->load( $code );
- $this->lock( $cacheKey );
+ $scopedLock = $this->getReentrantScopedLock( $cacheKey );
+ $this->load( $code, self::FOR_UPDATE );
$titleKey = wfMemcKey( 'messages', 'individual', $title );
-
if ( $text === false ) {
- # Article was deleted
+ // Article was deleted
$this->mCache[$code][$title] = '!NONEXISTENT';
- $this->mMemc->delete( $titleKey );
+ $this->wanCache->delete( $titleKey );
} elseif ( strlen( $text ) > $wgMaxMsgCacheEntrySize ) {
- # Check for size
+ // Check for size
$this->mCache[$code][$title] = '!TOO BIG';
- $this->mMemc->set( $titleKey, ' ' . $text, $this->mExpiry );
+ $this->wanCache->set( $titleKey, ' ' . $text, $this->mExpiry );
} else {
$this->mCache[$code][$title] = ' ' . $text;
- $this->mMemc->delete( $titleKey );
+ $this->wanCache->delete( $titleKey );
}
- # Update caches
- $this->saveToCaches( $this->mCache[$code], 'all', $code );
- $this->unlock( $cacheKey );
+ // Mark this cache as definitely "latest" (non-volatile) so
+ // load() calls do try to refresh the cache with slave data
+ $this->mCache[$code]['LATEST'] = time();
+
+ // Update caches if the lock was acquired
+ if ( $scopedLock ) {
+ $this->saveToCaches( $this->mCache[$code], 'all', $code );
+ }
+
+ ScopedCallback::consume( $scopedLock );
+ // Relay the purge to APC and other DCs
+ $this->wanCache->touchCheckKey( wfMemcKey( 'messages', $code ) );
// Also delete cached sidebar... just in case it is affected
$codes = array( $code );
@@ -554,19 +574,16 @@ class MessageCache {
$codes = array_keys( Language::fetchLanguageNames() );
}
- global $wgMemc;
foreach ( $codes as $code ) {
$sidebarKey = wfMemcKey( 'sidebar', $code );
- $wgMemc->delete( $sidebarKey );
+ $this->wanCache->delete( $sidebarKey, 5 );
}
// Update the message in the message blob store
- global $wgContLang;
$blobStore = new MessageBlobStore();
$blobStore->updateMessage( $wgContLang->lcfirst( $msg ) );
Hooks::run( 'MessageCacheReplace', array( $title, $text ) );
-
}
/**
@@ -598,63 +615,79 @@ class MessageCache {
* @param string|bool $code Language code (default: false)
* @return bool
*/
- protected function saveToCaches( $cache, $dest, $code = false ) {
- global $wgUseLocalMessageCache;
-
- $cacheKey = wfMemcKey( 'messages', $code );
-
+ protected function saveToCaches( array $cache, $dest, $code = false ) {
if ( $dest === 'all' ) {
+ $cacheKey = wfMemcKey( 'messages', $code );
$success = $this->mMemc->set( $cacheKey, $cache );
} else {
$success = true;
}
- # Save to local cache
- if ( $wgUseLocalMessageCache ) {
- $serialized = serialize( $cache );
- $hash = md5( $serialized );
- $this->mMemc->set( wfMemcKey( 'messages', $code, 'hash' ), $hash );
- $this->saveToLocal( $serialized, $hash, $code );
- }
+ $this->setValidationHash( $code, $cache );
+ $this->saveToLocalCache( $code, $cache );
return $success;
}
/**
- * Represents a write lock on the messages key.
+ * Get the md5 used to validate the local APC cache
*
- * Will retry MessageCache::MSG_WAIT_TIMEOUT times, each operations having
- * a timeout of MessageCache::MSG_LOCK_TIMEOUT.
- *
- * @param string $key
- * @return bool Success
+ * @param string $code
+ * @return array (hash or false, bool expiry/volatility status)
*/
- function lock( $key ) {
- $lockKey = $key . ':lock';
- $acquired = false;
- $testDone = false;
- for ( $i = 0; $i < MSG_WAIT_TIMEOUT && !$acquired; $i++ ) {
- $acquired = $this->mMemc->add( $lockKey, 1, MSG_LOCK_TIMEOUT );
- if ( $acquired ) {
- break;
- }
+ protected function getValidationHash( $code ) {
+ $curTTL = null;
+ $value = $this->wanCache->get(
+ wfMemcKey( 'messages', $code, 'hash', 'v1' ),
+ $curTTL,
+ array( wfMemcKey( 'messages', $code ) )
+ );
- # Fail fast if memcached is totally down
- if ( !$testDone ) {
- $testDone = true;
- if ( !$this->mMemc->set( wfMemcKey( 'test' ), 'test', 1 ) ) {
- break;
- }
+ if ( !$value ) {
+ // No hash found at all; cache must regenerate to be safe
+ $hash = false;
+ $expired = true;
+ } else {
+ $hash = $value['hash'];
+ if ( ( time() - $value['latest'] ) < WANObjectCache::HOLDOFF_TTL ) {
+ // Cache was recently updated via replace() and should be up-to-date
+ $expired = false;
+ } else {
+ // See if the "check" key was bumped after the hash was generated
+ $expired = ( $curTTL < 0 );
}
- sleep( 1 );
}
- return $acquired;
+ return array( $hash, $expired );
}
- function unlock( $key ) {
- $lockKey = $key . ':lock';
- $this->mMemc->delete( $lockKey );
+ /**
+ * Set the md5 used to validate the local disk cache
+ *
+ * If $cache has a 'LATEST' UNIX timestamp key, then the hash will not
+ * be treated as "volatile" by getValidationHash() for the next few seconds
+ *
+ * @param string $code
+ * @param array $cache Cached messages with a version
+ */
+ protected function setValidationHash( $code, array $cache ) {
+ $this->wanCache->set(
+ wfMemcKey( 'messages', $code, 'hash', 'v1' ),
+ array(
+ 'hash' => $cache['HASH'],
+ 'latest' => isset( $cache['LATEST'] ) ? $cache['LATEST'] : 0
+ ),
+ WANObjectCache::TTL_NONE
+ );
+ }
+
+ /**
+ * @param string $key A language message cache key that stores blobs
+ * @param integer $timeout Wait timeout in seconds
+ * @return null|ScopedCallback
+ */
+ protected function getReentrantScopedLock( $key, $timeout = self::WAIT_SEC ) {
+ return $this->mMemc->getScopedLock( $key, $timeout, self::LOCK_TTL, __METHOD__ );
}
/**
@@ -713,12 +746,7 @@ class MessageCache {
}
// Normalise title-case input (with some inlining)
- $lckey = strtr( $key, ' ', '_' );
- if ( ord( $lckey ) < 128 ) {
- $lckey[0] = strtolower( $lckey[0] );
- } else {
- $lckey = $wgContLang->lcfirst( $lckey );
- }
+ $lckey = MessageCache::normalizeKey( $key );
Hooks::run( 'MessageCache::get', array( &$lckey ) );
@@ -903,7 +931,7 @@ class MessageCache {
# Try the individual message cache
$titleKey = wfMemcKey( 'messages', 'individual', $title );
- $entry = $this->mMemc->get( $titleKey );
+ $entry = $this->wanCache->get( $titleKey );
if ( $entry ) {
if ( substr( $entry, 0, 1 ) === ' ' ) {
$this->mCache[$code][$title] = $entry;
@@ -917,14 +945,12 @@ class MessageCache {
return false;
} else {
# Corrupt/obsolete entry, delete it
- $this->mMemc->delete( $titleKey );
+ $this->wanCache->delete( $titleKey );
}
}
# Try loading it from the database
- $revision = Revision::newFromTitle(
- Title::makeTitle( NS_MEDIAWIKI, $title ), false, Revision::READ_LATEST
- );
+ $revision = Revision::newFromTitle( Title::makeTitle( NS_MEDIAWIKI, $title ) );
if ( $revision ) {
$content = $revision->getContent();
if ( !$content ) {
@@ -945,13 +971,13 @@ class MessageCache {
wfDebugLog(
'MessageCache',
__METHOD__ . ": message content doesn't provide wikitext "
- . "(content model: " . $content->getContentHandler() . ")"
+ . "(content model: " . $content->getModel() . ")"
);
$message = false; // negative caching
} else {
$this->mCache[$code][$title] = ' ' . $message;
- $this->mMemc->set( $titleKey, ' ' . $message, $this->mExpiry );
+ $this->wanCache->set( $titleKey, ' ' . $message, $this->mExpiry );
}
}
} else {
@@ -960,7 +986,7 @@ class MessageCache {
if ( $message === false ) { // negative caching
$this->mCache[$code][$title] = '!NONEXISTENT';
- $this->mMemc->set( $titleKey, '!NONEXISTENT', $this->mExpiry );
+ $this->wanCache->set( $titleKey, '!NONEXISTENT', $this->mExpiry );
}
return $message;
@@ -1042,7 +1068,8 @@ class MessageCache {
if ( !$title || !$title instanceof Title ) {
global $wgTitle;
- wfDebugLog( 'GlobalTitleFail', __METHOD__ . ' called by ' . wfGetAllCallers( 5 ) . ' with no title set.' );
+ wfDebugLog( 'GlobalTitleFail', __METHOD__ . ' called by ' .
+ wfGetAllCallers( 5 ) . ' with no title set.' );
$title = $wgTitle;
}
// Sometimes $wgTitle isn't set either...
@@ -1073,11 +1100,10 @@ class MessageCache {
function clear() {
$langs = Language::fetchLanguageNames( null, 'mw' );
foreach ( array_keys( $langs ) as $code ) {
- # Global cache
- $this->mMemc->delete( wfMemcKey( 'messages', $code ) );
- # Invalidate all local caches
- $this->mMemc->delete( wfMemcKey( 'messages', $code, 'hash' ) );
+ # Global and local caches
+ $this->wanCache->touchCheckKey( wfMemcKey( 'messages', $code ) );
}
+
$this->mLoadedLanguages = array();
}
@@ -1087,6 +1113,7 @@ class MessageCache {
*/
public function figureMessage( $key ) {
global $wgLanguageCode;
+
$pieces = explode( '/', $key );
if ( count( $pieces ) < 2 ) {
return array( $key, $wgLanguageCode );
diff --git a/includes/cache/ResourceFileCache.php b/includes/cache/ResourceFileCache.php
index 6d26a2d5..e1186efd 100644
--- a/includes/cache/ResourceFileCache.php
+++ b/includes/cache/ResourceFileCache.php
@@ -1,6 +1,6 @@
<?php
/**
- * Resource loader request result caching in the file system.
+ * ResourceLoader request result caching in the file system.
*
* 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
@@ -22,7 +22,7 @@
*/
/**
- * Resource loader request result caching in the file system.
+ * ResourceLoader request result caching in the file system.
*
* @ingroup Cache
*/
diff --git a/includes/cache/UserCache.php b/includes/cache/UserCache.php
index 8a42489c..51bf385b 100644
--- a/includes/cache/UserCache.php
+++ b/includes/cache/UserCache.php
@@ -123,11 +123,11 @@ class UserCache {
$lb = new LinkBatch();
foreach ( $usersToCheck as $userId => $name ) {
if ( $this->queryNeeded( $userId, 'userpage', $options ) ) {
- $lb->add( NS_USER, str_replace( ' ', '_', $row->user_name ) );
+ $lb->add( NS_USER, $name );
$this->typesCached[$userId]['userpage'] = 1;
}
if ( $this->queryNeeded( $userId, 'usertalk', $options ) ) {
- $lb->add( NS_USER_TALK, str_replace( ' ', '_', $row->user_name ) );
+ $lb->add( NS_USER_TALK, $name );
$this->typesCached[$userId]['usertalk'] = 1;
}
}
diff --git a/includes/changes/ChangesFeed.php b/includes/changes/ChangesFeed.php
index 28c2f7ed..28a1ccad 100644
--- a/includes/changes/ChangesFeed.php
+++ b/includes/changes/ChangesFeed.php
@@ -187,6 +187,10 @@ class ChangesFeed {
$sorted = array();
$n = 0;
foreach ( $rows as $obj ) {
+ if ( $obj->rc_type == RC_EXTERNAL ) {
+ continue;
+ }
+
if ( $n > 0 &&
$obj->rc_type == RC_EDIT &&
$obj->rc_namespace >= 0 &&
diff --git a/includes/changes/ChangesList.php b/includes/changes/ChangesList.php
index 932006d4..fdc9944f 100644
--- a/includes/changes/ChangesList.php
+++ b/includes/changes/ChangesList.php
@@ -204,7 +204,8 @@ class ChangesList extends ContextSource {
$code = $lang->getCode();
static $fastCharDiff = array();
if ( !isset( $fastCharDiff[$code] ) ) {
- $fastCharDiff[$code] = $config->get( 'MiserMode' ) || $context->msg( 'rc-change-size' )->plain() === '$1';
+ $fastCharDiff[$code] = $config->get( 'MiserMode' )
+ || $context->msg( 'rc-change-size' )->plain() === '$1';
}
$formattedSize = $lang->formatNum( $szdiff );
@@ -371,6 +372,19 @@ class ChangesList extends ContextSource {
}
/**
+ * @param RecentChange $rc
+ * @param bool $unpatrolled
+ * @param bool $watched
+ * @return string
+ * @since 1.26
+ */
+ public function getArticleLink( RecentChange $rc, $unpatrolled, $watched ) {
+ $s = '';
+ $this->insertArticleLink( $s, $rc, $unpatrolled, $watched );
+ return $s;
+ }
+
+ /**
* Get the timestamp from $rc formatted with current user's settings
* and a separator
*
@@ -543,6 +557,17 @@ class ChangesList extends ContextSource {
}
/**
+ * @param RecentChange $rc
+ * @return string
+ * @since 1.26
+ */
+ public function getRollback( RecentChange $rc ) {
+ $s = '';
+ $this->insertRollback( $s, $rc );
+ return $s;
+ }
+
+ /**
* @param string $s
* @param RecentChange $rc
* @param array $classes
@@ -560,6 +585,18 @@ class ChangesList extends ContextSource {
$s .= ' ' . $tagSummary;
}
+ /**
+ * @param RecentChange $rc
+ * @param array $classes
+ * @return string
+ * @since 1.26
+ */
+ public function getTags( RecentChange $rc, array &$classes ) {
+ $s = '';
+ $this->insertTags( $s, $rc, $classes );
+ return $s;
+ }
+
public function insertExtra( &$s, &$rc, &$classes ) {
// Empty, used for subclasses to add anything special.
}
diff --git a/includes/changes/EnhancedChangesList.php b/includes/changes/EnhancedChangesList.php
index 19277f10..d912e3a2 100644
--- a/includes/changes/EnhancedChangesList.php
+++ b/includes/changes/EnhancedChangesList.php
@@ -270,6 +270,20 @@ class EnhancedChangesList extends ChangesList {
$queryParams['curid'] = $curId;
+ # Sub-entries
+ $lines = '';
+ foreach ( $block as $i => $rcObj ) {
+ $line = $this->getLineData( $block, $rcObj, $queryParams );
+ $lines .= $line;
+ if ( !$line ) {
+ // completely ignore this RC entry if we don't want to render it
+ unset( $block[$i] );
+ }
+ }
+ // Further down are some assumptions that $block is a 0-indexed array
+ // with (count-1) as last key. Let's make sure it is.
+ $block = array_values( $block );
+
$r .= $this->getLogText( $block, $queryParams, $allLogs, $isnew, $namehidden );
$r .= ' <span class="mw-changeslist-separator">. .</span> ';
@@ -299,88 +313,133 @@ class EnhancedChangesList extends ChangesList {
$r .= $this->numberofWatchingusers( $block[0]->numberofWatchingusers );
$r .= '</td></tr>';
- # Sub-entries
- foreach ( $block as $rcObj ) {
- # Classes to apply -- TODO implement
- $classes = array();
- $type = $rcObj->mAttribs['rc_type'];
-
- $trClass = $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
- ? ' class="mw-enhanced-watched"' : '';
-
- $r .= '<tr' . $trClass . '><td></td><td class="mw-enhanced-rc">';
- $r .= $this->recentChangesFlags( array(
- 'newpage' => $type == RC_NEW,
- 'minor' => $rcObj->mAttribs['rc_minor'],
- 'unpatrolled' => $rcObj->unpatrolled,
- 'bot' => $rcObj->mAttribs['rc_bot'],
- ) );
- $r .= '&#160;</td><td class="mw-enhanced-rc-nested"><span class="mw-enhanced-rc-time">';
+ if ( !$lines ) {
+ // if there are no lines to be rendered (all aborted by hook), don't render the block
+ return '';
+ }
- $params = $queryParams;
+ $r .= $lines;
+ $r .= "</table>\n";
- if ( $rcObj->mAttribs['rc_this_oldid'] != 0 ) {
- $params['oldid'] = $rcObj->mAttribs['rc_this_oldid'];
- }
+ $this->rcCacheIndex++;
- # Log timestamp
- if ( $type == RC_LOG ) {
- $link = $rcObj->timestamp;
- # Revision link
- } elseif ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
- $link = '<span class="history-deleted">' . $rcObj->timestamp . '</span> ';
- } else {
+ return $r;
+ }
- $link = Linker::linkKnown(
- $rcObj->getTitle(),
- $rcObj->timestamp,
- array(),
- $params
- );
- if ( $this->isDeleted( $rcObj, Revision::DELETED_TEXT ) ) {
- $link = '<span class="history-deleted">' . $link . '</span> ';
- }
+ /**
+ * @param RCCacheEntry[] $block
+ * @param RCCacheEntry $rcObj
+ * @param array $queryParams
+ * @return string
+ * @throws Exception
+ * @throws FatalError
+ * @throws MWException
+ */
+ protected function getLineData( array $block, RCCacheEntry $rcObj, array $queryParams = array() ) {
+ $RCShowChangedSize = $this->getConfig()->get( 'RCShowChangedSize' );
+
+ # Classes to apply -- TODO implement
+ $classes = array();
+ $type = $rcObj->mAttribs['rc_type'];
+ $data = array();
+
+ $trClass = $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
+ ? ' class="mw-enhanced-watched"' : '';
+ $separator = ' <span class="mw-changeslist-separator">. .</span> ';
+
+ $data['recentChangesFlags'] = array(
+ 'newpage' => $type == RC_NEW,
+ 'minor' => $rcObj->mAttribs['rc_minor'],
+ 'unpatrolled' => $rcObj->unpatrolled,
+ 'bot' => $rcObj->mAttribs['rc_bot'],
+ );
+
+ $params = $queryParams;
+
+ if ( $rcObj->mAttribs['rc_this_oldid'] != 0 ) {
+ $params['oldid'] = $rcObj->mAttribs['rc_this_oldid'];
+ }
+
+ # Log timestamp
+ if ( $type == RC_LOG ) {
+ $link = $rcObj->timestamp;
+ # Revision link
+ } elseif ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
+ $link = '<span class="history-deleted">' . $rcObj->timestamp . '</span> ';
+ } else {
+ $link = Linker::linkKnown(
+ $rcObj->getTitle(),
+ $rcObj->timestamp,
+ array(),
+ $params
+ );
+ if ( $this->isDeleted( $rcObj, Revision::DELETED_TEXT ) ) {
+ $link = '<span class="history-deleted">' . $link . '</span> ';
}
- $r .= $link . '</span>';
+ }
+ $data['timestampLink'] = $link;
- if ( !$type == RC_LOG || $type == RC_NEW ) {
- $r .= ' ' . $this->msg( 'parentheses' )->rawParams(
+ $currentAndLastLinks = '';
+ if ( !$type == RC_LOG || $type == RC_NEW ) {
+ $currentAndLastLinks .= ' ' . $this->msg( 'parentheses' )->rawParams(
$rcObj->curlink .
- $this->message['pipe-separator'] .
- $rcObj->lastlink
+ $this->message['pipe-separator'] .
+ $rcObj->lastlink
)->escaped();
- }
- $r .= ' <span class="mw-changeslist-separator">. .</span> ';
+ }
+ $data['currentAndLastLinks'] = $currentAndLastLinks;
+ $data['separatorAfterCurrentAndLastLinks'] = $separator;
- # Character diff
- if ( $RCShowChangedSize ) {
- $cd = $this->formatCharacterDifference( $rcObj );
- if ( $cd !== '' ) {
- $r .= $cd . ' <span class="mw-changeslist-separator">. .</span> ';
- }
+ # Character diff
+ if ( $RCShowChangedSize ) {
+ $cd = $this->formatCharacterDifference( $rcObj );
+ if ( $cd !== '' ) {
+ $data['characterDiff'] = $cd;
+ $data['separatorAfterCharacterDiff'] = $separator;
}
+ }
- if ( $rcObj->mAttribs['rc_type'] == RC_LOG ) {
- $r .= $this->insertLogEntry( $rcObj );
- } else {
- # User links
- $r .= $rcObj->userlink;
- $r .= $rcObj->usertalklink;
- $r .= $this->insertComment( $rcObj );
- }
+ if ( $rcObj->mAttribs['rc_type'] == RC_LOG ) {
+ $data['logEntry'] = $this->insertLogEntry( $rcObj );
+ } else {
+ # User links
+ $data['userLink'] = $rcObj->userlink;
+ $data['userTalkLink'] = $rcObj->usertalklink;
+ $data['comment'] = $this->insertComment( $rcObj );
+ }
+
+ # Rollback
+ $data['rollback'] = $this->getRollback( $rcObj );
- # Rollback
- $this->insertRollback( $r, $rcObj );
- # Tags
- $this->insertTags( $r, $rcObj, $classes );
+ # Tags
+ $data['tags'] = $this->getTags( $rcObj, $classes );
- $r .= "</td></tr>\n";
+ // give the hook a chance to modify the data
+ $success = Hooks::run( 'EnhancedChangesListModifyLineData',
+ array( $this, &$data, $block, $rcObj ) );
+ if ( !$success ) {
+ // skip entry if hook aborted it
+ return '';
}
- $r .= "</table>\n";
- $this->rcCacheIndex++;
+ $line = '<tr' . $trClass . '><td></td><td class="mw-enhanced-rc">';
+ if ( isset( $data['recentChangesFlags'] ) ) {
+ $line .= $this->recentChangesFlags( $data['recentChangesFlags'] );
+ unset( $data['recentChangesFlags'] );
+ }
+ $line .= '&#160;</td><td class="mw-enhanced-rc-nested">';
- return $r;
+ if ( isset( $data['timestampLink'] ) ) {
+ $line .= '<span class="mw-enhanced-rc-time">' . $data['timestampLink'] . '</span>';
+ unset( $data['timestampLink'] );
+ }
+
+ // everything else: makes it easier for extensions to add or remove data
+ $line .= implode( '', $data );
+
+ $line .= "</td></tr>\n";
+
+ return $line;
}
/**
@@ -498,6 +557,8 @@ class EnhancedChangesList extends ChangesList {
* @return string A HTML formatted line (generated using $r)
*/
protected function recentChangesBlockLine( $rcObj ) {
+ $data = array();
+
$query['curid'] = $rcObj->mAttribs['rc_cur_id'];
$type = $rcObj->mAttribs['rc_type'];
@@ -512,32 +573,33 @@ class EnhancedChangesList extends ChangesList {
}
$classes[] = $rcObj->watched && $rcObj->mAttribs['rc_timestamp'] >= $rcObj->watched
? 'mw-changeslist-line-watched' : 'mw-changeslist-line-not-watched';
- $r = Html::openElement( 'table', array( 'class' => $classes ) ) .
- Html::openElement( 'tr' );
- $r .= '<td class="mw-enhanced-rc"><span class="mw-enhancedchanges-arrow-space"></span>';
# Flag and Timestamp
- $r .= $this->recentChangesFlags( array(
+ $data['recentChangesFlags'] = array(
'newpage' => $type == RC_NEW,
'minor' => $rcObj->mAttribs['rc_minor'],
'unpatrolled' => $rcObj->unpatrolled,
'bot' => $rcObj->mAttribs['rc_bot'],
- ) );
- $r .= '&#160;' . $rcObj->timestamp . '&#160;</td><td>';
+ );
+ // timestamp is not really a link here, but is called timestampLink
+ // for consistency with EnhancedChangesListModifyLineData
+ $data['timestampLink'] = $rcObj->timestamp;
+
# Article or log link
if ( $logType ) {
$logPage = new LogPage( $logType );
$logTitle = SpecialPage::getTitleFor( 'Log', $logType );
$logName = $logPage->getName()->escaped();
- $r .= $this->msg( 'parentheses' )
+ $data['logLink'] = $this->msg( 'parentheses' )
->rawParams( Linker::linkKnown( $logTitle, $logName ) )->escaped();
} else {
- $this->insertArticleLink( $r, $rcObj, $rcObj->unpatrolled, $rcObj->watched );
+ $data['articleLink'] = $this->getArticleLink( $rcObj, $rcObj->unpatrolled, $rcObj->watched );
}
+
# Diff and hist links
if ( $type != RC_LOG ) {
$query['action'] = 'history';
- $r .= ' ' . $this->msg( 'parentheses' )
+ $data['historyLink'] = ' ' . $this->msg( 'parentheses' )
->rawParams( $rcObj->difflink . $this->message['pipe-separator'] . Linker::linkKnown(
$rcObj->getTitle(),
$this->message['hist'],
@@ -545,31 +607,61 @@ class EnhancedChangesList extends ChangesList {
$query
) )->escaped();
}
- $r .= ' <span class="mw-changeslist-separator">. .</span> ';
+ $data['separatorAfterLinks'] = ' <span class="mw-changeslist-separator">. .</span> ';
+
# Character diff
if ( $this->getConfig()->get( 'RCShowChangedSize' ) ) {
$cd = $this->formatCharacterDifference( $rcObj );
if ( $cd !== '' ) {
- $r .= $cd . ' <span class="mw-changeslist-separator">. .</span> ';
+ $data['characterDiff'] = $cd;
+ $data['separatorAftercharacterDiff'] = ' <span class="mw-changeslist-separator">. .</span> ';
}
}
if ( $type == RC_LOG ) {
- $r .= $this->insertLogEntry( $rcObj );
+ $data['logEntry'] = $this->insertLogEntry( $rcObj );
} else {
- $r .= ' ' . $rcObj->userlink . $rcObj->usertalklink;
- $r .= $this->insertComment( $rcObj );
- $this->insertRollback( $r, $rcObj );
+ $data['userLink'] = $rcObj->userlink;
+ $data['userTalkLink'] = $rcObj->usertalklink;
+ $data['comment'] = $this->insertComment( $rcObj );
+ $data['rollback'] = $this->getRollback( $rcObj );
}
# Tags
- $this->insertTags( $r, $rcObj, $classes );
+ $data['tags'] = $this->getTags( $rcObj, $classes );
+
# Show how many people are watching this if enabled
- $r .= $this->numberofWatchingusers( $rcObj->numberofWatchingusers );
+ $data['watchingUsers'] = $this->numberofWatchingusers( $rcObj->numberofWatchingusers );
- $r .= "</td></tr></table>\n";
+ // give the hook a chance to modify the data
+ $success = Hooks::run( 'EnhancedChangesListModifyBlockLineData',
+ array( $this, &$data, $rcObj ) );
+ if ( !$success ) {
+ // skip entry if hook aborted it
+ return '';
+ }
- return $r;
+ $line = Html::openElement( 'table', array( 'class' => $classes ) ) .
+ Html::openElement( 'tr' );
+ $line .= '<td class="mw-enhanced-rc"><span class="mw-enhancedchanges-arrow-space"></span>';
+
+ if ( isset( $data['recentChangesFlags'] ) ) {
+ $line .= $this->recentChangesFlags( $data['recentChangesFlags'] );
+ unset( $data['recentChangesFlags'] );
+ }
+
+ if ( isset( $data['timestampLink'] ) ) {
+ $line .= '&#160;' . $data['timestampLink'];
+ unset( $data['timestampLink'] );
+ }
+ $line .= '&#160;</td><td>';
+
+ // everything else: makes it easier for extensions to add or remove data
+ $line .= implode( '', $data );
+
+ $line .= "</td></tr></table>\n";
+
+ return $line;
}
/**
diff --git a/includes/changes/RecentChange.php b/includes/changes/RecentChange.php
index b430bab9..87871f49 100644
--- a/includes/changes/RecentChange.php
+++ b/includes/changes/RecentChange.php
@@ -89,6 +89,16 @@ class RecentChange {
*/
public $counter = -1;
+ /**
+ * @var array Array of change types
+ */
+ private static $changeTypes = array(
+ 'edit' => RC_EDIT,
+ 'new' => RC_NEW,
+ 'log' => RC_LOG,
+ 'external' => RC_EXTERNAL,
+ );
+
# Factory methods
/**
@@ -119,18 +129,10 @@ class RecentChange {
return $retval;
}
- switch ( $type ) {
- case 'edit':
- return RC_EDIT;
- case 'new':
- return RC_NEW;
- case 'log':
- return RC_LOG;
- case 'external':
- return RC_EXTERNAL;
- default:
- throw new MWException( "Unknown type '$type'" );
+ if ( !array_key_exists( $type, self::$changeTypes ) ) {
+ throw new MWException( "Unknown type '$type'" );
}
+ return self::$changeTypes[$type];
}
/**
@@ -140,31 +142,25 @@ class RecentChange {
* @return string $type
*/
public static function parseFromRCType( $rcType ) {
- switch ( $rcType ) {
- case RC_EDIT:
- $type = 'edit';
- break;
- case RC_NEW:
- $type = 'new';
- break;
- case RC_LOG:
- $type = 'log';
- break;
- case RC_EXTERNAL:
- $type = 'external';
- break;
- default:
- $type = "$rcType";
- }
+ return array_search( $rcType, self::$changeTypes, true ) ?: "$rcType";
+ }
- return $type;
+ /**
+ * Get an array of all change types
+ *
+ * @since 1.26
+ *
+ * @return array
+ */
+ public static function getChangeTypes() {
+ return array_keys( self::$changeTypes );
}
/**
* Obtain the recent change with a given rc_id value
*
* @param int $rcid The rc_id value to retrieve
- * @return RecentChange
+ * @return RecentChange|null
*/
public static function newFromId( $rcid ) {
return self::newFromConds( array( 'rc_id' => $rcid ), __METHOD__ );
@@ -176,7 +172,7 @@ class RecentChange {
* @param array $conds Array of conditions
* @param mixed $fname Override the method name in profiling/logs
* @param array $options Query options
- * @return RecentChange
+ * @return RecentChange|null
*/
public static function newFromConds( $conds, $fname = __METHOD__, $options = array() ) {
$dbr = wfGetDB( DB_SLAVE );
@@ -332,6 +328,11 @@ class RecentChange {
$this->mExtra['pageStatus'] );
}
}
+
+ // Update the cached list of active users
+ if ( $this->mAttribs['rc_user'] > 0 ) {
+ JobQueueGroup::singleton()->lazyPush( RecentChangesUpdateJob::newCacheUpdateJob() );
+ }
}
/**
@@ -377,6 +378,13 @@ class RecentChange {
/** @var $formatter RCFeedFormatter */
$formatter = is_object( $feed['formatter'] ) ? $feed['formatter'] : new $feed['formatter']();
$line = $formatter->getLine( $feed, $this, $actionComment );
+ if ( !$line ) {
+ // T109544
+ // If a feed formatter returns null, this will otherwise cause an
+ // error in at least RedisPubSubFeedEngine.
+ // Not sure where/how this should best be handled.
+ continue;
+ }
$engine->send( $feed, $line );
}
@@ -512,8 +520,10 @@ class RecentChange {
* @param int $patrol
* @return RecentChange
*/
- public static function notifyEdit( $timestamp, &$title, $minor, &$user, $comment, $oldId,
- $lastTimestamp, $bot, $ip = '', $oldSize = 0, $newSize = 0, $newId = 0, $patrol = 0 ) {
+ public static function notifyEdit(
+ $timestamp, &$title, $minor, &$user, $comment, $oldId, $lastTimestamp,
+ $bot, $ip = '', $oldSize = 0, $newSize = 0, $newId = 0, $patrol = 0
+ ) {
$rc = new RecentChange;
$rc->mTitle = $title;
$rc->mPerformer = $user;
@@ -550,7 +560,13 @@ class RecentChange {
'newSize' => $newSize,
'pageStatus' => 'changed'
);
- $rc->save();
+
+ DeferredUpdates::addCallableUpdate( function() use ( $rc ) {
+ $rc->save();
+ if ( $rc->mAttribs['rc_patrolled'] ) {
+ PatrolLog::record( $rc, true, $rc->getPerformer() );
+ }
+ } );
return $rc;
}
@@ -571,8 +587,10 @@ class RecentChange {
* @param int $patrol
* @return RecentChange
*/
- public static function notifyNew( $timestamp, &$title, $minor, &$user, $comment, $bot,
- $ip = '', $size = 0, $newId = 0, $patrol = 0 ) {
+ public static function notifyNew(
+ $timestamp, &$title, $minor, &$user, $comment, $bot,
+ $ip = '', $size = 0, $newId = 0, $patrol = 0
+ ) {
$rc = new RecentChange;
$rc->mTitle = $title;
$rc->mPerformer = $user;
@@ -609,7 +627,13 @@ class RecentChange {
'newSize' => $size,
'pageStatus' => 'created'
);
- $rc->save();
+
+ DeferredUpdates::addCallableUpdate( function() use ( $rc ) {
+ $rc->save();
+ if ( $rc->mAttribs['rc_patrolled'] ) {
+ PatrolLog::record( $rc, true, $rc->getPerformer() );
+ }
+ } );
return $rc;
}
@@ -827,4 +851,21 @@ class RecentChange {
return wfTimestamp( TS_UNIX, $timestamp ) > time() - $tolerance - $wgRCMaxAge;
}
+
+ /**
+ * Parses and returns the rc_params attribute
+ *
+ * @since 1.26
+ *
+ * @return array|null
+ */
+ public function parseParams() {
+ $rcParams = $this->getAttribute( 'rc_params' );
+
+ MediaWiki\suppressWarnings();
+ $unserializedParams = unserialize( $rcParams );
+ MediaWiki\restoreWarnings();
+
+ return $unserializedParams;
+ }
}
diff --git a/includes/ChangeTags.php b/includes/changetags/ChangeTags.php
index 09665dfb..12f738fe 100644
--- a/includes/ChangeTags.php
+++ b/includes/changetags/ChangeTags.php
@@ -51,14 +51,26 @@ class ChangeTags {
$tags = explode( ',', $tags );
$displayTags = array();
foreach ( $tags as $tag ) {
+ if ( !$tag ) {
+ continue;
+ }
+ $description = self::tagDescription( $tag );
+ if ( $description === false ) {
+ continue;
+ }
$displayTags[] = Xml::tags(
'span',
array( 'class' => 'mw-tag-marker ' .
Sanitizer::escapeClass( "mw-tag-marker-$tag" ) ),
- self::tagDescription( $tag )
+ $description
);
$classes[] = Sanitizer::escapeClass( "mw-tag-$tag" );
}
+
+ if ( !$displayTags ) {
+ return array( '', array() );
+ }
+
$markers = wfMessage( 'tag-list-wrapper' )
->numParams( count( $displayTags ) )
->rawParams( $wgLang->commaList( $displayTags ) )
@@ -69,16 +81,30 @@ class ChangeTags {
}
/**
- * Get a short description for a tag
+ * Get a short description for a tag.
*
- * @param string $tag Tag
+ * Checks if message key "mediawiki:tag-$tag" exists. If it does not,
+ * returns the HTML-escaped tag name. Uses the message if the message
+ * exists, provided it is not disabled. If the message is disabled,
+ * we consider the tag hidden, and return false.
*
- * @return string Short description of the tag from "mediawiki:tag-$tag" if this message exists,
- * html-escaped version of $tag otherwise
+ * @param string $tag Tag
+ * @return string|bool Tag description or false if tag is to be hidden.
+ * @since 1.25 Returns false if tag is to be hidden.
*/
public static function tagDescription( $tag ) {
$msg = wfMessage( "tag-$tag" );
- return $msg->exists() ? $msg->parse() : htmlspecialchars( $tag );
+ if ( !$msg->exists() ) {
+ // No such message, so return the HTML-escaped tag name.
+ return htmlspecialchars( $tag );
+ }
+ if ( $msg->isDisabled() ) {
+ // The message exists but is disabled, hide the tag.
+ return false;
+ }
+
+ // Message exists and isn't disabled, use it.
+ return $msg->parse();
}
/**
@@ -127,8 +153,10 @@ class ChangeTags {
*
* @since 1.25
*/
- public static function updateTags( $tagsToAdd, $tagsToRemove, &$rc_id = null,
- &$rev_id = null, &$log_id = null, $params = null ) {
+ public static function updateTags(
+ $tagsToAdd, $tagsToRemove,
+ &$rc_id = null, &$rev_id = null, &$log_id = null, $params = null
+ ) {
$tagsToAdd = array_filter( (array)$tagsToAdd ); // Make sure we're submitting all tags...
$tagsToRemove = array_filter( (array)$tagsToRemove );
@@ -143,18 +171,28 @@ class ChangeTags {
// Might as well look for rcids and so on.
if ( !$rc_id ) {
// Info might be out of date, somewhat fractionally, on slave.
+ // LogEntry/LogPage and WikiPage match rev/log/rc timestamps,
+ // so use that relation to avoid full table scans.
if ( $log_id ) {
$rc_id = $dbw->selectField(
- 'recentchanges',
+ array( 'logging', 'recentchanges' ),
'rc_id',
- array( 'rc_logid' => $log_id ),
+ array(
+ 'log_id' => $log_id,
+ 'rc_timestamp = log_timestamp',
+ 'rc_logid = log_id'
+ ),
__METHOD__
);
} elseif ( $rev_id ) {
$rc_id = $dbw->selectField(
- 'recentchanges',
+ array( 'revision', 'recentchanges' ),
'rc_id',
- array( 'rc_this_oldid' => $rev_id ),
+ array(
+ 'rev_id' => $rev_id,
+ 'rc_timestamp = rev_timestamp',
+ 'rc_this_oldid = rev_id'
+ ),
__METHOD__
);
}
@@ -356,8 +394,9 @@ class ChangeTags {
* @return Status
* @since 1.25
*/
- public static function addTagsAccompanyingChangeWithChecks( array $tags,
- $rc_id, $rev_id, $log_id, $params, User $user ) {
+ public static function addTagsAccompanyingChangeWithChecks(
+ array $tags, $rc_id, $rev_id, $log_id, $params, User $user
+ ) {
// are we allowed to do this?
$result = self::canAddTagsAccompanyingChange( $tags, $user );
@@ -367,7 +406,7 @@ class ChangeTags {
}
// do it!
- self::addTags( $tagsToAdd, $rc_id, $rev_id, $log_id, $params );
+ self::addTags( $tags, $rc_id, $rev_id, $log_id, $params );
return Status::newGood( true );
}
@@ -390,21 +429,23 @@ class ChangeTags {
return Status::newFatal( 'tags-update-no-permission' );
}
- // to be added, a tag has to be explicitly defined
- // @todo Allow extensions to define tags that can be applied by users...
- $explicitlyDefinedTags = self::listExplicitlyDefinedTags();
- $diff = array_diff( $tagsToAdd, $explicitlyDefinedTags );
- if ( $diff ) {
- return self::restrictedTagError( 'tags-update-add-not-allowed-one',
- 'tags-update-add-not-allowed-multi', $diff );
+ if ( $tagsToAdd ) {
+ // to be added, a tag has to be explicitly defined
+ // @todo Allow extensions to define tags that can be applied by users...
+ $explicitlyDefinedTags = self::listExplicitlyDefinedTags();
+ $diff = array_diff( $tagsToAdd, $explicitlyDefinedTags );
+ if ( $diff ) {
+ return self::restrictedTagError( 'tags-update-add-not-allowed-one',
+ 'tags-update-add-not-allowed-multi', $diff );
+ }
}
- // to be removed, a tag has to be either explicitly defined or not defined
- // at all
- $definedTags = self::listDefinedTags();
- $diff = array_diff( $tagsToRemove, $explicitlyDefinedTags );
- if ( $diff ) {
- $intersect = array_intersect( $diff, $definedTags );
+ if ( $tagsToRemove ) {
+ // to be removed, a tag must not be defined by an extension, or equivalently it
+ // has to be either explicitly defined or not defined at all
+ // (assuming no edge case of a tag both explicitly-defined and extension-defined)
+ $extensionDefinedTags = self::listExtensionDefinedTags();
+ $intersect = array_intersect( $tagsToRemove, $extensionDefinedTags );
if ( $intersect ) {
return self::restrictedTagError( 'tags-update-remove-not-allowed-one',
'tags-update-remove-not-allowed-multi', $intersect );
@@ -491,7 +532,6 @@ class ChangeTags {
if ( $rev_id ) {
$rev = Revision::newFromId( $rev_id );
if ( $rev ) {
- $title = $rev->getTitle();
$logEntry->setTarget( $rev->getTitle() );
}
} elseif ( $log_id ) {
@@ -583,17 +623,16 @@ class ChangeTags {
* Build a text box to select a change tag
*
* @param string $selected Tag to select by default
- * @param bool $fullForm
- * - if false, then it returns an array of (label, form).
- * - if true, it returns an entire form around the selector.
- * @param Title $title Title object to send the form to.
- * Used when, and only when $fullForm is true.
+ * @param bool $fullForm Affects return value, see below
+ * @param Title $title Title object to send the form to. Used only if $fullForm is true.
+ * @param bool $ooui Use an OOUI TextInputWidget as selector instead of a non-OOUI input field
+ * You need to call OutputPage::enableOOUI() yourself.
* @return string|array
- * - if $fullForm is false: Array with
- * - if $fullForm is true: String, html fragment
+ * - if $fullForm is false: an array of (label, selector).
+ * - if $fullForm is true: HTML of entire form built around the selector.
*/
public static function buildTagFilterSelector( $selected = '',
- $fullForm = false, Title $title = null
+ $fullForm = false, Title $title = null, $ooui = false
) {
global $wgUseTagFilter;
@@ -606,14 +645,24 @@ class ChangeTags {
'label',
array( 'for' => 'tagfilter' ),
wfMessage( 'tag-filter' )->parse()
- ),
- Xml::input(
+ )
+ );
+
+ if ( $ooui ) {
+ $data[] = new OOUI\TextInputWidget( array(
+ 'id' => 'tagfilter',
+ 'name' => 'tagfilter',
+ 'value' => $selected,
+ 'classes' => 'mw-tagfilter-input',
+ ) );
+ } else {
+ $data[] = Xml::input(
'tagfilter',
20,
$selected,
array( 'class' => 'mw-tagfilter-input mw-ui-input mw-ui-input-inline', 'id' => 'tagfilter' )
- )
- );
+ );
+ }
if ( !$fullForm ) {
return $data;
@@ -680,6 +729,7 @@ class ChangeTags {
* @param User $user Who to attribute the action to
* @param int $tagCount For deletion only, how many usages the tag had before
* it was deleted.
+ * @return int ID of the inserted log entry
* @since 1.25
*/
protected static function logTagManagementAction( $action, $tag, $reason,
@@ -720,12 +770,6 @@ class ChangeTags {
return Status::newFatal( 'tags-manage-no-permission' );
}
- // non-existing tags cannot be activated
- $tagUsage = self::tagUsageStatistics();
- if ( !isset( $tagUsage[$tag] ) ) {
- return Status::newFatal( 'tags-activate-not-found', $tag );
- }
-
// defined tags cannot be activated (a defined tag is either extension-
// defined, in which case the extension chooses whether or not to active it;
// or user-defined, in which case it is considered active)
@@ -734,6 +778,12 @@ class ChangeTags {
return Status::newFatal( 'tags-activate-not-allowed', $tag );
}
+ // non-existing tags cannot be activated
+ $tagUsage = self::tagUsageStatistics();
+ if ( !isset( $tagUsage[$tag] ) ) { // we already know the tag is undefined
+ return Status::newFatal( 'tags-activate-not-found', $tag );
+ }
+
return Status::newGood();
}
@@ -858,7 +908,7 @@ class ChangeTags {
// does the tag already exist?
$tagUsage = self::tagUsageStatistics();
- if ( isset( $tagUsage[$tag] ) ) {
+ if ( isset( $tagUsage[$tag] ) || in_array( $tag, self::listDefinedTags() ) ) {
return Status::newFatal( 'tags-create-already-exists', $tag );
}
@@ -914,7 +964,7 @@ class ChangeTags {
*/
public static function deleteTagEverywhere( $tag ) {
$dbw = wfGetDB( DB_MASTER );
- $dbw->begin( __METHOD__ );
+ $dbw->startAtomic( __METHOD__ );
// delete from valid_tag
self::undefineTag( $tag );
@@ -935,7 +985,7 @@ class ChangeTags {
// delete from change_tag
$dbw->delete( 'change_tag', array( 'ct_tag' => $tag ), __METHOD__ );
- $dbw->commit( __METHOD__ );
+ $dbw->endAtomic( __METHOD__ );
// give extensions a chance
$status = Status::newGood();
@@ -968,11 +1018,11 @@ class ChangeTags {
return Status::newFatal( 'tags-manage-no-permission' );
}
- if ( !isset( $tagUsage[$tag] ) ) {
+ if ( !isset( $tagUsage[$tag] ) && !in_array( $tag, self::listDefinedTags() ) ) {
return Status::newFatal( 'tags-delete-not-found', $tag );
}
- if ( $tagUsage[$tag] > self::MAX_DELETE_USES ) {
+ if ( isset( $tagUsage[$tag] ) && $tagUsage[$tag] > self::MAX_DELETE_USES ) {
return Status::newFatal( 'tags-delete-too-many-uses', $tag, self::MAX_DELETE_USES );
}
@@ -1017,6 +1067,7 @@ class ChangeTags {
// store the tag usage statistics
$tagUsage = self::tagUsageStatistics();
+ $hitcount = isset( $tagUsage[$tag] ) ? $tagUsage[$tag] : 0;
// do it!
$deleteResult = self::deleteTagEverywhere( $tag );
@@ -1025,7 +1076,7 @@ class ChangeTags {
}
// log it
- $logId = self::logTagManagementAction( 'delete', $tag, $reason, $user, $tagUsage[$tag] );
+ $logId = self::logTagManagementAction( 'delete', $tag, $reason, $user, $hitcount );
$deleteResult->value = $logId;
return $deleteResult;
}
@@ -1037,21 +1088,18 @@ class ChangeTags {
* @since 1.25
*/
public static function listExtensionActivatedTags() {
- // Caching...
- global $wgMemc;
- $key = wfMemcKey( 'active-tags' );
- $tags = $wgMemc->get( $key );
- if ( $tags ) {
- return $tags;
- }
-
- // ask extensions which tags they consider active
- $extensionActive = array();
- Hooks::run( 'ChangeTagsListActive', array( &$extensionActive ) );
-
- // Short-term caching.
- $wgMemc->set( $key, $extensionActive, 300 );
- return $extensionActive;
+ return ObjectCache::getMainWANInstance()->getWithSetCallback(
+ wfMemcKey( 'active-tags' ),
+ function() {
+ // Ask extensions which tags they consider active
+ $extensionActive = array();
+ Hooks::run( 'ChangeTagsListActive', array( &$extensionActive ) );
+ return $extensionActive;
+ },
+ 300,
+ array( wfMemcKey( 'active-tags' ) ),
+ array( 'lockTSE' => INF )
+ );
}
/**
@@ -1078,28 +1126,21 @@ class ChangeTags {
* @since 1.25
*/
public static function listExplicitlyDefinedTags() {
- // Caching...
- global $wgMemc;
- $key = wfMemcKey( 'valid-tags-db' );
- $tags = $wgMemc->get( $key );
- if ( $tags ) {
- return $tags;
- }
-
- $emptyTags = array();
-
- // Some DB stuff
- $dbr = wfGetDB( DB_SLAVE );
- $res = $dbr->select( 'valid_tag', 'vt_tag', array(), __METHOD__ );
- foreach ( $res as $row ) {
- $emptyTags[] = $row->vt_tag;
- }
-
- $emptyTags = array_filter( array_unique( $emptyTags ) );
-
- // Short-term caching.
- $wgMemc->set( $key, $emptyTags, 300 );
- return $emptyTags;
+ $fname = __METHOD__;
+
+ return ObjectCache::getMainWANInstance()->getWithSetCallback(
+ wfMemcKey( 'valid-tags-db' ),
+ function() use ( $fname ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $tags = $dbr->selectFieldValues(
+ 'valid_tag', 'vt_tag', array(), $fname );
+
+ return array_filter( array_unique( $tags ) );
+ },
+ 300,
+ array( wfMemcKey( 'valid-tags-db' ) ),
+ array( 'lockTSE' => INF )
+ );
}
/**
@@ -1112,21 +1153,17 @@ class ChangeTags {
* @since 1.25
*/
public static function listExtensionDefinedTags() {
- // Caching...
- global $wgMemc;
- $key = wfMemcKey( 'valid-tags-hook' );
- $tags = $wgMemc->get( $key );
- if ( $tags ) {
- return $tags;
- }
-
- $emptyTags = array();
- Hooks::run( 'ListDefinedTags', array( &$emptyTags ) );
- $emptyTags = array_filter( array_unique( $emptyTags ) );
-
- // Short-term caching.
- $wgMemc->set( $key, $emptyTags, 300 );
- return $emptyTags;
+ return ObjectCache::getMainWANInstance()->getWithSetCallback(
+ wfMemcKey( 'valid-tags-hook' ),
+ function() {
+ $tags = array();
+ Hooks::run( 'ListDefinedTags', array( &$tags ) );
+ return array_filter( array_unique( $tags ) );
+ },
+ 300,
+ array( wfMemcKey( 'valid-tags-hook' ) ),
+ array( 'lockTSE' => INF )
+ );
}
/**
@@ -1135,10 +1172,12 @@ class ChangeTags {
* @since 1.25
*/
public static function purgeTagCacheAll() {
- global $wgMemc;
- $wgMemc->delete( wfMemcKey( 'active-tags' ) );
- $wgMemc->delete( wfMemcKey( 'valid-tags-db' ) );
- $wgMemc->delete( wfMemcKey( 'valid-tags-hook' ) );
+ $cache = ObjectCache::getMainWANInstance();
+
+ $cache->touchCheckKey( wfMemcKey( 'active-tags' ) );
+ $cache->touchCheckKey( wfMemcKey( 'valid-tags-db' ) );
+ $cache->touchCheckKey( wfMemcKey( 'valid-tags-hook' ) );
+
self::purgeTagUsageCache();
}
@@ -1147,13 +1186,15 @@ class ChangeTags {
* @since 1.25
*/
public static function purgeTagUsageCache() {
- global $wgMemc;
- $wgMemc->delete( wfMemcKey( 'change-tag-statistics' ) );
+ $cache = ObjectCache::getMainWANInstance();
+
+ $cache->touchCheckKey( wfMemcKey( 'change-tag-statistics' ) );
}
/**
* Returns a map of any tags used on the wiki to number of edits
* tagged with them, ordered descending by the hitcount.
+ * This does not include tags defined somewhere that have never been applied.
*
* Keeps a short-term cache in memory, so calling this multiple times in the
* same request should be fine.
@@ -1161,37 +1202,40 @@ class ChangeTags {
* @return array Array of string => int
*/
public static function tagUsageStatistics() {
- // Caching...
- global $wgMemc;
- $key = wfMemcKey( 'change-tag-statistics' );
- $stats = $wgMemc->get( $key );
- if ( $stats ) {
- return $stats;
+ static $cachedStats = null;
+
+ // Process cache to avoid I/O and repeated regens during holdoff
+ if ( $cachedStats !== null ) {
+ return $cachedStats;
}
- $out = array();
+ $fname = __METHOD__;
+ $cachedStats = ObjectCache::getMainWANInstance()->getWithSetCallback(
+ wfMemcKey( 'change-tag-statistics' ),
+ function() use ( $fname ) {
+ $out = array();
+
+ $dbr = wfGetDB( DB_SLAVE, 'vslow' );
+ $res = $dbr->select(
+ 'change_tag',
+ array( 'ct_tag', 'hitcount' => 'count(*)' ),
+ array(),
+ $fname,
+ array( 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' )
+ );
- $dbr = wfGetDB( DB_SLAVE );
- $res = $dbr->select(
- 'change_tag',
- array( 'ct_tag', 'hitcount' => 'count(*)' ),
- array(),
- __METHOD__,
- array( 'GROUP BY' => 'ct_tag', 'ORDER BY' => 'hitcount DESC' )
- );
+ foreach ( $res as $row ) {
+ $out[$row->ct_tag] = $row->hitcount;
+ }
- foreach ( $res as $row ) {
- $out[$row->ct_tag] = $row->hitcount;
- }
- foreach ( self::listDefinedTags() as $tag ) {
- if ( !isset( $out[$tag] ) ) {
- $out[$tag] = 0;
- }
- }
+ return $out;
+ },
+ 300,
+ array( wfMemcKey( 'change-tag-statistics' ) ),
+ array( 'lockTSE' => INF )
+ );
- // Cache for a very short time
- $wgMemc->set( $key, $out, 300 );
- return $out;
+ return $cachedStats;
}
/**
diff --git a/includes/changetags/ChangeTagsLogList.php b/includes/changetags/ChangeTagsLogList.php
index fe80695f..4526ee31 100644
--- a/includes/changetags/ChangeTagsLogList.php
+++ b/includes/changetags/ChangeTagsLogList.php
@@ -42,7 +42,8 @@ class ChangeTagsLogList extends ChangeTagsList {
$queryInfo['fields'],
$queryInfo['conds'],
$queryInfo['join_conds'],
- $queryInfo['options']
+ $queryInfo['options'],
+ ''
);
return $db->select(
$queryInfo['tables'],
diff --git a/includes/changetags/ChangeTagsRevisionList.php b/includes/changetags/ChangeTagsRevisionList.php
index 842d3272..ec401bc8 100644
--- a/includes/changetags/ChangeTagsRevisionList.php
+++ b/includes/changetags/ChangeTagsRevisionList.php
@@ -52,7 +52,8 @@ class ChangeTagsRevisionList extends ChangeTagsList {
$queryInfo['fields'],
$queryInfo['conds'],
$queryInfo['join_conds'],
- $queryInfo['options']
+ $queryInfo['options'],
+ ''
);
return $db->select(
$queryInfo['tables'],
diff --git a/includes/clientpool/RedisConnectionPool.php b/includes/clientpool/RedisConnectionPool.php
index dc95727d..ec0573ef 100644
--- a/includes/clientpool/RedisConnectionPool.php
+++ b/includes/clientpool/RedisConnectionPool.php
@@ -22,6 +22,10 @@
* @author Aaron Schulz
*/
+use MediaWiki\Logger\LoggerFactory;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+
/**
* Helper class to manage Redis connections.
*
@@ -35,7 +39,7 @@
* @ingroup Redis
* @since 1.21
*/
-class RedisConnectionPool {
+class RedisConnectionPool implements LoggerAwareInterface {
/**
* @name Pool settings.
* Settings there are shared for any connection made in this pool.
@@ -69,6 +73,11 @@ class RedisConnectionPool {
const SERVER_DOWN_TTL = 30;
/**
+ * @var LoggerInterface
+ */
+ protected $logger;
+
+ /**
* @param array $options
* @throws MWException
*/
@@ -77,6 +86,11 @@ class RedisConnectionPool {
throw new MWException( __CLASS__ . ' requires a Redis client library. ' .
'See https://www.mediawiki.org/wiki/Redis#Setup' );
}
+ if ( isset( $options['logger'] ) ) {
+ $this->setLogger( $options['logger'] );
+ } else {
+ $this->setLogger( LoggerFactory::getInstance( 'redis' ) );
+ }
$this->connectTimeout = $options['connectTimeout'];
$this->readTimeout = $options['readTimeout'];
$this->persistent = $options['persistent'];
@@ -93,6 +107,14 @@ class RedisConnectionPool {
}
/**
+ * @param LoggerInterface $logger
+ * @return null
+ */
+ public function setLogger( LoggerInterface $logger ) {
+ $this->logger = $logger;
+ }
+
+ /**
* @param array $options
* @return array
*/
@@ -136,7 +158,9 @@ class RedisConnectionPool {
// Initialize the object at the hash as needed...
if ( !isset( self::$instances[$id] ) ) {
self::$instances[$id] = new self( $options );
- wfDebug( "Creating a new " . __CLASS__ . " instance with id $id.\n" );
+ LoggerFactory::getInstance( 'redis' )->debug(
+ "Creating a new " . __CLASS__ . " instance with id $id."
+ );
}
return self::$instances[$id];
@@ -161,8 +185,11 @@ class RedisConnectionPool {
unset( $this->downServers[$server] );
} else {
// Server is dead
- wfDebug( "server $server is marked down for another " .
- ( $this->downServers[$server] - $now ) . " seconds, can't get connection\n" );
+ $this->logger->debug(
+ 'Server "{redis_server}" is marked down for another ' .
+ ( $this->downServers[$server] - $now ) . 'seconds',
+ array( 'redis_server' => $server )
+ );
return false;
}
@@ -175,7 +202,9 @@ class RedisConnectionPool {
$connection['free'] = false;
--$this->idlePoolSize;
- return new RedisConnRef( $this, $server, $connection['conn'] );
+ return new RedisConnRef(
+ $this, $server, $connection['conn'], $this->logger
+ );
}
}
}
@@ -189,7 +218,7 @@ class RedisConnectionPool {
} else {
// TCP connection
$hostPort = IP::splitHostAndPort( $server );
- if ( !$hostPort ) {
+ if ( !$server || !$hostPort ) {
throw new MWException( __CLASS__ . ": invalid configured server \"$server\"" );
}
list( $host, $port ) = $hostPort;
@@ -206,7 +235,10 @@ class RedisConnectionPool {
$result = $conn->connect( $host, $port, $this->connectTimeout );
}
if ( !$result ) {
- wfDebugLog( 'redis', "Could not connect to server $server" );
+ $this->logger->error(
+ 'Could not connect to server "{redis_server}"',
+ array( 'redis_server' => $server )
+ );
// Mark server down for some time to avoid further timeouts
$this->downServers[$server] = time() + self::SERVER_DOWN_TTL;
@@ -214,12 +246,21 @@ class RedisConnectionPool {
}
if ( $this->password !== null ) {
if ( !$conn->auth( $this->password ) ) {
- wfDebugLog( 'redis', "Authentication error connecting to $server" );
+ $this->logger->error(
+ 'Authentication error connecting to "{redis_server}"',
+ array( 'redis_server' => $server )
+ );
}
}
} catch ( RedisException $e ) {
$this->downServers[$server] = time() + self::SERVER_DOWN_TTL;
- wfDebugLog( 'redis', "Redis exception connecting to $server: " . $e->getMessage() );
+ $this->logger->error(
+ 'Redis exception connecting to "{redis_server}"',
+ array(
+ 'redis_server' => $server,
+ 'exception' => $e,
+ )
+ );
return false;
}
@@ -229,7 +270,7 @@ class RedisConnectionPool {
$conn->setOption( Redis::OPT_SERIALIZER, $this->serializer );
$this->connections[$server][] = array( 'conn' => $conn, 'free' => false );
- return new RedisConnRef( $this, $server, $conn );
+ return new RedisConnRef( $this, $server, $conn, $this->logger );
} else {
return false;
}
@@ -290,7 +331,7 @@ class RedisConnectionPool {
* @deprecated since 1.23
*/
public function handleException( $server, RedisConnRef $cref, RedisException $e ) {
- return $this->handleError( $cref, $e );
+ $this->handleError( $cref, $e );
}
/**
@@ -304,7 +345,13 @@ class RedisConnectionPool {
*/
public function handleError( RedisConnRef $cref, RedisException $e ) {
$server = $cref->getServer();
- wfDebugLog( 'redis', "Redis exception on server $server: " . $e->getMessage() . "\n" );
+ $this->logger->error(
+ 'Redis exception on server "{redis_server}"',
+ array(
+ 'redis_server' => $server,
+ 'exception' => $e,
+ )
+ );
foreach ( $this->connections[$server] as $key => $connection ) {
if ( $cref->isConnIdentical( $connection['conn'] ) ) {
$this->idlePoolSize -= $connection['free'] ? 1 : 0;
@@ -333,7 +380,10 @@ class RedisConnectionPool {
public function reauthenticateConnection( $server, Redis $conn ) {
if ( $this->password !== null ) {
if ( !$conn->auth( $this->password ) ) {
- wfDebugLog( 'redis', "Authentication error connecting to $server" );
+ $this->logger->error(
+ 'Authentication error connecting to "{redis_server}"',
+ array( 'redis_server' => $server )
+ );
return false;
}
@@ -382,14 +432,21 @@ class RedisConnRef {
protected $lastError; // string
/**
+ * @var LoggerInterface
+ */
+ protected $logger;
+
+ /**
* @param RedisConnectionPool $pool
* @param string $server
* @param Redis $conn
+ * @param LoggerInterface $logger
*/
- public function __construct( RedisConnectionPool $pool, $server, Redis $conn ) {
+ public function __construct( RedisConnectionPool $pool, $server, Redis $conn, LoggerInterface $logger ) {
$this->pool = $pool;
$this->server = $server;
$this->conn = $conn;
+ $this->logger = $logger;
}
/**
@@ -428,7 +485,10 @@ class RedisConnRef {
$this->pool->reauthenticateConnection( $this->server, $conn );
$conn->clearLastError();
$res = call_user_func_array( array( $conn, $name ), $arguments );
- wfDebugLog( 'redis', "Used automatic re-authentication for method '$name'." );
+ $this->logger->info(
+ "Used automatic re-authentication for method '$name'.",
+ array( 'redis_server' => $this->server )
+ );
}
} catch ( RedisException $e ) {
$this->pool->resetTimeout( $conn ); // restore
@@ -465,17 +525,29 @@ class RedisConnRef {
$this->pool->reauthenticateConnection( $server, $conn );
$conn->clearLastError();
$res = $conn->eval( $script, $params, $numKeys );
- wfDebugLog( 'redis', "Used automatic re-authentication for Lua script $sha1." );
+ $this->logger->info(
+ "Used automatic re-authentication for Lua script '$sha1'.",
+ array( 'redis_server' => $server )
+ );
}
// If the script is not in cache, use eval() to retry and cache it
if ( preg_match( '/^NOSCRIPT/', $conn->getLastError() ) ) {
$conn->clearLastError();
$res = $conn->eval( $script, $params, $numKeys );
- wfDebugLog( 'redis', "Used eval() for Lua script $sha1." );
+ $this->logger->info(
+ "Used eval() for Lua script '$sha1'.",
+ array( 'redis_server' => $server )
+ );
}
if ( $conn->getLastError() ) { // script bug?
- wfDebugLog( 'redis', "Lua script error on server $server: " . $conn->getLastError() );
+ $this->logger->error(
+ 'Lua script error on server "{redis_server}": {lua_error}',
+ array(
+ 'redis_server' => $server,
+ 'lua_error' => $conn->getLastError()
+ )
+ );
}
$this->lastError = $conn->getLastError() ?: $this->lastError;
diff --git a/includes/CdbCompat.php b/includes/compat/CdbCompat.php
index 0074cc96..0074cc96 100644
--- a/includes/CdbCompat.php
+++ b/includes/compat/CdbCompat.php
diff --git a/includes/compat/IPSetCompat.php b/includes/compat/IPSetCompat.php
new file mode 100644
index 00000000..79c60004
--- /dev/null
+++ b/includes/compat/IPSetCompat.php
@@ -0,0 +1,28 @@
+<?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
+ */
+
+/**
+ * Backward-compatibility alias for IPSet, which was moved out
+ * into an external library and namespaced.
+ *
+ * @deprecated since 1.26 use IPSet\IPSet directly
+ */
+class IPSet extends IPSet\IPSet {
+}
diff --git a/includes/libs/normal/UtfNormal.php b/includes/compat/normal/UtfNormal.php
index c9c05a07..c9c05a07 100644
--- a/includes/libs/normal/UtfNormal.php
+++ b/includes/compat/normal/UtfNormal.php
diff --git a/includes/libs/normal/UtfNormalDefines.php b/includes/compat/normal/UtfNormalDefines.php
index b8e44c77..b8e44c77 100644
--- a/includes/libs/normal/UtfNormalDefines.php
+++ b/includes/compat/normal/UtfNormalDefines.php
diff --git a/includes/libs/normal/UtfNormalUtil.php b/includes/compat/normal/UtfNormalUtil.php
index ad9a2b9a..9ed9bc24 100644
--- a/includes/libs/normal/UtfNormalUtil.php
+++ b/includes/compat/normal/UtfNormalUtil.php
@@ -27,6 +27,7 @@
use UtfNormal\Utils;
+
/**
* Return UTF-8 sequence for a given Unicode code point.
*
diff --git a/includes/config/ConfigFactory.php b/includes/config/ConfigFactory.php
index 12b0c399..b20794b1 100644
--- a/includes/config/ConfigFactory.php
+++ b/includes/config/ConfigFactory.php
@@ -46,6 +46,9 @@ class ConfigFactory {
*/
private static $self;
+ /**
+ * @return ConfigFactory
+ */
public static function getDefaultInstance() {
if ( !self::$self ) {
self::$self = new self;
diff --git a/includes/content/ContentHandler.php b/includes/content/ContentHandler.php
index 371b267e..bf91a4f0 100644
--- a/includes/content/ContentHandler.php
+++ b/includes/content/ContentHandler.php
@@ -207,26 +207,26 @@ abstract class ContentHandler {
}
}
- // Could this page contain custom CSS or JavaScript, based on the title?
- $isCssOrJsPage = NS_MEDIAWIKI == $ns && preg_match( '!\.(css|js)$!u', $title->getText(), $m );
- if ( $isCssOrJsPage ) {
+ // Could this page contain code based on the title?
+ $isCodePage = NS_MEDIAWIKI == $ns && preg_match( '!\.(css|js|json)$!u', $title->getText(), $m );
+ if ( $isCodePage ) {
$ext = $m[1];
}
// Hook can force JS/CSS
- Hooks::run( 'TitleIsCssOrJsPage', array( $title, &$isCssOrJsPage ), '1.25' );
+ Hooks::run( 'TitleIsCssOrJsPage', array( $title, &$isCodePage ), '1.25' );
- // Is this a .css subpage of a user page?
- $isJsCssSubpage = NS_USER == $ns
- && !$isCssOrJsPage
- && preg_match( "/\\/.*\\.(js|css)$/", $title->getText(), $m );
- if ( $isJsCssSubpage ) {
+ // Is this a user subpage containing code?
+ $isCodeSubpage = NS_USER == $ns
+ && !$isCodePage
+ && preg_match( "/\\/.*\\.(js|css|json)$/", $title->getText(), $m );
+ if ( $isCodeSubpage ) {
$ext = $m[1];
}
// Is this wikitext, according to $wgNamespaceContentModels or the DefaultModelFor hook?
$isWikitext = is_null( $model ) || $model == CONTENT_MODEL_WIKITEXT;
- $isWikitext = $isWikitext && !$isCssOrJsPage && !$isJsCssSubpage;
+ $isWikitext = $isWikitext && !$isCodePage && !$isCodeSubpage;
// Hook can override $isWikitext
Hooks::run( 'TitleIsWikitextPage', array( $title, &$isWikitext ), '1.25' );
@@ -237,6 +237,8 @@ abstract class ContentHandler {
return CONTENT_MODEL_JAVASCRIPT;
case 'css':
return CONTENT_MODEL_CSS;
+ case 'json':
+ return CONTENT_MODEL_JSON;
default:
return is_null( $model ) ? CONTENT_MODEL_TEXT : $model;
}
@@ -353,16 +355,20 @@ abstract class ContentHandler {
*
* @param string $name The content model ID, as given by a CONTENT_MODEL_XXX
* constant or returned by Revision::getContentModel().
+ * @param Language|null $lang The language to parse the message in (since 1.26)
*
* @throws MWException If the model ID isn't known.
* @return string The content model's localized name.
*/
- public static function getLocalizedName( $name ) {
+ public static function getLocalizedName( $name, Language $lang = null ) {
// Messages: content-model-wikitext, content-model-text,
// content-model-javascript, content-model-css
$key = "content-model-$name";
$msg = wfMessage( $key );
+ if ( $lang ) {
+ $msg->inLanguage( $lang );
+ }
return $msg->exists() ? $msg->plain() : $name;
}
@@ -629,7 +635,7 @@ abstract class ContentHandler {
// hook: get difference engine
$differenceEngine = null;
- if ( !wfRunHooks( 'GetDifferenceEngine',
+ if ( !Hooks::run( 'GetDifferenceEngine',
array( $context, $old, $new, $refreshCache, $unhide, &$differenceEngine )
) ) {
return $differenceEngine;
@@ -1021,7 +1027,7 @@ abstract class ContentHandler {
/**
* Returns true for content models that support caching using the
- * ParserCache mechanism. See WikiPage::isParserCacheUsed().
+ * ParserCache mechanism. See WikiPage::shouldCheckParserCache().
*
* @since 1.21
*
@@ -1058,6 +1064,24 @@ abstract class ContentHandler {
}
/**
+ * Return true if this content model supports direct editing, such as via EditPage.
+ *
+ * @return bool Default is false, and true for TextContent and it's derivatives.
+ */
+ public function supportsDirectEditing() {
+ return false;
+ }
+
+ /**
+ * Whether or not this content model supports direct editing via ApiEditPage
+ *
+ * @return bool Default is false, and true for TextContent and derivatives.
+ */
+ public function supportsDirectApiEditing() {
+ return $this->supportsDirectEditing();
+ }
+
+ /**
* Logs a deprecation warning, visible if $wgDevelopmentWarnings, but only if
* self::$enableDeprecationWarnings is set to true.
*
@@ -1112,7 +1136,7 @@ abstract class ContentHandler {
$handlers = Hooks::getHandlers( $event );
$handlerInfo = array();
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
foreach ( $handlers as $handler ) {
if ( is_array( $handler ) ) {
@@ -1135,7 +1159,7 @@ abstract class ContentHandler {
$handlerInfo[] = $info;
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
wfWarn( "Using obsolete hook $event via ContentHandler::runLegacyHooks()! Handlers: " .
implode( ', ', $handlerInfo ), 2 );
diff --git a/includes/content/CssContent.php b/includes/content/CssContent.php
index 8290603c..b4f5196d 100644
--- a/includes/content/CssContent.php
+++ b/includes/content/CssContent.php
@@ -33,6 +33,11 @@
class CssContent extends TextContent {
/**
+ * @var bool|Title|null
+ */
+ private $redirectTarget = false;
+
+ /**
* @param string $text CSS code.
* @param string $modelId the content content model
*/
@@ -74,4 +79,43 @@ class CssContent extends TextContent {
return $html;
}
+ /**
+ * @param Title $target
+ * @return CssContent
+ */
+ public function updateRedirect( Title $target ) {
+ if ( !$this->isRedirect() ) {
+ return $this;
+ }
+
+ return $this->getContentHandler()->makeRedirectContent( $target );
+ }
+
+ /**
+ * @return Title|null
+ */
+ public function getRedirectTarget() {
+ if ( $this->redirectTarget !== false ) {
+ return $this->redirectTarget;
+ }
+ $this->redirectTarget = null;
+ $text = $this->getNativeData();
+ if ( strpos( $text, '/* #REDIRECT */' ) === 0 ) {
+ // Extract the title from the url
+ preg_match( '/title=(.*?)&action=raw/', $text, $matches );
+ if ( isset( $matches[1] ) ) {
+ $title = Title::newFromText( $matches[1] );
+ if ( $title ) {
+ // Have a title, check that the current content equals what
+ // the redirect content should be
+ if ( $this->equals( $this->getContentHandler()->makeRedirectContent( $title ) ) ) {
+ $this->redirectTarget = $title;
+ }
+ }
+ }
+ }
+
+ return $this->redirectTarget;
+ }
+
}
diff --git a/includes/content/CssContentHandler.php b/includes/content/CssContentHandler.php
index b2a8676b..ae5f742a 100644
--- a/includes/content/CssContentHandler.php
+++ b/includes/content/CssContentHandler.php
@@ -39,4 +39,23 @@ class CssContentHandler extends CodeContentHandler {
protected function getContentClass() {
return 'CssContent';
}
+
+ public function supportsRedirects() {
+ return true;
+ }
+
+ /**
+ * Create a redirect that is also valid CSS
+ *
+ * @param Title $destination
+ * @param string $text ignored
+ * @return CssContent
+ */
+ public function makeRedirectContent( Title $destination, $text = '' ) {
+ // The parameters are passed as a string so the / is not url-encoded by wfArrayToCgi
+ $url = $destination->getFullURL( 'action=raw&ctype=text/css', false, PROTO_RELATIVE );
+ $class = $this->getContentClass();
+ return new $class( '/* #REDIRECT */@import ' . CSSMin::buildUrlValue( $url ) . ';' );
+ }
+
}
diff --git a/includes/content/JavaScriptContent.php b/includes/content/JavaScriptContent.php
index c0194c2e..6d236560 100644
--- a/includes/content/JavaScriptContent.php
+++ b/includes/content/JavaScriptContent.php
@@ -33,6 +33,11 @@
class JavaScriptContent extends TextContent {
/**
+ * @var bool|Title|null
+ */
+ private $redirectTarget = false;
+
+ /**
* @param string $text JavaScript code.
* @param string $modelId the content model name
*/
@@ -73,4 +78,46 @@ class JavaScriptContent extends TextContent {
return $html;
}
+ /**
+ * If this page is a redirect, return the content
+ * if it should redirect to $target instead
+ *
+ * @param Title $target
+ * @return JavaScriptContent
+ */
+ public function updateRedirect( Title $target ) {
+ if ( !$this->isRedirect() ) {
+ return $this;
+ }
+
+ return $this->getContentHandler()->makeRedirectContent( $target );
+ }
+
+ /**
+ * @return Title|null
+ */
+ public function getRedirectTarget() {
+ if ( $this->redirectTarget !== false ) {
+ return $this->redirectTarget;
+ }
+ $this->redirectTarget = null;
+ $text = $this->getNativeData();
+ if ( strpos( $text, '/* #REDIRECT */' ) === 0 ) {
+ // Extract the title from the url
+ preg_match( '/title=(.*?)\\\\u0026action=raw/', $text, $matches );
+ if ( isset( $matches[1] ) ) {
+ $title = Title::newFromText( $matches[1] );
+ if ( $title ) {
+ // Have a title, check that the current content equals what
+ // the redirect content should be
+ if ( $this->equals( $this->getContentHandler()->makeRedirectContent( $title ) ) ) {
+ $this->redirectTarget = $title;
+ }
+ }
+ }
+ }
+
+ return $this->redirectTarget;
+ }
+
}
diff --git a/includes/content/JavaScriptContentHandler.php b/includes/content/JavaScriptContentHandler.php
index d2218971..65e3a6f0 100644
--- a/includes/content/JavaScriptContentHandler.php
+++ b/includes/content/JavaScriptContentHandler.php
@@ -41,4 +41,22 @@ class JavaScriptContentHandler extends CodeContentHandler {
protected function getContentClass() {
return 'JavaScriptContent';
}
+
+ public function supportsRedirects() {
+ return true;
+ }
+
+ /**
+ * Create a redirect that is also valid JavaScript
+ *
+ * @param Title $destination
+ * @param string $text ignored
+ * @return JavaScriptContent
+ */
+ public function makeRedirectContent( Title $destination, $text = '' ) {
+ // The parameters are passed as a string so the / is not url-encoded by wfArrayToCgi
+ $url = $destination->getFullURL( 'action=raw&ctype=text/javascript', false, PROTO_RELATIVE );
+ $class = $this->getContentClass();
+ return new $class( '/* #REDIRECT */' . Xml::encodeJsCall( 'mw.loader.load', array( $url ) ) );
+ }
}
diff --git a/includes/content/TextContentHandler.php b/includes/content/TextContentHandler.php
index ffe1acbd..f5e87830 100644
--- a/includes/content/TextContentHandler.php
+++ b/includes/content/TextContentHandler.php
@@ -134,4 +134,13 @@ class TextContentHandler extends ContentHandler {
return new $class( '' );
}
+ /**
+ * @see ContentHandler::supportsDirectEditing
+ *
+ * @return bool Default is true for TextContent and derivatives.
+ */
+ public function supportsDirectEditing() {
+ return true;
+ }
+
}
diff --git a/includes/content/WikitextContent.php b/includes/content/WikitextContent.php
index dbe09f91..8beae393 100644
--- a/includes/content/WikitextContent.php
+++ b/includes/content/WikitextContent.php
@@ -82,7 +82,6 @@ class WikitextContent extends TextContent {
$text = $with->getNativeData();
if ( strval( $sectionId ) === '' ) {
-
return $with; # XXX: copy first?
}
@@ -273,12 +272,11 @@ class WikitextContent extends TextContent {
return false;
}
- $text = $this->getNativeData();
-
switch ( $wgArticleCountMethod ) {
case 'any':
return true;
case 'comma':
+ $text = $this->getNativeData();
return strpos( $text, ',' ) !== false;
case 'link':
if ( $hasLinks === null ) { # not known, find out
diff --git a/includes/context/ContextSource.php b/includes/context/ContextSource.php
index d526d84b..caf5afaa 100644
--- a/includes/context/ContextSource.php
+++ b/includes/context/ContextSource.php
@@ -168,6 +168,7 @@ abstract class ContextSource implements IContextSource {
* Parameters are the same as wfMessage()
*
* @since 1.18
+ * @param mixed ...
* @return Message
*/
public function msg( /* $args */ ) {
diff --git a/includes/context/DerivativeContext.php b/includes/context/DerivativeContext.php
index 00323cae..09c39396 100644
--- a/includes/context/DerivativeContext.php
+++ b/includes/context/DerivativeContext.php
@@ -26,7 +26,7 @@
* a different Title instance set on it.
* @since 1.19
*/
-class DerivativeContext extends ContextSource {
+class DerivativeContext extends ContextSource implements MutableContext {
/**
* @var WebRequest
*/
@@ -68,6 +68,11 @@ class DerivativeContext extends ContextSource {
private $config;
/**
+ * @var Stats
+ */
+ private $stats;
+
+ /**
* Constructor
* @param IContextSource $context Context to inherit from
*/
diff --git a/includes/context/IContextSource.php b/includes/context/IContextSource.php
index 713c5cbf..58bf5d98 100644
--- a/includes/context/IContextSource.php
+++ b/includes/context/IContextSource.php
@@ -132,8 +132,9 @@ interface IContextSource {
public function getStats();
/**
- * Get a Message object with context set
+ * Get a Message object with context set. See wfMessage for parameters.
*
+ * @param mixed ...
* @return Message
*/
public function msg();
diff --git a/includes/context/MutableContext.php b/includes/context/MutableContext.php
new file mode 100644
index 00000000..6358f11c
--- /dev/null
+++ b/includes/context/MutableContext.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Request-dependant objects containers.
+ *
+ * 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
+ *
+ * @since 1.26
+ *
+ * @file
+ */
+
+interface MutableContext {
+ /**
+ * Set the Config object
+ *
+ * @param Config $c
+ */
+ public function setConfig( Config $c );
+
+ /**
+ * Set the WebRequest object
+ *
+ * @param WebRequest $r
+ */
+ public function setRequest( WebRequest $r );
+
+ /**
+ * Set the Title object
+ *
+ * @param Title $t
+ */
+ public function setTitle( Title $t );
+
+ /**
+ * Set the WikiPage object
+ *
+ * @param WikiPage $p
+ */
+ public function setWikiPage( WikiPage $p );
+
+ /**
+ * Set the OutputPage object
+ *
+ * @param OutputPage $o
+ */
+ public function setOutput( OutputPage $o );
+
+ /**
+ * Set the User object
+ *
+ * @param User $u
+ */
+ public function setUser( User $u );
+
+ /**
+ * Set the Language object
+ *
+ * @param Language|string $l Language instance or language code
+ */
+ public function setLanguage( $l );
+
+ /**
+ * Set the Skin object
+ *
+ * @param Skin $s
+ */
+ public function setSkin( Skin $s );
+
+}
diff --git a/includes/context/RequestContext.php b/includes/context/RequestContext.php
index 4e790c04..93adde1f 100644
--- a/includes/context/RequestContext.php
+++ b/includes/context/RequestContext.php
@@ -25,7 +25,7 @@
/**
* Group all the pieces relevant to the context of a request into one instance
*/
-class RequestContext implements IContextSource {
+class RequestContext implements IContextSource, MutableContext {
/**
* @var WebRequest
*/
@@ -62,7 +62,7 @@ class RequestContext implements IContextSource {
private $skin;
/**
- * @var StatsdDataFactory
+ * @var \Liuggio\StatsdClient\Factory\StatsdDataFactory
*/
private $stats;
@@ -131,7 +131,7 @@ class RequestContext implements IContextSource {
public function getStats() {
if ( $this->stats === null ) {
$config = $this->getConfig();
- $prefix = $config->has( 'StatsdMetricPrefix' )
+ $prefix = $config->get( 'StatsdMetricPrefix' )
? rtrim( $config->get( 'StatsdMetricPrefix' ), '.' )
: 'MediaWiki';
$this->stats = new BufferingStatsdDataFactory( $prefix );
@@ -380,7 +380,6 @@ class RequestContext implements IContextSource {
*/
public function getSkin() {
if ( $this->skin === null ) {
-
$skin = null;
Hooks::run( 'RequestContextCreateSkin', array( $this, &$skin ) );
$factory = SkinFactory::getDefaultInstance();
@@ -428,6 +427,7 @@ class RequestContext implements IContextSource {
* Get a Message object with context set
* Parameters are the same as wfMessage()
*
+ * @param mixed ...
* @return Message
*/
public function msg() {
@@ -495,15 +495,17 @@ class RequestContext implements IContextSource {
/**
* Import an client IP address, HTTP headers, user ID, and session ID
*
- * This sets the current session and sets $wgUser and $wgRequest.
+ * This sets the current session, $wgUser, and $wgRequest from $params.
* Once the return value falls out of scope, the old context is restored.
- * This method should only be called in contexts (CLI or HTTP job runners)
- * where there is no session ID or end user receiving the response. This
+ * This method should only be called in contexts where there is no session
+ * ID or end user receiving the response (CLI or HTTP job runners). This
* is partly enforced, and is done so to avoid leaking cookies if certain
* error conditions arise.
*
- * This will setup the session from the given ID. This is useful when
- * background scripts inherit context when acting on behalf of a user.
+ * This is useful when background scripts inherit context when acting on
+ * behalf of a user. In general the 'sessionId' parameter should be set
+ * to an empty string unless session importing is *truly* needed. This
+ * feature is somewhat deprecated.
*
* @note suhosin.session.encrypt may interfere with this method.
*
diff --git a/includes/dao/DBAccessObjectUtils.php b/includes/dao/DBAccessObjectUtils.php
new file mode 100644
index 00000000..ad7804c2
--- /dev/null
+++ b/includes/dao/DBAccessObjectUtils.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * This file contains database access object related constants.
+ *
+ * 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 Database
+ */
+
+/**
+ * Helper class for DAO classes
+ *
+ * @since 1.26
+ */
+class DBAccessObjectUtils {
+ /**
+ * @param integer $bitfield
+ * @param integer $flags IDBAccessObject::READ_* constant
+ * @return bool Bitfield has flag $flag set
+ */
+ public static function hasFlags( $bitfield, $flags ) {
+ return ( $bitfield & $flags ) == $flags;
+ }
+
+ /**
+ * Get an appropriate DB index and options for a query
+ *
+ * @param integer $bitfield
+ * @return array (DB_MASTER/DB_SLAVE, SELECT options array)
+ */
+ public static function getDBOptions( $bitfield ) {
+ $index = self::hasFlags( $bitfield, IDBAccessObject::READ_LATEST )
+ ? DB_MASTER
+ : DB_SLAVE;
+
+ $options = array();
+ if ( self::hasFlags( $bitfield, IDBAccessObject::READ_EXCLUSIVE ) ) {
+ $options[] = 'FOR UPDATE';
+ } elseif ( self::hasFlags( $bitfield, IDBAccessObject::READ_LOCKING ) ) {
+ $options[] = 'LOCK IN SHARE MODE';
+ }
+
+ return array( $index, $options );
+ }
+}
diff --git a/includes/db/DBConnRef.php b/includes/db/DBConnRef.php
new file mode 100644
index 00000000..b4f3f792
--- /dev/null
+++ b/includes/db/DBConnRef.php
@@ -0,0 +1,524 @@
+<?php
+/**
+ * Helper class to handle automatically marking connections as reusable (via RAII pattern)
+ * as well handling deferring the actual network connection until the handle is used
+ *
+ * @note: proxy methods are defined explicity to avoid interface errors
+ * @ingroup Database
+ * @since 1.22
+ */
+class DBConnRef implements IDatabase {
+ /** @var LoadBalancer */
+ private $lb;
+
+ /** @var DatabaseBase|null */
+ private $conn;
+
+ /** @var array|null */
+ private $params;
+
+ /**
+ * @param LoadBalancer $lb
+ * @param DatabaseBase|array $conn Connection or (server index, group, wiki ID) array
+ */
+ public function __construct( LoadBalancer $lb, $conn ) {
+ $this->lb = $lb;
+ if ( $conn instanceof DatabaseBase ) {
+ $this->conn = $conn;
+ } else {
+ $this->params = $conn;
+ }
+ }
+
+ function __call( $name, array $arguments ) {
+ if ( $this->conn === null ) {
+ list( $db, $groups, $wiki ) = $this->params;
+ $this->conn = $this->lb->getConnection( $db, $groups, $wiki );
+ }
+
+ return call_user_func_array( array( $this->conn, $name ), $arguments );
+ }
+
+ public function getServerInfo() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function bufferResults( $buffer = null ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function trxLevel() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function trxTimestamp() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function tablePrefix( $prefix = null ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function dbSchema( $schema = null ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getLBInfo( $name = null ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function setLBInfo( $name, $value = null ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function implicitGroupby() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function implicitOrderby() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function lastQuery() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function doneWrites() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function lastDoneWrites() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function writesOrCallbacksPending() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function pendingWriteQueryDuration() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function isOpen() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function setFlag( $flag ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function clearFlag( $flag ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getFlag( $flag ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getProperty( $name ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getWikiID() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getType() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function open( $server, $user, $password, $dbName ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function fetchObject( $res ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function fetchRow( $res ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function numRows( $res ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function numFields( $res ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function fieldName( $res, $n ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function insertId() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function dataSeek( $res, $row ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function lastErrno() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function lastError() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function fieldInfo( $table, $field ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function affectedRows() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getSoftwareLink() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getServerVersion() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function close() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function reportConnectionError( $error = 'Unknown error' ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function query( $sql, $fname = __METHOD__, $tempIgnore = false ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function freeResult( $res ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function selectField(
+ $table, $var, $cond = '', $fname = __METHOD__, $options = array()
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function selectFieldValues(
+ $table, $var, $cond = '', $fname = __METHOD__, $options = array()
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function select(
+ $table, $vars, $conds = '', $fname = __METHOD__,
+ $options = array(), $join_conds = array()
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function selectSQLText(
+ $table, $vars, $conds = '', $fname = __METHOD__,
+ $options = array(), $join_conds = array()
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function selectRow(
+ $table, $vars, $conds, $fname = __METHOD__,
+ $options = array(), $join_conds = array()
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function estimateRowCount(
+ $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = array()
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function selectRowCount(
+ $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = array()
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function fieldExists( $table, $field, $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function indexExists( $table, $index, $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function tableExists( $table, $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function indexUnique( $table, $index ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function insert( $table, $a, $fname = __METHOD__, $options = array() ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function update( $table, $values, $conds, $fname = __METHOD__, $options = array() ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function makeList( $a, $mode = LIST_COMMA ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function makeWhereFrom2d( $data, $baseKey, $subKey ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function bitNot( $field ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function bitAnd( $fieldLeft, $fieldRight ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function bitOr( $fieldLeft, $fieldRight ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function buildConcat( $stringList ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function buildGroupConcatField(
+ $delim, $table, $field, $conds = '', $join_conds = array()
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function selectDB( $db ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getDBname() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getServer() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function addQuotes( $s ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function buildLike() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function anyChar() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function anyString() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function nextSequenceValue( $seqName ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function upsert(
+ $table, array $rows, array $uniqueIndexes, array $set, $fname = __METHOD__
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function deleteJoin(
+ $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = __METHOD__
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function delete( $table, $conds, $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function insertSelect(
+ $destTable, $srcTable, $varMap, $conds,
+ $fname = __METHOD__, $insertOptions = array(), $selectOptions = array()
+ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function unionSupportsOrderAndLimit() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function unionQueries( $sqls, $all ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function conditional( $cond, $trueVal, $falseVal ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function strreplace( $orig, $old, $new ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getServerUptime() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function wasDeadlock() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function wasLockTimeout() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function wasErrorReissuable() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function wasReadOnlyError() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function masterPosWait( DBMasterPos $pos, $timeout ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getSlavePos() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getMasterPos() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function onTransactionIdle( $callback ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function onTransactionPreCommitOrIdle( $callback ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function startAtomic( $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function endAtomic( $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function begin( $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function commit( $fname = __METHOD__, $flush = '' ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function rollback( $fname = __METHOD__, $flush = '' ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function listTables( $prefix = null, $fname = __METHOD__ ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function timestamp( $ts = 0 ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function timestampOrNull( $ts = null ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function resultObject( $result ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function ping() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getLag() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function maxListLen() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function encodeBlob( $b ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function decodeBlob( $b ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function setSessionOptions( array $options ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function setSchemaVars( $vars ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function lockIsFree( $lockName, $method ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function lock( $lockName, $method, $timeout = 5 ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function unlock( $lockName, $method ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function namedLocksEnqueue() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function getInfinity() {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function encodeExpiry( $expiry ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function decodeExpiry( $expiry, $format = TS_MW ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ public function setBigSelects( $value = true ) {
+ return $this->__call( __FUNCTION__, func_get_args() );
+ }
+
+ /**
+ * Clean up the connection when out of scope
+ */
+ function __destruct() {
+ if ( $this->conn !== null ) {
+ $this->lb->reuseConnection( $this->conn );
+ }
+ }
+}
diff --git a/includes/db/Database.php b/includes/db/Database.php
index 0c0248da..1e54f554 100644
--- a/includes/db/Database.php
+++ b/includes/db/Database.php
@@ -26,13 +26,6 @@
*/
/**
- * Interface for classes that implement or wrap DatabaseBase
- * @ingroup Database
- */
-interface IDatabase {
-}
-
-/**
* Database abstraction object
* @ingroup Database
*/
@@ -65,10 +58,11 @@ abstract class DatabaseBase implements IDatabase {
protected $mSchema;
protected $mFlags;
protected $mForeign;
- protected $mErrorCount = 0;
protected $mLBInfo = array();
protected $mDefaultBigSelects = null;
protected $mSchemaVars = false;
+ /** @var array */
+ protected $mSessionVars = array();
protected $preparedArgs;
@@ -142,6 +136,13 @@ abstract class DatabaseBase implements IDatabase {
private $mTrxAutomaticAtomic = false;
/**
+ * Track the seconds spent in write queries for the current transaction
+ *
+ * @var float
+ */
+ private $mTrxWriteDuration = 0.0;
+
+ /**
* @since 1.21
* @var resource File handle for upgrade
*/
@@ -228,7 +229,7 @@ abstract class DatabaseBase implements IDatabase {
* @param null|bool $ignoreErrors
* @return bool The previous value of the flag.
*/
- public function ignoreErrors( $ignoreErrors = null ) {
+ protected function ignoreErrors( $ignoreErrors = null ) {
return wfSetBit( $this->mFlags, DBO_IGNORE, $ignoreErrors );
}
@@ -258,15 +259,6 @@ abstract class DatabaseBase implements IDatabase {
}
/**
- * Get/set the number of errors logged. Only useful when errors are ignored
- * @param int $count The count to set, or omitted to leave it unchanged.
- * @return int The error count
- */
- public function errorCount( $count = null ) {
- return wfSetVar( $this->mErrorCount, $count );
- }
-
- /**
* Get/set the table prefix.
* @param string $prefix The table prefix to set, or omitted to leave it unchanged.
* @return string The previous table prefix.
@@ -474,6 +466,18 @@ abstract class DatabaseBase implements IDatabase {
}
/**
+ * Get the time spend running write queries for this
+ *
+ * High times could be due to scanning, updates, locking, and such
+ *
+ * @return float|bool Returns false if not transaction is active
+ * @since 1.26
+ */
+ public function pendingWriteQueryDuration() {
+ return $this->mTrxLevel ? $this->mTrxWriteDuration : false;
+ }
+
+ /**
* Is a connection to the database open?
* @return bool
*/
@@ -592,125 +596,6 @@ abstract class DatabaseBase implements IDatabase {
}
/**
- * Get the type of the DBMS, as it appears in $wgDBtype.
- *
- * @return string
- */
- abstract function getType();
-
- /**
- * Open a connection to the database. Usually aborts on failure
- *
- * @param string $server Database server host
- * @param string $user Database user name
- * @param string $password Database user password
- * @param string $dbName Database name
- * @return bool
- * @throws DBConnectionError
- */
- abstract function open( $server, $user, $password, $dbName );
-
- /**
- * Fetch the next row from the given result object, in object form.
- * Fields can be retrieved with $row->fieldname, with fields acting like
- * member variables.
- * If no more rows are available, false is returned.
- *
- * @param ResultWrapper|stdClass $res Object as returned from DatabaseBase::query(), etc.
- * @return stdClass|bool
- * @throws DBUnexpectedError Thrown if the database returns an error
- */
- abstract function fetchObject( $res );
-
- /**
- * Fetch the next row from the given result object, in associative array
- * form. Fields are retrieved with $row['fieldname'].
- * If no more rows are available, false is returned.
- *
- * @param ResultWrapper $res Result object as returned from DatabaseBase::query(), etc.
- * @return array|bool
- * @throws DBUnexpectedError Thrown if the database returns an error
- */
- abstract function fetchRow( $res );
-
- /**
- * Get the number of rows in a result object
- *
- * @param mixed $res A SQL result
- * @return int
- */
- abstract function numRows( $res );
-
- /**
- * Get the number of fields in a result object
- * @see http://www.php.net/mysql_num_fields
- *
- * @param mixed $res A SQL result
- * @return int
- */
- abstract function numFields( $res );
-
- /**
- * Get a field name in a result object
- * @see http://www.php.net/mysql_field_name
- *
- * @param mixed $res A SQL result
- * @param int $n
- * @return string
- */
- abstract function fieldName( $res, $n );
-
- /**
- * Get the inserted value of an auto-increment row
- *
- * The value inserted should be fetched from nextSequenceValue()
- *
- * Example:
- * $id = $dbw->nextSequenceValue( 'page_page_id_seq' );
- * $dbw->insert( 'page', array( 'page_id' => $id ) );
- * $id = $dbw->insertId();
- *
- * @return int
- */
- abstract function insertId();
-
- /**
- * Change the position of the cursor in a result object
- * @see http://www.php.net/mysql_data_seek
- *
- * @param mixed $res A SQL result
- * @param int $row
- */
- abstract function dataSeek( $res, $row );
-
- /**
- * Get the last error number
- * @see http://www.php.net/mysql_errno
- *
- * @return int
- */
- abstract function lastErrno();
-
- /**
- * Get a description of the last error
- * @see http://www.php.net/mysql_error
- *
- * @return string
- */
- abstract function lastError();
-
- /**
- * mysql_fetch_field() wrapper
- * Returns false if the field doesn't exist
- *
- * @param string $table Table name
- * @param string $field Field name
- *
- * @return Field
- */
- abstract function fieldInfo( $table, $field );
-
- /**
* Get information about an index into an object
* @param string $table Table name
* @param string $index Index name
@@ -720,14 +605,6 @@ abstract class DatabaseBase implements IDatabase {
abstract function indexInfo( $table, $index, $fname = __METHOD__ );
/**
- * Get the number of rows affected by the last write query
- * @see http://www.php.net/mysql_affected_rows
- *
- * @return int
- */
- abstract function affectedRows();
-
- /**
* Wrapper for addslashes()
*
* @param string $s String to be slashed.
@@ -736,24 +613,6 @@ abstract class DatabaseBase implements IDatabase {
abstract function strencode( $s );
/**
- * Returns a wikitext link to the DB's website, e.g.,
- * return "[http://www.mysql.com/ MySQL]";
- * Should at least contain plain text, if for some reason
- * your database has no website.
- *
- * @return string Wikitext of a link to the server software's web site
- */
- abstract function getSoftwareLink();
-
- /**
- * A string describing the current software version, like from
- * mysql_get_server_info().
- *
- * @return string Version information from the database server.
- */
- abstract function getServerVersion();
-
- /**
* Constructor.
*
* FIXME: It is possible to construct a Database object with no associated
@@ -794,15 +653,17 @@ abstract class DatabaseBase implements IDatabase {
}
}
+ $this->mSessionVars = $params['variables'];
+
/** Get the default table prefix*/
- if ( $tablePrefix == 'get from global' ) {
+ if ( $tablePrefix === 'get from global' ) {
$this->mTablePrefix = $wgDBprefix;
} else {
$this->mTablePrefix = $tablePrefix;
}
/** Get the database schema*/
- if ( $schema == 'get from global' ) {
+ if ( $schema === 'get from global' ) {
$this->mSchema = $wgDBmwschema;
} else {
$this->mSchema = $schema;
@@ -892,10 +753,6 @@ abstract class DatabaseBase implements IDatabase {
// Although postgres and oracle support schemas, we don't use them (yet)
// to maintain backwards compatibility
$defaultSchemas = array(
- 'mysql' => null,
- 'postgres' => null,
- 'sqlite' => null,
- 'oracle' => null,
'mssql' => 'get from global',
);
@@ -907,8 +764,11 @@ abstract class DatabaseBase implements IDatabase {
$p['password'] = isset( $p['password'] ) ? $p['password'] : false;
$p['dbname'] = isset( $p['dbname'] ) ? $p['dbname'] : false;
$p['flags'] = isset( $p['flags'] ) ? $p['flags'] : 0;
+ $p['variables'] = isset( $p['variables'] ) ? $p['variables'] : array();
$p['tablePrefix'] = isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : 'get from global';
- $p['schema'] = isset( $p['schema'] ) ? $p['schema'] : $defaultSchemas[$dbType];
+ if ( !isset( $p['schema'] ) ) {
+ $p['schema'] = isset( $defaultSchemas[$dbType] ) ? $defaultSchemas[$dbType] : null;
+ }
$p['foreign'] = isset( $p['foreign'] ) ? $p['foreign'] : false;
return new $class( $p );
@@ -998,6 +858,17 @@ abstract class DatabaseBase implements IDatabase {
}
/**
+ * Make sure isOpen() returns true as a sanity check
+ *
+ * @throws DBUnexpectedError
+ */
+ protected function assertOpen() {
+ if ( !$this->isOpen() ) {
+ throw new DBUnexpectedError( $this, "DB connection was already closed." );
+ }
+ }
+
+ /**
* Closes underlying database connection
* @since 1.20
* @return bool Whether connection was closed successfully
@@ -1034,7 +905,7 @@ abstract class DatabaseBase implements IDatabase {
* @param string $sql
* @return bool
*/
- public function isWriteQuery( $sql ) {
+ protected function isWriteQuery( $sql ) {
return !preg_match( '/^(?:SELECT|BEGIN|ROLLBACK|COMMIT|SET|SHOW|EXPLAIN|\(SELECT)\b/i', $sql );
}
@@ -1047,7 +918,7 @@ abstract class DatabaseBase implements IDatabase {
* @param string $sql
* @return bool
*/
- public function isTransactableQuery( $sql ) {
+ protected function isTransactableQuery( $sql ) {
$verb = substr( $sql, 0, strcspn( $sql, " \t\r\n" ) );
return !in_array( $verb, array( 'BEGIN', 'COMMIT', 'ROLLBACK', 'SHOW', 'SET' ) );
}
@@ -1153,13 +1024,12 @@ abstract class DatabaseBase implements IDatabase {
$queryId = MWDebug::query( $sql, $fname, $isMaster );
# Avoid fatals if close() was called
- if ( !$this->isOpen() ) {
- throw new DBUnexpectedError( $this, "DB connection was already closed." );
- }
+ $this->assertOpen();
# Do the query and handle errors
$startTime = microtime( true );
$ret = $this->doQuery( $commentedSql );
+ $queryRuntime = microtime( true ) - $startTime;
# Log the query time and feed it into the DB trx profiler
$this->getTransactionProfiler()->recordQueryCompletion(
$queryProf, $startTime, $isWriteQuery, $this->affectedRows() );
@@ -1191,6 +1061,7 @@ abstract class DatabaseBase implements IDatabase {
# Should be safe to silently retry (no trx and thus no callbacks)
$startTime = microtime( true );
$ret = $this->doQuery( $commentedSql );
+ $queryRuntime = microtime( true ) - $startTime;
# Log the query time and feed it into the DB trx profiler
$this->getTransactionProfiler()->recordQueryCompletion(
$queryProf, $startTime, $isWriteQuery, $this->affectedRows() );
@@ -1211,6 +1082,10 @@ abstract class DatabaseBase implements IDatabase {
$queryProfSection = false;
$totalProfSection = false;
+ if ( $isWriteQuery && $this->mTrxLevel ) {
+ $this->mTrxWriteDuration += $queryRuntime;
+ }
+
return $res;
}
@@ -1226,8 +1101,6 @@ abstract class DatabaseBase implements IDatabase {
* @throws DBQueryError
*/
public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
- ++$this->mErrorCount;
-
if ( $this->ignoreErrors() || $tempIgnore ) {
wfDebug( "SQL ERROR (ignored): $error\n" );
} else {
@@ -1421,6 +1294,7 @@ abstract class DatabaseBase implements IDatabase {
* @param string|array $options The query options. See DatabaseBase::select() for details.
*
* @return bool|array The values from the field, or false on failure
+ * @throws DBUnexpectedError
* @since 1.25
*/
public function selectFieldValues(
@@ -1881,7 +1755,7 @@ abstract class DatabaseBase implements IDatabase {
) {
$rows = 0;
$sql = $this->selectSQLText( $table, '1', $conds, $fname, $options );
- $res = $this->query( "SELECT COUNT(*) AS rowcount FROM ($sql) tmp_count" );
+ $res = $this->query( "SELECT COUNT(*) AS rowcount FROM ($sql) tmp_count", $fname );
if ( $res ) {
$row = $this->fetchRow( $res );
@@ -2015,9 +1889,6 @@ abstract class DatabaseBase implements IDatabase {
* This causes a multi-row INSERT on DBMSs that support it. The keys in
* each subarray must be identical to each other, and in the same order.
*
- * Usually throws a DBQueryError on failure. If errors are explicitly ignored,
- * returns success.
- *
* $options is an array of options, with boolean options encoded as values
* with numeric keys, in the same style as $options in
* DatabaseBase::select(). Supported options are:
@@ -2033,6 +1904,9 @@ abstract class DatabaseBase implements IDatabase {
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
* @param array $options Array of options
*
+ * @throws DBQueryError Usually throws a DBQueryError on failure. If errors are explicitly ignored,
+ * returns success.
+ *
* @return bool
*/
public function insert( $table, $a, $fname = __METHOD__, $options = array() ) {
@@ -2455,7 +2329,7 @@ abstract class DatabaseBase implements IDatabase {
}
# Quote $schema and merge it with the table name if needed
- if ( $schema !== null ) {
+ if ( strlen( $schema ) ) {
if ( $format == 'quoted' && !$this->isQuotedIdentifier( $schema ) ) {
$schema = $this->addIdentifierQuotes( $schema );
}
@@ -2842,6 +2716,7 @@ abstract class DatabaseBase implements IDatabase {
$rows = array( $rows );
}
+ // @FXIME: this is not atomic, but a trx would break affectedRows()
foreach ( $rows as $row ) {
# Delete rows which collide
if ( $uniqueIndexes ) {
@@ -3303,6 +3178,17 @@ abstract class DatabaseBase implements IDatabase {
}
/**
+ * Determines if the given query error was a connection drop
+ * STUB
+ *
+ * @param integer|string $errno
+ * @return bool
+ */
+ public function wasConnectionError( $errno ) {
+ return false;
+ }
+
+ /**
* Perform a deadlock-prone transaction.
*
* This function invokes a callback function to perform a set of write
@@ -3318,7 +3204,8 @@ abstract class DatabaseBase implements IDatabase {
* iteration, or false on error, for example if the retry limit was
* reached.
*
- * @return bool
+ * @return mixed
+ * @throws DBQueryError
*/
public function deadlockLoop() {
$args = func_get_args();
@@ -3332,15 +3219,13 @@ abstract class DatabaseBase implements IDatabase {
$this->begin( __METHOD__ );
+ $retVal = null;
$e = null;
do {
try {
$retVal = call_user_func_array( $function, $args );
break;
} catch ( DBQueryError $e ) {
- $error = $this->lastError();
- $errno = $this->lastErrno();
- $sql = $this->lastQuery();
if ( $this->wasDeadlock() ) {
// Retry after a randomized delay
usleep( mt_rand( self::DEADLOCK_DELAY_MIN, self::DEADLOCK_DELAY_MAX ) );
@@ -3525,7 +3410,11 @@ abstract class DatabaseBase implements IDatabase {
if ( !$this->mTrxLevel ) {
$this->begin( $fname );
$this->mTrxAutomatic = true;
- $this->mTrxAutomaticAtomic = true;
+ // If DBO_TRX is set, a series of startAtomic/endAtomic pairs will result
+ // in all changes being in one transaction to keep requests transactional.
+ if ( !$this->getFlag( DBO_TRX ) ) {
+ $this->mTrxAutomaticAtomic = true;
+ }
}
$this->mTrxAtomicLevels->push( $fname );
@@ -3605,19 +3494,18 @@ abstract class DatabaseBase implements IDatabase {
}
$this->runOnTransactionPreCommitCallbacks();
+ $writeTime = $this->pendingWriteQueryDuration();
$this->doCommit( $fname );
if ( $this->mTrxDoneWrites ) {
$this->mDoneWrites = microtime( true );
$this->getTransactionProfiler()->transactionWritingOut(
- $this->mServer, $this->mDBname, $this->mTrxShortId );
+ $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime );
}
$this->runOnTransactionIdleCallbacks();
}
# Avoid fatals if close() was called
- if ( !$this->isOpen() ) {
- throw new DBUnexpectedError( $this, "DB connection was already closed." );
- }
+ $this->assertOpen();
$this->doBegin( $fname );
$this->mTrxTimestamp = microtime( true );
@@ -3629,6 +3517,7 @@ abstract class DatabaseBase implements IDatabase {
$this->mTrxIdleCallbacks = array();
$this->mTrxPreCommitCallbacks = array();
$this->mTrxShortId = wfRandomString( 12 );
+ $this->mTrxWriteDuration = 0.0;
}
/**
@@ -3681,16 +3570,15 @@ abstract class DatabaseBase implements IDatabase {
}
# Avoid fatals if close() was called
- if ( !$this->isOpen() ) {
- throw new DBUnexpectedError( $this, "DB connection was already closed." );
- }
+ $this->assertOpen();
$this->runOnTransactionPreCommitCallbacks();
+ $writeTime = $this->pendingWriteQueryDuration();
$this->doCommit( $fname );
if ( $this->mTrxDoneWrites ) {
$this->mDoneWrites = microtime( true );
$this->getTransactionProfiler()->transactionWritingOut(
- $this->mServer, $this->mDBname, $this->mTrxShortId );
+ $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime );
}
$this->runOnTransactionIdleCallbacks();
}
@@ -3739,9 +3627,7 @@ abstract class DatabaseBase implements IDatabase {
}
# Avoid fatals if close() was called
- if ( !$this->isOpen() ) {
- throw new DBUnexpectedError( $this, "DB connection was already closed." );
- }
+ $this->assertOpen();
$this->doRollback( $fname );
$this->mTrxIdleCallbacks = array(); // cancel
@@ -3794,6 +3680,7 @@ abstract class DatabaseBase implements IDatabase {
* @param string $prefix Only show tables with this prefix, e.g. mw_
* @param string $fname Calling function name
* @throws MWException
+ * @return array
*/
function listTables( $prefix = null, $fname = __METHOD__ ) {
throw new MWException( 'DatabaseBase::listTables is not implemented in descendant class' );
@@ -3816,6 +3703,7 @@ abstract class DatabaseBase implements IDatabase {
* @param string $prefix Only show VIEWs with this prefix, eg. unit_test_
* @param string $fname Name of calling function
* @throws MWException
+ * @return array
* @since 1.22
*/
public function listViews( $prefix = null, $fname = __METHOD__ ) {
@@ -3827,6 +3715,7 @@ abstract class DatabaseBase implements IDatabase {
*
* @param string $name Name of the database-structure to test.
* @throws MWException
+ * @return bool
* @since 1.22
*/
public function isView( $name ) {
@@ -3988,9 +3877,9 @@ abstract class DatabaseBase implements IDatabase {
public function sourceFile(
$filename, $lineCallback = false, $resultCallback = false, $fname = false, $inputCallback = false
) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$fp = fopen( $filename, 'r' );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( false === $fp ) {
throw new MWException( "Could not open \"{$filename}\".\n" );
@@ -4205,7 +4094,7 @@ abstract class DatabaseBase implements IDatabase {
}
/**
- * Check to see if a named lock is available. This is non-blocking.
+ * Check to see if a named lock is available (non-blocking)
*
* @param string $lockName Name of lock to poll
* @param string $method Name of method calling us
@@ -4219,8 +4108,7 @@ abstract class DatabaseBase implements IDatabase {
/**
* Acquire a named lock
*
- * Abstracted from Filestore::lock() so child classes can implement for
- * their own needs.
+ * Named locks are not related to transactions
*
* @param string $lockName Name of lock to aquire
* @param string $method Name of method calling us
@@ -4232,7 +4120,9 @@ abstract class DatabaseBase implements IDatabase {
}
/**
- * Release a lock.
+ * Release a lock
+ *
+ * Named locks are not related to transactions
*
* @param string $lockName Name of lock to release
* @param string $method Name of method calling us
@@ -4246,6 +4136,16 @@ abstract class DatabaseBase implements IDatabase {
}
/**
+ * Check to see if a named lock used by lock() use blocking queues
+ *
+ * @return bool
+ * @since 1.26
+ */
+ public function namedLocksEnqueue() {
+ return false;
+ }
+
+ /**
* Lock specific tables
*
* @param array $read Array of tables to lock for read access
@@ -4328,7 +4228,7 @@ abstract class DatabaseBase implements IDatabase {
* @return string
*/
public function decodeExpiry( $expiry, $format = TS_MW ) {
- return ( $expiry == '' || $expiry == $this->getInfinity() )
+ return ( $expiry == '' || $expiry == 'infinity' || $expiry == $this->getInfinity() )
? 'infinity'
: wfTimestamp( $format, $expiry );
}
diff --git a/includes/db/DatabaseError.php b/includes/db/DatabaseError.php
index 86950a89..928de616 100644
--- a/includes/db/DatabaseError.php
+++ b/includes/db/DatabaseError.php
@@ -329,12 +329,19 @@ class DBQueryError extends DBExpectedError {
* @param string $fname
*/
function __construct( DatabaseBase $db, $error, $errno, $sql, $fname ) {
- $message = "A database error has occurred. Did you forget to run " .
- "maintenance/update.php after upgrading? See: " .
- "https://www.mediawiki.org/wiki/Manual:Upgrading#Run_the_update_script\n" .
- "Query: $sql\n" .
- "Function: $fname\n" .
- "Error: $errno $error\n";
+ if ( $db->wasConnectionError( $errno ) ) {
+ $message = "A connection error occured. \n" .
+ "Query: $sql\n" .
+ "Function: $fname\n" .
+ "Error: $errno $error\n";
+ } else {
+ $message = "A database error has occurred. Did you forget to run " .
+ "maintenance/update.php after upgrading? See: " .
+ "https://www.mediawiki.org/wiki/Manual:Upgrading#Run_the_update_script\n" .
+ "Query: $sql\n" .
+ "Function: $fname\n" .
+ "Error: $errno $error\n";
+ }
parent::__construct( $db, $message );
$this->error = $error;
diff --git a/includes/db/DatabaseMssql.php b/includes/db/DatabaseMssql.php
index 2b8f395f..85f1b96d 100644
--- a/includes/db/DatabaseMssql.php
+++ b/includes/db/DatabaseMssql.php
@@ -119,9 +119,9 @@ class DatabaseMssql extends DatabaseBase {
$connectionInfo['PWD'] = $password;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$this->mConn = sqlsrv_connect( $server, $connectionInfo );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $this->mConn === false ) {
throw new DBConnectionError( $this, $this->lastError() );
@@ -1089,7 +1089,9 @@ class DatabaseMssql extends DatabaseBase {
* @param string $s
* @return string
*/
- public function strencode( $s ) { # Should not be called by us
+ public function strencode( $s ) {
+ // Should not be called by us
+
return str_replace( "'", "''", $s );
}
diff --git a/includes/db/DatabaseMysql.php b/includes/db/DatabaseMysql.php
index 823d9b67..5b151477 100644
--- a/includes/db/DatabaseMysql.php
+++ b/includes/db/DatabaseMysql.php
@@ -33,10 +33,12 @@ class DatabaseMysql extends DatabaseMysqlBase {
* @return resource False on error
*/
protected function doQuery( $sql ) {
+ $conn = $this->getBindingHandle();
+
if ( $this->bufferResults() ) {
- $ret = mysql_query( $sql, $this->mConn );
+ $ret = mysql_query( $sql, $conn );
} else {
- $ret = mysql_unbuffered_query( $sql, $this->mConn );
+ $ret = mysql_unbuffered_query( $sql, $conn );
}
return $ret;
@@ -48,8 +50,7 @@ class DatabaseMysql extends DatabaseMysqlBase {
* @throws DBConnectionError
*/
protected function mysqlConnect( $realServer ) {
- # Fail now
- # Otherwise we get a suppressed fatal error, which is very hard to track down
+ # Avoid a suppressed fatal error, which is very hard to track down
if ( !extension_loaded( 'mysql' ) ) {
throw new DBConnectionError(
$this,
@@ -73,6 +74,9 @@ class DatabaseMysql extends DatabaseMysqlBase {
$conn = false;
+ # The kernel's default SYN retransmission period is far too slow for us,
+ # so we use a short timeout plus a manual retry. Retrying means that a small
+ # but finite rate of SYN packet loss won't cause user-visible errors.
for ( $i = 0; $i < $numAttempts && !$conn; $i++ ) {
if ( $i > 1 ) {
usleep( 1000 );
@@ -93,8 +97,10 @@ class DatabaseMysql extends DatabaseMysqlBase {
* @return bool
*/
protected function mysqlSetCharset( $charset ) {
+ $conn = $this->getBindingHandle();
+
if ( function_exists( 'mysql_set_charset' ) ) {
- return mysql_set_charset( $charset, $this->mConn );
+ return mysql_set_charset( $charset, $conn );
} else {
return $this->query( 'SET NAMES ' . $charset, __METHOD__ );
}
@@ -104,14 +110,18 @@ class DatabaseMysql extends DatabaseMysqlBase {
* @return bool
*/
protected function closeConnection() {
- return mysql_close( $this->mConn );
+ $conn = $this->getBindingHandle();
+
+ return mysql_close( $conn );
}
/**
* @return int
*/
function insertId() {
- return mysql_insert_id( $this->mConn );
+ $conn = $this->getBindingHandle();
+
+ return mysql_insert_id( $conn );
}
/**
@@ -129,7 +139,9 @@ class DatabaseMysql extends DatabaseMysqlBase {
* @return int
*/
function affectedRows() {
- return mysql_affected_rows( $this->mConn );
+ $conn = $this->getBindingHandle();
+
+ return mysql_affected_rows( $conn );
}
/**
@@ -137,9 +149,11 @@ class DatabaseMysql extends DatabaseMysqlBase {
* @return bool
*/
function selectDB( $db ) {
+ $conn = $this->getBindingHandle();
+
$this->mDBname = $db;
- return mysql_select_db( $db, $this->mConn );
+ return mysql_select_db( $db, $conn );
}
protected function mysqlFreeResult( $res ) {
@@ -183,10 +197,14 @@ class DatabaseMysql extends DatabaseMysqlBase {
}
protected function mysqlRealEscapeString( $s ) {
- return mysql_real_escape_string( $s, $this->mConn );
+ $conn = $this->getBindingHandle();
+
+ return mysql_real_escape_string( $s, $conn );
}
protected function mysqlPing() {
- return mysql_ping( $this->mConn );
+ $conn = $this->getBindingHandle();
+
+ return mysql_ping( $conn );
}
}
diff --git a/includes/db/DatabaseMysqlBase.php b/includes/db/DatabaseMysqlBase.php
index aac95a8c..be34242b 100644
--- a/includes/db/DatabaseMysqlBase.php
+++ b/includes/db/DatabaseMysqlBase.php
@@ -59,22 +59,16 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
function open( $server, $user, $password, $dbName ) {
global $wgAllDBsAreLocalhost, $wgSQLMode;
- # Debugging hack -- fake cluster
- if ( $wgAllDBsAreLocalhost ) {
- $realServer = 'localhost';
- } else {
- $realServer = $server;
- }
+ # Close/unset connection handle
$this->close();
+
+ # Debugging hack -- fake cluster
+ $realServer = $wgAllDBsAreLocalhost ? 'localhost' : $server;
$this->mServer = $server;
$this->mUser = $user;
$this->mPassword = $password;
$this->mDBname = $dbName;
- # The kernel's default SYN retransmission period is far too slow for us,
- # so we use a short timeout plus a manual retry. Retrying means that a small
- # but finite rate of SYN packet loss won't cause user-visible errors.
- $this->mConn = false;
$this->installErrorHandler();
try {
$this->mConn = $this->mysqlConnect( $realServer );
@@ -104,9 +98,9 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
}
if ( $dbName != '' ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$success = $this->selectDB( $dbName );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$success ) {
wfLogDBError(
"Error selecting database {db_name} on server {db_server}",
@@ -132,6 +126,15 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
if ( is_string( $wgSQLMode ) ) {
$set[] = 'sql_mode = ' . $this->addQuotes( $wgSQLMode );
}
+ // Set any custom settings defined by site config
+ // (e.g. https://dev.mysql.com/doc/refman/4.1/en/innodb-parameters.html)
+ foreach ( $this->mSessionVars as $var => $val ) {
+ // Escape strings but not numbers to avoid MySQL complaining
+ if ( !is_int( $val ) && !is_float( $val ) ) {
+ $val = $this->addQuotes( $val );
+ }
+ $set[] = $this->addIdentifierQuotes( $var ) . ' = ' . $val;
+ }
if ( $set ) {
// Use doQuery() to avoid opening implicit transactions (DBO_TRX)
@@ -194,9 +197,9 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = $this->mysqlFreeResult( $res );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$ok ) {
throw new DBUnexpectedError( $this, "Unable to free MySQL result" );
}
@@ -219,9 +222,9 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$row = $this->mysqlFetchObject( $res );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
$errno = $this->lastErrno();
// Unfortunately, mysql_fetch_object does not reset the last errno.
@@ -255,9 +258,9 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$row = $this->mysqlFetchArray( $res );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
$errno = $this->lastErrno();
// Unfortunately, mysql_fetch_array does not reset the last errno.
@@ -291,9 +294,9 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$n = $this->mysqlNumRows( $res );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
// Unfortunately, mysql_num_rows does not reset the last errno.
// We are not checking for any errors here, since
@@ -404,12 +407,12 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
function lastError() {
if ( $this->mConn ) {
# Even if it's non-zero, it can still be invalid
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$error = $this->mysqlError( $this->mConn );
if ( !$error ) {
$error = $this->mysqlError();
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
} else {
$error = $this->mysqlError();
}
@@ -577,9 +580,12 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
function ping() {
$ping = $this->mysqlPing();
if ( $ping ) {
+ // Connection was good or lost but reconnected...
+ // @note: mysqlnd (php 5.6+) does not support this (PHP bug 52561)
return true;
}
+ // Try a full disconnect/reconnect cycle if ping() failed
$this->closeConnection();
$this->mOpened = false;
$this->mConn = false;
@@ -873,6 +879,10 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
return ( $row->lockstatus == 1 );
}
+ public function namedLocksEnqueue() {
+ return true;
+ }
+
/**
* @param array $read
* @param array $write
@@ -930,7 +940,7 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
$value = $this->mDefaultBigSelects;
}
} elseif ( $this->mDefaultBigSelects === null ) {
- $this->mDefaultBigSelects = (bool)$this->selectField( false, '@@sql_big_selects' );
+ $this->mDefaultBigSelects = (bool)$this->selectField( false, '@@sql_big_selects', '', __METHOD__ );
}
$encValue = $value ? '1' : '0';
$this->query( "SET sql_big_selects=$encValue", __METHOD__ );
@@ -1045,6 +1055,32 @@ abstract class DatabaseMysqlBase extends DatabaseBase {
( $this->lastErrno() == 1290 && strpos( $this->lastError(), '--read-only' ) !== false );
}
+ function wasConnectionError( $errno ) {
+ return $errno == 2013 || $errno == 2006;
+ }
+
+ /**
+ * Get the underlying binding handle, mConn
+ *
+ * Makes sure that mConn is set (disconnects and ping() failure can unset it).
+ * This catches broken callers than catch and ignore disconnection exceptions.
+ * Unlike checking isOpen(), this is safe to call inside of open().
+ *
+ * @return resource|object
+ * @throws DBUnexpectedError
+ * @since 1.26
+ */
+ protected function getBindingHandle() {
+ if ( !$this->mConn ) {
+ throw new DBUnexpectedError(
+ $this,
+ 'DB connection was already closed or the connection dropped.'
+ );
+ }
+
+ return $this->mConn;
+ }
+
/**
* @param string $oldName
* @param string $newName
diff --git a/includes/db/DatabaseMysqli.php b/includes/db/DatabaseMysqli.php
index ad12e196..8ca23627 100644
--- a/includes/db/DatabaseMysqli.php
+++ b/includes/db/DatabaseMysqli.php
@@ -29,15 +29,20 @@
* @see Database
*/
class DatabaseMysqli extends DatabaseMysqlBase {
+ /** @var mysqli */
+ protected $mConn;
+
/**
* @param string $sql
* @return resource
*/
protected function doQuery( $sql ) {
+ $conn = $this->getBindingHandle();
+
if ( $this->bufferResults() ) {
- $ret = $this->mConn->query( $sql );
+ $ret = $conn->query( $sql );
} else {
- $ret = $this->mConn->query( $sql, MYSQLI_USE_RESULT );
+ $ret = $conn->query( $sql, MYSQLI_USE_RESULT );
}
return $ret;
@@ -50,8 +55,8 @@ class DatabaseMysqli extends DatabaseMysqlBase {
*/
protected function mysqlConnect( $realServer ) {
global $wgDBmysql5;
- # Fail now
- # Otherwise we get a suppressed fatal error, which is very hard to track down
+
+ # Avoid suppressed fatal error, which is very hard to track down
if ( !function_exists( 'mysqli_init' ) ) {
throw new DBConnectionError( $this, "MySQLi functions missing,"
. " have you compiled PHP with the --with-mysqli option?\n" );
@@ -116,8 +121,10 @@ class DatabaseMysqli extends DatabaseMysqlBase {
* @return bool
*/
protected function mysqlSetCharset( $charset ) {
- if ( method_exists( $this->mConn, 'set_charset' ) ) {
- return $this->mConn->set_charset( $charset );
+ $conn = $this->getBindingHandle();
+
+ if ( method_exists( $conn, 'set_charset' ) ) {
+ return $conn->set_charset( $charset );
} else {
return $this->query( 'SET NAMES ' . $charset, __METHOD__ );
}
@@ -127,14 +134,18 @@ class DatabaseMysqli extends DatabaseMysqlBase {
* @return bool
*/
protected function closeConnection() {
- return $this->mConn->close();
+ $conn = $this->getBindingHandle();
+
+ return $conn->close();
}
/**
* @return int
*/
function insertId() {
- return $this->mConn->insert_id;
+ $conn = $this->getBindingHandle();
+
+ return (int)$conn->insert_id;
}
/**
@@ -152,7 +163,9 @@ class DatabaseMysqli extends DatabaseMysqlBase {
* @return int
*/
function affectedRows() {
- return $this->mConn->affected_rows;
+ $conn = $this->getBindingHandle();
+
+ return $conn->affected_rows;
}
/**
@@ -160,9 +173,11 @@ class DatabaseMysqli extends DatabaseMysqlBase {
* @return bool
*/
function selectDB( $db ) {
+ $conn = $this->getBindingHandle();
+
$this->mDBname = $db;
- return $this->mConn->select_db( $db );
+ return $conn->select_db( $db );
}
/**
@@ -289,11 +304,15 @@ class DatabaseMysqli extends DatabaseMysqlBase {
* @return string
*/
protected function mysqlRealEscapeString( $s ) {
- return $this->mConn->real_escape_string( $s );
+ $conn = $this->getBindingHandle();
+
+ return $conn->real_escape_string( $s );
}
protected function mysqlPing() {
- return $this->mConn->ping();
+ $conn = $this->getBindingHandle();
+
+ return $conn->ping();
}
/**
diff --git a/includes/db/DatabaseOracle.php b/includes/db/DatabaseOracle.php
index 9b00fbd1..87c31646 100644
--- a/includes/db/DatabaseOracle.php
+++ b/includes/db/DatabaseOracle.php
@@ -220,9 +220,9 @@ class DatabaseOracle extends DatabaseBase {
function __destruct() {
if ( $this->mOpened ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$this->close();
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
}
@@ -306,7 +306,7 @@ class DatabaseOracle extends DatabaseBase {
$session_mode = $this->mFlags & DBO_SYSDBA ? OCI_SYSDBA : OCI_DEFAULT;
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
if ( $this->mFlags & DBO_PERSISTENT ) {
$this->mConn = oci_pconnect(
$this->mUser,
@@ -332,7 +332,7 @@ class DatabaseOracle extends DatabaseBase {
$session_mode
);
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $this->mUser != $this->mDBname ) {
//change current schema in session
@@ -393,7 +393,7 @@ class DatabaseOracle extends DatabaseBase {
$explain_count
);
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) {
$e = oci_error( $this->mConn );
@@ -411,7 +411,7 @@ class DatabaseOracle extends DatabaseBase {
}
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $explain_count > 0 ) {
return $this->doQuery( 'SELECT id, cardinality "ROWS" FROM plan_table ' .
@@ -687,7 +687,7 @@ class DatabaseOracle extends DatabaseBase {
}
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
if ( oci_execute( $stmt, $this->execFlags() ) === false ) {
$e = oci_error( $stmt );
@@ -702,7 +702,7 @@ class DatabaseOracle extends DatabaseBase {
$this->mAffectedRows = oci_num_rows( $stmt );
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( isset( $lob ) ) {
foreach ( $lob as $lob_v ) {
@@ -971,20 +971,6 @@ class DatabaseOracle extends DatabaseBase {
return $valuedata;
}
- function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
- # Ignore errors during error handling to avoid infinite
- # recursion
- $ignore = $this->ignoreErrors( true );
- ++$this->mErrorCount;
-
- if ( $ignore || $tempIgnore ) {
- wfDebug( "SQL ERROR (ignored): $error\n" );
- $this->ignoreErrors( $ignore );
- } else {
- throw new DBQueryError( $this, $error, $errno, $sql, $fname );
- }
- }
-
/**
* @return string Wikitext of a link to the server software's web site
*/
@@ -1250,9 +1236,9 @@ class DatabaseOracle extends DatabaseBase {
}
$sql = 'ALTER SESSION SET CURRENT_SCHEMA=' . strtoupper( $db );
$stmt = oci_parse( $this->mConn, $sql );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$success = oci_execute( $stmt );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$success ) {
$e = oci_error( $stmt );
if ( $e['code'] != '1435' ) {
@@ -1491,7 +1477,7 @@ class DatabaseOracle extends DatabaseBase {
}
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
if ( oci_execute( $stmt, $this->execFlags() ) === false ) {
$e = oci_error( $stmt );
@@ -1506,7 +1492,7 @@ class DatabaseOracle extends DatabaseBase {
$this->mAffectedRows = oci_num_rows( $stmt );
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( isset( $lob ) ) {
foreach ( $lob as $lob_v ) {
diff --git a/includes/db/DatabasePostgres.php b/includes/db/DatabasePostgres.php
index 9287f7a6..56a5b2cf 100644
--- a/includes/db/DatabasePostgres.php
+++ b/includes/db/DatabasePostgres.php
@@ -217,7 +217,7 @@ class PostgresTransactionState {
* @since 1.19
*/
class SavepointPostgres {
- /** @var DatabaseBase Establish a savepoint within a transaction */
+ /** @var DatabasePostgres Establish a savepoint within a transaction */
protected $dbw;
protected $id;
protected $didbegin;
@@ -551,9 +551,9 @@ class DatabasePostgres extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = pg_free_result( $res );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$ok ) {
throw new DBUnexpectedError( $this, "Unable to free Postgres result\n" );
}
@@ -568,9 +568,9 @@ class DatabasePostgres extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$row = pg_fetch_object( $res );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
# @todo FIXME: HACK HACK HACK HACK debug
# @todo hashar: not sure if the following test really trigger if the object
@@ -589,9 +589,9 @@ class DatabasePostgres extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$row = pg_fetch_array( $res );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( pg_last_error( $this->mConn ) ) {
throw new DBUnexpectedError(
$this,
@@ -606,9 +606,9 @@ class DatabasePostgres extends DatabaseBase {
if ( $res instanceof ResultWrapper ) {
$res = $res->result;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$n = pg_num_rows( $res );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( pg_last_error( $this->mConn ) ) {
throw new DBUnexpectedError(
$this,
@@ -1510,7 +1510,9 @@ SQL;
return pg_unescape_bytea( $b );
}
- function strencode( $s ) { # Should not be called by us
+ function strencode( $s ) {
+ // Should not be called by us
+
return pg_escape_string( $this->mConn, $s );
}
@@ -1702,4 +1704,5 @@ SQL;
}
} // end DatabasePostgres class
-class PostgresBlob extends Blob {}
+class PostgresBlob extends Blob {
+}
diff --git a/includes/db/DatabaseSqlite.php b/includes/db/DatabaseSqlite.php
index ed86bab1..656547b5 100644
--- a/includes/db/DatabaseSqlite.php
+++ b/includes/db/DatabaseSqlite.php
@@ -64,16 +64,16 @@ class DatabaseSqlite extends DatabaseBase {
$this->dbDir = isset( $p['dbDirectory'] ) ? $p['dbDirectory'] : $wgSQLiteDataDir;
if ( isset( $p['dbFilePath'] ) ) {
- $this->mFlags = isset( $p['flags'] ) ? $p['flags'] : 0;
- // Standalone .sqlite file mode
+ parent::__construct( $p );
+ // Standalone .sqlite file mode.
+ // Super doesn't open when $user is false, but we can work with $dbName,
+ // which is derived from the file path in this case.
$this->openFile( $p['dbFilePath'] );
- // @FIXME: clean up base constructor so this can call super instead
- $this->mTrxAtomicLevels = new SplStack;
} else {
$this->mDBname = $p['dbname'];
- // Stock wiki mode using standard file names per DB
+ // Stock wiki mode using standard file names per DB.
parent::__construct( $p );
- // parent doesn't open when $user is false, but we can work with $dbName
+ // Super doesn't open when $user is false, but we can work with $dbName
if ( $p['dbname'] && !$this->isOpen() ) {
if ( $this->open( $p['host'], $p['user'], $p['password'], $p['dbname'] ) ) {
if ( $wgSharedDB ) {
@@ -105,8 +105,10 @@ class DatabaseSqlite extends DatabaseBase {
*/
public static function newStandaloneInstance( $filename, array $p = array() ) {
$p['dbFilePath'] = $filename;
+ $p['schema'] = false;
+ $p['tablePrefix'] = '';
- return new self( $p );
+ return DatabaseBase::factory( 'sqlite', $p );
}
/**
@@ -282,7 +284,7 @@ class DatabaseSqlite extends DatabaseBase {
* @return bool
*/
function isWriteQuery( $sql ) {
- return parent::isWriteQuery( $sql ) && !preg_match( '/^ATTACH\b/i', $sql );
+ return parent::isWriteQuery( $sql ) && !preg_match( '/^(ATTACH|PRAGMA)\b/i', $sql );
}
/**
@@ -962,7 +964,36 @@ class DatabaseSqlite extends DatabaseBase {
}
}
- return $this->query( $sql, $fname );
+ $res = $this->query( $sql, $fname );
+
+ // Take over indexes
+ $indexList = $this->query( 'PRAGMA INDEX_LIST(' . $this->addQuotes( $oldName ) . ')' );
+ foreach ( $indexList as $index ) {
+ if ( strpos( $index->name, 'sqlite_autoindex' ) === 0 ) {
+ continue;
+ }
+
+ if ( $index->unique ) {
+ $sql = 'CREATE UNIQUE INDEX';
+ } else {
+ $sql = 'CREATE INDEX';
+ }
+ // Try to come up with a new index name, given indexes have database scope in SQLite
+ $indexName = $newName . '_' . $index->name;
+ $sql .= ' ' . $indexName . ' ON ' . $newName;
+
+ $indexInfo = $this->query( 'PRAGMA INDEX_INFO(' . $this->addQuotes( $index->name ) . ')' );
+ $fields = array();
+ foreach ( $indexInfo as $indexInfoRow ) {
+ $fields[ $indexInfoRow->seqno ] = $indexInfoRow->name;
+ }
+
+ $sql .= '(' . implode( ',', $fields ) . ')';
+
+ $this->query( $sql );
+ }
+
+ return $res;
}
/**
diff --git a/includes/db/IDatabase.php b/includes/db/IDatabase.php
new file mode 100644
index 00000000..49d0514d
--- /dev/null
+++ b/includes/db/IDatabase.php
@@ -0,0 +1,1513 @@
+<?php
+
+/**
+ * @defgroup Database Database
+ *
+ * This file deals with database interface functions
+ * and query specifics/optimisations.
+ *
+ * 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 Database
+ */
+
+/**
+ * Basic database interface for live and lazy-loaded DB handles
+ *
+ * @todo: loosen up DB classes from MWException
+ * @note: DatabaseBase and DBConnRef should be updated to reflect any changes
+ * @ingroup Database
+ */
+interface IDatabase {
+ /**
+ * A string describing the current software version, and possibly
+ * other details in a user-friendly way. Will be listed on Special:Version, etc.
+ * Use getServerVersion() to get machine-friendly information.
+ *
+ * @return string Version information from the database server
+ */
+ public function getServerInfo();
+
+ /**
+ * Turns buffering of SQL result sets on (true) or off (false). Default is
+ * "on".
+ *
+ * Unbuffered queries are very troublesome in MySQL:
+ *
+ * - If another query is executed while the first query is being read
+ * out, the first query is killed. This means you can't call normal
+ * MediaWiki functions while you are reading an unbuffered query result
+ * from a normal wfGetDB() connection.
+ *
+ * - Unbuffered queries cause the MySQL server to use large amounts of
+ * memory and to hold broad locks which block other queries.
+ *
+ * If you want to limit client-side memory, it's almost always better to
+ * split up queries into batches using a LIMIT clause than to switch off
+ * buffering.
+ *
+ * @param null|bool $buffer
+ * @return null|bool The previous value of the flag
+ */
+ public function bufferResults( $buffer = null );
+
+ /**
+ * Gets the current transaction level.
+ *
+ * Historically, transactions were allowed to be "nested". This is no
+ * longer supported, so this function really only returns a boolean.
+ *
+ * @return int The previous value
+ */
+ public function trxLevel();
+
+ /**
+ * Get the UNIX timestamp of the time that the transaction was established
+ *
+ * This can be used to reason about the staleness of SELECT data
+ * in REPEATABLE-READ transaction isolation level.
+ *
+ * @return float|null Returns null if there is not active transaction
+ * @since 1.25
+ */
+ public function trxTimestamp();
+
+ /**
+ * Get/set the table prefix.
+ * @param string $prefix The table prefix to set, or omitted to leave it unchanged.
+ * @return string The previous table prefix.
+ */
+ public function tablePrefix( $prefix = null );
+
+ /**
+ * Get/set the db schema.
+ * @param string $schema The database schema to set, or omitted to leave it unchanged.
+ * @return string The previous db schema.
+ */
+ public function dbSchema( $schema = null );
+
+ /**
+ * Get properties passed down from the server info array of the load
+ * balancer.
+ *
+ * @param string $name The entry of the info array to get, or null to get the
+ * whole array
+ *
+ * @return array|mixed|null
+ */
+ public function getLBInfo( $name = null );
+
+ /**
+ * Set the LB info array, or a member of it. If called with one parameter,
+ * the LB info array is set to that parameter. If it is called with two
+ * parameters, the member with the given name is set to the given value.
+ *
+ * @param string $name
+ * @param array $value
+ */
+ public function setLBInfo( $name, $value = null );
+
+ /**
+ * Returns true if this database does an implicit sort when doing GROUP BY
+ *
+ * @return bool
+ */
+ public function implicitGroupby();
+
+ /**
+ * Returns true if this database does an implicit order by when the column has an index
+ * For example: SELECT page_title FROM page LIMIT 1
+ *
+ * @return bool
+ */
+ public function implicitOrderby();
+
+ /**
+ * Return the last query that went through DatabaseBase::query()
+ * @return string
+ */
+ public function lastQuery();
+
+ /**
+ * Returns true if the connection may have been used for write queries.
+ * Should return true if unsure.
+ *
+ * @return bool
+ */
+ public function doneWrites();
+
+ /**
+ * Returns the last time the connection may have been used for write queries.
+ * Should return a timestamp if unsure.
+ *
+ * @return int|float UNIX timestamp or false
+ * @since 1.24
+ */
+ public function lastDoneWrites();
+
+ /**
+ * Returns true if there is a transaction open with possible write
+ * queries or transaction pre-commit/idle callbacks waiting on it to finish.
+ *
+ * @return bool
+ */
+ public function writesOrCallbacksPending();
+
+ /**
+ * Get the time spend running write queries for this
+ *
+ * High times could be due to scanning, updates, locking, and such
+ *
+ * @return float|bool Returns false if not transaction is active
+ * @since 1.26
+ */
+ public function pendingWriteQueryDuration();
+
+ /**
+ * Is a connection to the database open?
+ * @return bool
+ */
+ public function isOpen();
+
+ /**
+ * Set a flag for this connection
+ *
+ * @param int $flag DBO_* constants from Defines.php:
+ * - DBO_DEBUG: output some debug info (same as debug())
+ * - DBO_NOBUFFER: don't buffer results (inverse of bufferResults())
+ * - DBO_TRX: automatically start transactions
+ * - DBO_DEFAULT: automatically sets DBO_TRX if not in command line mode
+ * and removes it in command line mode
+ * - DBO_PERSISTENT: use persistant database connection
+ */
+ public function setFlag( $flag );
+
+ /**
+ * Clear a flag for this connection
+ *
+ * @param int $flag DBO_* constants from Defines.php:
+ * - DBO_DEBUG: output some debug info (same as debug())
+ * - DBO_NOBUFFER: don't buffer results (inverse of bufferResults())
+ * - DBO_TRX: automatically start transactions
+ * - DBO_DEFAULT: automatically sets DBO_TRX if not in command line mode
+ * and removes it in command line mode
+ * - DBO_PERSISTENT: use persistant database connection
+ */
+ public function clearFlag( $flag );
+
+ /**
+ * Returns a boolean whether the flag $flag is set for this connection
+ *
+ * @param int $flag DBO_* constants from Defines.php:
+ * - DBO_DEBUG: output some debug info (same as debug())
+ * - DBO_NOBUFFER: don't buffer results (inverse of bufferResults())
+ * - DBO_TRX: automatically start transactions
+ * - DBO_PERSISTENT: use persistant database connection
+ * @return bool
+ */
+ public function getFlag( $flag );
+
+ /**
+ * General read-only accessor
+ *
+ * @param string $name
+ * @return string
+ */
+ public function getProperty( $name );
+
+ /**
+ * @return string
+ */
+ public function getWikiID();
+
+ /**
+ * Get the type of the DBMS, as it appears in $wgDBtype.
+ *
+ * @return string
+ */
+ public function getType();
+
+ /**
+ * Open a connection to the database. Usually aborts on failure
+ *
+ * @param string $server Database server host
+ * @param string $user Database user name
+ * @param string $password Database user password
+ * @param string $dbName Database name
+ * @return bool
+ * @throws DBConnectionError
+ */
+ public function open( $server, $user, $password, $dbName );
+
+ /**
+ * Fetch the next row from the given result object, in object form.
+ * Fields can be retrieved with $row->fieldname, with fields acting like
+ * member variables.
+ * If no more rows are available, false is returned.
+ *
+ * @param ResultWrapper|stdClass $res Object as returned from DatabaseBase::query(), etc.
+ * @return stdClass|bool
+ * @throws DBUnexpectedError Thrown if the database returns an error
+ */
+ public function fetchObject( $res );
+
+ /**
+ * Fetch the next row from the given result object, in associative array
+ * form. Fields are retrieved with $row['fieldname'].
+ * If no more rows are available, false is returned.
+ *
+ * @param ResultWrapper $res Result object as returned from DatabaseBase::query(), etc.
+ * @return array|bool
+ * @throws DBUnexpectedError Thrown if the database returns an error
+ */
+ public function fetchRow( $res );
+
+ /**
+ * Get the number of rows in a result object
+ *
+ * @param mixed $res A SQL result
+ * @return int
+ */
+ public function numRows( $res );
+
+ /**
+ * Get the number of fields in a result object
+ * @see http://www.php.net/mysql_num_fields
+ *
+ * @param mixed $res A SQL result
+ * @return int
+ */
+ public function numFields( $res );
+
+ /**
+ * Get a field name in a result object
+ * @see http://www.php.net/mysql_field_name
+ *
+ * @param mixed $res A SQL result
+ * @param int $n
+ * @return string
+ */
+ public function fieldName( $res, $n );
+
+ /**
+ * Get the inserted value of an auto-increment row
+ *
+ * The value inserted should be fetched from nextSequenceValue()
+ *
+ * Example:
+ * $id = $dbw->nextSequenceValue( 'page_page_id_seq' );
+ * $dbw->insert( 'page', array( 'page_id' => $id ) );
+ * $id = $dbw->insertId();
+ *
+ * @return int
+ */
+ public function insertId();
+
+ /**
+ * Change the position of the cursor in a result object
+ * @see http://www.php.net/mysql_data_seek
+ *
+ * @param mixed $res A SQL result
+ * @param int $row
+ */
+ public function dataSeek( $res, $row );
+
+ /**
+ * Get the last error number
+ * @see http://www.php.net/mysql_errno
+ *
+ * @return int
+ */
+ public function lastErrno();
+
+ /**
+ * Get a description of the last error
+ * @see http://www.php.net/mysql_error
+ *
+ * @return string
+ */
+ public function lastError();
+
+ /**
+ * mysql_fetch_field() wrapper
+ * Returns false if the field doesn't exist
+ *
+ * @param string $table Table name
+ * @param string $field Field name
+ *
+ * @return Field
+ */
+ public function fieldInfo( $table, $field );
+
+ /**
+ * Get the number of rows affected by the last write query
+ * @see http://www.php.net/mysql_affected_rows
+ *
+ * @return int
+ */
+ public function affectedRows();
+
+ /**
+ * Returns a wikitext link to the DB's website, e.g.,
+ * return "[http://www.mysql.com/ MySQL]";
+ * Should at least contain plain text, if for some reason
+ * your database has no website.
+ *
+ * @return string Wikitext of a link to the server software's web site
+ */
+ public function getSoftwareLink();
+
+ /**
+ * A string describing the current software version, like from
+ * mysql_get_server_info().
+ *
+ * @return string Version information from the database server.
+ */
+ public function getServerVersion();
+
+ /**
+ * Closes a database connection.
+ * if it is open : commits any open transactions
+ *
+ * @throws MWException
+ * @return bool Operation success. true if already closed.
+ */
+ public function close();
+
+ /**
+ * @param string $error Fallback error message, used if none is given by DB
+ * @throws DBConnectionError
+ */
+ public function reportConnectionError( $error = 'Unknown error' );
+
+ /**
+ * Run an SQL query and return the result. Normally throws a DBQueryError
+ * on failure. If errors are ignored, returns false instead.
+ *
+ * In new code, the query wrappers select(), insert(), update(), delete(),
+ * etc. should be used where possible, since they give much better DBMS
+ * independence and automatically quote or validate user input in a variety
+ * of contexts. This function is generally only useful for queries which are
+ * explicitly DBMS-dependent and are unsupported by the query wrappers, such
+ * as CREATE TABLE.
+ *
+ * However, the query wrappers themselves should call this function.
+ *
+ * @param string $sql SQL query
+ * @param string $fname Name of the calling function, for profiling/SHOW PROCESSLIST
+ * comment (you can use __METHOD__ or add some extra info)
+ * @param bool $tempIgnore Whether to avoid throwing an exception on errors...
+ * maybe best to catch the exception instead?
+ * @throws MWException
+ * @return bool|ResultWrapper True for a successful write query, ResultWrapper object
+ * for a successful read query, or false on failure if $tempIgnore set
+ */
+ public function query( $sql, $fname = __METHOD__, $tempIgnore = false );
+
+ /**
+ * Report a query error. Log the error, and if neither the object ignore
+ * flag nor the $tempIgnore flag is set, throw a DBQueryError.
+ *
+ * @param string $error
+ * @param int $errno
+ * @param string $sql
+ * @param string $fname
+ * @param bool $tempIgnore
+ * @throws DBQueryError
+ */
+ public function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false );
+
+ /**
+ * Free a result object returned by query() or select(). It's usually not
+ * necessary to call this, just use unset() or let the variable holding
+ * the result object go out of scope.
+ *
+ * @param mixed $res A SQL result
+ */
+ public function freeResult( $res );
+
+ /**
+ * A SELECT wrapper which returns a single field from a single result row.
+ *
+ * Usually throws a DBQueryError on failure. If errors are explicitly
+ * ignored, returns false on failure.
+ *
+ * If no result rows are returned from the query, false is returned.
+ *
+ * @param string|array $table Table name. See DatabaseBase::select() for details.
+ * @param string $var The field name to select. This must be a valid SQL
+ * fragment: do not use unvalidated user input.
+ * @param string|array $cond The condition array. See DatabaseBase::select() for details.
+ * @param string $fname The function name of the caller.
+ * @param string|array $options The query options. See DatabaseBase::select() for details.
+ *
+ * @return bool|mixed The value from the field, or false on failure.
+ */
+ public function selectField(
+ $table, $var, $cond = '', $fname = __METHOD__, $options = array()
+ );
+
+ /**
+ * A SELECT wrapper which returns a list of single field values from result rows.
+ *
+ * Usually throws a DBQueryError on failure. If errors are explicitly
+ * ignored, returns false on failure.
+ *
+ * If no result rows are returned from the query, false is returned.
+ *
+ * @param string|array $table Table name. See DatabaseBase::select() for details.
+ * @param string $var The field name to select. This must be a valid SQL
+ * fragment: do not use unvalidated user input.
+ * @param string|array $cond The condition array. See DatabaseBase::select() for details.
+ * @param string $fname The function name of the caller.
+ * @param string|array $options The query options. See DatabaseBase::select() for details.
+ *
+ * @return bool|array The values from the field, or false on failure
+ * @since 1.25
+ */
+ public function selectFieldValues(
+ $table, $var, $cond = '', $fname = __METHOD__, $options = array()
+ );
+
+ /**
+ * Execute a SELECT query constructed using the various parameters provided.
+ * See below for full details of the parameters.
+ *
+ * @param string|array $table Table name
+ * @param string|array $vars Field names
+ * @param string|array $conds Conditions
+ * @param string $fname Caller function name
+ * @param array $options Query options
+ * @param array $join_conds Join conditions
+ *
+ *
+ * @param string|array $table
+ *
+ * May be either an array of table names, or a single string holding a table
+ * name. If an array is given, table aliases can be specified, for example:
+ *
+ * array( 'a' => 'user' )
+ *
+ * This includes the user table in the query, with the alias "a" available
+ * for use in field names (e.g. a.user_name).
+ *
+ * All of the table names given here are automatically run through
+ * DatabaseBase::tableName(), which causes the table prefix (if any) to be
+ * added, and various other table name mappings to be performed.
+ *
+ *
+ * @param string|array $vars
+ *
+ * May be either a field name or an array of field names. The field names
+ * can be complete fragments of SQL, for direct inclusion into the SELECT
+ * query. If an array is given, field aliases can be specified, for example:
+ *
+ * array( 'maxrev' => 'MAX(rev_id)' )
+ *
+ * This includes an expression with the alias "maxrev" in the query.
+ *
+ * If an expression is given, care must be taken to ensure that it is
+ * DBMS-independent.
+ *
+ *
+ * @param string|array $conds
+ *
+ * May be either a string containing a single condition, or an array of
+ * conditions. If an array is given, the conditions constructed from each
+ * element are combined with AND.
+ *
+ * Array elements may take one of two forms:
+ *
+ * - Elements with a numeric key are interpreted as raw SQL fragments.
+ * - Elements with a string key are interpreted as equality conditions,
+ * where the key is the field name.
+ * - If the value of such an array element is a scalar (such as a
+ * string), it will be treated as data and thus quoted appropriately.
+ * If it is null, an IS NULL clause will be added.
+ * - If the value is an array, an IN (...) clause will be constructed
+ * from its non-null elements, and an IS NULL clause will be added
+ * if null is present, such that the field may match any of the
+ * elements in the array. The non-null elements will be quoted.
+ *
+ * Note that expressions are often DBMS-dependent in their syntax.
+ * DBMS-independent wrappers are provided for constructing several types of
+ * expression commonly used in condition queries. See:
+ * - DatabaseBase::buildLike()
+ * - DatabaseBase::conditional()
+ *
+ *
+ * @param string|array $options
+ *
+ * Optional: Array of query options. Boolean options are specified by
+ * including them in the array as a string value with a numeric key, for
+ * example:
+ *
+ * array( 'FOR UPDATE' )
+ *
+ * The supported options are:
+ *
+ * - OFFSET: Skip this many rows at the start of the result set. OFFSET
+ * with LIMIT can theoretically be used for paging through a result set,
+ * but this is discouraged in MediaWiki for performance reasons.
+ *
+ * - LIMIT: Integer: return at most this many rows. The rows are sorted
+ * and then the first rows are taken until the limit is reached. LIMIT
+ * is applied to a result set after OFFSET.
+ *
+ * - FOR UPDATE: Boolean: lock the returned rows so that they can't be
+ * changed until the next COMMIT.
+ *
+ * - DISTINCT: Boolean: return only unique result rows.
+ *
+ * - GROUP BY: May be either an SQL fragment string naming a field or
+ * expression to group by, or an array of such SQL fragments.
+ *
+ * - HAVING: May be either an string containing a HAVING clause or an array of
+ * conditions building the HAVING clause. If an array is given, the conditions
+ * constructed from each element are combined with AND.
+ *
+ * - ORDER BY: May be either an SQL fragment giving a field name or
+ * expression to order by, or an array of such SQL fragments.
+ *
+ * - USE INDEX: This may be either a string giving the index name to use
+ * for the query, or an array. If it is an associative array, each key
+ * gives the table name (or alias), each value gives the index name to
+ * use for that table. All strings are SQL fragments and so should be
+ * validated by the caller.
+ *
+ * - EXPLAIN: In MySQL, this causes an EXPLAIN SELECT query to be run,
+ * instead of SELECT.
+ *
+ * And also the following boolean MySQL extensions, see the MySQL manual
+ * for documentation:
+ *
+ * - LOCK IN SHARE MODE
+ * - STRAIGHT_JOIN
+ * - HIGH_PRIORITY
+ * - SQL_BIG_RESULT
+ * - SQL_BUFFER_RESULT
+ * - SQL_SMALL_RESULT
+ * - SQL_CALC_FOUND_ROWS
+ * - SQL_CACHE
+ * - SQL_NO_CACHE
+ *
+ *
+ * @param string|array $join_conds
+ *
+ * Optional associative array of table-specific join conditions. In the
+ * most common case, this is unnecessary, since the join condition can be
+ * in $conds. However, it is useful for doing a LEFT JOIN.
+ *
+ * The key of the array contains the table name or alias. The value is an
+ * array with two elements, numbered 0 and 1. The first gives the type of
+ * join, the second is an SQL fragment giving the join condition for that
+ * table. For example:
+ *
+ * array( 'page' => array( 'LEFT JOIN', 'page_latest=rev_id' ) )
+ *
+ * @return ResultWrapper|bool If the query returned no rows, a ResultWrapper
+ * with no rows in it will be returned. If there was a query error, a
+ * DBQueryError exception will be thrown, except if the "ignore errors"
+ * option was set, in which case false will be returned.
+ */
+ public function select(
+ $table, $vars, $conds = '', $fname = __METHOD__,
+ $options = array(), $join_conds = array()
+ );
+
+ /**
+ * The equivalent of DatabaseBase::select() except that the constructed SQL
+ * is returned, instead of being immediately executed. This can be useful for
+ * doing UNION queries, where the SQL text of each query is needed. In general,
+ * however, callers outside of Database classes should just use select().
+ *
+ * @param string|array $table Table name
+ * @param string|array $vars Field names
+ * @param string|array $conds Conditions
+ * @param string $fname Caller function name
+ * @param string|array $options Query options
+ * @param string|array $join_conds Join conditions
+ *
+ * @return string SQL query string.
+ * @see DatabaseBase::select()
+ */
+ public function selectSQLText(
+ $table, $vars, $conds = '', $fname = __METHOD__,
+ $options = array(), $join_conds = array()
+ );
+
+ /**
+ * Single row SELECT wrapper. Equivalent to DatabaseBase::select(), except
+ * that a single row object is returned. If the query returns no rows,
+ * false is returned.
+ *
+ * @param string|array $table Table name
+ * @param string|array $vars Field names
+ * @param array $conds Conditions
+ * @param string $fname Caller function name
+ * @param string|array $options Query options
+ * @param array|string $join_conds Join conditions
+ *
+ * @return stdClass|bool
+ */
+ public function selectRow( $table, $vars, $conds, $fname = __METHOD__,
+ $options = array(), $join_conds = array()
+ );
+
+ /**
+ * Estimate the number of rows in dataset
+ *
+ * MySQL allows you to estimate the number of rows that would be returned
+ * by a SELECT query, using EXPLAIN SELECT. The estimate is provided using
+ * index cardinality statistics, and is notoriously inaccurate, especially
+ * when large numbers of rows have recently been added or deleted.
+ *
+ * For DBMSs that don't support fast result size estimation, this function
+ * will actually perform the SELECT COUNT(*).
+ *
+ * Takes the same arguments as DatabaseBase::select().
+ *
+ * @param string $table Table name
+ * @param string $vars Unused
+ * @param array|string $conds Filters on the table
+ * @param string $fname Function name for profiling
+ * @param array $options Options for select
+ * @return int Row count
+ */
+ public function estimateRowCount(
+ $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = array()
+ );
+
+ /**
+ * Get the number of rows in dataset
+ *
+ * This is useful when trying to do COUNT(*) but with a LIMIT for performance.
+ *
+ * Takes the same arguments as DatabaseBase::select().
+ *
+ * @param string $table Table name
+ * @param string $vars Unused
+ * @param array|string $conds Filters on the table
+ * @param string $fname Function name for profiling
+ * @param array $options Options for select
+ * @return int Row count
+ * @since 1.24
+ */
+ public function selectRowCount(
+ $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = array()
+ );
+
+ /**
+ * Determines whether a field exists in a table
+ *
+ * @param string $table Table name
+ * @param string $field Filed to check on that table
+ * @param string $fname Calling function name (optional)
+ * @return bool Whether $table has filed $field
+ */
+ public function fieldExists( $table, $field, $fname = __METHOD__ );
+
+ /**
+ * Determines whether an index exists
+ * Usually throws a DBQueryError on failure
+ * If errors are explicitly ignored, returns NULL on failure
+ *
+ * @param string $table
+ * @param string $index
+ * @param string $fname
+ * @return bool|null
+ */
+ public function indexExists( $table, $index, $fname = __METHOD__ );
+
+ /**
+ * Query whether a given table exists
+ *
+ * @param string $table
+ * @param string $fname
+ * @return bool
+ */
+ public function tableExists( $table, $fname = __METHOD__ );
+
+ /**
+ * Determines if a given index is unique
+ *
+ * @param string $table
+ * @param string $index
+ *
+ * @return bool
+ */
+ public function indexUnique( $table, $index );
+
+ /**
+ * INSERT wrapper, inserts an array into a table.
+ *
+ * $a may be either:
+ *
+ * - A single associative array. The array keys are the field names, and
+ * the values are the values to insert. The values are treated as data
+ * and will be quoted appropriately. If NULL is inserted, this will be
+ * converted to a database NULL.
+ * - An array with numeric keys, holding a list of associative arrays.
+ * This causes a multi-row INSERT on DBMSs that support it. The keys in
+ * each subarray must be identical to each other, and in the same order.
+ *
+ * Usually throws a DBQueryError on failure. If errors are explicitly ignored,
+ * returns success.
+ *
+ * $options is an array of options, with boolean options encoded as values
+ * with numeric keys, in the same style as $options in
+ * DatabaseBase::select(). Supported options are:
+ *
+ * - IGNORE: Boolean: if present, duplicate key errors are ignored, and
+ * any rows which cause duplicate key errors are not inserted. It's
+ * possible to determine how many rows were successfully inserted using
+ * DatabaseBase::affectedRows().
+ *
+ * @param string $table Table name. This will be passed through
+ * DatabaseBase::tableName().
+ * @param array $a Array of rows to insert
+ * @param string $fname Calling function name (use __METHOD__) for logs/profiling
+ * @param array $options Array of options
+ *
+ * @return bool
+ */
+ public function insert( $table, $a, $fname = __METHOD__, $options = array() );
+
+ /**
+ * UPDATE wrapper. Takes a condition array and a SET array.
+ *
+ * @param string $table Name of the table to UPDATE. This will be passed through
+ * DatabaseBase::tableName().
+ * @param array $values An array of values to SET. For each array element,
+ * the key gives the field name, and the value gives the data to set
+ * that field to. The data will be quoted by DatabaseBase::addQuotes().
+ * @param array $conds An array of conditions (WHERE). See
+ * DatabaseBase::select() for the details of the format of condition
+ * arrays. Use '*' to update all rows.
+ * @param string $fname The function name of the caller (from __METHOD__),
+ * for logging and profiling.
+ * @param array $options An array of UPDATE options, can be:
+ * - IGNORE: Ignore unique key conflicts
+ * - LOW_PRIORITY: MySQL-specific, see MySQL manual.
+ * @return bool
+ */
+ public function update( $table, $values, $conds, $fname = __METHOD__, $options = array() );
+
+ /**
+ * Makes an encoded list of strings from an array
+ *
+ * @param array $a Containing the data
+ * @param int $mode Constant
+ * - LIST_COMMA: Comma separated, no field names
+ * - LIST_AND: ANDed WHERE clause (without the WHERE). See the
+ * documentation for $conds in DatabaseBase::select().
+ * - LIST_OR: ORed WHERE clause (without the WHERE)
+ * - LIST_SET: Comma separated with field names, like a SET clause
+ * - LIST_NAMES: Comma separated field names
+ * @throws MWException|DBUnexpectedError
+ * @return string
+ */
+ public function makeList( $a, $mode = LIST_COMMA );
+
+ /**
+ * Build a partial where clause from a 2-d array such as used for LinkBatch.
+ * The keys on each level may be either integers or strings.
+ *
+ * @param array $data Organized as 2-d
+ * array(baseKeyVal => array(subKeyVal => [ignored], ...), ...)
+ * @param string $baseKey Field name to match the base-level keys to (eg 'pl_namespace')
+ * @param string $subKey Field name to match the sub-level keys to (eg 'pl_title')
+ * @return string|bool SQL fragment, or false if no items in array
+ */
+ public function makeWhereFrom2d( $data, $baseKey, $subKey );
+
+ /**
+ * @param string $field
+ * @return string
+ */
+ public function bitNot( $field );
+
+ /**
+ * @param string $fieldLeft
+ * @param string $fieldRight
+ * @return string
+ */
+ public function bitAnd( $fieldLeft, $fieldRight );
+
+ /**
+ * @param string $fieldLeft
+ * @param string $fieldRight
+ * @return string
+ */
+ public function bitOr( $fieldLeft, $fieldRight );
+
+ /**
+ * Build a concatenation list to feed into a SQL query
+ * @param array $stringList List of raw SQL expressions; caller is
+ * responsible for any quoting
+ * @return string
+ */
+ public function buildConcat( $stringList );
+
+ /**
+ * Build a GROUP_CONCAT or equivalent statement for a query.
+ *
+ * This is useful for combining a field for several rows into a single string.
+ * NULL values will not appear in the output, duplicated values will appear,
+ * and the resulting delimiter-separated values have no defined sort order.
+ * Code using the results may need to use the PHP unique() or sort() methods.
+ *
+ * @param string $delim Glue to bind the results together
+ * @param string|array $table Table name
+ * @param string $field Field name
+ * @param string|array $conds Conditions
+ * @param string|array $join_conds Join conditions
+ * @return string SQL text
+ * @since 1.23
+ */
+ public function buildGroupConcatField(
+ $delim, $table, $field, $conds = '', $join_conds = array()
+ );
+
+ /**
+ * Change the current database
+ *
+ * @param string $db
+ * @return bool Success or failure
+ */
+ public function selectDB( $db );
+
+ /**
+ * Get the current DB name
+ * @return string
+ */
+ public function getDBname();
+
+ /**
+ * Get the server hostname or IP address
+ * @return string
+ */
+ public function getServer();
+
+ /**
+ * Adds quotes and backslashes.
+ *
+ * @param string|Blob $s
+ * @return string
+ */
+ public function addQuotes( $s );
+
+ /**
+ * LIKE statement wrapper, receives a variable-length argument list with
+ * parts of pattern to match containing either string literals that will be
+ * escaped or tokens returned by anyChar() or anyString(). Alternatively,
+ * the function could be provided with an array of aforementioned
+ * parameters.
+ *
+ * Example: $dbr->buildLike( 'My_page_title/', $dbr->anyString() ) returns
+ * a LIKE clause that searches for subpages of 'My page title'.
+ * Alternatively:
+ * $pattern = array( 'My_page_title/', $dbr->anyString() );
+ * $query .= $dbr->buildLike( $pattern );
+ *
+ * @since 1.16
+ * @return string Fully built LIKE statement
+ */
+ public function buildLike();
+
+ /**
+ * Returns a token for buildLike() that denotes a '_' to be used in a LIKE query
+ *
+ * @return LikeMatch
+ */
+ public function anyChar();
+
+ /**
+ * Returns a token for buildLike() that denotes a '%' to be used in a LIKE query
+ *
+ * @return LikeMatch
+ */
+ public function anyString();
+
+ /**
+ * Returns an appropriately quoted sequence value for inserting a new row.
+ * MySQL has autoincrement fields, so this is just NULL. But the PostgreSQL
+ * subclass will return an integer, and save the value for insertId()
+ *
+ * Any implementation of this function should *not* involve reusing
+ * sequence numbers created for rolled-back transactions.
+ * See http://bugs.mysql.com/bug.php?id=30767 for details.
+ * @param string $seqName
+ * @return null|int
+ */
+ public function nextSequenceValue( $seqName );
+
+ /**
+ * REPLACE query wrapper.
+ *
+ * REPLACE is a very handy MySQL extension, which functions like an INSERT
+ * except that when there is a duplicate key error, the old row is deleted
+ * and the new row is inserted in its place.
+ *
+ * We simulate this with standard SQL with a DELETE followed by INSERT. To
+ * perform the delete, we need to know what the unique indexes are so that
+ * we know how to find the conflicting rows.
+ *
+ * It may be more efficient to leave off unique indexes which are unlikely
+ * to collide. However if you do this, you run the risk of encountering
+ * errors which wouldn't have occurred in MySQL.
+ *
+ * @param string $table The table to replace the row(s) in.
+ * @param array $uniqueIndexes Is an array of indexes. Each element may be either
+ * a field name or an array of field names
+ * @param array $rows Can be either a single row to insert, or multiple rows,
+ * in the same format as for DatabaseBase::insert()
+ * @param string $fname Calling function name (use __METHOD__) for logs/profiling
+ */
+ public function replace( $table, $uniqueIndexes, $rows, $fname = __METHOD__ );
+
+ /**
+ * INSERT ON DUPLICATE KEY UPDATE wrapper, upserts an array into a table.
+ *
+ * This updates any conflicting rows (according to the unique indexes) using
+ * the provided SET clause and inserts any remaining (non-conflicted) rows.
+ *
+ * $rows may be either:
+ * - A single associative array. The array keys are the field names, and
+ * the values are the values to insert. The values are treated as data
+ * and will be quoted appropriately. If NULL is inserted, this will be
+ * converted to a database NULL.
+ * - An array with numeric keys, holding a list of associative arrays.
+ * This causes a multi-row INSERT on DBMSs that support it. The keys in
+ * each subarray must be identical to each other, and in the same order.
+ *
+ * It may be more efficient to leave off unique indexes which are unlikely
+ * to collide. However if you do this, you run the risk of encountering
+ * errors which wouldn't have occurred in MySQL.
+ *
+ * Usually throws a DBQueryError on failure. If errors are explicitly ignored,
+ * returns success.
+ *
+ * @since 1.22
+ *
+ * @param string $table Table name. This will be passed through DatabaseBase::tableName().
+ * @param array $rows A single row or list of rows to insert
+ * @param array $uniqueIndexes List of single field names or field name tuples
+ * @param array $set An array of values to SET. For each array element, the
+ * key gives the field name, and the value gives the data to set that
+ * field to. The data will be quoted by DatabaseBase::addQuotes().
+ * @param string $fname Calling function name (use __METHOD__) for logs/profiling
+ * @throws Exception
+ * @return bool
+ */
+ public function upsert(
+ $table, array $rows, array $uniqueIndexes, array $set, $fname = __METHOD__
+ );
+
+ /**
+ * DELETE where the condition is a join.
+ *
+ * MySQL overrides this to use a multi-table DELETE syntax, in other databases
+ * we use sub-selects
+ *
+ * For safety, an empty $conds will not delete everything. If you want to
+ * delete all rows where the join condition matches, set $conds='*'.
+ *
+ * DO NOT put the join condition in $conds.
+ *
+ * @param string $delTable The table to delete from.
+ * @param string $joinTable The other table.
+ * @param string $delVar The variable to join on, in the first table.
+ * @param string $joinVar The variable to join on, in the second table.
+ * @param array $conds Condition array of field names mapped to variables,
+ * ANDed together in the WHERE clause
+ * @param string $fname Calling function name (use __METHOD__) for logs/profiling
+ * @throws DBUnexpectedError
+ */
+ public function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds,
+ $fname = __METHOD__
+ );
+
+ /**
+ * DELETE query wrapper.
+ *
+ * @param array $table Table name
+ * @param string|array $conds Array of conditions. See $conds in DatabaseBase::select()
+ * for the format. Use $conds == "*" to delete all rows
+ * @param string $fname Name of the calling function
+ * @throws DBUnexpectedError
+ * @return bool|ResultWrapper
+ */
+ public function delete( $table, $conds, $fname = __METHOD__ );
+
+ /**
+ * INSERT SELECT wrapper. Takes data from a SELECT query and inserts it
+ * into another table.
+ *
+ * @param string $destTable The table name to insert into
+ * @param string|array $srcTable May be either a table name, or an array of table names
+ * to include in a join.
+ *
+ * @param array $varMap Must be an associative array of the form
+ * array( 'dest1' => 'source1', ...). Source items may be literals
+ * rather than field names, but strings should be quoted with
+ * DatabaseBase::addQuotes()
+ *
+ * @param array $conds Condition array. See $conds in DatabaseBase::select() for
+ * the details of the format of condition arrays. May be "*" to copy the
+ * whole table.
+ *
+ * @param string $fname The function name of the caller, from __METHOD__
+ *
+ * @param array $insertOptions Options for the INSERT part of the query, see
+ * DatabaseBase::insert() for details.
+ * @param array $selectOptions Options for the SELECT part of the query, see
+ * DatabaseBase::select() for details.
+ *
+ * @return ResultWrapper
+ */
+ public function insertSelect( $destTable, $srcTable, $varMap, $conds,
+ $fname = __METHOD__,
+ $insertOptions = array(), $selectOptions = array()
+ );
+
+ /**
+ * Returns true if current database backend supports ORDER BY or LIMIT for separate subqueries
+ * within the UNION construct.
+ * @return bool
+ */
+ public function unionSupportsOrderAndLimit();
+
+ /**
+ * Construct a UNION query
+ * This is used for providing overload point for other DB abstractions
+ * not compatible with the MySQL syntax.
+ * @param array $sqls SQL statements to combine
+ * @param bool $all Use UNION ALL
+ * @return string SQL fragment
+ */
+ public function unionQueries( $sqls, $all );
+
+ /**
+ * Returns an SQL expression for a simple conditional. This doesn't need
+ * to be overridden unless CASE isn't supported in your DBMS.
+ *
+ * @param string|array $cond SQL expression which will result in a boolean value
+ * @param string $trueVal SQL expression to return if true
+ * @param string $falseVal SQL expression to return if false
+ * @return string SQL fragment
+ */
+ public function conditional( $cond, $trueVal, $falseVal );
+
+ /**
+ * Returns a comand for str_replace function in SQL query.
+ * Uses REPLACE() in MySQL
+ *
+ * @param string $orig Column to modify
+ * @param string $old Column to seek
+ * @param string $new Column to replace with
+ *
+ * @return string
+ */
+ public function strreplace( $orig, $old, $new );
+
+ /**
+ * Determines how long the server has been up
+ * STUB
+ *
+ * @return int
+ */
+ public function getServerUptime();
+
+ /**
+ * Determines if the last failure was due to a deadlock
+ * STUB
+ *
+ * @return bool
+ */
+ public function wasDeadlock();
+
+ /**
+ * Determines if the last failure was due to a lock timeout
+ * STUB
+ *
+ * @return bool
+ */
+ public function wasLockTimeout();
+
+ /**
+ * Determines if the last query error was something that should be dealt
+ * with by pinging the connection and reissuing the query.
+ * STUB
+ *
+ * @return bool
+ */
+ public function wasErrorReissuable();
+
+ /**
+ * Determines if the last failure was due to the database being read-only.
+ * STUB
+ *
+ * @return bool
+ */
+ public function wasReadOnlyError();
+
+ /**
+ * Wait for the slave to catch up to a given master position.
+ *
+ * @param DBMasterPos $pos
+ * @param int $timeout The maximum number of seconds to wait for
+ * synchronisation
+ * @return int Zero if the slave was past that position already,
+ * greater than zero if we waited for some period of time, less than
+ * zero if we timed out.
+ */
+ public function masterPosWait( DBMasterPos $pos, $timeout );
+
+ /**
+ * Get the replication position of this slave
+ *
+ * @return DBMasterPos|bool False if this is not a slave.
+ */
+ public function getSlavePos();
+
+ /**
+ * Get the position of this master
+ *
+ * @return DBMasterPos|bool False if this is not a master
+ */
+ public function getMasterPos();
+
+ /**
+ * Run an anonymous function as soon as there is no transaction pending.
+ * If there is a transaction and it is rolled back, then the callback is cancelled.
+ * Queries in the function will run in AUTO-COMMIT mode unless there are begin() calls.
+ * Callbacks must commit any transactions that they begin.
+ *
+ * This is useful for updates to different systems or when separate transactions are needed.
+ * For example, one might want to enqueue jobs into a system outside the database, but only
+ * after the database is updated so that the jobs will see the data when they actually run.
+ * It can also be used for updates that easily cause deadlocks if locks are held too long.
+ *
+ * @param callable $callback
+ * @since 1.20
+ */
+ public function onTransactionIdle( $callback );
+
+ /**
+ * Run an anonymous function before the current transaction commits or now if there is none.
+ * If there is a transaction and it is rolled back, then the callback is cancelled.
+ * Callbacks must not start nor commit any transactions.
+ *
+ * This is useful for updates that easily cause deadlocks if locks are held too long
+ * but where atomicity is strongly desired for these updates and some related updates.
+ *
+ * @param callable $callback
+ * @since 1.22
+ */
+ public function onTransactionPreCommitOrIdle( $callback );
+
+ /**
+ * Begin an atomic section of statements
+ *
+ * If a transaction has been started already, just keep track of the given
+ * section name to make sure the transaction is not committed pre-maturely.
+ * This function can be used in layers (with sub-sections), so use a stack
+ * to keep track of the different atomic sections. If there is no transaction,
+ * start one implicitly.
+ *
+ * The goal of this function is to create an atomic section of SQL queries
+ * without having to start a new transaction if it already exists.
+ *
+ * Atomic sections are more strict than transactions. With transactions,
+ * attempting to begin a new transaction when one is already running results
+ * in MediaWiki issuing a brief warning and doing an implicit commit. All
+ * atomic levels *must* be explicitly closed using DatabaseBase::endAtomic(),
+ * and any database transactions cannot be began or committed until all atomic
+ * levels are closed. There is no such thing as implicitly opening or closing
+ * an atomic section.
+ *
+ * @since 1.23
+ * @param string $fname
+ * @throws DBError
+ */
+ public function startAtomic( $fname = __METHOD__ );
+
+ /**
+ * Ends an atomic section of SQL statements
+ *
+ * Ends the next section of atomic SQL statements and commits the transaction
+ * if necessary.
+ *
+ * @since 1.23
+ * @see DatabaseBase::startAtomic
+ * @param string $fname
+ * @throws DBError
+ */
+ public function endAtomic( $fname = __METHOD__ );
+
+ /**
+ * Begin a transaction. If a transaction is already in progress,
+ * that transaction will be committed before the new transaction is started.
+ *
+ * Note that when the DBO_TRX flag is set (which is usually the case for web
+ * requests, but not for maintenance scripts), any previous database query
+ * will have started a transaction automatically.
+ *
+ * Nesting of transactions is not supported. Attempts to nest transactions
+ * will cause a warning, unless the current transaction was started
+ * automatically because of the DBO_TRX flag.
+ *
+ * @param string $fname
+ * @throws DBError
+ */
+ public function begin( $fname = __METHOD__ );
+
+ /**
+ * Commits a transaction previously started using begin().
+ * If no transaction is in progress, a warning is issued.
+ *
+ * Nesting of transactions is not supported.
+ *
+ * @param string $fname
+ * @param string $flush Flush flag, set to 'flush' to disable warnings about
+ * explicitly committing implicit transactions, or calling commit when no
+ * transaction is in progress. This will silently break any ongoing
+ * explicit transaction. Only set the flush flag if you are sure that it
+ * is safe to ignore these warnings in your context.
+ * @throws DBUnexpectedError
+ */
+ public function commit( $fname = __METHOD__, $flush = '' );
+
+ /**
+ * Rollback a transaction previously started using begin().
+ * If no transaction is in progress, a warning is issued.
+ *
+ * No-op on non-transactional databases.
+ *
+ * @param string $fname
+ * @param string $flush Flush flag, set to 'flush' to disable warnings about
+ * calling rollback when no transaction is in progress. This will silently
+ * break any ongoing explicit transaction. Only set the flush flag if you
+ * are sure that it is safe to ignore these warnings in your context.
+ * @throws DBUnexpectedError
+ * @since 1.23 Added $flush parameter
+ */
+ public function rollback( $fname = __METHOD__, $flush = '' );
+
+ /**
+ * List all tables on the database
+ *
+ * @param string $prefix Only show tables with this prefix, e.g. mw_
+ * @param string $fname Calling function name
+ * @throws MWException
+ * @return array
+ */
+ public function listTables( $prefix = null, $fname = __METHOD__ );
+
+ /**
+ * Convert a timestamp in one of the formats accepted by wfTimestamp()
+ * to the format used for inserting into timestamp fields in this DBMS.
+ *
+ * The result is unquoted, and needs to be passed through addQuotes()
+ * before it can be included in raw SQL.
+ *
+ * @param string|int $ts
+ *
+ * @return string
+ */
+ public function timestamp( $ts = 0 );
+
+ /**
+ * Convert a timestamp in one of the formats accepted by wfTimestamp()
+ * to the format used for inserting into timestamp fields in this DBMS. If
+ * NULL is input, it is passed through, allowing NULL values to be inserted
+ * into timestamp fields.
+ *
+ * The result is unquoted, and needs to be passed through addQuotes()
+ * before it can be included in raw SQL.
+ *
+ * @param string|int $ts
+ *
+ * @return string
+ */
+ public function timestampOrNull( $ts = null );
+
+ /**
+ * Take the result from a query, and wrap it in a ResultWrapper if
+ * necessary. Boolean values are passed through as is, to indicate success
+ * of write queries or failure.
+ *
+ * Once upon a time, DatabaseBase::query() returned a bare MySQL result
+ * resource, and it was necessary to call this function to convert it to
+ * a wrapper. Nowadays, raw database objects are never exposed to external
+ * callers, so this is unnecessary in external code. For compatibility with
+ * old code, ResultWrapper objects are passed through unaltered.
+ *
+ * @param bool|ResultWrapper|resource $result
+ * @return bool|ResultWrapper
+ */
+ public function resultObject( $result );
+
+ /**
+ * Ping the server and try to reconnect if it there is no connection
+ *
+ * @return bool Success or failure
+ */
+ public function ping();
+
+ /**
+ * Get slave lag. Currently supported only by MySQL.
+ *
+ * Note that this function will generate a fatal error on many
+ * installations. Most callers should use LoadBalancer::safeGetLag()
+ * instead.
+ *
+ * @return int Database replication lag in seconds
+ */
+ public function getLag();
+
+ /**
+ * Return the maximum number of items allowed in a list, or 0 for unlimited.
+ *
+ * @return int
+ */
+ public function maxListLen();
+
+ /**
+ * Some DBMSs have a special format for inserting into blob fields, they
+ * don't allow simple quoted strings to be inserted. To insert into such
+ * a field, pass the data through this function before passing it to
+ * DatabaseBase::insert().
+ *
+ * @param string $b
+ * @return string
+ */
+ public function encodeBlob( $b );
+
+ /**
+ * Some DBMSs return a special placeholder object representing blob fields
+ * in result objects. Pass the object through this function to return the
+ * original string.
+ *
+ * @param string|Blob $b
+ * @return string
+ */
+ public function decodeBlob( $b );
+
+ /**
+ * Override database's default behavior. $options include:
+ * 'connTimeout' : Set the connection timeout value in seconds.
+ * May be useful for very long batch queries such as
+ * full-wiki dumps, where a single query reads out over
+ * hours or days.
+ *
+ * @param array $options
+ * @return void
+ */
+ public function setSessionOptions( array $options );
+
+ /**
+ * Set variables to be used in sourceFile/sourceStream, in preference to the
+ * ones in $GLOBALS. If an array is set here, $GLOBALS will not be used at
+ * all. If it's set to false, $GLOBALS will be used.
+ *
+ * @param bool|array $vars Mapping variable name to value.
+ */
+ public function setSchemaVars( $vars );
+
+ /**
+ * Check to see if a named lock is available (non-blocking)
+ *
+ * @param string $lockName Name of lock to poll
+ * @param string $method Name of method calling us
+ * @return bool
+ * @since 1.20
+ */
+ public function lockIsFree( $lockName, $method );
+
+ /**
+ * Acquire a named lock
+ *
+ * Named locks are not related to transactions
+ *
+ * @param string $lockName Name of lock to aquire
+ * @param string $method Name of method calling us
+ * @param int $timeout
+ * @return bool
+ */
+ public function lock( $lockName, $method, $timeout = 5 );
+
+ /**
+ * Release a lock
+ *
+ * Named locks are not related to transactions
+ *
+ * @param string $lockName Name of lock to release
+ * @param string $method Name of method calling us
+ *
+ * @return int Returns 1 if the lock was released, 0 if the lock was not established
+ * by this thread (in which case the lock is not released), and NULL if the named
+ * lock did not exist
+ */
+ public function unlock( $lockName, $method );
+
+ /**
+ * Check to see if a named lock used by lock() use blocking queues
+ *
+ * @return bool
+ * @since 1.26
+ */
+ public function namedLocksEnqueue();
+
+ /**
+ * Find out when 'infinity' is. Most DBMSes support this. This is a special
+ * keyword for timestamps in PostgreSQL, and works with CHAR(14) as well
+ * because "i" sorts after all numbers.
+ *
+ * @return string
+ */
+ public function getInfinity();
+
+ /**
+ * Encode an expiry time into the DBMS dependent format
+ *
+ * @param string $expiry Timestamp for expiry, or the 'infinity' string
+ * @return string
+ */
+ public function encodeExpiry( $expiry );
+
+ /**
+ * Decode an expiry time into a DBMS independent format
+ *
+ * @param string $expiry DB timestamp field value for expiry
+ * @param int $format TS_* constant, defaults to TS_MW
+ * @return string
+ */
+ public function decodeExpiry( $expiry, $format = TS_MW );
+
+ /**
+ * Allow or deny "big selects" for this session only. This is done by setting
+ * the sql_big_selects session variable.
+ *
+ * This is a MySQL-specific feature.
+ *
+ * @param bool|string $value True for allow, false for deny, or "default" to
+ * restore the initial value
+ */
+ public function setBigSelects( $value = true );
+}
diff --git a/includes/db/LBFactory.php b/includes/db/LBFactory.php
index 4551e2d7..cf522b20 100644
--- a/includes/db/LBFactory.php
+++ b/includes/db/LBFactory.php
@@ -178,6 +178,15 @@ abstract class LBFactory {
}
/**
+ * Commit on all connections. Done for two reasons:
+ * 1. To commit changes to the masters.
+ * 2. To release the snapshot on all connections, master and slave.
+ */
+ public function commitAll() {
+ $this->forEachLBCallMethod( 'commitAll' );
+ }
+
+ /**
* Commit changes on all master connections
*/
public function commitMasterChanges() {
@@ -199,7 +208,7 @@ abstract class LBFactory {
*/
public function hasMasterChanges() {
$ret = false;
- $this->forEachLB( function ( $lb ) use ( &$ret ) {
+ $this->forEachLB( function ( LoadBalancer $lb ) use ( &$ret ) {
$ret = $ret || $lb->hasMasterChanges();
} );
return $ret;
diff --git a/includes/db/LBFactoryMulti.php b/includes/db/LBFactoryMulti.php
index aa305ab1..92fbccd6 100644
--- a/includes/db/LBFactoryMulti.php
+++ b/includes/db/LBFactoryMulti.php
@@ -232,7 +232,7 @@ class LBFactoryMulti extends LBFactory {
public function getMainLB( $wiki = false ) {
$section = $this->getSectionForWiki( $wiki );
if ( !isset( $this->mainLBs[$section] ) ) {
- $lb = $this->newMainLB( $wiki, $section );
+ $lb = $this->newMainLB( $wiki );
$lb->parentInfo( array( 'id' => "main-$section" ) );
$this->chronProt->initLB( $lb );
$this->mainLBs[$section] = $lb;
diff --git a/includes/db/LoadBalancer.php b/includes/db/LoadBalancer.php
index d9584e14..52dca087 100644
--- a/includes/db/LoadBalancer.php
+++ b/includes/db/LoadBalancer.php
@@ -60,8 +60,6 @@ class LoadBalancer {
private $mLastError = 'Unknown error';
/** @var integer Total connections opened */
private $connsOpened = 0;
- /** @var ProcessCacheLRU */
- private $mProcCache;
/** @var integer Warn when this many connection are held */
const CONN_HELD_WARN_THRESHOLD = 10;
@@ -113,8 +111,6 @@ class LoadBalancer {
}
}
}
-
- $this->mProcCache = new ProcessCacheLRU( 30 );
}
/**
@@ -214,7 +210,7 @@ class LoadBalancer {
* @return bool|int|string
*/
public function getReaderIndex( $group = false, $wiki = false ) {
- global $wgReadOnly, $wgDBtype;
+ global $wgDBtype;
# @todo FIXME: For now, only go through all this for mysql databases
if ( $wgDBtype != 'mysql' ) {
@@ -258,7 +254,7 @@ class LoadBalancer {
# meets our criteria
$currentLoads = $nonErrorLoads;
while ( count( $currentLoads ) ) {
- if ( $wgReadOnly || $this->mAllowLagged || $laggedSlaveMode ) {
+ if ( $this->mAllowLagged || $laggedSlaveMode ) {
$i = ArrayUtils::pickRandom( $currentLoads );
} else {
$i = false;
@@ -277,8 +273,6 @@ class LoadBalancer {
if ( $i === false && count( $currentLoads ) != 0 ) {
# All slaves lagged. Switch to read-only mode
wfDebugLog( 'replication', "All slaves lagged. Switch to read-only mode" );
- $wgReadOnly = 'The database has been automatically locked ' .
- 'while the slave database servers catch up to the master';
$i = ArrayUtils::pickRandom( $currentLoads );
$laggedSlaveMode = true;
}
@@ -293,8 +287,8 @@ class LoadBalancer {
return false;
}
- wfDebugLog( 'connect', __METHOD__ .
- ": Using reader #$i: {$this->mServers[$i]['host']}..." );
+ $serverName = $this->getServerName( $i );
+ wfDebugLog( 'connect', __METHOD__ . ": Using reader #$i: $serverName..." );
$conn = $this->openConnection( $i, $wiki );
if ( !$conn ) {
@@ -330,6 +324,10 @@ class LoadBalancer {
}
if ( $this->mReadIndex <= 0 && $this->mLoads[$i] > 0 && $group === false ) {
$this->mReadIndex = $i;
+ # Record if the generic reader index is in "lagged slave" mode
+ if ( $laggedSlaveMode ) {
+ $this->mLaggedSlaveMode = true;
+ }
}
$serverName = $this->getServerName( $i );
wfDebug( __METHOD__ . ": using server $serverName for group '$group'\n" );
@@ -357,6 +355,37 @@ class LoadBalancer {
}
/**
+ * Set the master wait position and wait for a "generic" slave to catch up to it
+ *
+ * This can be used a faster proxy for waitForAll()
+ *
+ * @param DBMasterPos $pos
+ * @param int $timeout Max seconds to wait; default is mWaitTimeout
+ * @return bool Success (able to connect and no timeouts reached)
+ * @since 1.26
+ */
+ public function waitForOne( $pos, $timeout = null ) {
+ $this->mWaitForPos = $pos;
+
+ $i = $this->mReadIndex;
+ if ( $i <= 0 ) {
+ // Pick a generic slave if there isn't one yet
+ $readLoads = $this->mLoads;
+ unset( $readLoads[$this->getWriterIndex()] ); // slaves only
+ $readLoads = array_filter( $readLoads ); // with non-zero load
+ $i = ArrayUtils::pickRandom( $readLoads );
+ }
+
+ if ( $i > 0 ) {
+ $ok = $this->doWait( $i, true, $timeout );
+ } else {
+ $ok = true; // no applicable loads
+ }
+
+ return $ok;
+ }
+
+ /**
* Set the master wait position and wait for ALL slaves to catch up to it
* @param DBMasterPos $pos
* @param int $timeout Max seconds to wait; default is mWaitTimeout
@@ -429,7 +458,7 @@ class LoadBalancer {
if ( $result == -1 || is_null( $result ) ) {
# Timed out waiting for slave, use master instead
- $server = $this->mServers[$index]['host'];
+ $server = $server = $this->getServerName( $index );
$msg = __METHOD__ . ": Timed out waiting on $server pos {$this->mWaitForPos}";
wfDebug( "$msg\n" );
wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
@@ -505,7 +534,6 @@ class LoadBalancer {
# Now we have an explicit index into the servers array
$conn = $this->openConnection( $i, $wiki );
if ( !$conn ) {
-
return $this->reportConnectionError();
}
@@ -618,25 +646,32 @@ class LoadBalancer {
public function openConnection( $i, $wiki = false ) {
if ( $wiki !== false ) {
$conn = $this->openForeignConnection( $i, $wiki );
-
- return $conn;
- }
- if ( isset( $this->mConns['local'][$i][0] ) ) {
+ } elseif ( isset( $this->mConns['local'][$i][0] ) ) {
$conn = $this->mConns['local'][$i][0];
} else {
$server = $this->mServers[$i];
$server['serverIndex'] = $i;
$conn = $this->reallyOpenConnection( $server, false );
+ $serverName = $this->getServerName( $i );
if ( $conn->isOpen() ) {
- wfDebug( "Connected to database $i at {$this->mServers[$i]['host']}\n" );
+ wfDebug( "Connected to database $i at $serverName\n" );
$this->mConns['local'][$i][0] = $conn;
} else {
- wfDebug( "Failed to connect to database $i at {$this->mServers[$i]['host']}\n" );
+ wfDebug( "Failed to connect to database $i at $serverName\n" );
$this->mErrorConnection = $conn;
$conn = false;
}
}
+ if ( $conn && !$conn->isOpen() ) {
+ // Connection was made but later unrecoverably lost for some reason.
+ // Do not return a handle that will just throw exceptions on use,
+ // but let the calling code (e.g. getReaderIndex) try another server.
+ // See DatabaseMyslBase::ping() for how this can happen.
+ $this->mErrorConnection = $conn;
+ $conn = false;
+ }
+
return $conn;
}
@@ -812,8 +847,9 @@ class LoadBalancer {
/**
* @return int
+ * @since 1.26
*/
- private function getWriterIndex() {
+ public function getWriterIndex() {
return 0;
}
@@ -854,12 +890,14 @@ class LoadBalancer {
*/
public function getServerName( $i ) {
if ( isset( $this->mServers[$i]['hostName'] ) ) {
- return $this->mServers[$i]['hostName'];
+ $name = $this->mServers[$i]['hostName'];
} elseif ( isset( $this->mServers[$i]['host'] ) ) {
- return $this->mServers[$i]['host'];
+ $name = $this->mServers[$i]['host'];
} else {
- return '';
+ $name = '';
}
+
+ return ( $name != '' ) ? $name : 'localhost';
}
/**
@@ -1096,9 +1134,12 @@ class LoadBalancer {
}
/**
- * @return bool
+ * @return bool Whether the generic connection for reads is highly "lagged"
*/
public function getLaggedSlaveMode() {
+ # Get a generic reader connection
+ $this->getConnection( DB_SLAVE );
+
return $this->mLaggedSlaveMode;
}
@@ -1195,16 +1236,8 @@ class LoadBalancer {
return array( 0 => 0 ); // no replication = no lag
}
- if ( $this->mProcCache->has( 'slave_lag', 'times', 1 ) ) {
- return $this->mProcCache->get( 'slave_lag', 'times' );
- }
-
# Send the request to the load monitor
- $times = $this->getLoadMonitor()->getLagTimes( array_keys( $this->mServers ), $wiki );
-
- $this->mProcCache->set( 'slave_lag', 'times', $times );
-
- return $times;
+ return $this->getLoadMonitor()->getLagTimes( array_keys( $this->mServers ), $wiki );
}
/**
@@ -1231,54 +1264,10 @@ class LoadBalancer {
/**
* Clear the cache for slag lag delay times
+ *
+ * This is only used for testing
*/
public function clearLagTimeCache() {
- $this->mProcCache->clear( 'slave_lag' );
- }
-}
-
-/**
- * Helper class to handle automatically marking connections as reusable (via RAII pattern)
- * as well handling deferring the actual network connection until the handle is used
- *
- * @ingroup Database
- * @since 1.22
- */
-class DBConnRef implements IDatabase {
- /** @var LoadBalancer */
- private $lb;
-
- /** @var DatabaseBase|null */
- private $conn;
-
- /** @var array|null */
- private $params;
-
- /**
- * @param LoadBalancer $lb
- * @param DatabaseBase|array $conn Connection or (server index, group, wiki ID) array
- */
- public function __construct( LoadBalancer $lb, $conn ) {
- $this->lb = $lb;
- if ( $conn instanceof DatabaseBase ) {
- $this->conn = $conn;
- } else {
- $this->params = $conn;
- }
- }
-
- public function __call( $name, $arguments ) {
- if ( $this->conn === null ) {
- list( $db, $groups, $wiki ) = $this->params;
- $this->conn = $this->lb->getConnection( $db, $groups, $wiki );
- }
-
- return call_user_func_array( array( $this->conn, $name ), $arguments );
- }
-
- public function __destruct() {
- if ( $this->conn !== null ) {
- $this->lb->reuseConnection( $this->conn );
- }
+ $this->getLoadMonitor()->clearCaches();
}
}
diff --git a/includes/db/LoadMonitor.php b/includes/db/LoadMonitor.php
index 91840dd9..4975ea19 100644
--- a/includes/db/LoadMonitor.php
+++ b/includes/db/LoadMonitor.php
@@ -64,90 +64,3 @@ class LoadMonitorNull implements LoadMonitor {
return array_fill_keys( $serverIndexes, 0 );
}
}
-
-/**
- * Basic MySQL load monitor with no external dependencies
- * Uses memcached to cache the replication lag for a short time
- *
- * @ingroup Database
- */
-class LoadMonitorMySQL implements LoadMonitor {
- /** @var LoadBalancer */
- public $parent;
- /** @var BagOStuff */
- protected $cache;
-
- public function __construct( $parent ) {
- global $wgMemc;
-
- $this->parent = $parent;
- $this->cache = $wgMemc ?: wfGetMainCache();
- }
-
- public function scaleLoads( &$loads, $group = false, $wiki = false ) {
- }
-
- public function getLagTimes( $serverIndexes, $wiki ) {
- if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) {
- // Single server only, just return zero without caching
- return array( 0 => 0 );
- }
-
- $expiry = 5;
- $requestRate = 10;
-
- $cache = $this->cache;
- $masterName = $this->parent->getServerName( 0 );
- $memcKey = wfMemcKey( 'lag_times', $masterName );
- $times = $cache->get( $memcKey );
- if ( is_array( $times ) ) {
- # Randomly recache with probability rising over $expiry
- $elapsed = time() - $times['timestamp'];
- $chance = max( 0, ( $expiry - $elapsed ) * $requestRate );
- if ( mt_rand( 0, $chance ) != 0 ) {
- unset( $times['timestamp'] ); // hide from caller
-
- return $times;
- }
- wfIncrStats( 'lag_cache_miss_expired' );
- } else {
- wfIncrStats( 'lag_cache_miss_absent' );
- }
-
- # Cache key missing or expired
- if ( $cache->add( "$memcKey:lock", 1, 10 ) ) {
- # Let this process alone update the cache value
- $unlocker = new ScopedCallback( function () use ( $cache, $memcKey ) {
- $cache->delete( $memcKey );
- } );
- } elseif ( is_array( $times ) ) {
- # Could not acquire lock but an old cache exists, so use it
- unset( $times['timestamp'] ); // hide from caller
-
- return $times;
- }
-
- $times = array();
- foreach ( $serverIndexes as $i ) {
- if ( $i == 0 ) { # Master
- $times[$i] = 0;
- } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) {
- $times[$i] = $conn->getLag();
- } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) {
- $times[$i] = $conn->getLag();
- // Close the connection to avoid sleeper connections piling up.
- // Note that the caller will pick one of these DBs and reconnect,
- // which is slightly inefficient, but this only matters for the lag
- // time cache miss cache, which is far less common that cache hits.
- $this->parent->closeConnection( $conn );
- }
- }
-
- # Add a timestamp key so we know when it was cached
- $times['timestamp'] = time();
- $cache->set( $memcKey, $times, $expiry + 10 );
- unset( $times['timestamp'] ); // hide from caller
-
- return $times;
- }
-}
diff --git a/includes/db/LoadMonitorMySQL.php b/includes/db/LoadMonitorMySQL.php
new file mode 100644
index 00000000..30084190
--- /dev/null
+++ b/includes/db/LoadMonitorMySQL.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Database
+ */
+
+/**
+ * Basic MySQL load monitor with no external dependencies
+ * Uses memcached to cache the replication lag for a short time
+ *
+ * @ingroup Database
+ */
+class LoadMonitorMySQL implements LoadMonitor {
+ /** @var LoadBalancer */
+ public $parent;
+ /** @var BagOStuff */
+ protected $srvCache;
+ /** @var BagOStuff */
+ protected $mainCache;
+
+ public function __construct( $parent ) {
+ $this->parent = $parent;
+
+ $this->srvCache = ObjectCache::newAccelerator( 'hash' );
+ $this->mainCache = wfGetMainCache();
+ }
+
+ public function scaleLoads( &$loads, $group = false, $wiki = false ) {
+ }
+
+ public function getLagTimes( $serverIndexes, $wiki ) {
+ if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) {
+ # Single server only, just return zero without caching
+ return array( 0 => 0 );
+ }
+
+ $key = $this->getLagTimeCacheKey();
+ # Randomize TTLs to reduce stampedes (4.0 - 5.0 sec)
+ $ttl = mt_rand( 4e6, 5e6 ) / 1e6;
+ # Keep keys around longer as fallbacks
+ $staleTTL = 60;
+
+ # (a) Check the local APC cache
+ $value = $this->srvCache->get( $key );
+ if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
+ wfDebugLog( 'replication', __FUNCTION__ . ": got lag times ($key) from local cache" );
+ return $value['lagTimes']; // cache hit
+ }
+ $staleValue = $value ?: false;
+
+ # (b) Check the shared cache and backfill APC
+ $value = $this->mainCache->get( $key );
+ if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
+ $this->srvCache->set( $key, $value, $staleTTL );
+ wfDebugLog( 'replication', __FUNCTION__ . ": got lag times ($key) from main cache" );
+
+ return $value['lagTimes']; // cache hit
+ }
+ $staleValue = $value ?: $staleValue;
+
+ # (c) Cache key missing or expired; regenerate and backfill
+ if ( $this->mainCache->lock( $key, 0, 10 ) ) {
+ # Let this process alone update the cache value
+ $cache = $this->mainCache;
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $unlocker = new ScopedCallback( function () use ( $cache, $key ) {
+ $cache->unlock( $key );
+ } );
+ } elseif ( $staleValue ) {
+ # Could not acquire lock but an old cache exists, so use it
+ return $staleValue['lagTimes'];
+ }
+
+ $lagTimes = array();
+ foreach ( $serverIndexes as $i ) {
+ if ( $i == 0 ) { # Master
+ $lagTimes[$i] = 0;
+ } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) {
+ $lagTimes[$i] = $conn->getLag();
+ } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) {
+ $lagTimes[$i] = $conn->getLag();
+ # Close the connection to avoid sleeper connections piling up.
+ # Note that the caller will pick one of these DBs and reconnect,
+ # which is slightly inefficient, but this only matters for the lag
+ # time cache miss cache, which is far less common that cache hits.
+ $this->parent->closeConnection( $conn );
+ }
+ }
+
+ # Add a timestamp key so we know when it was cached
+ $value = array( 'lagTimes' => $lagTimes, 'timestamp' => microtime( true ) );
+ $this->mainCache->set( $key, $value, $staleTTL );
+ $this->srvCache->set( $key, $value, $staleTTL );
+ wfDebugLog( 'replication', __FUNCTION__ . ": re-calculated lag times ($key)" );
+
+ return $value['lagTimes'];
+ }
+
+ public function clearCaches() {
+ $key = $this->getLagTimeCacheKey();
+ $this->srvCache->delete( $key );
+ $this->mainCache->delete( $key );
+ }
+
+ private function getLagTimeCacheKey() {
+ # Lag is per-server, not per-DB, so key on the master DB name
+ return wfGlobalCacheKey( 'lag-times', $this->parent->getServerName( 0 ) );
+ }
+}
diff --git a/includes/debug/MWDebug.php b/includes/debug/MWDebug.php
index ae2d9954..1249ebae 100644
--- a/includes/debug/MWDebug.php
+++ b/includes/debug/MWDebug.php
@@ -432,10 +432,8 @@ class MWDebug {
// Cannot use OutputPage::addJsConfigVars because those are already outputted
// by the time this method is called.
- $html = Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- ResourceLoader::makeConfigSetScript( array( 'debugInfo' => $debugInfo ) )
- )
+ $html = ResourceLoader::makeInlineScript(
+ ResourceLoader::makeConfigSetScript( array( 'debugInfo' => $debugInfo ) )
);
}
diff --git a/includes/debug/logger/LegacyLogger.php b/includes/debug/logger/LegacyLogger.php
index edaef4a7..0f4c6484 100644
--- a/includes/debug/logger/LegacyLogger.php
+++ b/includes/debug/logger/LegacyLogger.php
@@ -21,7 +21,9 @@
namespace MediaWiki\Logger;
use DateTimeZone;
+use Exception;
use MWDebug;
+use MWExceptionHandler;
use Psr\Log\AbstractLogger;
use Psr\Log\LogLevel;
use UDPTransport;
@@ -39,7 +41,7 @@ use UDPTransport;
* See documentation in DefaultSettings.php for detailed explanations of each
* variable.
*
- * @see \MediaWiki\Logger\LoggerFactory
+ * @see \\MediaWiki\\Logger\\LoggerFactory
* @since 1.25
* @author Bryan Davis <bd808@wikimedia.org>
* @copyright © 2014 Bryan Davis and Wikimedia Foundation.
@@ -52,10 +54,10 @@ class LegacyLogger extends AbstractLogger {
protected $channel;
/**
- * Convert Psr\Log\LogLevel constants into int for sane comparisons
+ * Convert Psr\\Log\\LogLevel constants into int for sane comparisons
* These are the same values that Monlog uses
*
- * @var array
+ * @var array $levelMapping
*/
protected static $levelMapping = array(
LogLevel::DEBUG => 100,
@@ -99,7 +101,7 @@ class LegacyLogger extends AbstractLogger {
*
* @param string $channel
* @param string $message
- * @param string|int $level Psr\Log\LogEvent constant or Monlog level int
+ * @param string|int $level Psr\\Log\\LogEvent constant or Monlog level int
* @param array $context
* @return bool True if message should be sent to disk/network, false
* otherwise
@@ -167,7 +169,7 @@ class LegacyLogger extends AbstractLogger {
* @return string
*/
public static function format( $channel, $message, $context ) {
- global $wgDebugLogGroups;
+ global $wgDebugLogGroups, $wgLogExceptionBacktrace;
if ( $channel === 'wfDebug' ) {
$text = self::formatAsWfDebug( $channel, $message, $context );
@@ -181,7 +183,7 @@ class LegacyLogger extends AbstractLogger {
} elseif ( $channel === 'profileoutput' ) {
// Legacy wfLogProfilingData formatitng
$forward = '';
- if ( isset( $context['forwarded_for'] )) {
+ if ( isset( $context['forwarded_for'] ) ) {
$forward = " forwarded for {$context['forwarded_for']}";
}
if ( isset( $context['client_ip'] ) ) {
@@ -215,6 +217,25 @@ class LegacyLogger extends AbstractLogger {
$text = self::formatAsWfDebugLog( $channel, $message, $context );
}
+ // Append stacktrace of exception if available
+ if ( $wgLogExceptionBacktrace && isset( $context['exception'] ) ) {
+ $e = $context['exception'];
+ $backtrace = false;
+
+ if ( $e instanceof Exception ) {
+ $backtrace = MWExceptionHandler::getRedactedTrace( $e );
+
+ } elseif ( is_array( $e ) && isset( $e['trace'] ) ) {
+ // Exception has already been unpacked as structured data
+ $backtrace = $e['trace'];
+ }
+
+ if ( $backtrace ) {
+ $text .= MWExceptionHandler::prettyPrintTrace( $backtrace ) .
+ "\n";
+ }
+ }
+
return self::interpolate( $text, $context );
}
@@ -253,7 +274,7 @@ class LegacyLogger extends AbstractLogger {
global $wgDBerrorLogTZ;
static $cachedTimezone = null;
- if ( $wgDBerrorLogTZ && !$cachedTimezone ) {
+ if ( !$cachedTimezone ) {
$cachedTimezone = new DateTimeZone( $wgDBerrorLogTZ );
}
@@ -301,7 +322,7 @@ class LegacyLogger extends AbstractLogger {
if ( strpos( $message, '{' ) !== false ) {
$replace = array();
foreach ( $context as $key => $val ) {
- $replace['{' . $key . '}'] = $val;
+ $replace['{' . $key . '}'] = self::flatten( $val );
}
$message = strtr( $message, $replace );
}
@@ -310,6 +331,66 @@ class LegacyLogger extends AbstractLogger {
/**
+ * Convert a logging context element to a string suitable for
+ * interpolation.
+ *
+ * @param mixed $item
+ * @return string
+ */
+ protected static function flatten( $item ) {
+ if ( null === $item ) {
+ return '[Null]';
+ }
+
+ if ( is_bool( $item ) ) {
+ return $item ? 'true' : 'false';
+ }
+
+ if ( is_float( $item ) ) {
+ if ( is_infinite( $item ) ) {
+ return ( $item > 0 ? '' : '-' ) . 'INF';
+ }
+ if ( is_nan( $item ) ) {
+ return 'NaN';
+ }
+ return $item;
+ }
+
+ if ( is_scalar( $item ) ) {
+ return (string) $item;
+ }
+
+ if ( is_array( $item ) ) {
+ return '[Array(' . count( $item ) . ')]';
+ }
+
+ if ( $item instanceof \DateTime ) {
+ return $item->format( 'c' );
+ }
+
+ if ( $item instanceof Exception ) {
+ return '[Exception ' . get_class( $item ) . '( ' .
+ $item->getFile() . ':' . $item->getLine() . ') ' .
+ $item->getMessage() . ']';
+ }
+
+ if ( is_object( $item ) ) {
+ if ( method_exists( $item, '__toString' ) ) {
+ return (string) $item;
+ }
+
+ return '[Object ' . get_class( $item ) . ']';
+ }
+
+ if ( is_resource( $item ) ) {
+ return '[Resource ' . get_resource_type( $item ) . ']';
+ }
+
+ return '[Unknown ' . gettype( $item ) . ']';
+ }
+
+
+ /**
* Select the appropriate log output destination for the given log event.
*
* If the event context contains 'destination'
@@ -365,7 +446,7 @@ class LegacyLogger extends AbstractLogger {
$transport = UDPTransport::newFromString( $file );
$transport->emit( $text );
} else {
- wfSuppressWarnings();
+ \MediaWiki\suppressWarnings();
$exists = file_exists( $file );
$size = $exists ? filesize( $file ) : false;
if ( !$exists ||
@@ -373,7 +454,7 @@ class LegacyLogger extends AbstractLogger {
) {
file_put_contents( $file, $text, FILE_APPEND );
}
- wfRestoreWarnings();
+ \MediaWiki\restoreWarnings();
}
}
diff --git a/includes/debug/logger/LegacySpi.php b/includes/debug/logger/LegacySpi.php
index 1bf39e41..6a7f1d05 100644
--- a/includes/debug/logger/LegacySpi.php
+++ b/includes/debug/logger/LegacySpi.php
@@ -30,7 +30,7 @@ namespace MediaWiki\Logger;
* );
* @endcode
*
- * @see \MediaWiki\Logger\LoggerFactory
+ * @see \\MediaWiki\\Logger\\LoggerFactory
* @since 1.25
* @author Bryan Davis <bd808@wikimedia.org>
* @copyright © 2014 Bryan Davis and Wikimedia Foundation.
@@ -47,7 +47,7 @@ class LegacySpi implements Spi {
* Get a logger instance.
*
* @param string $channel Logging channel
- * @return \Psr\Log\LoggerInterface Logger instance
+ * @return \\Psr\\Log\\LoggerInterface Logger instance
*/
public function getLogger( $channel ) {
if ( !isset( $this->singletons[$channel] ) ) {
diff --git a/includes/debug/logger/LoggerFactory.php b/includes/debug/logger/LoggerFactory.php
index b3078b9a..0b6965ff 100644
--- a/includes/debug/logger/LoggerFactory.php
+++ b/includes/debug/logger/LoggerFactory.php
@@ -25,7 +25,7 @@ use ObjectFactory;
/**
* PSR-3 logger instance factory.
*
- * Creation of \Psr\Log\LoggerInterface instances is managed via the
+ * Creation of \\Psr\\Log\\LoggerInterface instances is managed via the
* LoggerFactory::getInstance() static method which in turn delegates to the
* currently registered service provider.
*
@@ -38,7 +38,7 @@ use ObjectFactory;
* $wgMWLoggerDefaultSpi is expected to be an array usable by
* ObjectFactory::getObjectFromSpec() to create a class.
*
- * @see \MediaWiki\Logger\Spi
+ * @see \\MediaWiki\\Logger\\Spi
* @since 1.25
* @author Bryan Davis <bd808@wikimedia.org>
* @copyright © 2014 Bryan Davis and Wikimedia Foundation.
@@ -47,16 +47,16 @@ class LoggerFactory {
/**
* Service provider.
- * @var Spi $spi
+ * @var \MediaWiki\Logger\Spi $spi
*/
private static $spi;
/**
- * Register a service provider to create new \Psr\Log\LoggerInterface
+ * Register a service provider to create new \\Psr\\Log\\LoggerInterface
* instances.
*
- * @param Spi $provider Provider to register
+ * @param \\MediaWiki\\Logger\\Spi $provider Provider to register
*/
public static function registerProvider( Spi $provider ) {
self::$spi = $provider;
@@ -71,7 +71,7 @@ class LoggerFactory {
* Spi registration. $wgMWLoggerDefaultSpi is expected to be an
* array usable by ObjectFactory::getObjectFromSpec() to create a class.
*
- * @return Spi
+ * @return \\MediaWiki\\Logger\\Spi
* @see registerProvider()
* @see ObjectFactory::getObjectFromSpec()
*/
@@ -91,7 +91,7 @@ class LoggerFactory {
* Get a named logger instance from the currently configured logger factory.
*
* @param string $channel Logger channel (name)
- * @return \Psr\Log\LoggerInterface
+ * @return \\Psr\\Log\\LoggerInterface
*/
public static function getInstance( $channel ) {
if ( !interface_exists( '\Psr\Log\LoggerInterface' ) ) {
diff --git a/includes/debug/logger/MonologSpi.php b/includes/debug/logger/MonologSpi.php
index a07fdc4a..274e18e1 100644
--- a/includes/debug/logger/MonologSpi.php
+++ b/includes/debug/logger/MonologSpi.php
@@ -20,6 +20,7 @@
namespace MediaWiki\Logger;
+use MediaWiki\Logger\Monolog\BufferHandler;
use Monolog\Logger;
use ObjectFactory;
@@ -30,7 +31,7 @@ use ObjectFactory;
* Configured using an array of configuration data with the keys 'loggers',
* 'processors', 'handlers' and 'formatters'.
*
- * The ['loggers']['@default'] configuration will be used to create loggers
+ * The ['loggers']['\@default'] configuration will be used to create loggers
* for any channel that isn't explicitly named in the 'loggers' configuration
* section.
*
@@ -84,6 +85,7 @@ use ObjectFactory;
* 'logstash'
* ),
* 'formatter' => 'logstash',
+ * 'buffer' => true,
* ),
* 'udp2log' => array(
* 'class' => '\\MediaWiki\\Logger\\Monolog\\LegacyHandler',
@@ -129,7 +131,25 @@ class MonologSpi implements Spi {
* @param array $config Configuration data.
*/
public function __construct( array $config ) {
- $this->config = $config;
+ $this->config = array();
+ $this->mergeConfig( $config );
+ }
+
+
+ /**
+ * Merge additional configuration data into the configuration.
+ *
+ * @since 1.26
+ * @param array $config Configuration data.
+ */
+ public function mergeConfig( array $config ) {
+ foreach ( $config as $key => $value ) {
+ if ( isset( $this->config[$key] ) ) {
+ $this->config[$key] = array_merge( $this->config[$key], $value );
+ } else {
+ $this->config[$key] = $value;
+ }
+ }
$this->reset();
}
@@ -158,7 +178,7 @@ class MonologSpi implements Spi {
* name will return the cached instance.
*
* @param string $channel Logging channel
- * @return \Psr\Log\LoggerInterface Logger instance
+ * @return \\Psr\\Log\\LoggerInterface Logger instance
*/
public function getLogger( $channel ) {
if ( !isset( $this->singletons['loggers'][$channel] ) ) {
@@ -180,7 +200,7 @@ class MonologSpi implements Spi {
* Create a logger.
* @param string $channel Logger channel
* @param array $spec Configuration
- * @return \Monolog\Logger
+ * @return \\Monolog\\Logger
*/
protected function createLogger( $channel, $spec ) {
$obj = new Logger( $channel );
@@ -218,7 +238,7 @@ class MonologSpi implements Spi {
/**
* Create or return cached handler.
* @param string $name Processor name
- * @return \Monolog\Handler\HandlerInterface
+ * @return \\Monolog\\Handler\\HandlerInterface
*/
public function getHandler( $name ) {
if ( !isset( $this->singletons['handlers'][$name] ) ) {
@@ -229,6 +249,9 @@ class MonologSpi implements Spi {
$this->getFormatter( $spec['formatter'] )
);
}
+ if ( isset( $spec['buffer'] ) && $spec['buffer'] ) {
+ $handler = new BufferHandler( $handler );
+ }
$this->singletons['handlers'][$name] = $handler;
}
return $this->singletons['handlers'][$name];
@@ -238,7 +261,7 @@ class MonologSpi implements Spi {
/**
* Create or return cached formatter.
* @param string $name Formatter name
- * @return \Monolog\Formatter\FormatterInterface
+ * @return \\Monolog\\Formatter\\FormatterInterface
*/
public function getFormatter( $name ) {
if ( !isset( $this->singletons['formatters'][$name] ) ) {
diff --git a/includes/debug/logger/NullSpi.php b/includes/debug/logger/NullSpi.php
index a82d2c4c..c9c74821 100644
--- a/includes/debug/logger/NullSpi.php
+++ b/includes/debug/logger/NullSpi.php
@@ -23,7 +23,7 @@ namespace MediaWiki\Logger;
use Psr\Log\NullLogger;
/**
- * LoggerFactory service provider that creates \Psr\Log\NullLogger
+ * LoggerFactory service provider that creates \\Psr\\Log\\NullLogger
* instances. A NullLogger silently discards all log events sent to it.
*
* Usage:
@@ -33,7 +33,7 @@ use Psr\Log\NullLogger;
* );
* @endcode
*
- * @see \MediaWiki\Logger\LoggerFactory
+ * @see \\MediaWiki\\Logger\\LoggerFactory
* @since 1.25
* @author Bryan Davis <bd808@wikimedia.org>
* @copyright © 2014 Bryan Davis and Wikimedia Foundation.
@@ -41,7 +41,7 @@ use Psr\Log\NullLogger;
class NullSpi implements Spi {
/**
- * @var \Psr\Log\NullLogger $singleton
+ * @var \\Psr\\Log\\NullLogger $singleton
*/
protected $singleton;
@@ -55,7 +55,7 @@ class NullSpi implements Spi {
* Get a logger instance.
*
* @param string $channel Logging channel
- * @return \Psr\Log\NullLogger Logger instance
+ * @return \\Psr\\Log\\NullLogger Logger instance
*/
public function getLogger( $channel ) {
return $this->singleton;
diff --git a/includes/debug/logger/Spi.php b/includes/debug/logger/Spi.php
index 044789f2..51818a38 100644
--- a/includes/debug/logger/Spi.php
+++ b/includes/debug/logger/Spi.php
@@ -21,15 +21,15 @@
namespace MediaWiki\Logger;
/**
- * Service provider interface for \Psr\Log\LoggerInterface implementation
+ * Service provider interface for \\Psr\\Log\\LoggerInterface implementation
* libraries.
*
* MediaWiki can be configured to use a class implementing this interface to
- * create new \Psr\Log\LoggerInterface instances via either the
+ * create new \\Psr\\Log\\LoggerInterface instances via either the
* $wgMWLoggerDefaultSpi global variable or code that constructs an instance
* and registers it via the LoggerFactory::registerProvider() static method.
*
- * @see \MediaWiki\Logger\LoggerFactory
+ * @see \\MediaWiki\\Logger\\LoggerFactory
* @since 1.25
* @author Bryan Davis <bd808@wikimedia.org>
* @copyright © 2014 Bryan Davis and Wikimedia Foundation.
@@ -40,7 +40,7 @@ interface Spi {
* Get a logger instance.
*
* @param string $channel Logging channel
- * @return \Psr\Log\LoggerInterface Logger instance
+ * @return \\Psr\\Log\\LoggerInterface Logger instance
*/
public function getLogger( $channel );
diff --git a/includes/debug/logger/monolog/AvroFormatter.php b/includes/debug/logger/monolog/AvroFormatter.php
new file mode 100644
index 00000000..b6adab4a
--- /dev/null
+++ b/includes/debug/logger/monolog/AvroFormatter.php
@@ -0,0 +1,139 @@
+<?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\Logger\Monolog;
+
+use AvroIODatumWriter;
+use AvroIOBinaryEncoder;
+use AvroIOTypeException;
+use AvroNamedSchemata;
+use AvroSchema;
+use AvroStringIO;
+use AvroValidator;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Log message formatter that uses the apache Avro format.
+ *
+ * @since 1.26
+ * @author Erik Bernhardson <ebernhardson@wikimedia.org>
+ * @copyright © 2015 Erik Bernhardson and Wikimedia Foundation.
+ */
+class AvroFormatter implements FormatterInterface {
+ /**
+ * @var array Map from schema name to schema definition
+ */
+ protected $schemas;
+
+ /**
+ * @var AvroStringIO
+ */
+ protected $io;
+
+ /**
+ * @var AvroIOBinaryEncoder
+ */
+ protected $encoder;
+
+ /**
+ * @var AvroIODatumWriter
+ */
+ protected $writer;
+
+ /**
+ * @var array $schemas Map from Monolog channel to Avro schema.
+ * Each schema can be either the JSON string or decoded into PHP
+ * arrays.
+ */
+ public function __construct( array $schemas ) {
+ $this->schemas = $schemas;
+ $this->io = new AvroStringIO( '' );
+ $this->encoder = new AvroIOBinaryEncoder( $this->io );
+ $this->writer = new AvroIODatumWriter();
+ }
+
+ /**
+ * Formats the record context into a binary string per the
+ * schema configured for the records channel.
+ *
+ * @param array $record
+ * @return string|null The serialized record, or null if
+ * the record is not valid for the selected schema.
+ */
+ public function format( array $record ) {
+ $this->io->truncate();
+ $schema = $this->getSchema( $record['channel'] );
+ if ( $schema === null ) {
+ trigger_error( "The schema for channel '{$record['channel']}' is not available" );
+ return null;
+ }
+ try {
+ $this->writer->write_data( $schema, $record['context'], $this->encoder );
+ } catch ( AvroIOTypeException $e ) {
+ $errors = AvroValidator::getErrors( $schema, $record['context'] );
+ $json = json_encode( $errors );
+ trigger_error( "Avro failed to serialize record for {$record['channel']} : {$json}" );
+ return null;
+ }
+ return $this->io->string();
+ }
+
+ /**
+ * Format a set of records into a list of binary strings
+ * conforming to the configured schema.
+ *
+ * @param array $records
+ * @return string[]
+ */
+ public function formatBatch( array $records ) {
+ $result = array();
+ foreach ( $records as $record ) {
+ $message = $this->format( $record );
+ if ( $message !== null ) {
+ $result[] = $message;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Get the writer for the named channel
+ *
+ * @var string $channel Name of the schema to fetch
+ * @return AvroSchema|null
+ */
+ protected function getSchema( $channel ) {
+ if ( !isset( $this->schemas[$channel] ) ) {
+ return null;
+ }
+ if ( !$this->schemas[$channel] instanceof AvroSchema ) {
+ if ( is_string( $this->schemas[$channel] ) ) {
+ $this->schemas[$channel] = AvroSchema::parse( $this->schemas[$channel] );
+ } else {
+ $this->schemas[$channel] = AvroSchema::real_parse(
+ $this->schemas[$channel],
+ null,
+ new AvroNamedSchemata()
+ );
+ }
+ }
+ return $this->schemas[$channel];
+ }
+}
diff --git a/includes/api/ApiFormatDump.php b/includes/debug/logger/monolog/BufferHandler.php
index f34e1ae4..3ebd0b1f 100644
--- a/includes/api/ApiFormatDump.php
+++ b/includes/debug/logger/monolog/BufferHandler.php
@@ -1,10 +1,6 @@
<?php
/**
- *
- *
- * Created on August 8, 2010
- *
- * Copyright © 2010 Soxred93
+ * Helper class for the index.php entry point.
*
* 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
@@ -24,35 +20,28 @@
* @file
*/
-/**
- * API PHP's var_dump() output formatter
- * @deprecated since 1.24
- * @ingroup API
- */
-class ApiFormatDump extends ApiFormatBase {
+namespace MediaWiki\Logger\Monolog;
- public function getMimeType() {
- // This looks like it should be text/plain, but IE7 is so
- // brain-damaged it tries to parse text/plain as HTML if it
- // contains HTML tags. Using MIME text/text works around this bug
- return 'text/text';
- }
+use DeferredUpdates;
+use Monolog\Handler\BufferHandler as BaseBufferHandler;
- public function execute() {
- $this->markDeprecated();
- $data = $this->getResult()->getResultData( null, array(
- 'BC' => array(),
- 'Types' => array(),
- 'Strip' => 'all',
- ) );
- ob_start();
- var_dump( $data );
- $result = ob_get_contents();
- ob_end_clean();
- $this->printText( $result );
- }
-
- public function isDeprecated() {
- return true;
+/**
+ * Updates the Monolog BufferHandler to use DeferredUpdates rather
+ * than register_shutdown_function. On supported platforms this will
+ * use register_postsend_function or fastcgi_finish_request() to delay
+ * until after the request has shutdown and we are no longer delaying
+ * the web request.
+ */
+class BufferHandler extends BaseBufferHandler {
+ /**
+ * {@inheritDoc}
+ */
+ public function handle( array $record ) {
+ if (!$this->initialized) {
+ DeferredUpdates::addCallableUpdate( array( $this, 'close' ) );
+ $this->initialized = true;
+ }
+ return parent::handle( $record );
}
}
+
diff --git a/includes/debug/logger/monolog/KafkaHandler.php b/includes/debug/logger/monolog/KafkaHandler.php
new file mode 100644
index 00000000..59d7764a
--- /dev/null
+++ b/includes/debug/logger/monolog/KafkaHandler.php
@@ -0,0 +1,224 @@
+<?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\Logger\Monolog;
+
+use Kafka\MetaDataFromKafka;
+use Kafka\Produce;
+use MediaWiki\Logger\LoggerFactory;
+use Monolog\Handler\AbstractProcessingHandler;
+use Monolog\Logger;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Log handler sends log events to a kafka server.
+ *
+ * Constructor options array arguments:
+ * * alias: map from monolog channel to kafka topic name. When no
+ * alias exists the topic "monolog_$channel" will be used.
+ * * swallowExceptions: Swallow exceptions that occur while talking to
+ * kafka. Defaults to false.
+ * * logExceptions: Log exceptions talking to kafka here. Either null,
+ * the name of a channel to log to, or an object implementing
+ * FormatterInterface. Defaults to null.
+ *
+ * Requires the nmred/kafka-php library, version >= 1.3.0
+ *
+ * @since 1.26
+ * @author Erik Bernhardson <ebernhardson@wikimedia.org>
+ * @copyright © 2015 Erik Bernhardson and Wikimedia Foundation.
+ */
+class KafkaHandler extends AbstractProcessingHandler {
+ /**
+ * @var Produce Sends requests to kafka
+ */
+ protected $produce;
+
+ /**
+ * @var array Optional handler configuration
+ */
+ protected $options;
+
+ /**
+ * @var array Map from topic name to partition this request produces to
+ */
+ protected $partitions = array();
+
+ /**
+ * @var array defaults for constructor options
+ */
+ private static $defaultOptions = array(
+ 'alias' => array(), // map from monolog channel to kafka topic
+ 'swallowExceptions' => false, // swallow exceptions sending records
+ 'logExceptions' => null, // A PSR3 logger to inform about errors
+ );
+
+ /**
+ * @param Produce $produce Kafka instance to produce through
+ * @param array $options optional handler configuration
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct( Produce $produce, array $options, $level = Logger::DEBUG, $bubble = true ) {
+ parent::__construct( $level, $bubble );
+ $this->produce = $produce;
+ $this->options = array_merge( self::$defaultOptions, $options );
+ }
+
+ /**
+ * Constructs the necessary support objects and returns a KafkaHandler
+ * instance.
+ *
+ * @param string[] $kafkaServers
+ * @param array $options
+ * @param int $level The minimum logging level at which this handle will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble the stack or not
+ * @return KafkaHandler
+ */
+ public static function factory( $kafkaServers, array $options = array(), $level = Logger::DEBUG, $bubble = true ) {
+ $metadata = new MetaDataFromKafka( $kafkaServers );
+ $produce = new Produce( $metadata );
+ if ( isset( $options['logExceptions'] ) && is_string( $options['logExceptions'] ) ) {
+ $options['logExceptions'] = LoggerFactory::getInstance( $options['logExceptions'] );
+ }
+ return new self( $produce, $options, $level, $bubble );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write( array $record ) {
+ if ( $record['formatted'] !== null ) {
+ $this->addMessages( $record['channel'], array( $record['formatted'] ) );
+ $this->send();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function handleBatch( array $batch ) {
+ $channels = array();
+ foreach ( $batch as $record ) {
+ if ( $record['level'] < $this->level ) {
+ continue;
+ }
+ $channels[$record['channel']][] = $this->processRecord( $record );
+ }
+
+ $formatter = $this->getFormatter();
+ foreach ( $channels as $channel => $records ) {
+ $messages = array();
+ foreach ( $records as $idx => $record ) {
+ $message = $formatter->format( $record );
+ if ( $message !== null ) {
+ $messages[] = $message;
+ }
+ }
+ if ( $messages ) {
+ $this->addMessages($channel, $messages);
+ }
+ }
+
+ $this->send();
+ }
+
+ /**
+ * Send any records in the kafka client internal queue.
+ */
+ protected function send() {
+ try {
+ $this->produce->send();
+ } catch ( \Kafka\Exception $e ) {
+ $ignore = $this->warning(
+ 'Error sending records to kafka: {exception}',
+ array( 'exception' => $e ) );
+ if ( !$ignore ) {
+ throw $e;
+ }
+ }
+ }
+
+ /**
+ * @param string $topic Name of topic to get partition for
+ * @return int|null The random partition to produce to for this request,
+ * or null if a partition could not be determined.
+ */
+ protected function getRandomPartition( $topic ) {
+ if ( !array_key_exists( $topic, $this->partitions ) ) {
+ try {
+ $partitions = $this->produce->getAvailablePartitions( $topic );
+ } catch ( \Kafka\Exception $e ) {
+ $ignore = $this->warning(
+ 'Error getting metadata for kafka topic {topic}: {exception}',
+ array( 'topic' => $topic, 'exception' => $e ) );
+ if ( $ignore ) {
+ return null;
+ }
+ throw $e;
+ }
+ if ( $partitions ) {
+ $key = array_rand( $partitions );
+ $this->partitions[$topic] = $partitions[$key];
+ } else {
+ $details = $this->produce->getClient()->getTopicDetail( $topic );
+ $ignore = $this->warning(
+ 'No partitions available for kafka topic {topic}',
+ array( 'topic' => $topic, 'kafka' => $details )
+ );
+ if ( !$ignore ) {
+ throw new \RuntimeException( "No partitions available for kafka topic $topic" );
+ }
+ $this->partitions[$topic] = null;
+ }
+ }
+ return $this->partitions[$topic];
+ }
+
+ /**
+ * Adds records for a channel to the Kafka client internal queue.
+ *
+ * @param string $channel Name of Monolog channel records belong to
+ * @param array $records List of records to append
+ */
+ protected function addMessages( $channel, array $records ) {
+ if ( isset( $this->options['alias'][$channel] ) ) {
+ $topic = $this->options['alias'][$channel];
+ } else {
+ $topic = "monolog_$channel";
+ }
+ $partition = $this->getRandomPartition( $topic );
+ if ( $partition !== null ) {
+ $this->produce->setMessages( $topic, $partition, $records );
+ }
+ }
+
+ /**
+ * @param string $message PSR3 compatible message string
+ * @param array $context PSR3 compatible log context
+ * @return bool true if caller should ignore warning
+ */
+ protected function warning( $message, array $context = array() ) {
+ if ( $this->options['logExceptions'] instanceof LoggerInterface ) {
+ $this->options['logExceptions']->warning( $message, $context );
+ }
+ return $this->options['swallowExceptions'];
+ }
+}
diff --git a/includes/debug/logger/monolog/LegacyFormatter.php b/includes/debug/logger/monolog/LegacyFormatter.php
index 9ec15cb8..42e7caba 100644
--- a/includes/debug/logger/monolog/LegacyFormatter.php
+++ b/includes/debug/logger/monolog/LegacyFormatter.php
@@ -26,12 +26,12 @@ use Monolog\Formatter\NormalizerFormatter;
/**
* Log message formatter that mimics the legacy log message formatting of
* `wfDebug`, `wfDebugLog`, `wfLogDBError` and `wfErrorLog` global functions by
- * delegating the formatting to \MediaWiki\Logger\LegacyLogger.
+ * delegating the formatting to \\MediaWiki\\Logger\\LegacyLogger.
*
* @since 1.25
* @author Bryan Davis <bd808@wikimedia.org>
* @copyright © 2013 Bryan Davis and Wikimedia Foundation.
- * @see \MediaWiki\Logger\LegacyLogger
+ * @see \\MediaWiki\\Logger\\LegacyLogger
*/
class LegacyFormatter extends NormalizerFormatter {
diff --git a/includes/debug/logger/monolog/LineFormatter.php b/includes/debug/logger/monolog/LineFormatter.php
new file mode 100644
index 00000000..2ba7a53c
--- /dev/null
+++ b/includes/debug/logger/monolog/LineFormatter.php
@@ -0,0 +1,177 @@
+<?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\Logger\Monolog;
+
+use Exception;
+use Monolog\Formatter\LineFormatter as MonologLineFormatter;
+use MWExceptionHandler;
+
+/**
+ * Formats incoming records into a one-line string.
+ *
+ * An 'exeception' in the log record's context will be treated specially.
+ * It will be output for an '%exception%' placeholder in the format and
+ * excluded from '%context%' output if the '%exception%' placeholder is
+ * present.
+ *
+ * Exceptions that are logged with this formatter will optional have their
+ * stack traces appended. If that is done, MWExceptionHandler::redactedTrace()
+ * will be used to redact the trace information.
+ *
+ * @since 1.26
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @copyright © 2015 Bryan Davis and Wikimedia Foundation.
+ */
+class LineFormatter extends MonologLineFormatter {
+
+ /**
+ * @param string $format The format of the message
+ * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+ * @param bool $allowInlineLineBreaks Whether to allow inline line breaks in log entries
+ * @param bool $ignoreEmptyContextAndExtra
+ * @param bool $includeStacktraces
+ */
+ public function __construct(
+ $format = null, $dateFormat = null, $allowInlineLineBreaks = false,
+ $ignoreEmptyContextAndExtra = false, $includeStacktraces = false
+ ) {
+ parent::__construct(
+ $format, $dateFormat, $allowInlineLineBreaks,
+ $ignoreEmptyContextAndExtra
+ );
+ $this->includeStacktraces( $includeStacktraces );
+ }
+
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format( array $record ) {
+ // Drop the 'private' flag from the context
+ unset( $record['context']['private'] );
+
+ // Handle exceptions specially: pretty format and remove from context
+ // Will be output for a '%exception%' placeholder in format
+ $prettyException = '';
+ if ( isset( $record['context']['exception'] ) &&
+ strpos( $this->format, '%exception%' ) !== false
+ ) {
+ $e = $record['context']['exception'];
+ unset( $record['context']['exception'] );
+
+ if ( $e instanceof Exception ) {
+ $prettyException = $this->normalizeException( $e );
+ } elseif ( is_array( $e ) ) {
+ $prettyException = $this->normalizeExceptionArray( $e );
+ } else {
+ $prettyException = $this->stringify( $e );
+ }
+ }
+
+ $output = parent::format( $record );
+
+ if ( strpos( $output, '%exception%' ) !== false ) {
+ $output = str_replace( '%exception%', $prettyException, $output );
+ }
+ return $output;
+ }
+
+
+ /**
+ * Convert an Exception to a string.
+ *
+ * @param Exception $e
+ * @return string
+ */
+ protected function normalizeException( Exception $e ) {
+ return $this->normalizeExceptionArray( $this->exceptionAsArray( $e ) );
+ }
+
+
+ /**
+ * Convert an exception to an array of structured data.
+ *
+ * @param Exception $e
+ * @return array
+ */
+ protected function exceptionAsArray( Exception $e ) {
+ $out = array(
+ 'class' => get_class( $e ),
+ 'message' => $e->getMessage(),
+ 'code' => $e->getCode(),
+ 'file' => $e->getFile(),
+ 'line' => $e->getLine(),
+ 'trace' => MWExceptionHandler::redactTrace( $e->getTrace() ),
+ );
+
+ $prev = $e->getPrevious();
+ if ( $prev ) {
+ $out['previous'] = $this->exceptionAsArray( $prev );
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * Convert an array of Exception data to a string.
+ *
+ * @param array $e
+ * @return string
+ */
+ protected function normalizeExceptionArray( array $e ) {
+ $defaults = array(
+ 'class' => 'Unknown',
+ 'file' => 'unknown',
+ 'line' => null,
+ 'message' => 'unknown',
+ 'trace' => array(),
+ );
+ $e = array_merge( $defaults, $e );
+
+ $str = "\n[Exception {$e['class']}] (" .
+ "{$e['file']}:{$e['line']}) {$e['message']}";
+
+ if ( $this->includeStacktraces && $e['trace'] ) {
+ $str .= "\n" .
+ MWExceptionHandler::prettyPrintTrace( $e['trace'], ' ' );
+ }
+
+ if ( isset( $e['previous'] ) ) {
+ $prev = $e['previous'];
+ while ( $prev ) {
+ $prev = array_merge( $defaults, $prev );
+ $str .= "\nCaused by: [Exception {$prev['class']}] (" .
+ "{$prev['file']}:{$prev['line']}) {$prev['message']}";
+
+ if ( $this->includeStacktraces && $prev['trace'] ) {
+ $str .= "\n" .
+ MWExceptionHandler::prettyPrintTrace(
+ $prev['trace'], ' '
+ );
+ }
+
+ $prev = isset( $prev['previous'] ) ? $prev['previous'] : null;
+ }
+ }
+ return $str;
+ }
+}
diff --git a/includes/deferred/DeferredUpdates.php b/includes/deferred/DeferredUpdates.php
index 42816ddc..cd0266f6 100644
--- a/includes/deferred/DeferredUpdates.php
+++ b/includes/deferred/DeferredUpdates.php
@@ -34,13 +34,18 @@ interface DeferrableUpdate {
}
/**
- * Class for managing the deferred updates.
+ * Class for managing the deferred updates
+ *
+ * Deferred updates can be run at the end of the request,
+ * after the HTTP response has been sent. In CLI mode, updates
+ * are only deferred until there is no local master DB transaction.
+ * When updates are deferred, they go into a simple FIFO queue.
*
* @since 1.19
*/
class DeferredUpdates {
/**
- * Store of updates to be deferred until the end of the request.
+ * @var array Updates to be deferred until the end of the request.
*/
private static $updates = array();
@@ -49,18 +54,28 @@ class DeferredUpdates {
* @param DeferrableUpdate $update Some object that implements doUpdate()
*/
public static function addUpdate( DeferrableUpdate $update ) {
+ global $wgCommandLineMode;
+
array_push( self::$updates, $update );
- }
- /**
- * HTMLCacheUpdates are the most common deferred update people use. This
- * is a shortcut method for that.
- * @see HTMLCacheUpdate::__construct()
- * @param Title $title
- * @param string $table
- */
- public static function addHTMLCacheUpdate( $title, $table ) {
- self::addUpdate( new HTMLCacheUpdate( $title, $table ) );
+ // CLI scripts may forget to periodically flush these updates,
+ // so try to handle that rather than OOMing and losing them.
+ // Try to run the updates as soon as there is no local transaction.
+ static $waitingOnTrx = false; // de-duplicate callback
+ if ( $wgCommandLineMode && !$waitingOnTrx ) {
+ $lb = wfGetLB();
+ $dbw = $lb->getAnyOpenConnection( $lb->getWriterIndex() );
+ // Do the update as soon as there is no transaction
+ if ( $dbw && $dbw->trxLevel() ) {
+ $waitingOnTrx = true;
+ $dbw->onTransactionIdle( function() use ( &$waitingOnTrx ) {
+ DeferredUpdates::doUpdates();
+ $waitingOnTrx = false;
+ } );
+ } else {
+ self::doUpdates();
+ }
+ }
}
/**
@@ -80,23 +95,9 @@ class DeferredUpdates {
* prevent lock contention
*/
public static function doUpdates( $commit = '' ) {
- global $wgDeferredUpdateList;
-
- $updates = array_merge( $wgDeferredUpdateList, self::$updates );
+ $updates = self::$updates;
- // No need to get master connections in case of empty updates array
- if ( !count( $updates ) ) {
-
- return;
- }
-
- $dbw = false;
- $doCommit = $commit == 'commit';
- if ( $doCommit ) {
- $dbw = wfGetDB( DB_MASTER );
- }
-
- while ( $updates ) {
+ while ( count( $updates ) ) {
self::clearPendingUpdates();
/** @var DeferrableUpdate $update */
@@ -104,8 +105,8 @@ class DeferredUpdates {
try {
$update->doUpdate();
- if ( $doCommit && $dbw->trxLevel() ) {
- $dbw->commit( __METHOD__, 'flush' );
+ if ( $commit === 'commit' ) {
+ wfGetLBFactory()->commitMasterChanges();
}
} catch ( Exception $e ) {
// We don't want exceptions thrown during deferred updates to
@@ -116,9 +117,9 @@ class DeferredUpdates {
}
}
}
- $updates = array_merge( $wgDeferredUpdateList, self::$updates );
- }
+ $updates = self::$updates;
+ }
}
/**
@@ -126,7 +127,6 @@ class DeferredUpdates {
* want or need to call this. Unit tests need it though.
*/
public static function clearPendingUpdates() {
- global $wgDeferredUpdateList;
- $wgDeferredUpdateList = self::$updates = array();
+ self::$updates = array();
}
}
diff --git a/includes/deferred/HTMLCacheUpdate.php b/includes/deferred/HTMLCacheUpdate.php
index 79a10e68..a480aec8 100644
--- a/includes/deferred/HTMLCacheUpdate.php
+++ b/includes/deferred/HTMLCacheUpdate.php
@@ -55,8 +55,7 @@ class HTMLCacheUpdate implements DeferrableUpdate {
$count = $this->mTitle->getBacklinkCache()->getNumLinks( $this->mTable, 100 );
if ( $count >= 100 ) { // many backlinks
- JobQueueGroup::singleton()->push( $job );
- JobQueueGroup::singleton()->deduplicateRootJob( $job );
+ JobQueueGroup::singleton()->lazyPush( $job );
} else { // few backlinks ($count might be off even if 0)
$dbw = wfGetDB( DB_MASTER );
$dbw->onTransactionIdle( function () use ( $job ) {
diff --git a/includes/deferred/LinksDeletionUpdate.php b/includes/deferred/LinksDeletionUpdate.php
new file mode 100644
index 00000000..bbdfcf17
--- /dev/null
+++ b/includes/deferred/LinksDeletionUpdate.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * Updater for link tracking tables after a page edit.
+ *
+ * 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
+ */
+
+/**
+ * Update object handling the cleanup of links tables after a page was deleted.
+ **/
+class LinksDeletionUpdate extends SqlDataUpdate {
+ /** @var WikiPage The WikiPage that was deleted */
+ protected $mPage;
+
+ /**
+ * Constructor
+ *
+ * @param WikiPage $page Page we are updating
+ * @throws MWException
+ */
+ function __construct( WikiPage $page ) {
+ parent::__construct( false ); // no implicit transaction
+
+ $this->mPage = $page;
+
+ if ( !$page->exists() ) {
+ throw new MWException( "Page ID not known, perhaps the page doesn't exist?" );
+ }
+ }
+
+ /**
+ * Do some database updates after deletion
+ */
+ public function doUpdate() {
+ $title = $this->mPage->getTitle();
+ $id = $this->mPage->getId();
+
+ # Delete restrictions for it
+ $this->mDb->delete( 'page_restrictions', array( 'pr_page' => $id ), __METHOD__ );
+
+ # Fix category table counts
+ $cats = array();
+ $res = $this->mDb->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ );
+
+ foreach ( $res as $row ) {
+ $cats[] = $row->cl_to;
+ }
+
+ $this->mPage->updateCategoryCounts( array(), $cats );
+
+ # If using cascading deletes, we can skip some explicit deletes
+ if ( !$this->mDb->cascadingDeletes() ) {
+ # Delete outgoing links
+ $this->mDb->delete( 'pagelinks', array( 'pl_from' => $id ), __METHOD__ );
+ $this->mDb->delete( 'imagelinks', array( 'il_from' => $id ), __METHOD__ );
+ $this->mDb->delete( 'categorylinks', array( 'cl_from' => $id ), __METHOD__ );
+ $this->mDb->delete( 'templatelinks', array( 'tl_from' => $id ), __METHOD__ );
+ $this->mDb->delete( 'externallinks', array( 'el_from' => $id ), __METHOD__ );
+ $this->mDb->delete( 'langlinks', array( 'll_from' => $id ), __METHOD__ );
+ $this->mDb->delete( 'iwlinks', array( 'iwl_from' => $id ), __METHOD__ );
+ $this->mDb->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ );
+ $this->mDb->delete( 'page_props', array( 'pp_page' => $id ), __METHOD__ );
+ }
+
+ # If using cleanup triggers, we can skip some manual deletes
+ if ( !$this->mDb->cleanupTriggers() ) {
+ # Find recentchanges entries to clean up...
+ $rcIdsForTitle = $this->mDb->selectFieldValues( 'recentchanges',
+ 'rc_id',
+ array(
+ 'rc_type != ' . RC_LOG,
+ 'rc_namespace' => $title->getNamespace(),
+ 'rc_title' => $title->getDBkey()
+ ),
+ __METHOD__
+ );
+ $rcIdsForPage = $this->mDb->selectFieldValues( 'recentchanges',
+ 'rc_id',
+ array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ),
+ __METHOD__
+ );
+
+ # T98706: delete PK to avoid lock contention with RC delete log insertions
+ $rcIds = array_merge( $rcIdsForTitle, $rcIdsForPage );
+ if ( $rcIds ) {
+ $this->mDb->delete( 'recentchanges', array( 'rc_id' => $rcIds ), __METHOD__ );
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/includes/deferred/LinksUpdate.php b/includes/deferred/LinksUpdate.php
index e4f00e75..be5aff3b 100644
--- a/includes/deferred/LinksUpdate.php
+++ b/includes/deferred/LinksUpdate.php
@@ -267,7 +267,6 @@ class LinksUpdate extends SqlDataUpdate {
);
JobQueueGroup::singleton()->push( $job );
- JobQueueGroup::singleton()->deduplicateRootJob( $job );
}
}
@@ -936,87 +935,3 @@ class LinksUpdate extends SqlDataUpdate {
}
}
}
-
-/**
- * Update object handling the cleanup of links tables after a page was deleted.
- **/
-class LinksDeletionUpdate extends SqlDataUpdate {
- /** @var WikiPage The WikiPage that was deleted */
- protected $mPage;
-
- /**
- * Constructor
- *
- * @param WikiPage $page Page we are updating
- * @throws MWException
- */
- function __construct( WikiPage $page ) {
- parent::__construct( false ); // no implicit transaction
-
- $this->mPage = $page;
-
- if ( !$page->exists() ) {
- throw new MWException( "Page ID not known, perhaps the page doesn't exist?" );
- }
- }
-
- /**
- * Do some database updates after deletion
- */
- public function doUpdate() {
- $title = $this->mPage->getTitle();
- $id = $this->mPage->getId();
-
- # Delete restrictions for it
- $this->mDb->delete( 'page_restrictions', array( 'pr_page' => $id ), __METHOD__ );
-
- # Fix category table counts
- $cats = array();
- $res = $this->mDb->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ );
-
- foreach ( $res as $row ) {
- $cats[] = $row->cl_to;
- }
-
- $this->mPage->updateCategoryCounts( array(), $cats );
-
- # If using cascading deletes, we can skip some explicit deletes
- if ( !$this->mDb->cascadingDeletes() ) {
- # Delete outgoing links
- $this->mDb->delete( 'pagelinks', array( 'pl_from' => $id ), __METHOD__ );
- $this->mDb->delete( 'imagelinks', array( 'il_from' => $id ), __METHOD__ );
- $this->mDb->delete( 'categorylinks', array( 'cl_from' => $id ), __METHOD__ );
- $this->mDb->delete( 'templatelinks', array( 'tl_from' => $id ), __METHOD__ );
- $this->mDb->delete( 'externallinks', array( 'el_from' => $id ), __METHOD__ );
- $this->mDb->delete( 'langlinks', array( 'll_from' => $id ), __METHOD__ );
- $this->mDb->delete( 'iwlinks', array( 'iwl_from' => $id ), __METHOD__ );
- $this->mDb->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ );
- $this->mDb->delete( 'page_props', array( 'pp_page' => $id ), __METHOD__ );
- }
-
- # If using cleanup triggers, we can skip some manual deletes
- if ( !$this->mDb->cleanupTriggers() ) {
- # Clean up recentchanges entries...
- $this->mDb->delete( 'recentchanges',
- array( 'rc_type != ' . RC_LOG,
- 'rc_namespace' => $title->getNamespace(),
- 'rc_title' => $title->getDBkey() ),
- __METHOD__ );
- $this->mDb->delete( 'recentchanges',
- array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ),
- __METHOD__ );
- }
- }
-
- /**
- * Update all the appropriate counts in the category table.
- * @param array $added Associative array of category name => sort key
- * @param array $deleted Associative array of category name => sort key
- */
- function updateCategoryCounts( $added, $deleted ) {
- $a = WikiPage::factory( $this->mTitle );
- $a->updateCategoryCounts(
- array_keys( $added ), array_keys( $deleted )
- );
- }
-}
diff --git a/includes/deferred/SiteStatsUpdate.php b/includes/deferred/SiteStatsUpdate.php
index 97a17c39..ae75a754 100644
--- a/includes/deferred/SiteStatsUpdate.php
+++ b/includes/deferred/SiteStatsUpdate.php
@@ -65,6 +65,8 @@ class SiteStatsUpdate implements DeferrableUpdate {
public function doUpdate() {
global $wgSiteStatsAsyncFactor;
+ $this->doUpdateContextStats();
+
$rate = $wgSiteStatsAsyncFactor; // convenience
// If set to do so, only do actual DB updates 1 every $rate times.
// The other times, just update "pending delta" values in memcached.
@@ -128,7 +130,7 @@ class SiteStatsUpdate implements DeferrableUpdate {
*/
public static function cacheUpdate( $dbw ) {
global $wgActiveUserDays;
- $dbr = wfGetDB( DB_SLAVE, array( 'SpecialStatistics', 'vslow' ) );
+ $dbr = wfGetDB( DB_SLAVE, 'vslow' );
# Get non-bot users than did some recent action other than making accounts.
# If account creation is included, the number gets inflated ~20+ fold on enwiki.
$activeUsers = $dbr->selectField(
@@ -153,6 +155,16 @@ class SiteStatsUpdate implements DeferrableUpdate {
return $activeUsers;
}
+ protected function doUpdateContextStats() {
+ $stats = RequestContext::getMain()->getStats();
+ foreach ( array( 'edits', 'articles', 'pages', 'users', 'images' ) as $type ) {
+ $delta = $this->$type;
+ if ( $delta !== 0 ) {
+ $stats->updateCount( "site.$type", $delta );
+ }
+ }
+ }
+
protected function doUpdatePendingDeltas() {
$this->adjustPending( 'ss_total_edits', $this->edits );
$this->adjustPending( 'ss_good_articles', $this->articles );
diff --git a/includes/diff/DifferenceEngine.php b/includes/diff/DifferenceEngine.php
index 77bbd36a..c138eec2 100644
--- a/includes/diff/DifferenceEngine.php
+++ b/includes/diff/DifferenceEngine.php
@@ -685,24 +685,20 @@ class DifferenceEngine extends ContextSource {
$this->mCacheHit = true;
// Check if the diff should be hidden from this user
if ( !$this->loadRevisionData() ) {
-
return false;
} elseif ( $this->mOldRev &&
!$this->mOldRev->userCan( Revision::DELETED_TEXT, $this->getUser() )
) {
-
return false;
} elseif ( $this->mNewRev &&
!$this->mNewRev->userCan( Revision::DELETED_TEXT, $this->getUser() )
) {
-
return false;
}
// Short-circuit
if ( $this->mOldRev === false || ( $this->mOldRev && $this->mNewRev
&& $this->mOldRev->getID() == $this->mNewRev->getID() )
) {
-
return '';
}
// Cacheable?
@@ -714,7 +710,7 @@ class DifferenceEngine extends ContextSource {
if ( !$this->mRefreshCache ) {
$difftext = $wgMemc->get( $key );
if ( $difftext ) {
- wfIncrStats( 'diff_cache_hit' );
+ wfIncrStats( 'diff_cache.hit' );
$difftext = $this->localiseLineNumbers( $difftext );
$difftext .= "\n<!-- diff cache key $key -->\n";
@@ -726,7 +722,6 @@ class DifferenceEngine extends ContextSource {
// Loadtext is permission safe, this just clears out the diff
if ( !$this->loadText() ) {
-
return false;
}
@@ -734,12 +729,12 @@ class DifferenceEngine extends ContextSource {
// Save to cache for 7 days
if ( !Hooks::run( 'AbortDiffCache', array( &$this ) ) ) {
- wfIncrStats( 'diff_uncacheable' );
+ wfIncrStats( 'diff_cache.uncacheable' );
} elseif ( $key !== false && $difftext !== false ) {
- wfIncrStats( 'diff_cache_miss' );
+ wfIncrStats( 'diff_cache.miss' );
$wgMemc->set( $key, $difftext, 7 * 86400 );
} else {
- wfIncrStats( 'diff_uncacheable' );
+ wfIncrStats( 'diff_cache.uncacheable' );
}
// Replace line numbers with the text in the user's language
if ( $difftext !== false ) {
@@ -859,12 +854,10 @@ class DifferenceEngine extends ContextSource {
$tempFile1 = fopen( $tempName1, "w" );
if ( !$tempFile1 ) {
-
return false;
}
$tempFile2 = fopen( $tempName2, "w" );
if ( !$tempFile2 ) {
-
return false;
}
fwrite( $tempFile1, $otext );
@@ -1040,7 +1033,7 @@ class DifferenceEngine extends ContextSource {
$key = $title->quickUserCan( 'edit', $user ) ? 'editold' : 'viewsourceold';
$msg = $this->msg( $key )->escaped();
$editLink = $this->msg( 'parentheses' )->rawParams(
- Linker::linkKnown( $title, $msg, array( ), $editQuery ) )->escaped();
+ Linker::linkKnown( $title, $msg, array(), $editQuery ) )->escaped();
$header .= ' ' . Html::rawElement(
'span',
array( 'class' => 'mw-diff-edit' ),
@@ -1077,10 +1070,11 @@ class DifferenceEngine extends ContextSource {
// is often in a different language, mostly the page content language/dir
$tableClass = 'diff diff-contentalign-' . htmlspecialchars( $this->getDiffLang()->alignStart() );
$header = "<table class='$tableClass'>";
+ $userLang = htmlspecialchars( $this->getLanguage()->getHtmlCode() );
if ( !$diff && !$otitle ) {
$header .= "
- <tr style='vertical-align: top;'>
+ <tr style='vertical-align: top;' lang='{$userLang}'>
<td class='diff-ntitle'>{$ntitle}</td>
</tr>";
$multiColspan = 1;
@@ -1099,7 +1093,7 @@ class DifferenceEngine extends ContextSource {
}
if ( $otitle || $ntitle ) {
$header .= "
- <tr style='vertical-align: top;'>
+ <tr style='vertical-align: top;' lang='{$userLang}'>
<td colspan='$colspan' class='diff-otitle'>{$otitle}</td>
<td colspan='$colspan' class='diff-ntitle'>{$ntitle}</td>
</tr>";
@@ -1108,10 +1102,11 @@ class DifferenceEngine extends ContextSource {
if ( $multi != '' ) {
$header .= "<tr><td colspan='{$multiColspan}' style='text-align: center;' " .
- "class='diff-multi'>{$multi}</td></tr>";
+ "class='diff-multi' lang='{$userLang}'>{$multi}</td></tr>";
}
if ( $notice != '' ) {
- $header .= "<tr><td colspan='{$multiColspan}' style='text-align: center;'>{$notice}</td></tr>";
+ $header .= "<tr><td colspan='{$multiColspan}' style='text-align: center;' " .
+ "lang='{$userLang}'>{$notice}</td></tr>";
}
return $header . $diff . "</table>";
diff --git a/includes/diff/TableDiffFormatter.php b/includes/diff/TableDiffFormatter.php
index 5d0183ff..83e04a54 100644
--- a/includes/diff/TableDiffFormatter.php
+++ b/includes/diff/TableDiffFormatter.php
@@ -62,7 +62,7 @@ class TableDiffFormatter extends DiffFormatter {
protected function blockHeader( $xbeg, $xlen, $ybeg, $ylen ) {
// '<!--LINE \d+ -->' get replaced by a localised line number
// in DifferenceEngine::localiseLineNumbers
- $r = '<tr><td colspan="2" class="diff-lineno" id="L' . $xbeg . '" ><!--LINE ' . $xbeg . "--></td>\n" .
+ $r = '<tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l' . $xbeg . '" ><!--LINE ' . $xbeg . "--></td>\n" .
'<td colspan="2" class="diff-lineno"><!--LINE ' . $ybeg . "--></td></tr>\n";
return $r;
diff --git a/includes/diff/UnifiedDiffFormatter.php b/includes/diff/UnifiedDiffFormatter.php
index 32a76055..5f3ad3d7 100644
--- a/includes/diff/UnifiedDiffFormatter.php
+++ b/includes/diff/UnifiedDiffFormatter.php
@@ -38,6 +38,16 @@ class UnifiedDiffFormatter extends DiffFormatter {
/**
* @param string[] $lines
+ * @param string $prefix
+ */
+ protected function lines( $lines, $prefix = ' ' ) {
+ foreach ( $lines as $line ) {
+ echo "{$prefix}{$line}\n";
+ }
+ }
+
+ /**
+ * @param string[] $lines
*/
protected function added( $lines ) {
$this->lines( $lines, '+' );
diff --git a/includes/exception/BadTitleError.php b/includes/exception/BadTitleError.php
index e62f8bd6..039b9c60 100644
--- a/includes/exception/BadTitleError.php
+++ b/includes/exception/BadTitleError.php
@@ -28,11 +28,22 @@
*/
class BadTitleError extends ErrorPageError {
/**
- * @param string|Message $msg A message key (default: 'badtitletext')
+ * @param string|Message|MalformedTitleException $msg A message key (default: 'badtitletext'), or
+ * a MalformedTitleException to figure out things from
* @param array $params Parameter to wfMessage()
*/
public function __construct( $msg = 'badtitletext', $params = array() ) {
- parent::__construct( 'badtitle', $msg, $params );
+ if ( $msg instanceof MalformedTitleException ) {
+ $errorMessage = $msg->getErrorMessage();
+ if ( !$errorMessage ) {
+ parent::__construct( 'badtitle', 'badtitletext', array() );
+ } else {
+ $errorMessageParams = $msg->getErrorMessageParameters();
+ parent::__construct( 'badtitle', $errorMessage, $errorMessageParams );
+ }
+ } else {
+ parent::__construct( 'badtitle', $msg, $params );
+ }
}
/**
@@ -47,5 +58,4 @@ class BadTitleError extends ErrorPageError {
$wgOut->setStatusCode( 400 );
parent::report();
}
-
}
diff --git a/includes/exception/HttpError.php b/includes/exception/HttpError.php
index b81c5731..9211bf82 100644
--- a/includes/exception/HttpError.php
+++ b/includes/exception/HttpError.php
@@ -35,7 +35,7 @@ class HttpError extends MWException {
*
* @param int $httpCode HTTP status code to send to the client
* @param string|Message $content Content of the message
- * @param string|Message $header Content of the header (\<title\> and \<h1\>)
+ * @param string|Message|null $header Content of the header (\<title\> and \<h1\>)
*/
public function __construct( $httpCode, $content, $header = null ) {
parent::__construct( $content );
@@ -74,9 +74,7 @@ class HttpError extends MWException {
public function report() {
$this->doLog();
- $httpMessage = HttpStatus::getMessage( $this->httpCode );
-
- header( "Status: {$this->httpCode} {$httpMessage}", true, $this->httpCode );
+ HttpStatus::header( $this->httpCode );
header( 'Content-type: text/html; charset=utf-8' );
print $this->getHTML();
@@ -113,21 +111,21 @@ class HttpError extends MWException {
*/
public function getHTML() {
if ( $this->header === null ) {
- $header = HttpStatus::getMessage( $this->httpCode );
+ $titleHtml = htmlspecialchars( HttpStatus::getMessage( $this->httpCode ) );
} elseif ( $this->header instanceof Message ) {
- $header = $this->header->escaped();
+ $titleHtml = $this->header->escaped();
} else {
- $header = htmlspecialchars( $this->header );
+ $titleHtml = htmlspecialchars( $this->header );
}
if ( $this->content instanceof Message ) {
- $content = $this->content->escaped();
+ $contentHtml = $this->content->escaped();
} else {
- $content = htmlspecialchars( $this->content );
+ $contentHtml = nl2br( htmlspecialchars( $this->content ) );
}
return "<!DOCTYPE html>\n" .
- "<html><head><title>$header</title></head>\n" .
- "<body><h1>$header</h1><p>$content</p></body></html>\n";
+ "<html><head><title>$titleHtml</title></head>\n" .
+ "<body><h1>$titleHtml</h1><p>$contentHtml</p></body></html>\n";
}
}
diff --git a/includes/exception/MWException.php b/includes/exception/MWException.php
index 478fead1..c0186f9f 100644
--- a/includes/exception/MWException.php
+++ b/includes/exception/MWException.php
@@ -238,8 +238,7 @@ class MWException extends Exception {
} elseif ( self::isCommandLine() ) {
MWExceptionHandler::printError( $this->getText() );
} else {
- self::header( 'HTTP/1.1 500 MediaWiki exception' );
- self::header( 'Status: 500 MediaWiki exception' );
+ self::statusHeader( 500 );
self::header( "Content-Type: $wgMimeType; charset=utf-8" );
$this->reportHTML();
@@ -266,4 +265,9 @@ class MWException extends Exception {
header( $header );
}
}
+ private static function statusHeader( $code ) {
+ if ( !headers_sent() ) {
+ HttpStatus::header( $code );
+ }
+ }
}
diff --git a/includes/exception/MWExceptionHandler.php b/includes/exception/MWExceptionHandler.php
index a58705f6..d25f1a82 100644
--- a/includes/exception/MWExceptionHandler.php
+++ b/includes/exception/MWExceptionHandler.php
@@ -18,37 +18,47 @@
* @file
*/
+use MediaWiki\Logger\LoggerFactory;
+
/**
* Handler class for MWExceptions
* @ingroup Exception
*/
class MWExceptionHandler {
+ /**
+ * @var string $reservedMemory
+ */
protected static $reservedMemory;
+ /**
+ * @var array $fatalErrorTypes
+ */
protected static $fatalErrorTypes = array(
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR,
/* HHVM's FATAL_ERROR level */ 16777217,
);
+ /**
+ * @var bool $handledFatalCallback
+ */
+ protected static $handledFatalCallback = false;
/**
* Install handlers with PHP.
*/
public static function installHandler() {
- set_exception_handler( array( 'MWExceptionHandler', 'handleException' ) );
- set_error_handler( array( 'MWExceptionHandler', 'handleError' ) );
+ set_exception_handler( 'MWExceptionHandler::handleException' );
+ set_error_handler( 'MWExceptionHandler::handleError' );
// Reserve 16k of memory so we can report OOM fatals
self::$reservedMemory = str_repeat( ' ', 16384 );
- register_shutdown_function(
- array( 'MWExceptionHandler', 'handleFatalError' )
- );
+ register_shutdown_function( 'MWExceptionHandler::handleFatalError' );
}
/**
* Report an exception to the user
- * @param Exception $e
+ * @param Exception|Throwable $e
*/
- protected static function report( Exception $e ) {
+ protected static function report( $e ) {
global $wgShowExceptionDetails;
$cmdLine = MWException::isCommandLine();
@@ -86,7 +96,7 @@ class MWExceptionHandler {
$message = "Exception encountered, of type \"" . get_class( $e ) . "\"";
if ( $wgShowExceptionDetails ) {
- $message .= "\n" . MWExceptionHandler::getLogMessage( $e ) . "\nBacktrace:\n" .
+ $message .= "\n" . self::getLogMessage( $e ) . "\nBacktrace:\n" .
self::getRedactedTraceAsString( $e ) . "\n";
}
@@ -122,15 +132,16 @@ class MWExceptionHandler {
* transaction could be aborted properly.
*
* @since 1.23
- * @param Exception $e
+ * @param Exception|Throwable $e
*/
- public static function rollbackMasterChangesAndLog( Exception $e ) {
+ public static function rollbackMasterChangesAndLog( $e ) {
$factory = wfGetLBFactory();
if ( $factory->hasMasterChanges() ) {
- wfDebugLog( 'Bug56269',
+ $logger = LoggerFactory::getInstance( 'Bug56269' );
+ $logger->warning(
'Exception thrown with an uncommited database transaction: ' .
- MWExceptionHandler::getLogMessage( $e ) . "\n" .
- $e->getTraceAsString()
+ self::getLogMessage( $e ),
+ self::getLogContext( $e )
);
$factory->rollbackMasterChanges();
}
@@ -148,9 +159,9 @@ class MWExceptionHandler {
* }
*
* @since 1.25
- * @param Exception $e
+ * @param Exception|Throwable $e
*/
- public static function handleException( Exception $e ) {
+ public static function handleException( $e ) {
try {
// Rollback DBs to avoid transaction notices. This may fail
// to rollback some DB due to connection issues or exceptions.
@@ -173,24 +184,36 @@ class MWExceptionHandler {
}
/**
+ * Handler for set_error_handler() callback notifications.
+ *
+ * Receive a callback from the interpreter for a raised error, create an
+ * ErrorException, and log the exception to the 'error' logging
+ * channel(s). If the raised error is a fatal error type (only under HHVM)
+ * delegate to handleFatalError() instead.
+ *
* @since 1.25
+ *
* @param int $level Error level raised
* @param string $message
* @param string $file
* @param int $line
+ *
+ * @see logError()
*/
- public static function handleError( $level, $message, $file = null, $line = null ) {
- // Map error constant to error name (reverse-engineer PHP error reporting)
- $channel = 'error';
+ public static function handleError(
+ $level, $message, $file = null, $line = null
+ ) {
+ if ( in_array( $level, self::$fatalErrorTypes ) ) {
+ return call_user_func_array(
+ 'MWExceptionHandler::handleFatalError', func_get_args()
+ );
+ }
+
+ // Map error constant to error name (reverse-engineer PHP error
+ // reporting)
switch ( $level ) {
- case E_ERROR:
- case E_CORE_ERROR:
- case E_COMPILE_ERROR:
- case E_USER_ERROR:
case E_RECOVERABLE_ERROR:
- case E_PARSE:
$levelName = 'Error';
- $channel = 'fatal';
break;
case E_WARNING:
case E_CORE_WARNING:
@@ -209,17 +232,13 @@ class MWExceptionHandler {
case E_USER_DEPRECATED:
$levelName = 'Deprecated';
break;
- case /* HHVM's FATAL_ERROR */ 16777217:
- $levelName = 'Fatal';
- $channel = 'fatal';
- break;
default:
$levelName = 'Unknown error';
break;
}
$e = new ErrorException( "PHP $levelName: $message", 0, $level, $file, $line );
- self::logError( $e, $channel );
+ self::logError( $e, 'error' );
// This handler is for logging only. Return false will instruct PHP
// to continue regular handling.
@@ -228,42 +247,101 @@ class MWExceptionHandler {
/**
- * Look for a fatal error as the cause of the request termination and log
- * as an exception.
+ * Dual purpose callback used as both a set_error_handler() callback and
+ * a registered shutdown function. Receive a callback from the interpreter
+ * for a raised error or system shutdown, check for a fatal error, and log
+ * to the 'fatal' logging channel.
*
* Special handling is included for missing class errors as they may
* indicate that the user needs to install 3rd-party libraries via
* Composer or other means.
*
* @since 1.25
+ *
+ * @param int $level Error level raised
+ * @param string $message Error message
+ * @param string $file File that error was raised in
+ * @param int $line Line number error was raised at
+ * @param array $context Active symbol table point of error
+ * @param array $trace Backtrace at point of error (undocumented HHVM
+ * feature)
+ * @return bool Always returns false
*/
- public static function handleFatalError() {
+ public static function handleFatalError(
+ $level = null, $message = null, $file = null, $line = null,
+ $context = null, $trace = null
+ ) {
+ // Free reserved memory so that we have space to process OOM
+ // errors
self::$reservedMemory = null;
- $lastError = error_get_last();
- if ( $lastError &&
- isset( $lastError['type'] ) &&
- in_array( $lastError['type'], self::$fatalErrorTypes )
- ) {
- $msg = "Fatal Error: {$lastError['message']}";
- // HHVM: Class undefined: foo
- // PHP5: Class 'foo' not found
- if ( preg_match( "/Class (undefined: \w+|'\w+' not found)/",
- $lastError['message']
- ) ) {
- // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
- $msg = <<<TXT
+ if ( $level === null ) {
+ // Called as a shutdown handler, get data from error_get_last()
+ if ( static::$handledFatalCallback ) {
+ // Already called once (probably as an error handler callback
+ // under HHVM) so don't log again.
+ return false;
+ }
+
+ $lastError = error_get_last();
+ if ( $lastError !== null ) {
+ $level = $lastError['type'];
+ $message = $lastError['message'];
+ $file = $lastError['file'];
+ $line = $lastError['line'];
+ } else {
+ $level = 0;
+ $message = '';
+ }
+ }
+
+ if ( !in_array( $level, self::$fatalErrorTypes ) ) {
+ // Only interested in fatal errors, others should have been
+ // handled by MWExceptionHandler::handleError
+ return false;
+ }
+
+ $msg = "[{exception_id}] PHP Fatal Error: {$message}";
+
+ // Look at message to see if this is a class not found failure
+ // HHVM: Class undefined: foo
+ // PHP5: Class 'foo' not found
+ if ( preg_match( "/Class (undefined: \w+|'\w+' not found)/", $msg ) ) {
+ // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
+ $msg = <<<TXT
{$msg}
MediaWiki or an installed extension requires this class but it is not embedded directly in MediaWiki's git repository and must be installed separately by the end user.
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
- }
- $e = new ErrorException( $msg, 0, $lastError['type'] );
- self::logError( $e, 'fatal' );
+ // @codingStandardsIgnoreEnd
}
+
+ // We can't just create an exception and log it as it is likely that
+ // the interpreter has unwound the stack already. If that is true the
+ // stacktrace we would get would be functionally empty. If however we
+ // have been called as an error handler callback *and* HHVM is in use
+ // we will have been provided with a useful stacktrace that we can
+ // log.
+ $trace = $trace ?: debug_backtrace();
+ $logger = LoggerFactory::getInstance( 'fatal' );
+ $logger->error( $msg, array(
+ 'exception' => array(
+ 'class' => 'ErrorException',
+ 'message' => "PHP Fatal Error: {$message}",
+ 'code' => $level,
+ 'file' => $file,
+ 'line' => $line,
+ 'trace' => static::redactTrace( $trace ),
+ ),
+ 'exception_id' => wfRandomString( 8 ),
+ ) );
+
+ // Remember call so we don't double process via HHVM's fatal
+ // notifications and the shutdown hook behavior
+ static::$handledFatalCallback = true;
+ return false;
}
/**
@@ -272,20 +350,34 @@ TXT;
* Like Exception::getTraceAsString, but replaces argument values with
* argument type or class name.
*
- * @param Exception $e
+ * @param Exception|Throwable $e
* @return string
+ * @see prettyPrintTrace()
*/
- public static function getRedactedTraceAsString( Exception $e ) {
+ public static function getRedactedTraceAsString( $e ) {
+ return self::prettyPrintTrace( self::getRedactedTrace( $e ) );
+ }
+
+ /**
+ * Generate a string representation of a stacktrace.
+ *
+ * @param array $trace
+ * @param string $pad Constant padding to add to each line of trace
+ * @return string
+ * @since 1.26
+ */
+ public static function prettyPrintTrace( array $trace, $pad = '' ) {
$text = '';
- foreach ( self::getRedactedTrace( $e ) as $level => $frame ) {
+ foreach ( $trace as $level => $frame ) {
if ( isset( $frame['file'] ) && isset( $frame['line'] ) ) {
- $text .= "#{$level} {$frame['file']}({$frame['line']}): ";
+ $text .= "{$pad}#{$level} {$frame['file']}({$frame['line']}): ";
} else {
- // 'file' and 'line' are unset for calls via call_user_func (bug 55634)
- // This matches behaviour of Exception::getTraceAsString to instead
- // display "[internal function]".
- $text .= "#{$level} [internal function]: ";
+ // 'file' and 'line' are unset for calls via call_user_func
+ // (bug 55634) This matches behaviour of
+ // Exception::getTraceAsString to instead display "[internal
+ // function]".
+ $text .= "{$pad}#{$level} [internal function]: ";
}
if ( isset( $frame['class'] ) ) {
@@ -302,7 +394,7 @@ TXT;
}
$level = $level + 1;
- $text .= "#{$level} {main}";
+ $text .= "{$pad}#{$level} {main}";
return $text;
}
@@ -315,10 +407,24 @@ TXT;
* or its type (if the element is a PHP primitive).
*
* @since 1.22
- * @param Exception $e
+ * @param Exception|Throwable $e
* @return array
*/
- public static function getRedactedTrace( Exception $e ) {
+ public static function getRedactedTrace( $e ) {
+ return static::redactTrace( $e->getTrace() );
+ }
+
+ /**
+ * Redact a stacktrace generated by Exception::getTrace(),
+ * debug_backtrace() or similar means. Replaces each element in each
+ * frame's argument array with the name of its class (if the element is an
+ * object) or its type (if the element is a PHP primitive).
+ *
+ * @since 1.26
+ * @param array $trace Stacktrace
+ * @return array Stacktrace with arugment values converted to data types
+ */
+ public static function redactTrace( array $trace ) {
return array_map( function ( $frame ) {
if ( isset( $frame['args'] ) ) {
$frame['args'] = array_map( function ( $arg ) {
@@ -326,7 +432,7 @@ TXT;
}, $frame['args'] );
}
return $frame;
- }, $e->getTrace() );
+ }, $trace );
}
/**
@@ -336,10 +442,10 @@ TXT;
* $wgShowExceptionDetails is set to false), to the entry in the debug log.
*
* @since 1.22
- * @param Exception $e
+ * @param Exception|Throwable $e
* @return string
*/
- public static function getLogId( Exception $e ) {
+ public static function getLogId( $e ) {
if ( !isset( $e->_mwLogId ) ) {
$e->_mwLogId = wfRandomString( 8 );
}
@@ -365,10 +471,10 @@ TXT;
* Get a message formatting the exception message and its origin.
*
* @since 1.22
- * @param Exception $e
+ * @param Exception|Throwable $e
* @return string
*/
- public static function getLogMessage( Exception $e ) {
+ public static function getLogMessage( $e ) {
$id = self::getLogId( $e );
$type = get_class( $e );
$file = $e->getFile();
@@ -380,6 +486,65 @@ TXT;
}
/**
+ * Get a PSR-3 log event context from an Exception.
+ *
+ * Creates a structured array containing information about the provided
+ * exception that can be used to augment a log message sent to a PSR-3
+ * logger.
+ *
+ * @param Exception|Throwable $e
+ * @return array
+ */
+ public static function getLogContext( $e ) {
+ return array(
+ 'exception' => $e,
+ 'exception_id' => static::getLogId( $e ),
+ );
+ }
+
+ /**
+ * Get a structured representation of an Exception.
+ *
+ * Returns an array of structured data (class, message, code, file,
+ * backtrace) derived from the given exception. The backtrace information
+ * will be redacted as per getRedactedTraceAsArray().
+ *
+ * @param Exception|Throwable $e
+ * @return array
+ * @since 1.26
+ */
+ public static function getStructuredExceptionData( $e ) {
+ global $wgLogExceptionBacktrace;
+ $data = array(
+ 'id' => self::getLogId( $e ),
+ 'type' => get_class( $e ),
+ 'file' => $e->getFile(),
+ 'line' => $e->getLine(),
+ 'message' => $e->getMessage(),
+ 'code' => $e->getCode(),
+ 'url' => self::getURL() ?: null,
+ );
+
+ if ( $e instanceof ErrorException &&
+ ( error_reporting() & $e->getSeverity() ) === 0
+ ) {
+ // Flag surpressed errors
+ $data['suppressed'] = true;
+ }
+
+ if ( $wgLogExceptionBacktrace ) {
+ $data['backtrace'] = self::getRedactedTrace( $e );
+ }
+
+ $previous = $e->getPrevious();
+ if ( $previous !== null ) {
+ $data['previous'] = self::getStructuredExceptionData( $previous );
+ }
+
+ return $data;
+ }
+
+ /**
* Serialize an Exception object to JSON.
*
* The JSON object will have keys 'id', 'file', 'line', 'message', and
@@ -427,39 +592,14 @@ TXT;
* @endcode
*
* @since 1.23
- * @param Exception $e
+ * @param Exception|Throwable $e
* @param bool $pretty Add non-significant whitespace to improve readability (default: false).
* @param int $escaping Bitfield consisting of FormatJson::.*_OK class constants.
* @return string|false JSON string if successful; false upon failure
*/
- public static function jsonSerializeException( Exception $e, $pretty = false, $escaping = 0 ) {
- global $wgLogExceptionBacktrace;
-
- $exceptionData = array(
- 'id' => self::getLogId( $e ),
- 'type' => get_class( $e ),
- 'file' => $e->getFile(),
- 'line' => $e->getLine(),
- 'message' => $e->getMessage(),
- );
-
- if ( $e instanceof ErrorException && ( error_reporting() & $e->getSeverity() ) === 0 ) {
- // Flag surpressed errors
- $exceptionData['suppressed'] = true;
- }
-
- // Because MediaWiki is first and foremost a web application, we set a
- // 'url' key unconditionally, but set it to null if the exception does
- // not occur in the context of a web request, as a way of making that
- // fact visible and explicit.
- $exceptionData['url'] = self::getURL() ?: null;
-
- if ( $wgLogExceptionBacktrace ) {
- // Argument values may not be serializable, so redact them.
- $exceptionData['backtrace'] = self::getRedactedTrace( $e );
- }
-
- return FormatJson::encode( $exceptionData, $pretty, $escaping );
+ public static function jsonSerializeException( $e, $pretty = false, $escaping = 0 ) {
+ $data = self::getStructuredExceptionData( $e );
+ return FormatJson::encode( $data, $pretty, $escaping );
}
/**
@@ -469,22 +609,20 @@ TXT;
* it is also used to handle PHP exceptions or exceptions from other libraries.
*
* @since 1.22
- * @param Exception $e
+ * @param Exception|Throwable $e
*/
- public static function logException( Exception $e ) {
- global $wgLogExceptionBacktrace;
-
+ public static function logException( $e ) {
if ( !( $e instanceof MWException ) || $e->isLoggable() ) {
- $log = self::getLogMessage( $e );
- if ( $wgLogExceptionBacktrace ) {
- wfDebugLog( 'exception', $log . "\n" . $e->getTraceAsString() );
- } else {
- wfDebugLog( 'exception', $log );
- }
+ $logger = LoggerFactory::getInstance( 'exception' );
+ $logger->error(
+ self::getLogMessage( $e ),
+ self::getLogContext( $e )
+ );
$json = self::jsonSerializeException( $e, false, FormatJson::ALL_OK );
if ( $json !== false ) {
- wfDebugLog( 'exception-json', $json, 'private' );
+ $logger = LoggerFactory::getInstance( 'exception-json' );
+ $logger->error( $json, array( 'private' => true ) );
}
Hooks::run( 'LogException', array( $e, false ) );
@@ -499,24 +637,23 @@ TXT;
* @param string $channel
*/
protected static function logError( ErrorException $e, $channel ) {
- global $wgLogExceptionBacktrace;
-
// The set_error_handler callback is independent from error_reporting.
- // Filter out unwanted errors manually (e.g. when wfSuppressWarnings is active).
+ // Filter out unwanted errors manually (e.g. when
+ // MediaWiki\suppressWarnings is active).
$suppressed = ( error_reporting() & $e->getSeverity() ) === 0;
if ( !$suppressed ) {
- $log = self::getLogMessage( $e );
- if ( $wgLogExceptionBacktrace ) {
- wfDebugLog( $channel, $log . "\n" . $e->getTraceAsString() );
- } else {
- wfDebugLog( $channel, $log );
- }
+ $logger = LoggerFactory::getInstance( $channel );
+ $logger->error(
+ self::getLogMessage( $e ),
+ self::getLogContext( $e )
+ );
}
// Include all errors in the json log (surpressed errors will be flagged)
$json = self::jsonSerializeException( $e, false, FormatJson::ALL_OK );
if ( $json !== false ) {
- wfDebugLog( "$channel-json", $json, 'private' );
+ $logger = LoggerFactory::getInstance( "{$channel}-json" );
+ $logger->error( $json, array( 'private' => true ) );
}
Hooks::run( 'LogException', array( $e, $suppressed ) );
diff --git a/includes/filebackend/FSFile.php b/includes/filebackend/FSFile.php
index 6ee9b2e0..213bb87d 100644
--- a/includes/filebackend/FSFile.php
+++ b/includes/filebackend/FSFile.php
@@ -75,9 +75,9 @@ class FSFile {
* @return string|bool TS_MW timestamp or false on failure
*/
public function getTimestamp() {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$timestamp = filemtime( $this->path );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $timestamp !== false ) {
$timestamp = wfTimestamp( TS_MW, $timestamp );
}
@@ -200,13 +200,12 @@ class FSFile {
public function getSha1Base36( $recache = false ) {
if ( $this->sha1Base36 !== null && !$recache ) {
-
return $this->sha1Base36;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$this->sha1Base36 = sha1_file( $this->path );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $this->sha1Base36 !== false ) {
$this->sha1Base36 = wfBaseConvert( $this->sha1Base36, 16, 36, 31 );
diff --git a/includes/filebackend/FileBackend.php b/includes/filebackend/FileBackend.php
index b87e26d3..cd82ab10 100644
--- a/includes/filebackend/FileBackend.php
+++ b/includes/filebackend/FileBackend.php
@@ -380,12 +380,15 @@ abstract class FileBackend {
$op['headers']['Content-Disposition'] = $op['disposition'];
}
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doOperationsInternal( $ops, $opts );
}
/**
* @see FileBackend::doOperations()
+ * @param array $ops
+ * @param array $opts
*/
abstract protected function doOperationsInternal( array $ops, array $opts );
@@ -612,12 +615,14 @@ abstract class FileBackend {
$op['headers']['Content-Disposition'] = $op['disposition'];
}
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doQuickOperationsInternal( $ops );
}
/**
* @see FileBackend::doQuickOperations()
+ * @param array $ops
* @since 1.20
*/
abstract protected function doQuickOperationsInternal( array $ops );
@@ -756,12 +761,14 @@ abstract class FileBackend {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doPrepare( $params );
}
/**
* @see FileBackend::prepare()
+ * @param array $params
*/
abstract protected function doPrepare( array $params );
@@ -785,12 +792,14 @@ abstract class FileBackend {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doSecure( $params );
}
/**
* @see FileBackend::secure()
+ * @param array $params
*/
abstract protected function doSecure( array $params );
@@ -816,12 +825,14 @@ abstract class FileBackend {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doPublish( $params );
}
/**
* @see FileBackend::publish()
+ * @param array $params
*/
abstract protected function doPublish( array $params );
@@ -840,12 +851,14 @@ abstract class FileBackend {
if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
return $this->doClean( $params );
}
/**
* @see FileBackend::clean()
+ * @param array $params
*/
abstract protected function doClean( array $params );
@@ -1289,7 +1302,7 @@ abstract class FileBackend {
*
* @param array $ops List of file operations to FileBackend::doOperations()
* @param Status $status Status to update on lock/unlock
- * @return array List of ScopedFileLocks or null values
+ * @return ScopedLock|null
* @since 1.20
*/
abstract public function getScopedLocksForOps( array $ops, Status $status );
diff --git a/includes/filebackend/FileBackendGroup.php b/includes/filebackend/FileBackendGroup.php
index 1b88db7e..9bb15825 100644
--- a/includes/filebackend/FileBackendGroup.php
+++ b/includes/filebackend/FileBackendGroup.php
@@ -160,6 +160,8 @@ class FileBackendGroup {
$config['fileJournal'] = isset( $config['fileJournal'] )
? FileJournal::factory( $config['fileJournal'], $name )
: FileJournal::factory( array( 'class' => 'NullFileJournal' ), $name );
+ $config['wanCache'] = ObjectCache::getMainWANInstance();
+
$this->backends[$name]['instance'] = new $class( $config );
}
diff --git a/includes/filebackend/FileBackendMultiWrite.php b/includes/filebackend/FileBackendMultiWrite.php
index f2d13eeb..1603d44f 100644
--- a/includes/filebackend/FileBackendMultiWrite.php
+++ b/includes/filebackend/FileBackendMultiWrite.php
@@ -33,20 +33,22 @@
* Only use this class when transitioning from one storage system to another.
*
* Read operations are only done on the 'master' backend for consistency.
- * Write operations are performed on all backends, in the order defined.
- * If an operation fails on one backend it will be rolled back from the others.
+ * Write operations are performed on all backends, starting with the master.
+ * This makes a best-effort to have transactional semantics, but since requests
+ * may sometimes fail, the use of "autoResync" or background scripts to fix
+ * inconsistencies is important.
*
* @ingroup FileBackend
* @since 1.19
*/
class FileBackendMultiWrite extends FileBackend {
- /** @var array Prioritized list of FileBackendStore objects.
- * array of (backend index => backends)
- */
+ /** @var FileBackendStore[] Prioritized list of FileBackendStore objects */
protected $backends = array();
/** @var int Index of master backend */
protected $masterIndex = -1;
+ /** @var int Index of read affinity backend */
+ protected $readIndex = -1;
/** @var int Bitfield */
protected $syncChecks = 0;
@@ -54,12 +56,6 @@ class FileBackendMultiWrite extends FileBackend {
/** @var string|bool */
protected $autoResync = false;
- /** @var array */
- protected $noPushDirConts = array();
-
- /** @var bool */
- protected $noPushQuickOps = false;
-
/* Possible internal backend consistency checks */
const CHECK_SIZE = 1;
const CHECK_TIME = 2;
@@ -75,6 +71,7 @@ class FileBackendMultiWrite extends FileBackend {
* FileBackendStore class, but with these additional settings:
* - class : The name of the backend class
* - isMultiMaster : This must be set for one backend.
+ * - readAffinity : Use this for reads without 'latest' set.
* - template: : If given a backend name, this will use
* the config of that backend as a template.
* Values specified here take precedence.
@@ -88,8 +85,6 @@ class FileBackendMultiWrite extends FileBackend {
* Use "conservative" to limit resyncing to copying newer master
* backend files over older (or non-existing) clone backend files.
* Cases that cannot be handled will result in operation abortion.
- * - noPushQuickOps : (hack) Only apply doQuickOperations() to the master backend.
- * - noPushDirConts : (hack) Only apply directory functions to the master backend.
*
* @param array $config
* @throws FileBackendError
@@ -102,12 +97,6 @@ class FileBackendMultiWrite extends FileBackend {
$this->autoResync = isset( $config['autoResync'] )
? $config['autoResync']
: false;
- $this->noPushQuickOps = isset( $config['noPushQuickOps'] )
- ? $config['noPushQuickOps']
- : false;
- $this->noPushDirConts = isset( $config['noPushDirConts'] )
- ? $config['noPushDirConts']
- : array();
// Construct backends here rather than via registration
// to keep these backends hidden from outside the proxy.
$namesUsed = array();
@@ -134,6 +123,9 @@ class FileBackendMultiWrite extends FileBackend {
$this->masterIndex = $index; // this is the "master"
$config['fileJournal'] = $this->fileJournal; // log under proxy backend
}
+ if ( !empty( $config['readAffinity'] ) ) {
+ $this->readIndex = $index; // prefer this for reads
+ }
// Create sub-backend object
if ( !isset( $config['class'] ) ) {
throw new FileBackendError( 'No class given for a backend config.' );
@@ -144,6 +136,9 @@ class FileBackendMultiWrite extends FileBackend {
if ( $this->masterIndex < 0 ) { // need backends and must have a master
throw new FileBackendError( 'No master backend defined.' );
}
+ if ( $this->readIndex < 0 ) {
+ $this->readIndex = $this->masterIndex; // default
+ }
}
final protected function doOperationsInternal( array $ops, array $opts ) {
@@ -154,6 +149,7 @@ class FileBackendMultiWrite extends FileBackend {
// Try to lock those files for the scope of this function...
if ( empty( $opts['nonLocking'] ) ) {
// Try to lock those files for the scope of this function...
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scopeLock = $this->getScopedLocksForOps( $ops, $status );
if ( !$status->isOK() ) {
return $status; // abort
@@ -328,8 +324,8 @@ class FileBackendMultiWrite extends FileBackend {
$cStat = $cBackend->getFileStat( array( 'src' => $cPath, 'latest' => true ) );
if ( $cStat === null || ( $cSha1 !== false && !$cStat ) ) { // sanity
$status->fatal( 'backend-fail-internal', $cBackend->getName() );
- wfDebugLog( 'FileOperation', __METHOD__
- . ': File is not available on the clone backend' );
+ wfDebugLog( 'FileOperation', __METHOD__ .
+ ': File is not available on the clone backend' );
continue; // file is not available on the clone backend...
}
if ( $mSha1 === $cSha1 ) {
@@ -433,7 +429,7 @@ class FileBackendMultiWrite extends FileBackend {
*/
protected function substPaths( $paths, FileBackendStore $backend ) {
return preg_replace(
- '!^mwstore://' . preg_quote( $this->name ) . '/!',
+ '!^mwstore://' . preg_quote( $this->name, '!' ) . '/!',
StringUtils::escapeRegexReplacement( "mwstore://{$backend->getName()}/" ),
$paths // string or array
);
@@ -460,12 +456,10 @@ class FileBackendMultiWrite extends FileBackend {
$masterStatus = $this->backends[$this->masterIndex]->doQuickOperations( $realOps );
$status->merge( $masterStatus );
// Propagate the operations to the clone backends...
- if ( !$this->noPushQuickOps ) {
- foreach ( $this->backends as $index => $backend ) {
- if ( $index !== $this->masterIndex ) { // not done already
- $realOps = $this->substOpBatchPaths( $ops, $backend );
- $status->merge( $backend->doQuickOperations( $realOps ) );
- }
+ foreach ( $this->backends as $index => $backend ) {
+ if ( $index !== $this->masterIndex ) { // not done already
+ $realOps = $this->substOpBatchPaths( $ops, $backend );
+ $status->merge( $backend->doQuickOperations( $realOps ) );
}
}
// Make 'success', 'successCount', and 'failCount' fields reflect
@@ -478,24 +472,11 @@ class FileBackendMultiWrite extends FileBackend {
return $status;
}
- /**
- * @param string $path Storage path
- * @return bool Path container should have dir changes pushed to all backends
- */
- protected function replicateContainerDirChanges( $path ) {
- list( , $shortCont, ) = self::splitStoragePath( $path );
-
- return !in_array( $shortCont, $this->noPushDirConts );
- }
-
protected function doPrepare( array $params ) {
$status = Status::newGood();
- $replicate = $this->replicateContainerDirChanges( $params['dir'] );
foreach ( $this->backends as $index => $backend ) {
- if ( $replicate || $index == $this->masterIndex ) {
- $realParams = $this->substOpPaths( $params, $backend );
- $status->merge( $backend->doPrepare( $realParams ) );
- }
+ $realParams = $this->substOpPaths( $params, $backend );
+ $status->merge( $backend->doPrepare( $realParams ) );
}
return $status;
@@ -503,12 +484,9 @@ class FileBackendMultiWrite extends FileBackend {
protected function doSecure( array $params ) {
$status = Status::newGood();
- $replicate = $this->replicateContainerDirChanges( $params['dir'] );
foreach ( $this->backends as $index => $backend ) {
- if ( $replicate || $index == $this->masterIndex ) {
- $realParams = $this->substOpPaths( $params, $backend );
- $status->merge( $backend->doSecure( $realParams ) );
- }
+ $realParams = $this->substOpPaths( $params, $backend );
+ $status->merge( $backend->doSecure( $realParams ) );
}
return $status;
@@ -516,12 +494,9 @@ class FileBackendMultiWrite extends FileBackend {
protected function doPublish( array $params ) {
$status = Status::newGood();
- $replicate = $this->replicateContainerDirChanges( $params['dir'] );
foreach ( $this->backends as $index => $backend ) {
- if ( $replicate || $index == $this->masterIndex ) {
- $realParams = $this->substOpPaths( $params, $backend );
- $status->merge( $backend->doPublish( $realParams ) );
- }
+ $realParams = $this->substOpPaths( $params, $backend );
+ $status->merge( $backend->doPublish( $realParams ) );
}
return $status;
@@ -529,12 +504,9 @@ class FileBackendMultiWrite extends FileBackend {
protected function doClean( array $params ) {
$status = Status::newGood();
- $replicate = $this->replicateContainerDirChanges( $params['dir'] );
foreach ( $this->backends as $index => $backend ) {
- if ( $replicate || $index == $this->masterIndex ) {
- $realParams = $this->substOpPaths( $params, $backend );
- $status->merge( $backend->doClean( $realParams ) );
- }
+ $realParams = $this->substOpPaths( $params, $backend );
+ $status->merge( $backend->doClean( $realParams ) );
}
return $status;
@@ -542,44 +514,52 @@ class FileBackendMultiWrite extends FileBackend {
public function concatenate( array $params ) {
// We are writing to an FS file, so we don't need to do this per-backend
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->concatenate( $realParams );
+ return $this->backends[$index]->concatenate( $realParams );
}
public function fileExists( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->fileExists( $realParams );
+ return $this->backends[$index]->fileExists( $realParams );
}
public function getFileTimestamp( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->getFileTimestamp( $realParams );
+ return $this->backends[$index]->getFileTimestamp( $realParams );
}
public function getFileSize( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->getFileSize( $realParams );
+ return $this->backends[$index]->getFileSize( $realParams );
}
public function getFileStat( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->getFileStat( $realParams );
+ return $this->backends[$index]->getFileStat( $realParams );
}
public function getFileXAttributes( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->getFileXAttributes( $realParams );
+ return $this->backends[$index]->getFileXAttributes( $realParams );
}
public function getFileContentsMulti( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
- $contentsM = $this->backends[$this->masterIndex]->getFileContentsMulti( $realParams );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
+
+ $contentsM = $this->backends[$index]->getFileContentsMulti( $realParams );
$contents = array(); // (path => FSFile) mapping using the proxy backend's name
foreach ( $contentsM as $path => $data ) {
@@ -590,26 +570,31 @@ class FileBackendMultiWrite extends FileBackend {
}
public function getFileSha1Base36( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->getFileSha1Base36( $realParams );
+ return $this->backends[$index]->getFileSha1Base36( $realParams );
}
public function getFileProps( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->getFileProps( $realParams );
+ return $this->backends[$index]->getFileProps( $realParams );
}
public function streamFile( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->streamFile( $realParams );
+ return $this->backends[$index]->streamFile( $realParams );
}
public function getLocalReferenceMulti( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
- $fsFilesM = $this->backends[$this->masterIndex]->getLocalReferenceMulti( $realParams );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
+
+ $fsFilesM = $this->backends[$index]->getLocalReferenceMulti( $realParams );
$fsFiles = array(); // (path => FSFile) mapping using the proxy backend's name
foreach ( $fsFilesM as $path => $fsFile ) {
@@ -620,8 +605,10 @@ class FileBackendMultiWrite extends FileBackend {
}
public function getLocalCopyMulti( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
- $tempFilesM = $this->backends[$this->masterIndex]->getLocalCopyMulti( $realParams );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
+
+ $tempFilesM = $this->backends[$index]->getLocalCopyMulti( $realParams );
$tempFiles = array(); // (path => TempFSFile) mapping using the proxy backend's name
foreach ( $tempFilesM as $path => $tempFile ) {
@@ -632,9 +619,10 @@ class FileBackendMultiWrite extends FileBackend {
}
public function getFileHttpUrl( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
- return $this->backends[$this->masterIndex]->getFileHttpUrl( $realParams );
+ return $this->backends[$index]->getFileHttpUrl( $realParams );
}
public function directoryExists( array $params ) {
@@ -667,13 +655,15 @@ class FileBackendMultiWrite extends FileBackend {
}
public function preloadCache( array $paths ) {
- $realPaths = $this->substPaths( $paths, $this->backends[$this->masterIndex] );
- $this->backends[$this->masterIndex]->preloadCache( $realPaths );
+ $realPaths = $this->substPaths( $paths, $this->backends[$this->readIndex] );
+ $this->backends[$this->readIndex]->preloadCache( $realPaths );
}
public function preloadFileStat( array $params ) {
- $realParams = $this->substOpPaths( $params, $this->backends[$this->masterIndex] );
- return $this->backends[$this->masterIndex]->preloadFileStat( $realParams );
+ $index = $this->getReadIndexFromParams( $params );
+ $realParams = $this->substOpPaths( $params, $this->backends[$index] );
+
+ return $this->backends[$index]->preloadFileStat( $realParams );
}
public function getScopedLocksForOps( array $ops, Status $status ) {
@@ -688,6 +678,14 @@ class FileBackendMultiWrite extends FileBackend {
);
// Actually acquire the locks
- return array( $this->getScopedFileLocks( $pbPaths, 'mixed', $status ) );
+ return $this->getScopedFileLocks( $pbPaths, 'mixed', $status );
+ }
+
+ /**
+ * @param array $params
+ * @return int The master or read affinity backend index, based on $params['latest']
+ */
+ protected function getReadIndexFromParams( array $params ) {
+ return !empty( $params['latest'] ) ? $this->masterIndex : $this->readIndex;
}
}
diff --git a/includes/filebackend/FileBackendStore.php b/includes/filebackend/FileBackendStore.php
index 25e87d43..94339643 100644
--- a/includes/filebackend/FileBackendStore.php
+++ b/includes/filebackend/FileBackendStore.php
@@ -36,7 +36,7 @@
* @since 1.19
*/
abstract class FileBackendStore extends FileBackend {
- /** @var BagOStuff */
+ /** @var WANObjectCache */
protected $memCache;
/** @var ProcessCacheLRU Map of paths to small (RAM/disk) cache items */
protected $cheapCache;
@@ -58,6 +58,7 @@ abstract class FileBackendStore extends FileBackend {
/**
* @see FileBackend::__construct()
* Additional $config params include:
+ * - wanCache : WANOBjectCache object to use for persistent caching.
* - mimeCallback : Callback that takes (storage path, content, file system path) and
* returns the MIME type of the file or 'unknown/unknown'. The file
* system path parameter should be used if the content one is null.
@@ -72,7 +73,7 @@ abstract class FileBackendStore extends FileBackend {
// @todo handle the case of extension-less files using the contents
return StreamFile::contentTypeFromPath( $storagePath ) ?: 'unknown/unknown';
};
- $this->memCache = new EmptyBagOStuff(); // disabled by default
+ $this->memCache = WANObjectCache::newEmpty(); // disabled by default
$this->cheapCache = new ProcessCacheLRU( self::CACHE_CHEAP_SIZE );
$this->expensiveCache = new ProcessCacheLRU( self::CACHE_EXPENSIVE_SIZE );
}
@@ -376,9 +377,9 @@ abstract class FileBackendStore extends FileBackend {
unset( $params['latest'] ); // sanity
// Check that the specified temp file is valid...
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = ( is_file( $tmpPath ) && filesize( $tmpPath ) == 0 );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$ok ) { // not present or not empty
$status->fatal( 'backend-fail-opentemp', $tmpPath );
@@ -693,9 +694,9 @@ abstract class FileBackendStore extends FileBackend {
protected function doGetFileContentsMulti( array $params ) {
$contents = array();
foreach ( $this->doGetLocalReferenceMulti( $params ) as $path => $fsFile ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$contents[$path] = $fsFile ? file_get_contents( $fsFile->getPath() ) : false;
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
return $contents;
@@ -1057,7 +1058,7 @@ abstract class FileBackendStore extends FileBackend {
public function getScopedLocksForOps( array $ops, Status $status ) {
$paths = $this->getPathsToLockForOpsInternal( $this->getOperationsInternal( $ops ) );
- return array( $this->getScopedFileLocks( $paths, 'mixed', $status ) );
+ return $this->getScopedFileLocks( $paths, 'mixed', $status );
}
final protected function doOperationsInternal( array $ops, array $opts ) {
@@ -1075,6 +1076,7 @@ abstract class FileBackendStore extends FileBackend {
// Build up a list of files to lock...
$paths = $this->getPathsToLockForOpsInternal( $performOps );
// Try to lock those files for the scope of this function...
+
$scopeLock = $this->getScopedFileLocks( $paths, 'mixed', $status );
if ( !$status->isOK() ) {
return $status; // abort
@@ -1363,19 +1365,38 @@ abstract class FileBackendStore extends FileBackend {
abstract protected function directoriesAreVirtual();
/**
- * Check if a container name is valid.
+ * Check if a short container name is valid
+ *
+ * This checks for length and illegal characters.
+ * This may disallow certain characters that can appear
+ * in the prefix used to make the full container name.
+ *
+ * @param string $container
+ * @return bool
+ */
+ final protected static function isValidShortContainerName( $container ) {
+ // Suffixes like '.xxx' (hex shard chars) or '.seg' (file segments)
+ // might be used by subclasses. Reserve the dot character for sanity.
+ // The only way dots end up in containers (e.g. resolveStoragePath)
+ // is due to the wikiId container prefix or the above suffixes.
+ return self::isValidContainerName( $container ) && !preg_match( '/[.]/', $container );
+ }
+
+ /**
+ * Check if a full container name is valid
+ *
* This checks for length and illegal characters.
+ * Limiting the characters makes migrations to other stores easier.
*
* @param string $container
* @return bool
*/
final protected static function isValidContainerName( $container ) {
- // This accounts for Swift and S3 restrictions while leaving room
- // for things like '.xxx' (hex shard chars) or '.seg' (segments).
- // This disallows directory separators or traversal characters.
+ // This accounts for NTFS, Swift, and Ceph restrictions
+ // and disallows directory separators or traversal characters.
// Note that matching strings URL encode to the same string;
- // in Swift, the length restriction is *after* URL encoding.
- return preg_match( '/^[a-z0-9][a-z0-9-_]{0,199}$/i', $container );
+ // in Swift/Ceph, the length restriction is *after* URL encoding.
+ return (bool)preg_match( '/^[a-z0-9][a-z0-9-_.]{0,199}$/i', $container );
}
/**
@@ -1392,17 +1413,17 @@ abstract class FileBackendStore extends FileBackend {
* @return array (container, path, container suffix) or (null, null, null) if invalid
*/
final protected function resolveStoragePath( $storagePath ) {
- list( $backend, $container, $relPath ) = self::splitStoragePath( $storagePath );
+ list( $backend, $shortCont, $relPath ) = self::splitStoragePath( $storagePath );
if ( $backend === $this->name ) { // must be for this backend
$relPath = self::normalizeContainerPath( $relPath );
- if ( $relPath !== null ) {
+ if ( $relPath !== null && self::isValidShortContainerName( $shortCont ) ) {
// Get shard for the normalized path if this container is sharded
- $cShard = $this->getContainerShard( $container, $relPath );
+ $cShard = $this->getContainerShard( $shortCont, $relPath );
// Validate and sanitize the relative path (backend-specific)
- $relPath = $this->resolveContainerPath( $container, $relPath );
+ $relPath = $this->resolveContainerPath( $shortCont, $relPath );
if ( $relPath !== null ) {
// Prepend any wiki ID prefix to the container name
- $container = $this->fullContainerName( $container );
+ $container = $this->fullContainerName( $shortCont );
if ( self::isValidContainerName( $container ) ) {
// Validate and sanitize the container name (backend-specific)
$container = $this->resolveContainerName( "{$container}{$cShard}" );
@@ -1592,7 +1613,7 @@ abstract class FileBackendStore extends FileBackend {
* @param array $val Information to cache
*/
final protected function setContainerCache( $container, array $val ) {
- $this->memCache->add( $this->containerCacheKey( $container ), $val, 14 * 86400 );
+ $this->memCache->set( $this->containerCacheKey( $container ), $val, 14 * 86400 );
}
/**
@@ -1602,7 +1623,7 @@ abstract class FileBackendStore extends FileBackend {
* @param string $container Resolved container name
*/
final protected function deleteContainerCache( $container ) {
- if ( !$this->memCache->set( $this->containerCacheKey( $container ), 'PURGED', 300 ) ) {
+ if ( !$this->memCache->delete( $this->containerCacheKey( $container ), 300 ) ) {
trigger_error( "Unable to delete stat cache for container $container." );
}
}
@@ -1682,21 +1703,8 @@ abstract class FileBackendStore extends FileBackend {
$age = time() - wfTimestamp( TS_UNIX, $val['mtime'] );
$ttl = min( 7 * 86400, max( 300, floor( .1 * $age ) ) );
$key = $this->fileCacheKey( $path );
- // Set the cache unless it is currently salted with the value "PURGED".
- // Using add() handles this except it also is a no-op in that case where
- // the current value is not "latest" but $val is, so use CAS in that case.
- if ( !$this->memCache->add( $key, $val, $ttl ) && !empty( $val['latest'] ) ) {
- $this->memCache->merge(
- $key,
- function ( BagOStuff $cache, $key, $cValue ) use ( $val ) {
- return ( is_array( $cValue ) && empty( $cValue['latest'] ) )
- ? $val // update the stat cache with the lastest info
- : false; // do nothing (cache is salted or some error happened)
- },
- $ttl,
- 1
- );
- }
+ // Set the cache unless it is currently salted.
+ $this->memCache->set( $key, $val, $ttl );
}
/**
@@ -1712,7 +1720,7 @@ abstract class FileBackendStore extends FileBackend {
if ( $path === null ) {
return; // invalid storage path
}
- if ( !$this->memCache->set( $this->fileCacheKey( $path ), 'PURGED', 300 ) ) {
+ if ( !$this->memCache->delete( $this->fileCacheKey( $path ), 300 ) ) {
trigger_error( "Unable to delete stat cache for file $path." );
}
}
diff --git a/includes/filebackend/FileOp.php b/includes/filebackend/FileOp.php
index 66d87943..5d4e8e11 100644
--- a/includes/filebackend/FileOp.php
+++ b/includes/filebackend/FileOp.php
@@ -577,9 +577,9 @@ class StoreFileOp extends FileOp {
}
protected function getSourceSha1Base36() {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$hash = sha1_file( $this->params['src'] );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $hash !== false ) {
$hash = wfBaseConvert( $hash, 16, 36, 31 );
}
diff --git a/includes/filebackend/MemoryFileBackend.php b/includes/filebackend/MemoryFileBackend.php
index 7c2f8256..2879ddde 100644
--- a/includes/filebackend/MemoryFileBackend.php
+++ b/includes/filebackend/MemoryFileBackend.php
@@ -35,6 +35,10 @@ class MemoryFileBackend extends FileBackendStore {
/** @var array Map of (file path => (data,mtime) */
protected $files = array();
+ public function getFeatures() {
+ return self::ATTR_UNICODE_PATHS;
+ }
+
public function isPathUsableInternal( $storagePath ) {
return true;
}
@@ -67,9 +71,9 @@ class MemoryFileBackend extends FileBackendStore {
return $status;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$data = file_get_contents( $params['src'] );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $data === false ) { // source doesn't exist?
$status->fatal( 'backend-fail-store', $params['src'], $params['dst'] );
diff --git a/includes/filebackend/SwiftFileBackend.php b/includes/filebackend/SwiftFileBackend.php
index 5f406c9b..408194f4 100644
--- a/includes/filebackend/SwiftFileBackend.php
+++ b/includes/filebackend/SwiftFileBackend.php
@@ -128,7 +128,9 @@ class SwiftFileBackend extends FileBackendStore {
// HTTP helper client
$this->http = new MultiHttpClient( array() );
// Cache container information to mask latency
- $this->memCache = wfGetMainCache();
+ if ( isset( $config['wanCache'] ) && $config['wanCache'] instanceof WANObjectCache ) {
+ $this->memCache = $config['wanCache'];
+ }
// Process cache for container info
$this->containerStatCache = new ProcessCacheLRU( 300 );
// Cache auth token information to avoid RTTs
@@ -136,13 +138,12 @@ class SwiftFileBackend extends FileBackendStore {
if ( PHP_SAPI === 'cli' ) {
$this->srvCache = wfGetMainCache(); // preferrably memcached
} else {
- try { // look for APC, XCache, WinCache, ect...
- $this->srvCache = ObjectCache::newAccelerator( array() );
- } catch ( Exception $e ) {
- }
+ // look for APC, XCache, WinCache, ect...
+ $this->srvCache = ObjectCache::newAccelerator( CACHE_NONE );
}
+ } else {
+ $this->srvCache = new EmptyBagOStuff();
}
- $this->srvCache = $this->srvCache ?: new EmptyBagOStuff();
}
public function getFeatures() {
@@ -171,30 +172,40 @@ class SwiftFileBackend extends FileBackendStore {
/**
* Sanitize and filter the custom headers from a $params array.
- * We only allow certain Content- and X-Content- headers.
+ * Only allows certain "standard" Content- and X-Content- headers.
*
* @param array $params
* @return array Sanitized value of 'headers' field in $params
*/
protected function sanitizeHdrs( array $params ) {
+ return isset( $params['headers'] )
+ ? $this->getCustomHeaders( $params['headers'] )
+ : array();
+
+ }
+
+ /**
+ * @param array $rawHeaders
+ * @return array Custom non-metadata HTTP headers
+ */
+ protected function getCustomHeaders( array $rawHeaders ) {
$headers = array();
// Normalize casing, and strip out illegal headers
- if ( isset( $params['headers'] ) ) {
- foreach ( $params['headers'] as $name => $value ) {
- $name = strtolower( $name );
- if ( preg_match( '/^content-(type|length)$/', $name ) ) {
- continue; // blacklisted
- } elseif ( preg_match( '/^(x-)?content-/', $name ) ) {
- $headers[$name] = $value; // allowed
- } elseif ( preg_match( '/^content-(disposition)/', $name ) ) {
- $headers[$name] = $value; // allowed
- }
+ foreach ( $rawHeaders as $name => $value ) {
+ $name = strtolower( $name );
+ if ( preg_match( '/^content-(type|length)$/', $name ) ) {
+ continue; // blacklisted
+ } elseif ( preg_match( '/^(x-)?content-/', $name ) ) {
+ $headers[$name] = $value; // allowed
+ } elseif ( preg_match( '/^content-(disposition)/', $name ) ) {
+ $headers[$name] = $value; // allowed
}
}
// By default, Swift has annoyingly low maximum header value limits
if ( isset( $headers['content-disposition'] ) ) {
$disposition = '';
+ // @note: assume FileBackend::makeContentDisposition() already used
foreach ( explode( ';', $headers['content-disposition'] ) as $part ) {
$part = trim( $part );
$new = ( $disposition === '' ) ? $part : "{$disposition};{$part}";
@@ -210,6 +221,35 @@ class SwiftFileBackend extends FileBackendStore {
return $headers;
}
+ /**
+ * @param array $rawHeaders
+ * @return array Custom metadata headers
+ */
+ protected function getMetadataHeaders( array $rawHeaders ) {
+ $headers = array();
+ foreach ( $rawHeaders as $name => $value ) {
+ $name = strtolower( $name );
+ if ( strpos( $name, 'x-object-meta-' ) === 0 ) {
+ $headers[$name] = $value;
+ }
+ }
+
+ return $headers;
+ }
+
+ /**
+ * @param array $rawHeaders
+ * @return array Custom metadata headers with prefix removed
+ */
+ protected function getMetadata( array $rawHeaders ) {
+ $metadata = array();
+ foreach ( $this->getMetadataHeaders( $rawHeaders ) as $name => $value ) {
+ $metadata[substr( $name, strlen( 'x-object-meta-' ) )] = $value;
+ }
+
+ return $metadata;
+ }
+
protected function doCreateInternal( array $params ) {
$status = Status::newGood();
@@ -235,16 +275,16 @@ class SwiftFileBackend extends FileBackendStore {
'body' => $params['content']
) );
- $be = $this;
+ $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
} elseif ( $rcode === 412 ) {
$status->fatal( 'backend-fail-contenttype', $params['dst'] );
} else {
- $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
@@ -268,9 +308,9 @@ class SwiftFileBackend extends FileBackendStore {
return $status;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$sha1Hash = sha1_file( $params['src'] );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $sha1Hash === false ) { // source doesn't exist?
$status->fatal( 'backend-fail-store', $params['src'], $params['dst'] );
@@ -298,16 +338,16 @@ class SwiftFileBackend extends FileBackendStore {
'body' => $handle // resource
) );
- $be = $this;
+ $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
} elseif ( $rcode === 412 ) {
$status->fatal( 'backend-fail-contenttype', $params['dst'] );
} else {
- $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
@@ -347,16 +387,16 @@ class SwiftFileBackend extends FileBackendStore {
) + $this->sanitizeHdrs( $params ), // extra headers merged into object
) );
- $be = $this;
+ $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
} elseif ( $rcode === 404 ) {
$status->fatal( 'backend-fail-copy', $params['src'], $params['dst'] );
} else {
- $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
@@ -405,9 +445,9 @@ class SwiftFileBackend extends FileBackendStore {
);
}
- $be = $this;
+ $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $request['method'] === 'PUT' && $rcode === 201 ) {
// good
@@ -416,7 +456,7 @@ class SwiftFileBackend extends FileBackendStore {
} elseif ( $rcode === 404 ) {
$status->fatal( 'backend-fail-move', $params['src'], $params['dst'] );
} else {
- $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
@@ -446,9 +486,9 @@ class SwiftFileBackend extends FileBackendStore {
'headers' => array()
) );
- $be = $this;
+ $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 204 ) {
// good
@@ -457,7 +497,7 @@ class SwiftFileBackend extends FileBackendStore {
$status->fatal( 'backend-fail-delete', $params['src'] );
}
} else {
- $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
@@ -505,16 +545,16 @@ class SwiftFileBackend extends FileBackendStore {
'headers' => $metaHdrs + $customHdrs
) );
- $be = $this;
+ $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $be, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 202 ) {
// good
} elseif ( $rcode === 404 ) {
$status->fatal( 'backend-fail-describe', $params['src'] );
} else {
- $be->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
@@ -664,17 +704,24 @@ class SwiftFileBackend extends FileBackendStore {
return $objHdrs; // nothing to do
}
+ /** @noinspection PhpUnusedLocalVariableInspection */
$ps = Profiler::instance()->scopedProfileIn( __METHOD__ . "-{$this->name}" );
- trigger_error( "$path was not stored with SHA-1 metadata.", E_USER_WARNING );
+ wfDebugLog( 'SwiftBackend', __METHOD__ . ": $path was not stored with SHA-1 metadata." );
+
+ $objHdrs['x-object-meta-sha1base36'] = false;
$auth = $this->getAuthentication();
if ( !$auth ) {
- $objHdrs['x-object-meta-sha1base36'] = false;
-
return $objHdrs; // failed
}
+ // Find prior custom HTTP headers
+ $postHeaders = $this->getCustomHeaders( $objHdrs );
+ // Find prior metadata headers
+ $postHeaders += $this->getMetadataHeaders( $objHdrs );
+
$status = Status::newGood();
+ /** @noinspection PhpUnusedLocalVariableInspection */
$scopeLockS = $this->getScopedFileLocks( array( $path ), LockManager::LOCK_UW, $status );
if ( $status->isOK() ) {
$tmpFile = $this->getLocalCopy( array( 'src' => $path, 'latest' => 1 ) );
@@ -682,20 +729,24 @@ class SwiftFileBackend extends FileBackendStore {
$hash = $tmpFile->getSha1Base36();
if ( $hash !== false ) {
$objHdrs['x-object-meta-sha1base36'] = $hash;
+ // Merge new SHA1 header into the old ones
+ $postHeaders['x-object-meta-sha1base36'] = $hash;
list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $path );
- list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $this->http->run( array(
+ list( $rcode ) = $this->http->run( array(
'method' => 'POST',
'url' => $this->storageUrl( $auth, $srcCont, $srcRel ),
- 'headers' => $this->authTokenHeaders( $auth ) + $objHdrs
+ 'headers' => $this->authTokenHeaders( $auth ) + $postHeaders
) );
if ( $rcode >= 200 && $rcode <= 299 ) {
+ $this->deleteFileCache( $path );
+
return $objHdrs; // success
}
}
}
}
- trigger_error( "Unable to set SHA-1 metadata for $path", E_USER_WARNING );
- $objHdrs['x-object-meta-sha1base36'] = false;
+
+ wfDebugLog( 'SwiftBackend', __METHOD__ . ": unable to set SHA-1 metadata for $path" );
return $objHdrs; // failed
}
@@ -1544,22 +1595,16 @@ class SwiftFileBackend extends FileBackendStore {
*/
protected function getStatFromHeaders( array $rhdrs ) {
// Fetch all of the custom metadata headers
- $metadata = array();
- foreach ( $rhdrs as $name => $value ) {
- if ( strpos( $name, 'x-object-meta-' ) === 0 ) {
- $metadata[substr( $name, strlen( 'x-object-meta-' ) )] = $value;
- }
- }
+ $metadata = $this->getMetadata( $rhdrs );
// Fetch all of the custom raw HTTP headers
$headers = $this->sanitizeHdrs( array( 'headers' => $rhdrs ) );
+
return array(
// Convert various random Swift dates to TS_MW
'mtime' => $this->convertSwiftDate( $rhdrs['last-modified'], TS_MW ),
// Empty objects actually return no content-length header in Ceph
'size' => isset( $rhdrs['content-length'] ) ? (int)$rhdrs['content-length'] : 0,
- 'sha1' => isset( $rhdrs['x-object-meta-sha1base36'] )
- ? $rhdrs['x-object-meta-sha1base36']
- : null,
+ 'sha1' => isset( $metadata['sha1base36'] ) ? $metadata['sha1base36'] : null,
// Note: manifiest ETags are not an MD5 of the file
'md5' => ctype_xdigit( $rhdrs['etag'] ) ? $rhdrs['etag'] : null,
'xattr' => array( 'metadata' => $metadata, 'headers' => $headers )
diff --git a/includes/filebackend/TempFSFile.php b/includes/filebackend/TempFSFile.php
index 791be7fc..46b53600 100644
--- a/includes/filebackend/TempFSFile.php
+++ b/includes/filebackend/TempFSFile.php
@@ -59,15 +59,14 @@ class TempFSFile extends FSFile {
$ext = ( $extension != '' ) ? ".{$extension}" : "";
for ( $attempt = 1; true; $attempt++ ) {
$path = "{$base}-{$attempt}{$ext}";
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$newFileHandle = fopen( $path, 'x' );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $newFileHandle ) {
fclose( $newFileHandle );
break; // got it
}
if ( $attempt >= 5 ) {
-
return null; // give up
}
}
@@ -84,9 +83,9 @@ class TempFSFile extends FSFile {
*/
public function purge() {
$this->canDelete = false; // done
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = unlink( $this->path );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
unset( self::$pathsCollect[$this->path] );
@@ -96,7 +95,7 @@ class TempFSFile extends FSFile {
/**
* Clean up the temporary file only after an object goes out of scope
*
- * @param stdClass $object
+ * @param object $object
* @return TempFSFile This object
*/
public function bind( $object ) {
@@ -144,9 +143,9 @@ class TempFSFile extends FSFile {
*/
public static function purgeAllOnShutdown() {
foreach ( self::$pathsCollect as $path ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
unlink( $path );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
}
diff --git a/includes/filebackend/lockmanager/DBLockManager.php b/includes/filebackend/lockmanager/DBLockManager.php
index 39a55635..b81cf3e4 100644
--- a/includes/filebackend/lockmanager/DBLockManager.php
+++ b/includes/filebackend/lockmanager/DBLockManager.php
@@ -96,7 +96,7 @@ abstract class DBLockManager extends QuorumLockManager {
// Tracks peers that couldn't be queried recently to avoid lengthy
// connection timeouts. This is useless if each bucket has one peer.
try {
- $this->statusCache = ObjectCache::newAccelerator( array() );
+ $this->statusCache = ObjectCache::newAccelerator();
} catch ( Exception $e ) {
trigger_error( __CLASS__ .
" using multiple DB peers without apc, xcache, or wincache." );
diff --git a/includes/filebackend/lockmanager/FSLockManager.php b/includes/filebackend/lockmanager/FSLockManager.php
index bce6b34c..6f46f0e4 100644
--- a/includes/filebackend/lockmanager/FSLockManager.php
+++ b/includes/filebackend/lockmanager/FSLockManager.php
@@ -117,9 +117,9 @@ class FSLockManager extends LockManager {
if ( isset( $this->handles[$path] ) ) {
$handle = $this->handles[$path];
} else {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$handle = fopen( $this->getLockPath( $path ), 'a+' );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$handle ) { // lock dir missing?
wfMkdirParents( $this->lockDir );
$handle = fopen( $this->getLockPath( $path ), 'a+' ); // try again
diff --git a/includes/filebackend/lockmanager/LockManager.php b/includes/filebackend/lockmanager/LockManager.php
index 615ba77e..8115fd42 100644
--- a/includes/filebackend/lockmanager/LockManager.php
+++ b/includes/filebackend/lockmanager/LockManager.php
@@ -102,7 +102,6 @@ abstract class LockManager {
* @since 1.22
*/
final public function lockByType( array $pathsByType, $timeout = 0 ) {
- $status = Status::newGood();
$pathsByType = $this->normalizePathsByType( $pathsByType );
$msleep = array( 0, 50, 100, 300, 500 ); // retry backoff times
$start = microtime( true );
diff --git a/includes/filerepo/FileBackendDBRepoWrapper.php b/includes/filerepo/FileBackendDBRepoWrapper.php
new file mode 100644
index 00000000..c83e5b1b
--- /dev/null
+++ b/includes/filerepo/FileBackendDBRepoWrapper.php
@@ -0,0 +1,356 @@
+<?php
+/**
+ * Proxy backend that manages file layout rewriting for FileRepo.
+ *
+ * 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 FileRepo
+ * @ingroup FileBackend
+ * @author Aaron Schulz
+ */
+
+/**
+ * @brief Proxy backend that manages file layout rewriting for FileRepo.
+ *
+ * LocalRepo may be configured to store files under their title names or by SHA-1.
+ * This acts as a shim in the later case, providing backwards compatability for
+ * most callers. All "public"/"deleted" zone files actually go in an "original"
+ * container and are never changed.
+ *
+ * This requires something like thumb_handler.php and img_auth.php for client viewing of files.
+ *
+ * @ingroup FileRepo
+ * @ingroup FileBackend
+ * @since 1.25
+ */
+class FileBackendDBRepoWrapper extends FileBackend {
+ /** @var FileBackend */
+ protected $backend;
+ /** @var string */
+ protected $repoName;
+ /** @var Closure */
+ protected $dbHandleFunc;
+ /** @var ProcessCacheLRU */
+ protected $resolvedPathCache;
+ /** @var DBConnRef[] */
+ protected $dbs;
+
+ public function __construct( array $config ) {
+ $config['name'] = $config['backend']->getName();
+ $config['wikiId'] = $config['backend']->getWikiId();
+ parent::__construct( $config );
+ $this->backend = $config['backend'];
+ $this->repoName = $config['repoName'];
+ $this->dbHandleFunc = $config['dbHandleFactory'];
+ $this->resolvedPathCache = new ProcessCacheLRU( 100 );
+ }
+
+ /**
+ * Get the underlying FileBackend that is being wrapped
+ *
+ * @return FileBackend
+ */
+ public function getInternalBackend() {
+ return $this->backend;
+ }
+
+ /**
+ * Translate a legacy "title" path to it's "sha1" counterpart
+ *
+ * E.g. mwstore://local-backend/local-public/a/ab/<name>.jpg
+ * => mwstore://local-backend/local-original/x/y/z/<sha1>.jpg
+ *
+ * @param string $path
+ * @param bool $latest
+ * @return string
+ */
+ public function getBackendPath( $path, $latest = true ) {
+ $paths = $this->getBackendPaths( array( $path ), $latest );
+ return current( $paths );
+ }
+
+ /**
+ * Translate legacy "title" paths to their "sha1" counterparts
+ *
+ * E.g. mwstore://local-backend/local-public/a/ab/<name>.jpg
+ * => mwstore://local-backend/local-original/x/y/z/<sha1>.jpg
+ *
+ * @param array $paths
+ * @param bool $latest
+ * @return array Translated paths in same order
+ */
+ public function getBackendPaths( array $paths, $latest = true ) {
+ $db = $this->getDB( $latest ? DB_MASTER : DB_SLAVE );
+
+ // @TODO: batching
+ $resolved = array();
+ foreach ( $paths as $i => $path ) {
+ if ( !$latest && $this->resolvedPathCache->has( $path, 'target', 10 ) ) {
+ $resolved[$i] = $this->resolvedPathCache->get( $path, 'target' );
+ continue;
+ }
+
+ list( , $container ) = FileBackend::splitStoragePath( $path );
+
+ if ( $container === "{$this->repoName}-public" ) {
+ $name = basename( $path );
+ if ( strpos( $path, '!' ) !== false ) {
+ $sha1 = $db->selectField( 'oldimage', 'oi_sha1',
+ array( 'oi_archive_name' => $name ),
+ __METHOD__
+ );
+ } else {
+ $sha1 = $db->selectField( 'image', 'img_sha1',
+ array( 'img_name' => $name ),
+ __METHOD__
+ );
+ }
+ if ( !strlen( $sha1 ) ) {
+ $resolved[$i] = $path; // give up
+ continue;
+ }
+ $resolved[$i] = $this->getPathForSHA1( $sha1 );
+ $this->resolvedPathCache->set( $path, 'target', $resolved[$i] );
+ } elseif ( $container === "{$this->repoName}-deleted" ) {
+ $name = basename( $path ); // <hash>.<ext>
+ $sha1 = substr( $name, 0, strpos( $name, '.' ) ); // ignore extension
+ $resolved[$i] = $this->getPathForSHA1( $sha1 );
+ $this->resolvedPathCache->set( $path, 'target', $resolved[$i] );
+ } else {
+ $resolved[$i] = $path;
+ }
+ }
+
+ $res = array();
+ foreach ( $paths as $i => $path ) {
+ $res[$i] = $resolved[$i];
+ }
+
+ return $res;
+ }
+
+ protected function doOperationsInternal( array $ops, array $opts ) {
+ return $this->backend->doOperationsInternal( $this->mungeOpPaths( $ops ), $opts );
+ }
+
+ protected function doQuickOperationsInternal( array $ops ) {
+ return $this->backend->doQuickOperationsInternal( $this->mungeOpPaths( $ops ) );
+ }
+
+ protected function doPrepare( array $params ) {
+ return $this->backend->doPrepare( $params );
+ }
+
+ protected function doSecure( array $params ) {
+ return $this->backend->doSecure( $params );
+ }
+
+ protected function doPublish( array $params ) {
+ return $this->backend->doPublish( $params );
+ }
+
+ protected function doClean( array $params ) {
+ return $this->backend->doClean( $params );
+ }
+
+ public function concatenate( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function fileExists( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function getFileTimestamp( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function getFileSize( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function getFileStat( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function getFileXAttributes( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function getFileSha1Base36( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function getFileProps( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function streamFile( array $params ) {
+ // The stream methods use the file extension to determine the
+ // Content-Type (as MediaWiki should already validate it on upload).
+ // The translated SHA1 path has no extension, so this needs to use
+ // the untranslated path extension.
+ $type = StreamFile::contentTypeFromPath( $params['src'] );
+ if ( $type && $type != 'unknown/unknown' ) {
+ $params['headers'][] = "Content-type: $type";
+ }
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function getFileContentsMulti( array $params ) {
+ return $this->translateArrayResults( __FUNCTION__, $params );
+ }
+
+ public function getLocalReferenceMulti( array $params ) {
+ return $this->translateArrayResults( __FUNCTION__, $params );
+ }
+
+ public function getLocalCopyMulti( array $params ) {
+ return $this->translateArrayResults( __FUNCTION__, $params );
+ }
+
+ public function getFileHttpUrl( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function directoryExists( array $params ) {
+ return $this->backend->directoryExists( $params );
+ }
+
+ public function getDirectoryList( array $params ) {
+ return $this->backend->getDirectoryList( $params );
+ }
+
+ public function getFileList( array $params ) {
+ return $this->backend->getFileList( $params );
+ }
+
+ public function getFeatures() {
+ return $this->backend->getFeatures();
+ }
+
+ public function clearCache( array $paths = null ) {
+ $this->backend->clearCache( null ); // clear all
+ }
+
+ public function preloadCache( array $paths ) {
+ $paths = $this->getBackendPaths( $paths );
+ $this->backend->preloadCache( $paths );
+ }
+
+ public function preloadFileStat( array $params ) {
+ return $this->translateSrcParams( __FUNCTION__, $params );
+ }
+
+ public function getScopedLocksForOps( array $ops, Status $status ) {
+ return $this->backend->getScopedLocksForOps( $ops, $status );
+ }
+
+ /**
+ * Get the ultimate original storage path for a file
+ *
+ * Use this when putting a new file into the system
+ *
+ * @param string $sha1 File SHA-1 base36
+ * @return string
+ */
+ public function getPathForSHA1( $sha1 ) {
+ if ( strlen( $sha1 ) < 3 ) {
+ throw new InvalidArgumentException( "Invalid file SHA-1." );
+ }
+ return $this->backend->getContainerStoragePath( "{$this->repoName}-original" ) .
+ "/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
+ }
+
+ /**
+ * Get a connection to the repo file registry DB
+ *
+ * @param integer $index
+ * @return DBConnRef
+ */
+ protected function getDB( $index ) {
+ if ( !isset( $this->dbs[$index] ) ) {
+ $func = $this->dbHandleFunc;
+ $this->dbs[$index] = $func( $index );
+ }
+ return $this->dbs[$index];
+ }
+
+ /**
+ * Translates paths found in the "src" or "srcs" keys of a params array
+ *
+ * @param string $function
+ * @param array $params
+ */
+ protected function translateSrcParams( $function, array $params ) {
+ $latest = !empty( $params['latest'] );
+
+ if ( isset( $params['src'] ) ) {
+ $params['src'] = $this->getBackendPath( $params['src'], $latest );
+ }
+
+ if ( isset( $params['srcs'] ) ) {
+ $params['srcs'] = $this->getBackendPaths( $params['srcs'], $latest );
+ }
+
+ return $this->backend->$function( $params );
+ }
+
+ /**
+ * Translates paths when the backend function returns results keyed by paths
+ *
+ * @param string $function
+ * @param array $params
+ * @return array
+ */
+ protected function translateArrayResults( $function, array $params ) {
+ $origPaths = $params['srcs'];
+ $params['srcs'] = $this->getBackendPaths( $params['srcs'], !empty( $params['latest'] ) );
+ $pathMap = array_combine( $params['srcs'], $origPaths );
+
+ $results = $this->backend->$function( $params );
+
+ $contents = array();
+ foreach ( $results as $path => $result ) {
+ $contents[$pathMap[$path]] = $result;
+ }
+
+ return $contents;
+ }
+
+ /**
+ * Translate legacy "title" source paths to their "sha1" counterparts
+ *
+ * This leaves destination paths alone since we don't want those to mutate
+ *
+ * @param array $ops
+ * @return array
+ */
+ protected function mungeOpPaths( array $ops ) {
+ // Ops that use 'src' and do not mutate core file data there
+ static $srcRefOps = array( 'store', 'copy', 'describe' );
+ foreach ( $ops as &$op ) {
+ if ( isset( $op['src'] ) && in_array( $op['op'], $srcRefOps ) ) {
+ $op['src'] = $this->getBackendPath( $op['src'], true );
+ }
+ if ( isset( $op['srcs'] ) ) {
+ $op['srcs'] = $this->getBackendPaths( $op['srcs'], true );
+ }
+ }
+ return $ops;
+ }
+}
diff --git a/includes/filerepo/FileRepo.php b/includes/filerepo/FileRepo.php
index cef1176d..7370c5cd 100644
--- a/includes/filerepo/FileRepo.php
+++ b/includes/filerepo/FileRepo.php
@@ -49,6 +49,9 @@ class FileRepo {
/** @var int */
public $descriptionCacheExpiry;
+ /** @var bool */
+ protected $hasSha1Storage = false;
+
/** @var FileBackend */
protected $backend;
@@ -63,7 +66,7 @@ class FileRepo {
protected $transformVia404;
/** @var string URL of image description pages, e.g.
- * http://en.wikipedia.org/wiki/File:
+ * https://en.wikipedia.org/wiki/File:
*/
protected $descBaseUrl;
@@ -76,7 +79,7 @@ class FileRepo {
* to $wgScriptExtension, e.g. .php5 defaults to .php */
protected $scriptExtension;
- /** @var string Equivalent to $wgArticlePath, e.g. http://en.wikipedia.org/wiki/$1 */
+ /** @var string Equivalent to $wgArticlePath, e.g. https://en.wikipedia.org/wiki/$1 */
protected $articleUrl;
/** @var bool Equivalent to $wgCapitalLinks (or $wgCapitalLinkOverrides[NS_FILE],
@@ -433,16 +436,16 @@ class FileRepo {
$img = $this->newFile( $title, $time );
if ( $img ) {
$img->load( $flags );
- }
- if ( $img && $img->exists() ) {
- if ( !$img->isDeleted( File::DELETED_FILE ) ) {
- return $img; // always OK
- } elseif ( !empty( $options['private'] ) &&
- $img->userCan( File::DELETED_FILE,
- $options['private'] instanceof User ? $options['private'] : null
- )
- ) {
- return $img;
+ if ( $img->exists() ) {
+ if ( !$img->isDeleted( File::DELETED_FILE ) ) {
+ return $img; // always OK
+ } elseif ( !empty( $options['private'] ) &&
+ $img->userCan( File::DELETED_FILE,
+ $options['private'] instanceof User ? $options['private'] : null
+ )
+ ) {
+ return $img;
+ }
}
}
}
@@ -909,9 +912,9 @@ class FileRepo {
$status->merge( $backend->doOperations( $operations, $opts ) );
// Cleanup for disk source files...
foreach ( $sourceFSFilesToDelete as $file ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
unlink( $file ); // FS cleanup
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
return $status;
@@ -1297,9 +1300,9 @@ class FileRepo {
}
// Cleanup for disk source files...
foreach ( $sourceFSFilesToDelete as $file ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
unlink( $file ); // FS cleanup
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
return $status;
@@ -1885,6 +1888,14 @@ class FileRepo {
return $ret;
}
+
+ /**
+ * Returns whether or not storage is SHA-1 based
+ * @return boolean
+ */
+ public function hasSha1Storage() {
+ return $this->hasSha1Storage;
+ }
}
/**
diff --git a/includes/filerepo/ForeignAPIRepo.php b/includes/filerepo/ForeignAPIRepo.php
index 71d2b919..4ffbf4ad 100644
--- a/includes/filerepo/ForeignAPIRepo.php
+++ b/includes/filerepo/ForeignAPIRepo.php
@@ -31,7 +31,7 @@ use MediaWiki\Logger\LoggerFactory;
* $wgForeignFileRepos[] = array(
* 'class' => 'ForeignAPIRepo',
* 'name' => 'shared',
- * 'apibase' => 'http://en.wikipedia.org/w/api.php',
+ * 'apibase' => 'https://en.wikipedia.org/w/api.php',
* 'fetchDescription' => true, // Optional
* 'descriptionCacheExpiry' => 3600,
* );
@@ -74,7 +74,7 @@ class ForeignAPIRepo extends FileRepo {
global $wgLocalFileRepo;
parent::__construct( $info );
- // http://commons.wikimedia.org/w/api.php
+ // https://commons.wikimedia.org/w/api.php
$this->mApiBase = isset( $info['apibase'] ) ? $info['apibase'] : null;
if ( isset( $info['apiThumbCacheExpiry'] ) ) {
diff --git a/includes/filerepo/ForeignDBRepo.php b/includes/filerepo/ForeignDBRepo.php
index 6e9e6add..dfdb3753 100644
--- a/includes/filerepo/ForeignDBRepo.php
+++ b/includes/filerepo/ForeignDBRepo.php
@@ -76,17 +76,8 @@ class ForeignDBRepo extends LocalRepo {
*/
function getMasterDB() {
if ( !isset( $this->dbConn ) ) {
- $this->dbConn = DatabaseBase::factory( $this->dbType,
- array(
- 'host' => $this->dbServer,
- 'user' => $this->dbUser,
- 'password' => $this->dbPassword,
- 'dbname' => $this->dbName,
- 'flags' => $this->dbFlags,
- 'tablePrefix' => $this->tablePrefix,
- 'foreign' => true,
- )
- );
+ $func = $this->getDBFactory();
+ $this->dbConn = $func( DB_MASTER );
}
return $this->dbConn;
@@ -100,6 +91,25 @@ class ForeignDBRepo extends LocalRepo {
}
/**
+ * @return Closure
+ */
+ protected function getDBFactory() {
+ return function( $index ) {
+ return DatabaseBase::factory( $this->dbType,
+ array(
+ 'host' => $this->dbServer,
+ 'user' => $this->dbUser,
+ 'password' => $this->dbPassword,
+ 'dbname' => $this->dbName,
+ 'flags' => $this->dbFlags,
+ 'tablePrefix' => $this->tablePrefix,
+ 'foreign' => true,
+ )
+ );
+ };
+ }
+
+ /**
* @return bool
*/
function hasSharedCache() {
diff --git a/includes/filerepo/ForeignDBViaLBRepo.php b/includes/filerepo/ForeignDBViaLBRepo.php
index 8153ffb4..f49b716f 100644
--- a/includes/filerepo/ForeignDBViaLBRepo.php
+++ b/includes/filerepo/ForeignDBViaLBRepo.php
@@ -66,6 +66,16 @@ class ForeignDBViaLBRepo extends LocalRepo {
return wfGetDB( DB_SLAVE, array(), $this->wiki );
}
+ /**
+ * @return Closure
+ */
+ protected function getDBFactory() {
+ $wiki = $this->wiki;
+ return function( $index ) use ( $wiki ) {
+ return wfGetDB( $index, array(), $wiki );
+ };
+ }
+
function hasSharedCache() {
return $this->hasSharedCache;
}
diff --git a/includes/filerepo/LocalRepo.php b/includes/filerepo/LocalRepo.php
index 926fd0b8..6a2c0640 100644
--- a/includes/filerepo/LocalRepo.php
+++ b/includes/filerepo/LocalRepo.php
@@ -29,6 +29,9 @@
* @ingroup FileRepo
*/
class LocalRepo extends FileRepo {
+ /** @var bool */
+ protected $hasSha1Storage = false;
+
/** @var array */
protected $fileFactory = array( 'LocalFile', 'newFromTitle' );
@@ -47,6 +50,20 @@ class LocalRepo extends FileRepo {
/** @var array */
protected $oldFileFactoryKey = array( 'OldLocalFile', 'newFromKey' );
+ function __construct( array $info = null ) {
+ parent::__construct( $info );
+
+ $this->hasSha1Storage = isset( $info['storageLayout'] ) && $info['storageLayout'] === 'sha1';
+
+ if ( $this->hasSha1Storage() ) {
+ $this->backend = new FileBackendDBRepoWrapper( array(
+ 'backend' => $this->backend,
+ 'repoName' => $this->name,
+ 'dbHandleFactory' => $this->getDBFactory()
+ ) );
+ }
+ }
+
/**
* @throws MWException
* @param stdClass $row
@@ -82,6 +99,11 @@ class LocalRepo extends FileRepo {
* @return FileRepoStatus
*/
function cleanupDeletedBatch( array $storageKeys ) {
+ if ( $this->hasSha1Storage() ) {
+ wfDebug( __METHOD__ . ": skipped because storage uses sha1 paths\n" );
+ return Status::newGood();
+ }
+
$backend = $this->backend; // convenience
$root = $this->getZonePath( 'deleted' );
$dbw = $this->getMasterDB();
@@ -90,7 +112,7 @@ class LocalRepo extends FileRepo {
foreach ( $storageKeys as $key ) {
$hashPath = $this->getDeletedHashPath( $key );
$path = "$root/$hashPath$key";
- $dbw->begin( __METHOD__ );
+ $dbw->startAtomic( __METHOD__ );
// Check for usage in deleted/hidden files and preemptively
// lock the key to avoid any future use until we are finished.
$deleted = $this->deletedFileHasKey( $key, 'lock' );
@@ -106,7 +128,7 @@ class LocalRepo extends FileRepo {
wfDebug( __METHOD__ . ": $key still in use\n" );
$status->successCount++;
}
- $dbw->commit( __METHOD__ );
+ $dbw->endAtomic( __METHOD__ );
}
return $status;
@@ -170,7 +192,7 @@ class LocalRepo extends FileRepo {
* @return bool|Title
*/
function checkRedirect( Title $title ) {
- global $wgMemc;
+ $cache = ObjectCache::getMainWANInstance();
$title = File::normalizeTitle( $title, 'exception' );
@@ -181,7 +203,7 @@ class LocalRepo extends FileRepo {
} else {
$expiry = 86400; // has invalidation, 1 day
}
- $cachedValue = $wgMemc->get( $memcKey );
+ $cachedValue = $cache->get( $memcKey );
if ( $cachedValue === ' ' || $cachedValue === '' ) {
// Does not exist
return false;
@@ -191,7 +213,7 @@ class LocalRepo extends FileRepo {
$id = $this->getArticleID( $title );
if ( !$id ) {
- $wgMemc->add( $memcKey, " ", $expiry );
+ $cache->set( $memcKey, " ", $expiry );
return false;
}
@@ -205,11 +227,11 @@ class LocalRepo extends FileRepo {
if ( $row && $row->rd_namespace == NS_FILE ) {
$targetTitle = Title::makeTitle( $row->rd_namespace, $row->rd_title );
- $wgMemc->add( $memcKey, $targetTitle->getDBkey(), $expiry );
+ $cache->set( $memcKey, $targetTitle->getDBkey(), $expiry );
return $targetTitle;
} else {
- $wgMemc->add( $memcKey, '', $expiry );
+ $cache->set( $memcKey, '', $expiry );
return false;
}
@@ -275,17 +297,17 @@ class LocalRepo extends FileRepo {
);
};
- $repo = $this;
+ $that = $this;
$applyMatchingFiles = function ( ResultWrapper $res, &$searchSet, &$finalFiles )
- use ( $repo, $fileMatchesSearch, $flags )
+ use ( $that, $fileMatchesSearch, $flags )
{
global $wgContLang;
- $info = $repo->getInfo();
+ $info = $that->getInfo();
foreach ( $res as $row ) {
- $file = $repo->newFileFromRow( $row );
+ $file = $that->newFileFromRow( $row );
// There must have been a search for this DB key, but this has to handle the
// cases were title capitalization is different on the client and repo wikis.
- $dbKeysLook = array( str_replace( ' ', '_', $file->getName() ) );
+ $dbKeysLook = array( strtr( $file->getName(), ' ', '_' ) );
if ( !empty( $info['initialCapital'] ) ) {
// Search keys for "hi.png" and "Hi.png" should use the "Hi.png file"
$dbKeysLook[] = $wgContLang->lcfirst( $file->getName() );
@@ -470,6 +492,16 @@ class LocalRepo extends FileRepo {
}
/**
+ * Get a callback to get a DB handle given an index (DB_SLAVE/DB_MASTER)
+ * @return Closure
+ */
+ protected function getDBFactory() {
+ return function( $index ) {
+ return wfGetDB( $index );
+ };
+ }
+
+ /**
* Get a key on the primary cache for this repository.
* Returns false if the repository's cache is not accessible at this site.
* The parameters are the parts of the key, as for wfMemcKey().
@@ -489,14 +521,15 @@ class LocalRepo extends FileRepo {
* @return void
*/
function invalidateImageRedirect( Title $title ) {
- global $wgMemc;
+ $cache = ObjectCache::getMainWANInstance();
+
$memcKey = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
if ( $memcKey ) {
// Set a temporary value for the cache key, to ensure
// that this value stays purged long enough so that
// it isn't refreshed with a stale value due to a
// lagged slave.
- $wgMemc->set( $memcKey, ' PURGED', 12 );
+ $cache->delete( $memcKey, 12 );
}
}
@@ -513,4 +546,56 @@ class LocalRepo extends FileRepo {
'favicon' => wfExpandUrl( $wgFavicon ),
) );
}
+
+ public function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) {
+ return $this->skipWriteOperationIfSha1( __FUNCTION__, func_get_args() );
+ }
+
+ public function storeBatch( array $triplets, $flags = 0 ) {
+ return $this->skipWriteOperationIfSha1( __FUNCTION__, func_get_args() );
+ }
+
+ public function cleanupBatch( array $files, $flags = 0 ) {
+ return $this->skipWriteOperationIfSha1( __FUNCTION__, func_get_args() );
+ }
+
+ public function publish(
+ $srcPath,
+ $dstRel,
+ $archiveRel,
+ $flags = 0,
+ array $options = array()
+ ) {
+ return $this->skipWriteOperationIfSha1( __FUNCTION__, func_get_args() );
+ }
+
+ public function publishBatch( array $ntuples, $flags = 0 ) {
+ return $this->skipWriteOperationIfSha1( __FUNCTION__, func_get_args() );
+ }
+
+ public function delete( $srcRel, $archiveRel ) {
+ return $this->skipWriteOperationIfSha1( __FUNCTION__, func_get_args() );
+ }
+
+ public function deleteBatch( array $sourceDestPairs ) {
+ return $this->skipWriteOperationIfSha1( __FUNCTION__, func_get_args() );
+ }
+
+ /**
+ * Skips the write operation if storage is sha1-based, executes it normally otherwise
+ *
+ * @param string $function
+ * @param array $args
+ * @return FileRepoStatus
+ */
+ protected function skipWriteOperationIfSha1( $function, array $args ) {
+ $this->assertWritableRepo(); // fail out if read-only
+
+ if ( $this->hasSha1Storage() ) {
+ wfDebug( __METHOD__ . ": skipped because storage uses sha1 paths\n" );
+ return Status::newGood();
+ } else {
+ return call_user_func_array( 'parent::' . $function, $args );
+ }
+ }
}
diff --git a/includes/filerepo/file/ArchivedFile.php b/includes/filerepo/file/ArchivedFile.php
index 1d454283..1aec4464 100644
--- a/includes/filerepo/file/ArchivedFile.php
+++ b/includes/filerepo/file/ArchivedFile.php
@@ -485,7 +485,7 @@ class ArchivedFile {
if ( $type == 'text' ) {
return $this->user_text;
} elseif ( $type == 'id' ) {
- return $this->user;
+ return (int)$this->user;
}
throw new MWException( "Unknown type '$type'." );
@@ -587,6 +587,6 @@ class ArchivedFile {
$this->load();
$title = $this->getTitle();
- return Revision::userCanBitfield( $this->deleted, $field, $user, $title ? : null );
+ return Revision::userCanBitfield( $this->deleted, $field, $user, $title ?: null );
}
}
diff --git a/includes/filerepo/file/File.php b/includes/filerepo/file/File.php
index 6edd6fcc..f40d216c 100644
--- a/includes/filerepo/file/File.php
+++ b/includes/filerepo/file/File.php
@@ -163,7 +163,8 @@ abstract class File implements IDBAccessObject {
* @param FileRepo|bool $repo
*/
function __construct( $title, $repo ) {
- if ( $title !== false ) { // subclasses may not use MW titles
+ // Some subclasses do not use $title, but set name/title some other way
+ if ( $title !== false ) {
$title = self::normalizeTitle( $title, 'exception' );
}
$this->title = $title;
@@ -212,14 +213,15 @@ abstract class File implements IDBAccessObject {
}
/**
- * Normalize a file extension to the common form, and ensure it's clean.
- * Extensions with non-alphanumeric characters will be discarded.
+ * Normalize a file extension to the common form, making it lowercase and checking some synonyms,
+ * and ensure it's clean. Extensions with non-alphanumeric characters will be discarded.
+ * Keep in sync with mw.Title.normalizeExtension() in JS.
*
- * @param string $ext (without the .)
- * @return string
+ * @param string $extension File extension (without the leading dot)
+ * @return string File extension in canonical form
*/
- static function normalizeExtension( $ext ) {
- $lower = strtolower( $ext );
+ static function normalizeExtension( $extension ) {
+ $lower = strtolower( $extension );
$squish = array(
'htm' => 'html',
'jpeg' => 'jpg',
@@ -420,7 +422,13 @@ abstract class File implements IDBAccessObject {
public function getLocalRefPath() {
$this->assertRepoDefined();
if ( !isset( $this->fsFile ) ) {
+ $starttime = microtime( true );
$this->fsFile = $this->repo->getLocalReference( $this->getPath() );
+
+ $statTiming = microtime( true ) - $starttime;
+ RequestContext::getMain()->getStats()->timing(
+ 'media.thumbnail.generate.fetchoriginal', 1000 * $statTiming );
+
if ( !$this->fsFile ) {
$this->fsFile = false; // null => false; cache negative hits
}
@@ -1091,7 +1099,9 @@ abstract class File implements IDBAccessObject {
* @return bool|MediaTransformOutput
*/
public function generateAndSaveThumb( $tmpFile, $transformParams, $flags ) {
- global $wgUseSquid, $wgIgnoreImageErrors;
+ global $wgIgnoreImageErrors;
+
+ $stats = RequestContext::getMain()->getStats();
$handler = $this->getHandler();
@@ -1108,10 +1118,15 @@ abstract class File implements IDBAccessObject {
$this->generateBucketsIfNeeded( $normalisedParams, $flags );
}
+ $starttime = microtime( true );
+
// Actually render the thumbnail...
$thumb = $handler->doTransform( $this, $tmpThumbPath, $thumbUrl, $transformParams );
$tmpFile->bind( $thumb ); // keep alive with $thumb
+ $statTiming = microtime( true ) - $starttime;
+ $stats->timing( 'media.thumbnail.generate.transform', 1000 * $statTiming );
+
if ( !$thumb ) { // bad params?
$thumb = false;
} elseif ( $thumb->isError() ) { // transform error
@@ -1122,6 +1137,9 @@ abstract class File implements IDBAccessObject {
}
} elseif ( $this->repo && $thumb->hasFile() && !$thumb->fileIsSource() ) {
// Copy the thumbnail from the file system into storage...
+
+ $starttime = microtime( true );
+
$disposition = $this->getThumbDisposition( $thumbName );
$status = $this->repo->quickImport( $tmpThumbPath, $thumbPath, $disposition );
if ( $status->isOK() ) {
@@ -1129,19 +1147,14 @@ abstract class File implements IDBAccessObject {
} else {
$thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $transformParams, $flags );
}
+
+ $statTiming = microtime( true ) - $starttime;
+ $stats->timing( 'media.thumbnail.generate.store', 1000 * $statTiming );
+
// Give extensions a chance to do something with this thumbnail...
Hooks::run( 'FileTransformed', array( $this, $thumb, $tmpThumbPath, $thumbPath ) );
}
- // Purge. Useful in the event of Core -> Squid connection failure or squid
- // purge collisions from elsewhere during failure. Don't keep triggering for
- // "thumbs" which have the main image URL though (bug 13776)
- if ( $wgUseSquid ) {
- if ( !$thumb || $thumb->isError() || $thumb->getUrl() != $this->getURL() ) {
- SquidUpdate::purge( array( $thumbUrl ) );
- }
- }
-
return $thumb;
}
@@ -1166,13 +1179,13 @@ abstract class File implements IDBAccessObject {
return false;
}
+ $starttime = microtime( true );
+
$params['physicalWidth'] = $bucket;
$params['width'] = $bucket;
$params = $this->getHandler()->sanitizeParamsForBucketing( $params );
- $bucketName = $this->getBucketThumbName( $bucket );
-
$tmpFile = $this->makeTransformTmpFile( $bucketPath );
if ( !$tmpFile ) {
@@ -1181,6 +1194,8 @@ abstract class File implements IDBAccessObject {
$thumb = $this->generateAndSaveThumb( $tmpFile, $params, $flags );
+ $buckettime = microtime( true ) - $starttime;
+
if ( !$thumb || $thumb->isError() ) {
return false;
}
@@ -1190,6 +1205,9 @@ abstract class File implements IDBAccessObject {
// this object exists
$tmpFile->bind( $this );
+ RequestContext::getMain()->getStats()->timing(
+ 'media.thumbnail.generate.bucket', 1000 * $buckettime );
+
return true;
}
@@ -2230,4 +2248,13 @@ abstract class File implements IDBAccessObject {
$handler = $this->getHandler();
return $handler ? $handler->isExpensiveToThumbnail( $this ) : false;
}
+
+ /**
+ * Whether the thumbnails created on the same server as this code is running.
+ * @since 1.25
+ * @return bool
+ */
+ public function isTransformedLocally() {
+ return true;
+ }
}
diff --git a/includes/filerepo/file/ForeignAPIFile.php b/includes/filerepo/file/ForeignAPIFile.php
index 3d5d5d60..3c78290c 100644
--- a/includes/filerepo/file/ForeignAPIFile.php
+++ b/includes/filerepo/file/ForeignAPIFile.php
@@ -219,11 +219,15 @@ class ForeignAPIFile extends File {
}
/**
- * @param string $method
+ * @param string $type
* @return int|null|string
*/
- public function getUser( $method = 'text' ) {
- return isset( $this->mInfo['user'] ) ? strval( $this->mInfo['user'] ) : null;
+ public function getUser( $type = 'text' ) {
+ if ( $type == 'text' ) {
+ return isset( $this->mInfo['user'] ) ? strval( $this->mInfo['user'] ) : null;
+ } elseif ( $type == 'id' ) {
+ return 0; // What makes sense here, for a remote user?
+ }
}
/**
@@ -365,4 +369,13 @@ class ForeignAPIFile extends File {
# Clear out the thumbnail directory if empty
$this->repo->quickCleanDir( $dir );
}
+
+ /**
+ * The thumbnail is created on the foreign server and fetched over internet
+ * @since 1.25
+ * @return bool
+ */
+ public function isTransformedLocally() {
+ return false;
+ }
}
diff --git a/includes/filerepo/file/LocalFile.php b/includes/filerepo/file/LocalFile.php
index b4cced38..d2c37e61 100644
--- a/includes/filerepo/file/LocalFile.php
+++ b/includes/filerepo/file/LocalFile.php
@@ -243,21 +243,19 @@ class LocalFile extends File {
* @return bool
*/
function loadFromCache() {
- global $wgMemc;
-
$this->dataLoaded = false;
$this->extraDataLoaded = false;
$key = $this->getCacheKey();
if ( !$key ) {
-
return false;
}
- $cachedValues = $wgMemc->get( $key );
+ $cache = ObjectCache::getMainWANInstance();
+ $cachedValues = $cache->get( $key );
// Check if the key existed and belongs to this version of MediaWiki
- if ( isset( $cachedValues['version'] ) && $cachedValues['version'] == MW_FILE_VERSION ) {
+ if ( is_array( $cachedValues ) && $cachedValues['version'] == MW_FILE_VERSION ) {
wfDebug( "Pulling file metadata from cache key $key\n" );
$this->fileExists = $cachedValues['fileExists'];
if ( $this->fileExists ) {
@@ -271,9 +269,9 @@ class LocalFile extends File {
}
if ( $this->dataLoaded ) {
- wfIncrStats( 'image_cache_hit' );
+ wfIncrStats( 'image_cache.hit' );
} else {
- wfIncrStats( 'image_cache_miss' );
+ wfIncrStats( 'image_cache.miss' );
}
return $this->dataLoaded;
@@ -283,22 +281,20 @@ class LocalFile extends File {
* Save the file metadata to memcached
*/
function saveToCache() {
- global $wgMemc;
-
$this->load();
- $key = $this->getCacheKey();
+ $key = $this->getCacheKey();
if ( !$key ) {
return;
}
$fields = $this->getCacheFields( '' );
- $cache = array( 'version' => MW_FILE_VERSION );
- $cache['fileExists'] = $this->fileExists;
+ $cacheVal = array( 'version' => MW_FILE_VERSION );
+ $cacheVal['fileExists'] = $this->fileExists;
if ( $this->fileExists ) {
foreach ( $fields as $field ) {
- $cache[$field] = $this->$field;
+ $cacheVal[$field] = $this->$field;
}
}
@@ -306,13 +302,26 @@ class LocalFile extends File {
// If the cache value gets to large it will not fit in memcached and nothing will
// get cached at all, causing master queries for any file access.
foreach ( $this->getLazyCacheFields( '' ) as $field ) {
- if ( isset( $cache[$field] ) && strlen( $cache[$field] ) > 100 * 1024 ) {
- unset( $cache[$field] ); // don't let the value get too big
+ if ( isset( $cacheVal[$field] ) && strlen( $cacheVal[$field] ) > 100 * 1024 ) {
+ unset( $cacheVal[$field] ); // don't let the value get too big
}
}
// Cache presence for 1 week and negatives for 1 day
- $wgMemc->set( $key, $cache, $this->fileExists ? 86400 * 7 : 86400 );
+ $cache = ObjectCache::getMainWANInstance();
+ $cache->set( $key, $cacheVal, $this->fileExists ? 86400 * 7 : 86400 );
+ }
+
+ /**
+ * Purge the file object/metadata cache
+ */
+ function invalidateCache() {
+ $key = $this->getCacheKey();
+ if ( !$key ) {
+ return;
+ }
+
+ ObjectCache::getMainWANInstance()->delete( $key );
}
/**
@@ -493,9 +502,17 @@ class LocalFile extends File {
$decoded['mime'] = $decoded['major_mime'] . '/' . $decoded['minor_mime'];
}
- # Trim zero padding from char/binary field
+ // Trim zero padding from char/binary field
$decoded['sha1'] = rtrim( $decoded['sha1'], "\0" );
+ // Normalize some fields to integer type, per their database definition.
+ // Use unary + so that overflows will be upgraded to double instead of
+ // being trucated as with intval(). This is important to allow >2GB
+ // files on 32-bit systems.
+ foreach ( array( 'size', 'width', 'height', 'bits' ) as $field ) {
+ $decoded[$field] = +$decoded[$field];
+ }
+
return $decoded;
}
@@ -612,7 +629,7 @@ class LocalFile extends File {
__METHOD__
);
- $this->saveToCache();
+ $this->invalidateCache();
$this->unlock(); // done
@@ -734,7 +751,7 @@ class LocalFile extends File {
if ( $type == 'text' ) {
return $this->user_text;
} elseif ( $type == 'id' ) {
- return $this->user;
+ return (int)$this->user;
}
}
@@ -753,7 +770,7 @@ class LocalFile extends File {
function getBitDepth() {
$this->load();
- return $this->bits;
+ return (int)$this->bits;
}
/**
@@ -842,25 +859,7 @@ class LocalFile extends File {
* Refresh metadata in memcached, but don't touch thumbnails or squid
*/
function purgeMetadataCache() {
- $this->loadFromDB( File::READ_LATEST );
- $this->saveToCache();
- $this->purgeHistory();
- }
-
- /**
- * Purge the shared history (OldLocalFile) cache.
- *
- * @note This used to purge old thumbnails as well.
- */
- function purgeHistory() {
- global $wgMemc;
-
- $hashedName = md5( $this->getName() );
- $oldKey = $this->repo->getSharedCacheKey( 'oldfile', $hashedName );
-
- if ( $oldKey ) {
- $wgMemc->delete( $oldKey );
- }
+ $this->invalidateCache();
}
/**
@@ -1406,11 +1405,8 @@ class LocalFile extends File {
# to after $wikiPage->doEdit has been called.
$dbw->commit( __METHOD__ );
- # Save to memcache.
- # We shall not saveToCache before the commit since otherwise
- # in case of a rollback there is an usable file from memcached
- # which in fact doesn't really exist (bug 24978)
- $this->saveToCache();
+ # Update memcache after the commit
+ $this->invalidateCache();
if ( $exists ) {
# Invalidate the cache for the description page
@@ -1471,7 +1467,7 @@ class LocalFile extends File {
* The archive name should be passed through to recordUpload for database
* registration.
*
- * @param string $srcPath Local filesystem path to the source image
+ * @param string $srcPath Local filesystem path or virtual URL to the source image
* @param int $flags A bitwise combination of:
* File::DELETE_SOURCE Delete the source file, i.e. move rather than copy
* @param array $options Optional additional parameters
@@ -1489,7 +1485,7 @@ class LocalFile extends File {
* The archive name should be passed through to recordUpload for database
* registration.
*
- * @param string $srcPath Local filesystem path to the source image
+ * @param string $srcPath Local filesystem path or virtual URL to the source image
* @param string $dstRel Target relative path
* @param int $flags A bitwise combination of:
* File::DELETE_SOURCE Delete the source file, i.e. move rather than copy
@@ -1498,7 +1494,8 @@ class LocalFile extends File {
* archive name, or an empty string if it was a new file.
*/
function publishTo( $srcPath, $dstRel, $flags = 0, array $options = array() ) {
- if ( $this->getRepo()->getReadOnlyReason() !== false ) {
+ $repo = $this->getRepo();
+ if ( $repo->getReadOnlyReason() !== false ) {
return $this->readOnlyFatalStatus();
}
@@ -1506,13 +1503,29 @@ class LocalFile extends File {
$archiveName = wfTimestamp( TS_MW ) . '!' . $this->getName();
$archiveRel = 'archive/' . $this->getHashPath() . $archiveName;
- $flags = $flags & File::DELETE_SOURCE ? LocalRepo::DELETE_SOURCE : 0;
- $status = $this->repo->publish( $srcPath, $dstRel, $archiveRel, $flags, $options );
- if ( $status->value == 'new' ) {
- $status->value = '';
+ if ( $repo->hasSha1Storage() ) {
+ $sha1 = $repo->isVirtualUrl( $srcPath )
+ ? $repo->getFileSha1( $srcPath )
+ : File::sha1Base36( $srcPath );
+ $dst = $repo->getBackend()->getPathForSHA1( $sha1 );
+ $status = $repo->quickImport( $srcPath, $dst );
+ if ( $flags & File::DELETE_SOURCE ) {
+ unlink( $srcPath );
+ }
+
+ if ( $this->exists() ) {
+ $status->value = $archiveName;
+ }
} else {
- $status->value = $archiveName;
+ $flags = $flags & File::DELETE_SOURCE ? LocalRepo::DELETE_SOURCE : 0;
+ $status = $repo->publish( $srcPath, $dstRel, $archiveRel, $flags, $options );
+
+ if ( $status->value == 'new' ) {
+ $status->value = '';
+ } else {
+ $status->value = $archiveName;
+ }
}
$this->unlock(); // done
@@ -1612,21 +1625,21 @@ class LocalFile extends File {
// Hack: the lock()/unlock() pair is nested in a transaction so the locking is not
// tied to BEGIN/COMMIT. To avoid slow purges in the transaction, move them outside.
- $file = $this;
+ $that = $this;
$this->getRepo()->getMasterDB()->onTransactionIdle(
- function () use ( $file, $archiveNames ) {
+ function () use ( $that, $archiveNames ) {
global $wgUseSquid;
- $file->purgeEverything();
+ $that->purgeEverything();
foreach ( $archiveNames as $archiveName ) {
- $file->purgeOldThumbnails( $archiveName );
+ $that->purgeOldThumbnails( $archiveName );
}
if ( $wgUseSquid ) {
// Purge the squid
$purgeUrls = array();
foreach ( $archiveNames as $archiveName ) {
- $purgeUrls[] = $file->getArchiveUrl( $archiveName );
+ $purgeUrls[] = $that->getArchiveUrl( $archiveName );
}
SquidUpdate::purge( $purgeUrls );
}
@@ -1667,7 +1680,6 @@ class LocalFile extends File {
$this->purgeOldThumbnails( $archiveName );
if ( $status->isOK() ) {
$this->purgeDescription();
- $this->purgeHistory();
}
if ( $wgUseSquid ) {
@@ -1811,7 +1823,7 @@ class LocalFile extends File {
array( 'img_sha1' => $this->sha1 ),
array( 'img_name' => $this->getName() ),
__METHOD__ );
- $this->saveToCache();
+ $this->invalidateCache();
}
$this->unlock(); // done
@@ -1954,14 +1966,14 @@ class LocalFileDeleteBatch {
$this->status = $file->repo->newGood();
}
- function addCurrent() {
+ public function addCurrent() {
$this->srcRels['.'] = $this->file->getRel();
}
/**
* @param string $oldName
*/
- function addOld( $oldName ) {
+ public function addOld( $oldName ) {
$this->srcRels[$oldName] = $this->file->getArchiveRel( $oldName );
$this->archiveUrls[] = $this->file->getArchiveUrl( $oldName );
}
@@ -1970,7 +1982,7 @@ class LocalFileDeleteBatch {
* Add the old versions of the image to the batch
* @return array List of archive names from old versions
*/
- function addOlds() {
+ public function addOlds() {
$archiveNames = array();
$dbw = $this->file->repo->getMasterDB();
@@ -1991,7 +2003,7 @@ class LocalFileDeleteBatch {
/**
* @return array
*/
- function getOldRels() {
+ protected function getOldRels() {
if ( !isset( $this->srcRels['.'] ) ) {
$oldRels =& $this->srcRels;
$deleteCurrent = false;
@@ -2063,7 +2075,7 @@ class LocalFileDeleteBatch {
return $hashes;
}
- function doDBInserts() {
+ protected function doDBInserts() {
$dbw = $this->file->repo->getMasterDB();
$encTimestamp = $dbw->addQuotes( $dbw->timestamp() );
$encUserId = $dbw->addQuotes( $this->user->getId() );
@@ -2178,8 +2190,8 @@ class LocalFileDeleteBatch {
* Run the transaction
* @return FileRepoStatus
*/
- function execute() {
-
+ public function execute() {
+ $repo = $this->file->getRepo();
$this->file->lock();
// Prepare deletion batch
@@ -2193,7 +2205,7 @@ class LocalFileDeleteBatch {
if ( isset( $hashes[$name] ) ) {
$hash = $hashes[$name];
$key = $hash . $dotExt;
- $dstRel = $this->file->repo->getDeletedHashPath( $key ) . $key;
+ $dstRel = $repo->getDeletedHashPath( $key ) . $key;
$this->deletionBatch[$name] = array( $srcRel, $dstRel );
}
}
@@ -2206,20 +2218,22 @@ class LocalFileDeleteBatch {
// them in a separate transaction, then run the file ops, then update the fa_name fields.
$this->doDBInserts();
- // Removes non-existent file from the batch, so we don't get errors.
- // This also handles files in the 'deleted' zone deleted via revision deletion.
- $checkStatus = $this->removeNonexistentFiles( $this->deletionBatch );
- if ( !$checkStatus->isGood() ) {
- $this->status->merge( $checkStatus );
- return $this->status;
- }
- $this->deletionBatch = $checkStatus->value;
+ if ( !$repo->hasSha1Storage() ) {
+ // Removes non-existent file from the batch, so we don't get errors.
+ // This also handles files in the 'deleted' zone deleted via revision deletion.
+ $checkStatus = $this->removeNonexistentFiles( $this->deletionBatch );
+ if ( !$checkStatus->isGood() ) {
+ $this->status->merge( $checkStatus );
+ return $this->status;
+ }
+ $this->deletionBatch = $checkStatus->value;
- // Execute the file deletion batch
- $status = $this->file->repo->deleteBatch( $this->deletionBatch );
+ // Execute the file deletion batch
+ $status = $this->file->repo->deleteBatch( $this->deletionBatch );
- if ( !$status->isGood() ) {
- $this->status->merge( $status );
+ if ( !$status->isGood() ) {
+ $this->status->merge( $status );
+ }
}
if ( !$this->status->isOK() ) {
@@ -2245,7 +2259,7 @@ class LocalFileDeleteBatch {
* @param array $batch
* @return Status
*/
- function removeNonexistentFiles( $batch ) {
+ protected function removeNonexistentFiles( $batch ) {
$files = $newBatch = array();
foreach ( $batch as $batchItem ) {
@@ -2306,7 +2320,7 @@ class LocalFileRestoreBatch {
* Add a file by ID
* @param int $fa_id
*/
- function addId( $fa_id ) {
+ public function addId( $fa_id ) {
$this->ids[] = $fa_id;
}
@@ -2314,14 +2328,14 @@ class LocalFileRestoreBatch {
* Add a whole lot of files by ID
* @param int[] $ids
*/
- function addIds( $ids ) {
+ public function addIds( $ids ) {
$this->ids = array_merge( $this->ids, $ids );
}
/**
* Add all revisions of the file
*/
- function addAll() {
+ public function addAll() {
$this->all = true;
}
@@ -2333,12 +2347,13 @@ class LocalFileRestoreBatch {
* So we save the batch and let the caller call cleanup()
* @return FileRepoStatus
*/
- function execute() {
+ public function execute() {
global $wgLang;
+ $repo = $this->file->getRepo();
if ( !$this->all && !$this->ids ) {
// Do nothing
- return $this->file->repo->newGood();
+ return $repo->newGood();
}
$lockOwnsTrx = $this->file->lock();
@@ -2395,9 +2410,9 @@ class LocalFileRestoreBatch {
continue;
}
- $deletedRel = $this->file->repo->getDeletedHashPath( $row->fa_storage_key ) .
+ $deletedRel = $repo->getDeletedHashPath( $row->fa_storage_key ) .
$row->fa_storage_key;
- $deletedUrl = $this->file->repo->getVirtualUrl() . '/deleted/' . $deletedRel;
+ $deletedUrl = $repo->getVirtualUrl() . '/deleted/' . $deletedRel;
if ( isset( $row->fa_sha1 ) ) {
$sha1 = $row->fa_sha1;
@@ -2511,27 +2526,29 @@ class LocalFileRestoreBatch {
$status->error( 'undelete-missing-filearchive', $id );
}
- // Remove missing files from batch, so we don't get errors when undeleting them
- $checkStatus = $this->removeNonexistentFiles( $storeBatch );
- if ( !$checkStatus->isGood() ) {
- $status->merge( $checkStatus );
- return $status;
- }
- $storeBatch = $checkStatus->value;
+ if ( !$repo->hasSha1Storage() ) {
+ // Remove missing files from batch, so we don't get errors when undeleting them
+ $checkStatus = $this->removeNonexistentFiles( $storeBatch );
+ if ( !$checkStatus->isGood() ) {
+ $status->merge( $checkStatus );
+ return $status;
+ }
+ $storeBatch = $checkStatus->value;
- // Run the store batch
- // Use the OVERWRITE_SAME flag to smooth over a common error
- $storeStatus = $this->file->repo->storeBatch( $storeBatch, FileRepo::OVERWRITE_SAME );
- $status->merge( $storeStatus );
+ // Run the store batch
+ // Use the OVERWRITE_SAME flag to smooth over a common error
+ $storeStatus = $this->file->repo->storeBatch( $storeBatch, FileRepo::OVERWRITE_SAME );
+ $status->merge( $storeStatus );
- if ( !$status->isGood() ) {
- // Even if some files could be copied, fail entirely as that is the
- // easiest thing to do without data loss
- $this->cleanupFailedBatch( $storeStatus, $storeBatch );
- $status->ok = false;
- $this->file->unlock();
+ if ( !$status->isGood() ) {
+ // Even if some files could be copied, fail entirely as that is the
+ // easiest thing to do without data loss
+ $this->cleanupFailedBatch( $storeStatus, $storeBatch );
+ $status->ok = false;
+ $this->file->unlock();
- return $status;
+ return $status;
+ }
}
// Run the DB updates
@@ -2555,7 +2572,7 @@ class LocalFileRestoreBatch {
}
// If store batch is empty (all files are missing), deletion is to be considered successful
- if ( $status->successCount > 0 || !$storeBatch ) {
+ if ( $status->successCount > 0 || !$storeBatch || $repo->hasSha1Storage() ) {
if ( !$exists ) {
wfDebug( __METHOD__ . " restored {$status->successCount} items, creating a new current\n" );
@@ -2565,7 +2582,6 @@ class LocalFileRestoreBatch {
} else {
wfDebug( __METHOD__ . " restored {$status->successCount} as archived versions\n" );
$this->file->purgeDescription();
- $this->file->purgeHistory();
}
}
@@ -2579,7 +2595,7 @@ class LocalFileRestoreBatch {
* @param array $triplets
* @return Status
*/
- function removeNonexistentFiles( $triplets ) {
+ protected function removeNonexistentFiles( $triplets ) {
$files = $filteredTriplets = array();
foreach ( $triplets as $file ) {
$files[$file[0]] = $file[0];
@@ -2605,7 +2621,7 @@ class LocalFileRestoreBatch {
* @param array $batch
* @return array
*/
- function removeNonexistentFromCleanup( $batch ) {
+ protected function removeNonexistentFromCleanup( $batch ) {
$files = $newBatch = array();
$repo = $this->file->repo;
@@ -2630,7 +2646,7 @@ class LocalFileRestoreBatch {
* This should be called from outside the transaction in which execute() was called.
* @return FileRepoStatus
*/
- function cleanup() {
+ public function cleanup() {
if ( !$this->cleanupBatch ) {
return $this->file->repo->newGood();
}
@@ -2649,7 +2665,7 @@ class LocalFileRestoreBatch {
* @param Status $storeStatus
* @param array $storeBatch
*/
- function cleanupFailedBatch( $storeStatus, $storeBatch ) {
+ protected function cleanupFailedBatch( $storeStatus, $storeBatch ) {
$cleanupBatch = array();
foreach ( $storeStatus->success as $i => $success ) {
@@ -2707,7 +2723,7 @@ class LocalFileMoveBatch {
/**
* Add the current image to the batch
*/
- function addCurrent() {
+ public function addCurrent() {
$this->cur = array( $this->oldRel, $this->newRel );
}
@@ -2715,7 +2731,7 @@ class LocalFileMoveBatch {
* Add the old versions of the image to the batch
* @return array List of archive names from old versions
*/
- function addOlds() {
+ public function addOlds() {
$archiveBase = 'archive';
$this->olds = array();
$this->oldCount = 0;
@@ -2765,7 +2781,7 @@ class LocalFileMoveBatch {
* Perform the move.
* @return FileRepoStatus
*/
- function execute() {
+ public function execute() {
$repo = $this->file->repo;
$status = $repo->newGood();
@@ -2796,22 +2812,26 @@ class LocalFileMoveBatch {
wfDebugLog( 'imagemove', "Renamed {$this->file->getName()} in database: " .
"{$statusDb->successCount} successes, {$statusDb->failCount} failures" );
- // Copy the files into their new location.
- // If a prior process fataled copying or cleaning up files we tolerate any
- // of the existing files if they are identical to the ones being stored.
- $statusMove = $repo->storeBatch( $triplets, FileRepo::OVERWRITE_SAME );
- wfDebugLog( 'imagemove', "Moved files for {$this->file->getName()}: " .
- "{$statusMove->successCount} successes, {$statusMove->failCount} failures" );
- if ( !$statusMove->isGood() ) {
- // Delete any files copied over (while the destination is still locked)
- $this->cleanupTarget( $triplets );
- $destFile->unlock();
- $this->file->unlockAndRollback(); // unlocks the destination
- wfDebugLog( 'imagemove', "Error in moving files: " . $statusMove->getWikiText() );
- $statusMove->ok = false;
-
- return $statusMove;
+ if ( !$repo->hasSha1Storage() ) {
+ // Copy the files into their new location.
+ // If a prior process fataled copying or cleaning up files we tolerate any
+ // of the existing files if they are identical to the ones being stored.
+ $statusMove = $repo->storeBatch( $triplets, FileRepo::OVERWRITE_SAME );
+ wfDebugLog( 'imagemove', "Moved files for {$this->file->getName()}: " .
+ "{$statusMove->successCount} successes, {$statusMove->failCount} failures" );
+ if ( !$statusMove->isGood() ) {
+ // Delete any files copied over (while the destination is still locked)
+ $this->cleanupTarget( $triplets );
+ $destFile->unlock();
+ $this->file->unlockAndRollback(); // unlocks the destination
+ wfDebugLog( 'imagemove', "Error in moving files: " . $statusMove->getWikiText() );
+ $statusMove->ok = false;
+
+ return $statusMove;
+ }
+ $status->merge( $statusMove );
}
+
$destFile->unlock();
$this->file->unlock(); // done
@@ -2819,7 +2839,6 @@ class LocalFileMoveBatch {
$this->cleanupSource( $triplets );
$status->merge( $statusDb );
- $status->merge( $statusMove );
return $status;
}
@@ -2830,7 +2849,7 @@ class LocalFileMoveBatch {
*
* @return FileRepoStatus
*/
- function doDBUpdates() {
+ protected function doDBUpdates() {
$repo = $this->file->repo;
$status = $repo->newGood();
$dbw = $this->db;
@@ -2882,7 +2901,7 @@ class LocalFileMoveBatch {
* Generate triplets for FileRepo::storeBatch().
* @return array
*/
- function getMoveTriplets() {
+ protected function getMoveTriplets() {
$moves = array_merge( array( $this->cur ), $this->olds );
$triplets = array(); // The format is: (srcUrl, destZone, destUrl)
@@ -2904,7 +2923,7 @@ class LocalFileMoveBatch {
* @param array $triplets
* @return Status
*/
- function removeNonexistentFiles( $triplets ) {
+ protected function removeNonexistentFiles( $triplets ) {
$files = array();
foreach ( $triplets as $file ) {
@@ -2934,7 +2953,7 @@ class LocalFileMoveBatch {
* files. Called if something went wrong half way.
* @param array $triplets
*/
- function cleanupTarget( $triplets ) {
+ protected function cleanupTarget( $triplets ) {
// Create dest pairs from the triplets
$pairs = array();
foreach ( $triplets as $triplet ) {
@@ -2950,7 +2969,7 @@ class LocalFileMoveBatch {
* Called at the end of the move process if everything else went ok.
* @param array $triplets
*/
- function cleanupSource( $triplets ) {
+ protected function cleanupSource( $triplets ) {
// Create source file names from the triplets
$files = array();
foreach ( $triplets as $triplet ) {
diff --git a/includes/gallery/PackedImageGallery.php b/includes/gallery/PackedImageGallery.php
index 52a49ddb..821c85fb 100644
--- a/includes/gallery/PackedImageGallery.php
+++ b/includes/gallery/PackedImageGallery.php
@@ -21,8 +21,8 @@
*/
class PackedImageGallery extends TraditionalImageGallery {
- function __construct( $mode = 'traditional' ) {
- parent::__construct( $mode );
+ function __construct( $mode = 'traditional', IContextSource $context = null ) {
+ parent::__construct( $mode, $context );
// Does not support per row option.
$this->mPerRow = 0;
}
diff --git a/includes/gallery/PackedOverlayImageGallery.php b/includes/gallery/PackedOverlayImageGallery.php
index 01360d05..e1ee7faf 100644
--- a/includes/gallery/PackedOverlayImageGallery.php
+++ b/includes/gallery/PackedOverlayImageGallery.php
@@ -40,7 +40,7 @@ class PackedOverlayImageGallery extends PackedImageGallery {
# ATTENTION: The newline after <div class="gallerytext"> is needed to
# accommodate htmltidy which in version 4.8.6 generated crackpot HTML
- # in its absence, see: http://bugzilla.wikimedia.org/show_bug.cgi?id=1765
+ # in its absence, see: https://phabricator.wikimedia.org/T3765
# -Ævar
$thumbWidth = $this->getGBWidth( $thumb ) - $this->getThumbPadding() - $this->getGBPadding();
diff --git a/includes/gallery/TraditionalImageGallery.php b/includes/gallery/TraditionalImageGallery.php
index 7a0206c2..181c7b8e 100644
--- a/includes/gallery/TraditionalImageGallery.php
+++ b/includes/gallery/TraditionalImageGallery.php
@@ -49,8 +49,10 @@ class TraditionalImageGallery extends ImageGalleryBase {
if ( $this->mParser ) {
$this->mParser->getOutput()->addModules( $modules );
+ $this->mParser->getOutput()->addModuleStyles( 'mediawiki.page.gallery.styles' );
} else {
$this->getOutput()->addModules( $modules );
+ $this->getOutput()->addModuleStyles( 'mediawiki.page.gallery.styles' );
}
$output = Xml::openElement( 'ul', $attribs );
if ( $this->mCaption ) {
@@ -205,7 +207,7 @@ class TraditionalImageGallery extends ImageGalleryBase {
protected function wrapGalleryText( $galleryText, $thumb ) {
# ATTENTION: The newline after <div class="gallerytext"> is needed to
# accommodate htmltidy which in version 4.8.6 generated crackpot html in
- # its absence, see: http://bugzilla.wikimedia.org/show_bug.cgi?id=1765
+ # its absence, see: https://phabricator.wikimedia.org/T3765
# -Ævar
return "\n\t\t\t" . '<div class="gallerytext">' . "\n"
diff --git a/includes/htmlform/HTMLAutoCompleteSelectField.php b/includes/htmlform/HTMLAutoCompleteSelectField.php
index 49053628..55cd5d0c 100644
--- a/includes/htmlform/HTMLAutoCompleteSelectField.php
+++ b/includes/htmlform/HTMLAutoCompleteSelectField.php
@@ -98,11 +98,12 @@ class HTMLAutoCompleteSelectField extends HTMLTextField {
return true;
}
- function getAttributes( array $list ) {
+ // FIXME Ewww, this shouldn't be adding any attributes not requested in $list :(
+ public function getAttributes( array $list, array $mappings = null ) {
$attribs = array(
'type' => 'text',
'data-autocomplete' => FormatJson::encode( array_keys( $this->autocomplete ) ),
- ) + parent::getAttributes( $list );
+ ) + parent::getAttributes( $list, $mappings );
if ( $this->getOptions() ) {
$attribs['data-hide-if'] = FormatJson::encode(
@@ -162,4 +163,13 @@ class HTMLAutoCompleteSelectField extends HTMLTextField {
return $ret;
}
+ /**
+ * Get the OOUI version of this input.
+ * @param string $value
+ * @return false
+ */
+ function getInputOOUI( $value ) {
+ // To be implemented, for now override the function from HTMLTextField
+ return false;
+ }
}
diff --git a/includes/htmlform/HTMLButtonField.php b/includes/htmlform/HTMLButtonField.php
index 09c0ad97..56a23ad2 100644
--- a/includes/htmlform/HTMLButtonField.php
+++ b/includes/htmlform/HTMLButtonField.php
@@ -10,20 +10,54 @@
class HTMLButtonField extends HTMLFormField {
protected $buttonType = 'button';
+ /** @var array $mFlags Flags to add to OOUI Button widget */
+ protected $mFlags = array();
+
public function __construct( $info ) {
$info['nodata'] = true;
+ if ( isset( $info['flags'] ) )
+ $this->mFlags = $info['flags'];
parent::__construct( $info );
}
public function getInputHTML( $value ) {
+ $flags = '';
+ $prefix = 'mw-htmlform-';
+ if ( $this->mParent instanceof VFormHTMLForm ||
+ $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' )
+ ) {
+ $prefix = 'mw-ui-';
+ // add mw-ui-button separately, so the descriptor doesn't need to set it
+ $flags .= ' ' . $prefix.'button';
+ }
+ foreach ( $this->mFlags as $flag ) {
+ $flags .= ' ' . $prefix . $flag;
+ }
$attr = array(
- 'class' => 'mw-htmlform-submit ' . $this->mClass,
+ 'class' => 'mw-htmlform-submit ' . $this->mClass . $flags,
'id' => $this->mID,
) + $this->getAttributes( array( 'disabled', 'tabindex' ) );
return Html::input( $this->mName, $value, $this->buttonType, $attr );
}
+ /**
+ * Get the OOUI widget for this field.
+ * @param string $value
+ * @return OOUI\\ButtonInputWidget
+ */
+ public function getInputOOUI( $value ) {
+ return new OOUI\ButtonInputWidget( array(
+ 'name' => $this->mName,
+ 'value' => $value,
+ 'label' => $value,
+ 'type' => $this->buttonType,
+ 'classes' => array( 'mw-htmlform-submit', $this->mClass ),
+ 'id' => $this->mID,
+ 'flags' => $this->mFlags,
+ ) + $this->getAttributes( array( 'disabled', 'tabindex' ), array( 'tabindex' => 'tabIndex' ) ) );
+ }
+
protected function needsLabel() {
return false;
}
diff --git a/includes/htmlform/HTMLCheckField.php b/includes/htmlform/HTMLCheckField.php
index 4942327f..9666c4ea 100644
--- a/includes/htmlform/HTMLCheckField.php
+++ b/includes/htmlform/HTMLCheckField.php
@@ -20,9 +20,15 @@ class HTMLCheckField extends HTMLFormField {
$attr['class'] = $this->mClass;
}
- $chkLabel = Xml::check( $this->mName, $value, $attr )
- . '&#160;'
- . Html::rawElement( 'label', array( 'for' => $this->mID ), $this->mLabel );
+ $attrLabel = array( 'for' => $this->mID );
+ if ( isset( $attr['title'] ) ) {
+ // propagate tooltip to label
+ $attrLabel['title'] = $attr['title'];
+ }
+
+ $chkLabel = Xml::check( $this->mName, $value, $attr ) .
+ '&#160;' .
+ Html::rawElement( 'label', $attrLabel, $this->mLabel );
if ( $wgUseMediaWikiUIEverywhere || $this->mParent instanceof VFormHTMLForm ) {
$chkLabel = Html::rawElement(
@@ -36,12 +42,60 @@ class HTMLCheckField extends HTMLFormField {
}
/**
+ * Get the OOUI version of this field.
+ * @since 1.26
+ * @param string $value
+ * @return OOUI\\CheckboxInputWidget The checkbox widget.
+ */
+ public function getInputOOUI( $value ) {
+ if ( !empty( $this->mParams['invert'] ) ) {
+ $value = !$value;
+ }
+
+ $attr = $this->getTooltipAndAccessKey();
+ $attr['id'] = $this->mID;
+ $attr['name'] = $this->mName;
+
+ $attr += $this->getAttributes( array( 'disabled', 'tabindex' ), array( 'tabindex' => 'tabIndex' ) );
+
+ if ( $this->mClass !== '' ) {
+ $attr['classes'] = array( $this->mClass );
+ }
+
+ $attr['selected'] = $value;
+ $attr['value'] = '1'; // Nasty hack, but needed to make this work
+
+ return new OOUI\CheckboxInputWidget( $attr );
+ }
+
+ /**
* For a checkbox, the label goes on the right hand side, and is
* added in getInputHTML(), rather than HTMLFormField::getRow()
+ *
+ * ...unless OOUI is being used, in which case we actually return
+ * the label here.
+ *
* @return string
*/
function getLabel() {
- return '&#160;';
+ if ( $this->mParent instanceof OOUIHTMLForm ) {
+ return $this->mLabel;
+ } elseif (
+ $this->mParent instanceof HTMLForm &&
+ $this->mParent->getDisplayFormat() === 'div'
+ ) {
+ return '';
+ } else {
+ return '&#160;';
+ }
+ }
+
+ /**
+ * Get label alignment when generating field for OOUI.
+ * @return string 'left', 'right', 'top' or 'inline'
+ */
+ protected function getLabelAlignOOUI() {
+ return 'inline';
}
/**
diff --git a/includes/htmlform/HTMLCheckMatrix.php b/includes/htmlform/HTMLCheckMatrix.php
index 83f12665..a0566a03 100644
--- a/includes/htmlform/HTMLCheckMatrix.php
+++ b/includes/htmlform/HTMLCheckMatrix.php
@@ -85,7 +85,13 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
$rows = $this->mParams['rows'];
$columns = $this->mParams['columns'];
- $attribs = $this->getAttributes( array( 'disabled', 'tabindex' ) );
+ $mappings = array();
+
+ if ( $this->mParent instanceof OOUIHTMLForm ) {
+ $mappings['tabindex'] = 'tabIndex';
+ }
+
+ $attribs = $this->getAttributes( array( 'disabled', 'tabindex' ), $mappings );
// Build the column headers
$headerContents = Html::rawElement( 'td', array(), '&#160;' );
@@ -113,9 +119,8 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
foreach ( $columns as $columnTag ) {
$thisTag = "$columnTag-$rowTag";
// Construct the checkbox
- $thisId = "{$this->mID}-$thisTag";
$thisAttribs = array(
- 'id' => $thisId,
+ 'id' => "{$this->mID}-$thisTag",
'value' => $thisTag,
);
$checked = in_array( $thisTag, (array)$value, true );
@@ -126,17 +131,13 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
$checked = true;
$thisAttribs['disabled'] = 1;
}
- $chkBox = Xml::check( "{$this->mName}[]", $checked, $attribs + $thisAttribs );
- if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
- $chkBox = Html::openElement( 'div', array( 'class' => 'mw-ui-checkbox' ) ) .
- $chkBox .
- Html::element( 'label', array( 'for' => $thisId ) ) .
- Html::closeElement( 'div' );
- }
+
+ $checkbox = $this->getOneCheckbox( $checked, $attribs + $thisAttribs );
+
$rowContents .= Html::rawElement(
'td',
array(),
- $chkBox
+ $checkbox
);
}
$tableContents .= Html::rawElement( 'tr', array(), "\n$rowContents\n" );
@@ -150,6 +151,25 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable {
return $html;
}
+ protected function getOneCheckbox( $checked, $attribs ) {
+ if ( $this->mParent instanceof OOUIHTMLForm ) {
+ return new OOUI\CheckboxInputWidget( array(
+ 'name' => "{$this->mName}[]",
+ 'selected' => $checked,
+ 'value' => $attribs['value'],
+ ) + $attribs );
+ } else {
+ $checkbox = Xml::check( "{$this->mName}[]", $checked, $attribs );
+ if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
+ $checkbox = Html::openElement( 'div', array( 'class' => 'mw-ui-checkbox' ) ) .
+ $checkbox .
+ Html::element( 'label', array( 'for' => $attribs['id'] ) ) .
+ Html::closeElement( 'div' );
+ }
+ return $checkbox;
+ }
+ }
+
protected function isTagForcedOff( $tag ) {
return isset( $this->mParams['force-options-off'] )
&& in_array( $tag, $this->mParams['force-options-off'] );
diff --git a/includes/htmlform/HTMLForm.php b/includes/htmlform/HTMLForm.php
index ce140038..08fa0a91 100644
--- a/includes/htmlform/HTMLForm.php
+++ b/includes/htmlform/HTMLForm.php
@@ -51,6 +51,7 @@
* 'id' -- HTML id attribute
* 'cssclass' -- CSS class
* 'csshelpclass' -- CSS class used to style help text
+ * 'dir' -- Direction of the element.
* 'options' -- associative array mapping labels to values.
* Some field types support multi-level arrays.
* 'options-messages' -- associative array mapping message keys to values.
@@ -75,14 +76,35 @@
* 'size' -- the length of text fields
* 'filter-callback -- a function name to give you the chance to
* massage the inputted value before it's processed.
- * @see HTMLForm::filter()
+ * @see HTMLFormField::filter()
* 'validation-callback' -- a function name to give you the chance
* to impose extra validation on the field input.
- * @see HTMLForm::validate()
+ * @see HTMLFormField::validate()
* 'name' -- By default, the 'name' attribute of the input field
* is "wp{$fieldname}". If you want a different name
* (eg one without the "wp" prefix), specify it here and
* it will be used without modification.
+ * 'hide-if' -- expression given as an array stating when the field
+ * should be hidden. The first array value has to be the
+ * expression's logic operator. Supported expressions:
+ * 'NOT'
+ * [ 'NOT', array $expression ]
+ * To hide a field if a given expression is not true.
+ * '==='
+ * [ '===', string $fieldName, string $value ]
+ * To hide a field if another field identified by
+ * $field has the value $value.
+ * '!=='
+ * [ '!==', string $fieldName, string $value ]
+ * Same as [ 'NOT', [ '===', $fieldName, $value ]
+ * 'OR', 'AND', 'NOR', 'NAND'
+ * [ 'XXX', array $expression1, ..., array $expressionN ]
+ * To hide a field if one or more (OR), all (AND),
+ * neither (NOR) or not all (NAND) given expressions
+ * are evaluated as true.
+ * The expressions will be given to a JavaScript frontend
+ * module which will continually update the field's
+ * visibility.
*
* Since 1.20, you can chain mutators to ease the form generation:
* @par Example:
@@ -103,6 +125,7 @@ class HTMLForm extends ContextSource {
public static $typeMappings = array(
'api' => 'HTMLApiField',
'text' => 'HTMLTextField',
+ 'textwithbutton' => 'HTMLTextFieldWithButton',
'textarea' => 'HTMLTextAreaField',
'select' => 'HTMLSelectField',
'radio' => 'HTMLRadioField',
@@ -116,6 +139,7 @@ class HTMLForm extends ContextSource {
'selectorother' => 'HTMLSelectOrOtherField',
'selectandother' => 'HTMLSelectAndOtherField',
'namespaceselect' => 'HTMLSelectNamespace',
+ 'namespaceselectwithbutton' => 'HTMLSelectNamespaceWithButton',
'tagfilter' => 'HTMLTagFilter',
'submit' => 'HTMLSubmitField',
'hidden' => 'HTMLHiddenField',
@@ -129,6 +153,8 @@ class HTMLForm extends ContextSource {
'email' => 'HTMLTextField',
'password' => 'HTMLTextField',
'url' => 'HTMLTextField',
+ 'title' => 'HTMLTitleTextField',
+ 'user' => 'HTMLUserTextField',
);
public $mFieldData;
@@ -141,7 +167,7 @@ class HTMLForm extends ContextSource {
protected $mFieldTree;
protected $mShowReset = false;
protected $mShowSubmit = true;
- protected $mSubmitModifierClass = 'mw-ui-constructive';
+ protected $mSubmitFlags = array( 'constructive', 'primary' );
protected $mSubmitCallback;
protected $mValidationErrorMessage;
@@ -216,12 +242,12 @@ class HTMLForm extends ContextSource {
*/
protected $availableSubclassDisplayFormats = array(
'vform',
+ 'ooui',
);
/**
* Construct a HTMLForm object for given display type. May return a HTMLForm subclass.
*
- * @throws MWException When the display format requested is not known
* @param string $displayFormat
* @param mixed $arguments... Additional arguments to pass to the constructor.
* @return HTMLForm
@@ -234,6 +260,9 @@ class HTMLForm extends ContextSource {
case 'vform':
$reflector = new ReflectionClass( 'VFormHTMLForm' );
return $reflector->newInstanceArgs( $arguments );
+ case 'ooui':
+ $reflector = new ReflectionClass( 'OOUIHTMLForm' );
+ return $reflector->newInstanceArgs( $arguments );
default:
$reflector = new ReflectionClass( 'HTMLForm' );
$form = $reflector->newInstanceArgs( $arguments );
@@ -266,7 +295,10 @@ class HTMLForm extends ContextSource {
}
// Evil hack for mobile :(
- if ( !$this->getConfig()->get( 'HTMLFormAllowTableFormat' ) && $this->displayFormat === 'table' ) {
+ if (
+ !$this->getConfig()->get( 'HTMLFormAllowTableFormat' )
+ && $this->displayFormat === 'table'
+ ) {
$this->displayFormat = 'div';
}
@@ -405,7 +437,9 @@ class HTMLForm extends ContextSource {
* @throws MWException
* @return HTMLFormField Instance of a subclass of HTMLFormField
*/
- public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) {
+ public static function loadInputFromParameters( $fieldname, $descriptor,
+ HTMLForm $parent = null
+ ) {
$class = static::getClassFromDescriptor( $fieldname, $descriptor );
$descriptor['fieldname'] = $fieldname;
@@ -677,6 +711,21 @@ class HTMLForm extends ContextSource {
}
/**
+ * Get header text.
+ *
+ * @param string|null $section The section to get the header text for
+ * @since 1.26
+ * @return string
+ */
+ function getHeaderText( $section = null ) {
+ if ( is_null( $section ) ) {
+ return $this->mHeader;
+ } else {
+ return isset( $this->mSectionHeaders[$section] ) ? $this->mSectionHeaders[$section] : '';
+ }
+ }
+
+ /**
* Add footer text, inside the form.
*
* @param string $msg Complete text of message to display
@@ -717,6 +766,21 @@ class HTMLForm extends ContextSource {
}
/**
+ * Get footer text.
+ *
+ * @param string|null $section The section to get the footer text for
+ * @since 1.26
+ * @return string
+ */
+ function getFooterText( $section = null ) {
+ if ( is_null( $section ) ) {
+ return $this->mFooter;
+ } else {
+ return isset( $this->mSectionFooters[$section] ) ? $this->mSectionFooters[$section] : '';
+ }
+ }
+
+ /**
* Add text to the end of the display.
*
* @param string $msg Complete text of message to display
@@ -834,14 +898,15 @@ class HTMLForm extends ContextSource {
# For good measure (it is the default)
$this->getOutput()->preventClickjacking();
$this->getOutput()->addModules( 'mediawiki.htmlform' );
+ $this->getOutput()->addModuleStyles( 'mediawiki.htmlform.styles' );
$html = ''
. $this->getErrors( $submitResult )
- . $this->mHeader
+ . $this->getHeaderText()
. $this->getBody()
. $this->getHiddenFields()
. $this->getButtons()
- . $this->mFooter;
+ . $this->getFooterText();
$html = $this->wrapForm( $html );
@@ -861,7 +926,6 @@ class HTMLForm extends ContextSource {
$attribs = array(
'action' => $this->getAction(),
'method' => $this->getMethod(),
- 'class' => array( 'visualClear' ),
'enctype' => $encType,
);
if ( !empty( $this->mId ) ) {
@@ -880,10 +944,11 @@ class HTMLForm extends ContextSource {
function wrapForm( $html ) {
# Include a <fieldset> wrapper for style, if requested.
if ( $this->mWrapperLegend !== false ) {
- $html = Xml::fieldset( $this->mWrapperLegend, $html );
+ $legend = is_string( $this->mWrapperLegend ) ? $this->mWrapperLegend : false;
+ $html = Xml::fieldset( $legend, $html );
}
- return Html::rawElement( 'form', $this->getFormAttributes(), $html );
+ return Html::rawElement( 'form', $this->getFormAttributes() + array( 'class' => 'visualClear' ), $html );
}
/**
@@ -940,7 +1005,10 @@ class HTMLForm extends ContextSource {
$attribs['class'] = array( 'mw-htmlform-submit' );
if ( $useMediaWikiUIEverywhere ) {
- array_push( $attribs['class'], 'mw-ui-button', $this->mSubmitModifierClass );
+ foreach ( $this->mSubmitFlags as $flag ) {
+ array_push( $attribs['class'], 'mw-ui-' . $flag );
+ }
+ array_push( $attribs['class'], 'mw-ui-button' );
}
$buttons .= Xml::submitButton( $this->getSubmitText(), $attribs ) . "\n";
@@ -1067,7 +1135,7 @@ class HTMLForm extends ContextSource {
* @since 1.24
*/
public function setSubmitDestructive() {
- $this->mSubmitModifierClass = 'mw-ui-destructive';
+ $this->mSubmitFlags = array( 'destructive', 'primary' );
}
/**
@@ -1075,7 +1143,7 @@ class HTMLForm extends ContextSource {
* @since 1.25
*/
public function setSubmitProgressive() {
- $this->mSubmitModifierClass = 'mw-ui-progressive';
+ $this->mSubmitFlags = array( 'progressive', 'primary' );
}
/**
@@ -1187,9 +1255,10 @@ class HTMLForm extends ContextSource {
* Prompt the whole form to be wrapped in a "<fieldset>", with
* this text as its "<legend>" element.
*
- * @param string|bool $legend HTML to go inside the "<legend>" element, or
- * false for no <legend>
- * Will be escaped
+ * @param string|bool $legend If false, no wrapper or legend will be displayed.
+ * If true, a wrapper will be displayed, but no legend.
+ * If a string, a wrapper will be displayed with that string as a legend.
+ * The string will be escaped before being output (this doesn't support HTML).
*
* @return HTMLForm $this for chaining calls (since 1.20)
*/
@@ -1263,11 +1332,14 @@ class HTMLForm extends ContextSource {
* @return HTMLForm $this for chaining calls (since 1.20)
*/
public function setMethod( $method = 'post' ) {
- $this->mMethod = $method;
+ $this->mMethod = strtolower( $method );
return $this;
}
+ /**
+ * @return string Always lowercase
+ */
public function getMethod() {
return $this->mMethod;
}
@@ -1291,7 +1363,7 @@ class HTMLForm extends ContextSource {
&$hasUserVisibleFields = false ) {
$displayFormat = $this->getDisplayFormat();
- $html = '';
+ $html = array();
$subsectionHtml = '';
$hasLabel = false;
@@ -1303,7 +1375,7 @@ class HTMLForm extends ContextSource {
$v = empty( $value->mParams['nodata'] )
? $this->mFieldData[$key]
: $value->getDefault();
- $html .= $value->$getFieldHtmlMethod( $v );
+ $html[] = $value->$getFieldHtmlMethod( $v );
$labelValue = trim( $value->getLabel() );
if ( $labelValue != '&#160;' && $labelValue !== '' ) {
@@ -1330,12 +1402,9 @@ class HTMLForm extends ContextSource {
$legend = $this->getLegend( $key );
- if ( isset( $this->mSectionHeaders[$key] ) ) {
- $section = $this->mSectionHeaders[$key] . $section;
- }
- if ( isset( $this->mSectionFooters[$key] ) ) {
- $section .= $this->mSectionFooters[$key];
- }
+ $section = $this->getHeaderText( $key ) .
+ $section .
+ $this->getFooterText( $key );
$attributes = array();
if ( $fieldsetIDPrefix ) {
@@ -1349,36 +1418,56 @@ class HTMLForm extends ContextSource {
}
}
- if ( $displayFormat !== 'raw' ) {
- $classes = array();
+ $html = $this->formatSection( $html, $sectionName, $hasLabel );
- if ( !$hasLabel ) { // Avoid strange spacing when no labels exist
- $classes[] = 'mw-htmlform-nolabel';
+ if ( $subsectionHtml ) {
+ if ( $this->mSubSectionBeforeFields ) {
+ return $subsectionHtml . "\n" . $html;
+ } else {
+ return $html . "\n" . $subsectionHtml;
}
+ } else {
+ return $html;
+ }
+ }
- $attribs = array(
- 'class' => implode( ' ', $classes ),
- );
+ /**
+ * Put a form section together from the individual fields' HTML, merging it and wrapping.
+ * @param array $fieldsHtml
+ * @param string $sectionName
+ * @param bool $anyFieldHasLabel
+ * @return string HTML
+ */
+ protected function formatSection( array $fieldsHtml, $sectionName, $anyFieldHasLabel ) {
+ $displayFormat = $this->getDisplayFormat();
+ $html = implode( '', $fieldsHtml );
- if ( $sectionName ) {
- $attribs['id'] = Sanitizer::escapeId( $sectionName );
- }
+ if ( $displayFormat === 'raw' ) {
+ return $html;
+ }
- if ( $displayFormat === 'table' ) {
- $html = Html::rawElement( 'table',
- $attribs,
- Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n";
- } elseif ( $displayFormat === 'inline' ) {
- $html = Html::rawElement( 'span', $attribs, "\n$html\n" );
- } else {
- $html = Html::rawElement( 'div', $attribs, "\n$html\n" );
- }
+ $classes = array();
+
+ if ( !$anyFieldHasLabel ) { // Avoid strange spacing when no labels exist
+ $classes[] = 'mw-htmlform-nolabel';
+ }
+
+ $attribs = array(
+ 'class' => implode( ' ', $classes ),
+ );
+
+ if ( $sectionName ) {
+ $attribs['id'] = Sanitizer::escapeId( $sectionName );
}
- if ( $this->mSubSectionBeforeFields ) {
- return $subsectionHtml . "\n" . $html;
+ if ( $displayFormat === 'table' ) {
+ return Html::rawElement( 'table',
+ $attribs,
+ Html::rawElement( 'tbody', array(), "\n$html\n" ) ) . "\n";
+ } elseif ( $displayFormat === 'inline' ) {
+ return Html::rawElement( 'span', $attribs, "\n$html\n" );
} else {
- return $html . "\n" . $subsectionHtml;
+ return Html::rawElement( 'div', $attribs, "\n$html\n" );
}
}
diff --git a/includes/htmlform/HTMLFormField.php b/includes/htmlform/HTMLFormField.php
index 9576c77c..13756e3d 100644
--- a/includes/htmlform/HTMLFormField.php
+++ b/includes/htmlform/HTMLFormField.php
@@ -10,6 +10,7 @@ abstract class HTMLFormField {
protected $mValidationCallback;
protected $mFilterCallback;
protected $mName;
+ protected $mDir;
protected $mLabel; # String label. Set on construction
protected $mID;
protected $mClass = '';
@@ -44,6 +45,17 @@ abstract class HTMLFormField {
abstract function getInputHTML( $value );
/**
+ * Same as getInputHTML, but returns an OOUI object.
+ * Defaults to false, which getOOUI will interpret as "use the HTML version"
+ *
+ * @param string $value
+ * @return OOUI\\Widget|false
+ */
+ function getInputOOUI( $value ) {
+ return false;
+ }
+
+ /**
* Get a translated interface message
*
* This is a wrapper around $this->mParent->msg() if $this->mParent is set
@@ -377,6 +389,10 @@ abstract class HTMLFormField {
$this->mName = $params['name'];
}
+ if ( isset( $params['dir'] ) ) {
+ $this->mDir = $params['dir'];
+ }
+
$validName = Sanitizer::escapeId( $this->mName );
$validName = str_replace( array( '.5B', '.5D' ), array( '[', ']' ), $validName );
if ( $this->mName != $validName && !isset( $params['nodata'] ) ) {
@@ -508,12 +524,20 @@ abstract class HTMLFormField {
'mw-htmlform-nolabel' => ( $label === '' )
);
- $field = Html::rawElement(
- 'div',
- array( 'class' => $outerDivClass ) + $cellAttributes,
- $inputHtml . "\n$errors"
- );
- $divCssClasses = array( "mw-htmlform-field-$fieldType", $this->mClass, $this->mVFormClass, $errorClass );
+ $horizontalLabel = isset( $this->mParams['horizontal-label'] )
+ ? $this->mParams['horizontal-label'] : false;
+
+ if ( $horizontalLabel ) {
+ $field = '&#160;' . $inputHtml . "\n$errors";
+ } else {
+ $field = Html::rawElement(
+ 'div',
+ array( 'class' => $outerDivClass ) + $cellAttributes,
+ $inputHtml . "\n$errors"
+ );
+ }
+ $divCssClasses = array( "mw-htmlform-field-$fieldType",
+ $this->mClass, $this->mVFormClass, $errorClass );
$wrapperAttributes = array(
'class' => $divCssClasses,
@@ -529,6 +553,75 @@ abstract class HTMLFormField {
}
/**
+ * Get the OOUI version of the div. Falls back to getDiv by default.
+ * @since 1.26
+ *
+ * @param string $value The value to set the input to.
+ *
+ * @return OOUI\\FieldLayout|OOUI\\ActionFieldLayout
+ */
+ public function getOOUI( $value ) {
+ $inputField = $this->getInputOOUI( $value );
+
+ if ( !$inputField ) {
+ // This field doesn't have an OOUI implementation yet at all. Fall back to getDiv() to
+ // generate the whole field, label and errors and all, then wrap it in a Widget.
+ // It might look weird, but it'll work OK.
+ return $this->getFieldLayoutOOUI(
+ new OOUI\Widget( array( 'content' => new OOUI\HtmlSnippet( $this->getDiv( $value ) ) ) ),
+ array( 'infusable' => false )
+ );
+ }
+
+ $infusable = true;
+ if ( is_string( $inputField ) ) {
+ // We have an OOUI implementation, but it's not proper, and we got a load of HTML.
+ // Cheat a little and wrap it in a widget. It won't be infusable, though, since client-side
+ // JavaScript doesn't know how to rebuilt the contents.
+ $inputField = new OOUI\Widget( array( 'content' => new OOUI\HtmlSnippet( $inputField ) ) );
+ $infusable = false;
+ }
+
+ $fieldType = get_class( $this );
+ $helpText = $this->getHelpText();
+ $errors = $this->getErrorsRaw( $value );
+ foreach ( $errors as &$error ) {
+ $error = new OOUI\HtmlSnippet( $error );
+ }
+
+ $config = array(
+ 'classes' => array( "mw-htmlform-field-$fieldType", $this->mClass ),
+ 'align' => $this->getLabelAlignOOUI(),
+ 'label' => $this->getLabel(),
+ 'help' => $helpText !== null ? new OOUI\HtmlSnippet( $helpText ) : null,
+ 'errors' => $errors,
+ 'infusable' => $infusable,
+ );
+
+ return $this->getFieldLayoutOOUI( $inputField, $config );
+ }
+
+ /**
+ * Get label alignment when generating field for OOUI.
+ * @return string 'left', 'right', 'top' or 'inline'
+ */
+ protected function getLabelAlignOOUI() {
+ return 'top';
+ }
+
+ /**
+ * Get a FieldLayout (or subclass thereof) to wrap this field in when using OOUI output.
+ * @return OOUI\\FieldLayout|OOUI\\ActionFieldLayout
+ */
+ protected function getFieldLayoutOOUI( $inputField, $config ) {
+ if ( isset( $this->mClassWithButton ) ) {
+ $buttonWidget = $this->mClassWithButton->getInputOOUI( '' );
+ return new OOUI\ActionFieldLayout( $inputField, $buttonWidget, $config );
+ }
+ return new OOUI\FieldLayout( $inputField, $config );
+ }
+
+ /**
* Get the complete raw fields for the input, including help text,
* labels, and whatever.
* @since 1.20
@@ -657,7 +750,7 @@ abstract class HTMLFormField {
/**
* Determine the help text to display
* @since 1.20
- * @return string
+ * @return string HTML
*/
public function getHelpText() {
$helptext = null;
@@ -692,7 +785,7 @@ abstract class HTMLFormField {
* @since 1.20
*
* @param string $value The value of the input
- * @return array
+ * @return array array( $errors, $errorClass )
*/
public function getErrorsAndErrorClass( $value ) {
$errors = $this->validate( $value, $this->mParent->mFieldData );
@@ -708,6 +801,35 @@ abstract class HTMLFormField {
return array( $errors, $errorClass );
}
+ /**
+ * Determine form errors to display, returning them in an array.
+ *
+ * @since 1.26
+ * @param string $value The value of the input
+ * @return string[] Array of error HTML strings
+ */
+ public function getErrorsRaw( $value ) {
+ $errors = $this->validate( $value, $this->mParent->mFieldData );
+
+ if ( is_bool( $errors ) || !$this->mParent->wasSubmitted() ) {
+ $errors = array();
+ }
+
+ if ( !is_array( $errors ) ) {
+ $errors = array( $errors );
+ }
+ foreach ( $errors as &$error ) {
+ if ( $error instanceof Message ) {
+ $error = $error->parse();
+ }
+ }
+
+ return $errors;
+ }
+
+ /**
+ * @return string
+ */
function getLabel() {
return is_null( $this->mLabel ) ? '' : $this->mLabel;
}
@@ -729,6 +851,8 @@ abstract class HTMLFormField {
$displayFormat = $this->mParent->getDisplayFormat();
$html = '';
+ $horizontalLabel = isset( $this->mParams['horizontal-label'] )
+ ? $this->mParams['horizontal-label'] : false;
if ( $displayFormat === 'table' ) {
$html =
@@ -736,7 +860,7 @@ abstract class HTMLFormField {
array( 'class' => 'mw-label' ) + $cellAttributes,
Html::rawElement( 'label', $for, $labelValue ) );
} elseif ( $hasLabel || $this->mShowEmptyLabels ) {
- if ( $displayFormat === 'div' ) {
+ if ( $displayFormat === 'div' && !$horizontalLabel ) {
$html =
Html::rawElement( 'div',
array( 'class' => 'mw-label' ) + $cellAttributes,
@@ -771,23 +895,43 @@ abstract class HTMLFormField {
}
/**
+ * Get a translated key if necessary.
+ * @param array|null $mappings Array of mappings, 'original' => 'translated'
+ * @param string $key
+ * @return string
+ */
+ protected function getMappedKey( $mappings, $key ) {
+ if ( !is_array( $mappings ) ) {
+ return $key;
+ }
+
+ if ( !empty( $mappings[$key] ) ) {
+ return $mappings[$key];
+ }
+
+ return $key;
+ }
+
+ /**
* Returns the given attributes from the parameters
*
* @param array $list List of attributes to get
+ * @param array $mappings Optional - Key/value map of attribute names to use instead of the ones passed in
* @return array Attributes
*/
- public function getAttributes( array $list ) {
+ public function getAttributes( array $list, array $mappings = null ) {
static $boolAttribs = array( 'disabled', 'required', 'autofocus', 'multiple', 'readonly' );
$ret = array();
-
foreach ( $list as $key ) {
+ $mappedKey = $this->getMappedKey( $mappings, $key );
+
if ( in_array( $key, $boolAttribs ) ) {
if ( !empty( $this->mParams[$key] ) ) {
- $ret[$key] = '';
+ $ret[$mappedKey] = $mappedKey;
}
} elseif ( isset( $this->mParams[$key] ) ) {
- $ret[$key] = $this->mParams[$key];
+ $ret[$mappedKey] = $this->mParams[$key];
}
}
@@ -877,6 +1021,29 @@ abstract class HTMLFormField {
}
/**
+ * Get options and make them into arrays suitable for OOUI.
+ * @return array Options for inclusion in a select or whatever.
+ */
+ public function getOptionsOOUI() {
+ $oldoptions = $this->getOptions();
+
+ if ( $oldoptions === null ) {
+ return null;
+ }
+
+ $options = array();
+
+ foreach ( $oldoptions as $text => $data ) {
+ $options[] = array(
+ 'data' => $data,
+ 'label' => $text,
+ );
+ }
+
+ return $options;
+ }
+
+ /**
* flatten an array of options to a single array, for instance,
* a set of "<options>" inside "<optgroups>".
*
diff --git a/includes/htmlform/HTMLFormFieldWithButton.php b/includes/htmlform/HTMLFormFieldWithButton.php
new file mode 100644
index 00000000..6b02c49d
--- /dev/null
+++ b/includes/htmlform/HTMLFormFieldWithButton.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Enables HTMLFormField elements to be build with a button.
+ */
+class HTMLFormFieldWithButton extends HTMLFormField {
+ /** @var string $mButtonClass CSS class for the button in this field */
+ protected $mButtonClass = '';
+
+ /** @var string|integer $mButtonId Element ID for the button in this field */
+ protected $mButtonId = '';
+
+ /** @var string $mButtonName Name the button in this field */
+ protected $mButtonName = '';
+
+ /** @var string $mButtonType Type of the button in this field (e.g. button or submit) */
+ protected $mButtonType = 'submit';
+
+ /** @var string $mButtonType Value for the button in this field */
+ protected $mButtonValue;
+
+ /** @var string $mButtonType Value for the button in this field */
+ protected $mButtonFlags = array( 'primary', 'progressive' );
+
+ public function __construct( $info ) {
+ if ( isset( $info['buttonclass'] ) ) {
+ $this->mButtonClass = $info['buttonclass'];
+ }
+ if ( isset( $info['buttonid'] ) ) {
+ $this->mButtonId = $info['buttonid'];
+ }
+ if ( isset( $info['buttonname'] ) ) {
+ $this->mButtonName = $info['buttonname'];
+ }
+ if ( isset( $info['buttondefault'] ) ) {
+ $this->mButtonValue = $info['buttondefault'];
+ }
+ if ( isset( $info['buttontype'] ) ) {
+ $this->mButtonType = $info['buttontype'];
+ }
+ if ( isset( $info['buttonflags'] ) ) {
+ $this->mButtonFlags = $info['buttonflags'];
+ }
+ parent::__construct( $info );
+ }
+
+ public function getInputHTML( $value ) {
+ $attr = array(
+ 'class' => 'mw-htmlform-submit ' . $this->mButtonClass,
+ 'id' => $this->mButtonId,
+ ) + $this->getAttributes( array( 'disabled', 'tabindex' ) );
+
+ return Html::input( $this->mButtonName, $this->mButtonValue, $this->mButtonType, $attr );
+ }
+
+ public function getInputOOUI( $value ) {
+ return new OOUI\ButtonInputWidget( array(
+ 'name' => $this->mButtonName,
+ 'value' => $this->mButtonValue,
+ 'type' => $this->mButtonType,
+ 'label' => $this->mButtonValue,
+ 'flags' => $this->mButtonFlags,
+ ) );
+ }
+
+ /**
+ * Combines the passed element with a button.
+ * @param String $element Element to combine the button with.
+ * @return String
+ */
+ public function getElement( $element ) {
+ return $element . '&#160;' . $this->getInputHTML( '' );
+ }
+}
diff --git a/includes/htmlform/HTMLInfoField.php b/includes/htmlform/HTMLInfoField.php
index a422047a..a667653a 100644
--- a/includes/htmlform/HTMLInfoField.php
+++ b/includes/htmlform/HTMLInfoField.php
@@ -14,6 +14,16 @@ class HTMLInfoField extends HTMLFormField {
return !empty( $this->mParams['raw'] ) ? $value : htmlspecialchars( $value );
}
+ public function getInputOOUI( $value ) {
+ if ( !empty( $this->mParams['raw'] ) ) {
+ $value = new OOUI\HtmlSnippet( $value );
+ }
+
+ return new OOUI\LabelWidget( array(
+ 'label' => $value,
+ ) );
+ }
+
public function getTableRow( $value ) {
if ( !empty( $this->mParams['rawrow'] ) ) {
return $value;
diff --git a/includes/htmlform/HTMLMultiSelectField.php b/includes/htmlform/HTMLMultiSelectField.php
index 8d28b59e..523f0455 100644
--- a/includes/htmlform/HTMLMultiSelectField.php
+++ b/includes/htmlform/HTMLMultiSelectField.php
@@ -38,34 +38,19 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable
$html = '';
$attribs = $this->getAttributes( array( 'disabled', 'tabindex' ) );
- $elementFunc = array( 'Html', $this->mOptionsLabelsNotFromMessage ? 'rawElement' : 'element' );
foreach ( $options as $label => $info ) {
if ( is_array( $info ) ) {
$html .= Html::rawElement( 'h1', array(), $label ) . "\n";
$html .= $this->formatOptions( $info, $value );
} else {
- $thisAttribs = array( 'id' => "{$this->mID}-$info", 'value' => $info );
-
- // @todo: Make this use checkLabel for consistency purposes
- $checkbox = Xml::check(
- $this->mName . '[]',
- in_array( $info, $value, true ),
- $attribs + $thisAttribs
- );
- $checkbox .= '&#160;' . call_user_func( $elementFunc,
- 'label',
- array( 'for' => "{$this->mID}-$info" ),
- $label
+ $thisAttribs = array(
+ 'id' => "{$this->mID}-$info",
+ 'value' => $info,
);
+ $checked = in_array( $info, $value, true );
- if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
- $checkbox = Html::rawElement(
- 'div',
- array( 'class' => 'mw-ui-checkbox' ),
- $checkbox
- );
- }
+ $checkbox = $this->getOneCheckbox( $checked, $attribs + $thisAttribs, $label );
$html .= ' ' . Html::rawElement(
'div',
@@ -78,6 +63,41 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable
return $html;
}
+ protected function getOneCheckbox( $checked, $attribs, $label ) {
+ if ( $this->mParent instanceof OOUIHTMLForm ) {
+ if ( $this->mOptionsLabelsNotFromMessage ) {
+ $label = new OOUI\HtmlSnippet( $label );
+ }
+ return new OOUI\FieldLayout(
+ new OOUI\CheckboxInputWidget( array(
+ 'name' => "{$this->mName}[]",
+ 'selected' => $checked,
+ 'value' => $attribs['value'],
+ ) + $attribs ),
+ array(
+ 'label' => $label,
+ 'align' => 'inline',
+ )
+ );
+ } else {
+ $elementFunc = array( 'Html', $this->mOptionsLabelsNotFromMessage ? 'rawElement' : 'element' );
+ $checkbox =
+ Xml::check( "{$this->mName}[]", $checked, $attribs ) .
+ '&#160;' .
+ call_user_func( $elementFunc,
+ 'label',
+ array( 'for' => $attribs['id'] ),
+ $label
+ );
+ if ( $this->mParent->getConfig()->get( 'UseMediaWikiUIEverywhere' ) ) {
+ $checkbox = Html::openElement( 'div', array( 'class' => 'mw-ui-checkbox' ) ) .
+ $checkbox .
+ Html::closeElement( 'div' );
+ }
+ return $checkbox;
+ }
+ }
+
/**
* @param WebRequest $request
*
diff --git a/includes/htmlform/HTMLRadioField.php b/includes/htmlform/HTMLRadioField.php
index 0f005408..2d057042 100644
--- a/includes/htmlform/HTMLRadioField.php
+++ b/includes/htmlform/HTMLRadioField.php
@@ -38,6 +38,23 @@ class HTMLRadioField extends HTMLFormField {
return $html;
}
+ function getInputOOUI( $value ) {
+ $options = array();
+ foreach ( $this->getOptions() as $label => $data ) {
+ $options[] = array(
+ 'data' => $data,
+ 'label' => $this->mOptionsLabelsNotFromMessage ? new OOUI\HtmlSnippet( $label ) : $label,
+ );
+ }
+
+ return new OOUI\RadioSelectInputWidget( array(
+ 'name' => $this->mName,
+ 'value' => $value,
+ 'options' => $options,
+ 'classes' => 'mw-htmlform-flatlist-item',
+ ) + $this->getAttributes( array( 'disabled', 'tabindex' ), array( 'tabindex' => 'tabIndex' ) ) );
+ }
+
function formatOptions( $options, $value ) {
$html = '';
diff --git a/includes/htmlform/HTMLSelectAndOtherField.php b/includes/htmlform/HTMLSelectAndOtherField.php
index a1c0c957..0e4f4f32 100644
--- a/includes/htmlform/HTMLSelectAndOtherField.php
+++ b/includes/htmlform/HTMLSelectAndOtherField.php
@@ -64,6 +64,10 @@ class HTMLSelectAndOtherField extends HTMLSelectField {
return "$select<br />\n$textbox";
}
+ function getInputOOUI( $value ) {
+ return false;
+ }
+
/**
* @param WebRequest $request
*
@@ -71,7 +75,6 @@ class HTMLSelectAndOtherField extends HTMLSelectField {
*/
function loadDataFromRequest( $request ) {
if ( $request->getCheck( $this->mName ) ) {
-
$list = $request->getText( $this->mName );
$text = $request->getText( $this->mName . '-other' );
diff --git a/includes/htmlform/HTMLSelectField.php b/includes/htmlform/HTMLSelectField.php
index a198037a..6ba69666 100644
--- a/includes/htmlform/HTMLSelectField.php
+++ b/includes/htmlform/HTMLSelectField.php
@@ -41,4 +41,26 @@ class HTMLSelectField extends HTMLFormField {
return $select->getHTML();
}
+
+ function getInputOOUI( $value ) {
+ $disabled = false;
+ $allowedParams = array( 'tabindex' );
+ $attribs = $this->getAttributes( $allowedParams, array( 'tabindex' => 'tabIndex' ) );
+
+ if ( $this->mClass !== '' ) {
+ $attribs['classes'] = array( $this->mClass );
+ }
+
+ if ( !empty( $this->mParams['disabled'] ) ) {
+ $disabled = true;
+ }
+
+ return new OOUI\DropdownInputWidget( array(
+ 'name' => $this->mName,
+ 'id' => $this->mID,
+ 'options' => $this->getOptionsOOUI(),
+ 'value' => strval( $value ),
+ 'disabled' => $disabled,
+ ) + $attribs );
+ }
}
diff --git a/includes/htmlform/HTMLSelectNamespace.php b/includes/htmlform/HTMLSelectNamespace.php
index 96381062..4efdfbf3 100644
--- a/includes/htmlform/HTMLSelectNamespace.php
+++ b/includes/htmlform/HTMLSelectNamespace.php
@@ -3,11 +3,16 @@
* Wrapper for Html::namespaceSelector to use in HTMLForm
*/
class HTMLSelectNamespace extends HTMLFormField {
+ public function __construct( $params ) {
+ parent::__construct( $params );
+ $this->mAllValue = isset( $this->mParams['all'] ) ? $this->mParams['all'] : 'all';
+ }
+
function getInputHTML( $value ) {
return Html::namespaceSelector(
array(
'selected' => $value,
- 'all' => 'all'
+ 'all' => $this->mAllValue
), array(
'name' => $this->mName,
'id' => $this->mID,
@@ -15,4 +20,13 @@ class HTMLSelectNamespace extends HTMLFormField {
)
);
}
+
+ public function getInputOOUI( $value ) {
+ return new MediaWiki\Widget\NamespaceInputWidget( array(
+ 'value' => $value,
+ 'name' => $this->mName,
+ 'id' => $this->mID,
+ 'includeAllValue' => $this->mAllValue,
+ ) );
+ }
}
diff --git a/includes/htmlform/HTMLSelectNamespaceWithButton.php b/includes/htmlform/HTMLSelectNamespaceWithButton.php
new file mode 100644
index 00000000..24b15bd7
--- /dev/null
+++ b/includes/htmlform/HTMLSelectNamespaceWithButton.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Creates a Html::namespaceSelector input field with a button assigned to the input field.
+ */
+class HTMLSelectNamespaceWithButton extends HTMLSelectNamespace {
+ /** @var HTMLFormClassWithButton $mClassWithButton */
+ protected $mClassWithButton = null;
+
+ public function __construct( $info ) {
+ $this->mClassWithButton = new HTMLFormFieldWithButton( $info );
+ parent::__construct( $info );
+ }
+
+ public function getInputHTML( $value ) {
+ return $this->mClassWithButton->getElement( parent::getInputHTML( $value ) );
+ }
+}
diff --git a/includes/htmlform/HTMLSelectOrOtherField.php b/includes/htmlform/HTMLSelectOrOtherField.php
index cbf7d122..3e7acdf8 100644
--- a/includes/htmlform/HTMLSelectOrOtherField.php
+++ b/includes/htmlform/HTMLSelectOrOtherField.php
@@ -62,6 +62,10 @@ class HTMLSelectOrOtherField extends HTMLTextField {
return "$select<br />\n$textbox";
}
+ function getInputOOUI( $value ) {
+ return false;
+ }
+
/**
* @param WebRequest $request
*
diff --git a/includes/htmlform/HTMLSubmitField.php b/includes/htmlform/HTMLSubmitField.php
index 653c08c0..938e428a 100644
--- a/includes/htmlform/HTMLSubmitField.php
+++ b/includes/htmlform/HTMLSubmitField.php
@@ -6,4 +6,6 @@
*/
class HTMLSubmitField extends HTMLButtonField {
protected $buttonType = 'submit';
+
+ protected $mFlags = array( 'primary', 'constructive' );
}
diff --git a/includes/htmlform/HTMLTextAreaField.php b/includes/htmlform/HTMLTextAreaField.php
index 21173d2a..aeb4b7c2 100644
--- a/includes/htmlform/HTMLTextAreaField.php
+++ b/includes/htmlform/HTMLTextAreaField.php
@@ -12,11 +12,21 @@ class HTMLTextAreaField extends HTMLFormField {
return isset( $this->mParams['rows'] ) ? $this->mParams['rows'] : static::DEFAULT_ROWS;
}
+ function getSpellCheck() {
+ $val = isset( $this->mParams['spellcheck'] ) ? $this->mParams['spellcheck'] : null;
+ if ( is_bool( $val ) ) {
+ // "spellcheck" attribute literally requires "true" or "false" to work.
+ return $val === true ? 'true' : 'false';
+ }
+ return null;
+ }
+
function getInputHTML( $value ) {
$attribs = array(
'id' => $this->mID,
'cols' => $this->getCols(),
'rows' => $this->getRows(),
+ 'spellcheck' => $this->getSpellCheck(),
) + $this->getTooltipAndAccessKey();
if ( $this->mClass !== '' ) {
@@ -35,4 +45,38 @@ class HTMLTextAreaField extends HTMLFormField {
$attribs += $this->getAttributes( $allowedParams );
return Html::textarea( $this->mName, $value, $attribs );
}
+
+ function getInputOOUI( $value ) {
+ if ( isset( $this->mParams['cols'] ) ) {
+ throw new Exception( "OOUIHTMLForm does not support the 'cols' parameter for textareas" );
+ }
+
+ $attribs = $this->getTooltipAndAccessKey();
+
+ if ( $this->mClass !== '' ) {
+ $attribs['classes'] = array( $this->mClass );
+ }
+
+ $allowedParams = array(
+ 'placeholder',
+ 'tabindex',
+ 'disabled',
+ 'readonly',
+ 'required',
+ 'autofocus',
+ );
+
+ $attribs += $this->getAttributes( $allowedParams, array(
+ 'tabindex' => 'tabIndex',
+ 'readonly' => 'readOnly',
+ ) );
+
+ return new OOUI\TextInputWidget( array(
+ 'id' => $this->mID,
+ 'name' => $this->mName,
+ 'multiline' => true,
+ 'value' => $value,
+ 'rows' => $this->getRows(),
+ ) + $attribs );
+ }
}
diff --git a/includes/htmlform/HTMLTextField.php b/includes/htmlform/HTMLTextField.php
index 88df49db..157116d8 100644
--- a/includes/htmlform/HTMLTextField.php
+++ b/includes/htmlform/HTMLTextField.php
@@ -5,12 +5,23 @@ class HTMLTextField extends HTMLFormField {
return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 45;
}
+ function getSpellCheck() {
+ $val = isset( $this->mParams['spellcheck'] ) ? $this->mParams['spellcheck'] : null;
+ if ( is_bool( $val ) ) {
+ // "spellcheck" attribute literally requires "true" or "false" to work.
+ return $val === true ? 'true' : 'false';
+ }
+ return null;
+ }
+
function getInputHTML( $value ) {
$attribs = array(
'id' => $this->mID,
'name' => $this->mName,
'size' => $this->getSize(),
'value' => $value,
+ 'dir' => $this->mDir,
+ 'spellcheck' => $this->getSpellCheck(),
) + $this->getTooltipAndAccessKey();
if ( $this->mClass !== '' ) {
@@ -40,6 +51,11 @@ class HTMLTextField extends HTMLFormField {
$attribs += $this->getAttributes( $allowedParams );
# Extract 'type'
+ $type = $this->getType( $attribs );
+ return Html::input( $this->mName, $value, $type, $attribs );
+ }
+
+ protected function getType( &$attribs ) {
$type = isset( $attribs['type'] ) ? $attribs['type'] : 'text';
unset( $attribs['type'] );
@@ -65,6 +81,49 @@ class HTMLTextField extends HTMLFormField {
}
}
- return Html::input( $this->mName, $value, $type, $attribs );
+ return $type;
+ }
+
+ function getInputOOUI( $value ) {
+ $attribs = $this->getTooltipAndAccessKey();
+
+ if ( $this->mClass !== '' ) {
+ $attribs['classes'] = array( $this->mClass );
+ }
+
+ # @todo Enforce pattern, step, required, readonly on the server side as
+ # well
+ $allowedParams = array(
+ 'autofocus',
+ 'autosize',
+ 'disabled',
+ 'flags',
+ 'indicator',
+ 'maxlength',
+ 'placeholder',
+ 'readonly',
+ 'required',
+ 'tabindex',
+ 'type',
+ );
+
+ $attribs += $this->getAttributes( $allowedParams, array(
+ 'maxlength' => 'maxLength',
+ 'readonly' => 'readOnly',
+ 'tabindex' => 'tabIndex',
+ ) );
+
+ $type = $this->getType( $attribs );
+
+ return $this->getInputWidget( array(
+ 'id' => $this->mID,
+ 'name' => $this->mName,
+ 'value' => $value,
+ 'type' => $type,
+ ) + $attribs );
+ }
+
+ protected function getInputWidget( $params ) {
+ return new OOUI\TextInputWidget( $params );
}
}
diff --git a/includes/htmlform/HTMLTextFieldWithButton.php b/includes/htmlform/HTMLTextFieldWithButton.php
new file mode 100644
index 00000000..c6dac322
--- /dev/null
+++ b/includes/htmlform/HTMLTextFieldWithButton.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Creates a text input field with a button assigned to the input field.
+ */
+class HTMLTextFieldWithButton extends HTMLTextField {
+ /** @var HTMLFormClassWithButton $mClassWithButton */
+ protected $mClassWithButton = null;
+
+ public function __construct( $info ) {
+ $this->mClassWithButton = new HTMLFormFieldWithButton( $info );
+ parent::__construct( $info );
+ }
+
+ public function getInputHTML( $value ) {
+ return $this->mClassWithButton->getElement( parent::getInputHTML( $value ) );
+ }
+}
diff --git a/includes/htmlform/HTMLTitleTextField.php b/includes/htmlform/HTMLTitleTextField.php
new file mode 100644
index 00000000..a225c67c
--- /dev/null
+++ b/includes/htmlform/HTMLTitleTextField.php
@@ -0,0 +1,81 @@
+<?php
+
+use MediaWiki\Widget\TitleInputWidget;
+
+/**
+ * Implements a text input field for page titles.
+ * Automatically does validation that the title is valid,
+ * as well as autocompletion if using the OOUI display format.
+ *
+ * Note: Forms using GET requests will need to make sure the title value is not
+ * an empty string.
+ *
+ * Optional parameters:
+ * 'namespace' - Namespace the page must be in
+ * 'relative' - If true and 'namespace' given, strip/add the namespace from/to the title as needed
+ * 'creatable' - Whether to validate the title is creatable (not a special page)
+ * 'exists' - Whether to validate that the title already exists
+ *
+ * @since 1.26
+ */
+class HTMLTitleTextField extends HTMLTextField {
+ public function __construct( $params ) {
+ $params += array(
+ 'namespace' => false,
+ 'relative' => false,
+ 'creatable' => false,
+ 'exists' => false,
+ );
+
+ parent::__construct( $params );
+ }
+
+ public function validate( $value, $alldata ) {
+ if ( $this->mParent->getMethod() === 'get' && $value === '' ) {
+ // If the form is a GET form and has no value, assume it hasn't been
+ // submitted yet, and skip validation
+ return parent::validate( $value, $alldata );
+ }
+ try {
+ if ( !$this->mParams['relative'] ) {
+ $title = Title::newFromTextThrow( $value );
+ } else {
+ // Can't use Title::makeTitleSafe(), because it doesn't throw useful exceptions
+ global $wgContLang;
+ $namespaceName = $wgContLang->getNsText( $this->mParams['namespace'] );
+ $title = Title::newFromTextThrow( $namespaceName . ':' . $value );
+ }
+ } catch ( MalformedTitleException $e ) {
+ $msg = $this->msg( $e->getErrorMessage() );
+ $params = $e->getErrorMessageParameters();
+ if ( $params ) {
+ $msg->params( $params );
+ }
+ return $msg->parse();
+ }
+
+ $text = $title->getPrefixedText();
+ if ( $this->mParams['namespace'] !== false && !$title->inNamespace( $this->mParams['namespace'] ) ) {
+ return $this->msg( 'htmlform-title-badnamespace', $this->mParams['namespace'], $text )->parse();
+ }
+
+ if ( $this->mParams['creatable'] && !$title->canExist() ) {
+ return $this->msg( 'htmlform-title-not-creatable', $text )->escaped();
+ }
+
+ if ( $this->mParams['exists'] && !$title->exists() ) {
+ return $this->msg( 'htmlform-title-not-exists', $text )->parse();
+ }
+
+ return parent::validate( $value, $alldata );
+ }
+
+ protected function getInputWidget( $params ) {
+ $this->mParent->getOutput()->addModules( 'mediawiki.widgets' );
+ if ( $this->mParams['namespace'] !== false ) {
+ $params['namespace'] = $this->mParams['namespace'];
+ }
+ $params['relative'] = $this->mParams['relative'];
+ return new TitleInputWidget( $params );
+ }
+}
diff --git a/includes/htmlform/HTMLUserTextField.php b/includes/htmlform/HTMLUserTextField.php
new file mode 100644
index 00000000..9617c0a3
--- /dev/null
+++ b/includes/htmlform/HTMLUserTextField.php
@@ -0,0 +1,47 @@
+<?php
+
+use MediaWiki\Widget\UserInputWidget;
+
+/**
+ * Implements a text input field for user names.
+ * Automatically auto-completes if using the OOUI display format.
+ *
+ * FIXME: Does not work for forms that support GET requests.
+ *
+ * Optional parameters:
+ * 'exists' - Whether to validate that the user already exists
+ *
+ * @since 1.26
+ */
+class HTMLUserTextField extends HTMLTextField {
+ public function __construct( $params ) {
+ $params += array(
+ 'exists' => false,
+ 'ipallowed' => false,
+ );
+
+ parent::__construct( $params );
+ }
+
+ public function validate( $value, $alldata ) {
+ // check, if a user exists with the given username
+ $user = User::newFromName( $value, false );
+
+ if ( !$user ) {
+ return $this->msg( 'htmlform-user-not-valid', $value )->parse();
+ } elseif (
+ ( $this->mParams['exists'] && $user->getId() === 0 ) &&
+ !( $this->mParams['ipallowed'] && User::isIP( $value ) )
+ ) {
+ return $this->msg( 'htmlform-user-not-exists', $user->getName() )->parse();
+ }
+
+ return parent::validate( $value, $alldata );
+ }
+
+ protected function getInputWidget( $params ) {
+ $this->mParent->getOutput()->addModules( 'mediawiki.widgets.UserInputWidget' );
+
+ return new UserInputWidget( $params );
+ }
+}
diff --git a/includes/htmlform/OOUIHTMLForm.php b/includes/htmlform/OOUIHTMLForm.php
new file mode 100644
index 00000000..84d40a14
--- /dev/null
+++ b/includes/htmlform/OOUIHTMLForm.php
@@ -0,0 +1,221 @@
+<?php
+
+/**
+ * HTML form generation and submission handling, OOUI style.
+ *
+ * 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
+ */
+
+/**
+ * Compact stacked vertical format for forms, implemented using OOUI widgets.
+ */
+class OOUIHTMLForm extends HTMLForm {
+ private $oouiErrors;
+
+ public function __construct( $descriptor, $context = null, $messagePrefix = '' ) {
+ parent::__construct( $descriptor, $context, $messagePrefix );
+ $this->getOutput()->enableOOUI();
+ $this->getOutput()->addModuleStyles( 'mediawiki.htmlform.ooui.styles' );
+ }
+
+ /**
+ * Symbolic display format name.
+ * @var string
+ */
+ protected $displayFormat = 'ooui';
+
+ public static function loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent = null ) {
+ $field = parent::loadInputFromParameters( $fieldname, $descriptor, $parent );
+ $field->setShowEmptyLabel( false );
+ return $field;
+ }
+
+ function getButtons() {
+ $buttons = '';
+
+ if ( $this->mShowSubmit ) {
+ $attribs = array( 'infusable' => true );
+
+ if ( isset( $this->mSubmitID ) ) {
+ $attribs['id'] = $this->mSubmitID;
+ }
+
+ if ( isset( $this->mSubmitName ) ) {
+ $attribs['name'] = $this->mSubmitName;
+ }
+
+ if ( isset( $this->mSubmitTooltip ) ) {
+ $attribs += Linker::tooltipAndAccesskeyAttribs( $this->mSubmitTooltip );
+ }
+
+ $attribs['classes'] = array( 'mw-htmlform-submit' );
+ $attribs['type'] = 'submit';
+ $attribs['label'] = $this->getSubmitText();
+ $attribs['value'] = $this->getSubmitText();
+ $attribs['flags'] = $this->mSubmitFlags;
+
+ $buttons .= new OOUI\ButtonInputWidget( $attribs );
+ }
+
+ if ( $this->mShowReset ) {
+ $buttons .= new OOUI\ButtonInputWidget( array(
+ 'type' => 'reset',
+ 'label' => $this->msg( 'htmlform-reset' )->text(),
+ ) );
+ }
+
+ foreach ( $this->mButtons as $button ) {
+ $attrs = array();
+
+ if ( $button['attribs'] ) {
+ $attrs += $button['attribs'];
+ }
+
+ if ( isset( $button['id'] ) ) {
+ $attrs['id'] = $button['id'];
+ }
+
+ $attrs['classes'] = isset( $attrs['class'] ) ? (array)$attrs['class'] : array();
+
+ $buttons .= new OOUI\ButtonInputWidget( array(
+ 'type' => 'submit',
+ 'name' => $button['name'],
+ 'value' => $button['value'],
+ 'label' => $button['value'],
+ ) + $attrs );
+ }
+
+ $html = Html::rawElement( 'div',
+ array( 'class' => 'mw-htmlform-submit-buttons' ), "\n$buttons" ) . "\n";
+
+ return $html;
+ }
+
+ /**
+ * Put a form section together from the individual fields' HTML, merging it and wrapping.
+ * @param OOUI\\FieldLayout[] $fieldsHtml
+ * @param string $sectionName
+ * @param bool $anyFieldHasLabel Unused
+ * @return string HTML
+ */
+ protected function formatSection( array $fieldsHtml, $sectionName, $anyFieldHasLabel ) {
+ $config = array(
+ 'items' => $fieldsHtml,
+ );
+ if ( $sectionName ) {
+ $config['id'] = Sanitizer::escapeId( $sectionName );
+ }
+ if ( is_string( $this->mWrapperLegend ) ) {
+ $config['label'] = $this->mWrapperLegend;
+ }
+ return new OOUI\FieldsetLayout( $config );
+ }
+
+ /**
+ * @param string|array|Status $err
+ * @return string
+ */
+ function getErrors( $err ) {
+ if ( !$err ) {
+ $errors = array();
+ } else if ( $err instanceof Status ) {
+ if ( $err->isOK() ) {
+ $errors = array();
+ } else {
+ $errors = $err->getErrorsByType( 'error' );
+ foreach ( $errors as &$error ) {
+ // Input: array( 'message' => 'foo', 'errors' => array( 'a', 'b', 'c' ) )
+ // Output: array( 'foo', 'a', 'b', 'c' )
+ $error = array_merge( array( $error['message'] ), $error['params'] );
+ }
+ }
+ } else {
+ $errors = $err;
+ if ( !is_array( $errors ) ) {
+ $errors = array( $errors );
+ }
+ }
+
+ foreach ( $errors as &$error ) {
+ if ( is_array( $error ) ) {
+ $msg = array_shift( $error );
+ } else {
+ $msg = $error;
+ $error = array();
+ }
+ $error = $this->msg( $msg, $error )->parse();
+ $error = new OOUI\HtmlSnippet( $error );
+ }
+
+ // Used in getBody()
+ $this->oouiErrors = $errors;
+ return '';
+ }
+
+ function getHeaderText( $section = null ) {
+ if ( is_null( $section ) ) {
+ // We handle $this->mHeader elsewhere, in getBody()
+ return '';
+ } else {
+ return parent::getHeaderText( $section );
+ }
+ }
+
+ function getBody() {
+ $fieldset = parent::getBody();
+ // FIXME This only works for forms with no subsections
+ if ( $fieldset instanceof OOUI\FieldsetLayout ) {
+ $classes = array( 'mw-htmlform-ooui-header' );
+ if ( !$this->mHeader ) {
+ $classes[] = 'mw-htmlform-ooui-header-empty';
+ }
+ if ( $this->oouiErrors ) {
+ $classes[] = 'mw-htmlform-ooui-header-errors';
+ }
+ $fieldset->addItems( array(
+ new OOUI\FieldLayout(
+ new OOUI\LabelWidget( array( 'label' => new OOUI\HtmlSnippet( $this->mHeader ) ) ),
+ array(
+ 'align' => 'top',
+ 'errors' => $this->oouiErrors,
+ 'classes' => $classes,
+ )
+ )
+ ), 0 );
+ }
+ return $fieldset;
+ }
+
+ function wrapForm( $html ) {
+ $form = new OOUI\FormLayout( $this->getFormAttributes() + array(
+ 'classes' => array( 'mw-htmlform-ooui' ),
+ 'content' => new OOUI\HtmlSnippet( $html ),
+ ) );
+
+ // Include a wrapper for style, if requested.
+ $form = new OOUI\PanelLayout( array(
+ 'classes' => array( 'mw-htmlform-ooui-wrapper' ),
+ 'expanded' => false,
+ 'padded' => $this->mWrapperLegend !== false,
+ 'framed' => $this->mWrapperLegend !== false,
+ 'content' => $form,
+ ) );
+
+ return $form;
+ }
+}
diff --git a/includes/htmlform/VFormHTMLForm.php b/includes/htmlform/VFormHTMLForm.php
index 0c0e4252..3788379d 100644
--- a/includes/htmlform/VFormHTMLForm.php
+++ b/includes/htmlform/VFormHTMLForm.php
@@ -65,7 +65,7 @@ class VFormHTMLForm extends HTMLForm {
protected function getFormAttributes() {
$attribs = parent::getFormAttributes();
- array_push( $attribs['class'], 'mw-ui-vform', 'mw-ui-container' );
+ $attribs['class'] = array( 'mw-ui-vform', 'mw-ui-container', 'visualClear' );
return $attribs;
}
@@ -95,8 +95,10 @@ class VFormHTMLForm extends HTMLForm {
$attribs['class'] = array(
'mw-htmlform-submit',
'mw-ui-button mw-ui-big mw-ui-block',
- $this->mSubmitModifierClass,
);
+ foreach ( $this->mSubmitFlags as $flag ) {
+ $attribs['class'][] = 'mw-ui-' . $flag;
+ }
$buttons .= Xml::submitButton( $this->getSubmitText(), $attribs ) . "\n";
}
diff --git a/includes/installer/DatabaseInstaller.php b/includes/installer/DatabaseInstaller.php
index 6ccf2d55..752450fb 100644
--- a/includes/installer/DatabaseInstaller.php
+++ b/includes/installer/DatabaseInstaller.php
@@ -649,10 +649,10 @@ abstract class DatabaseInstaller {
return $status;
}
global $IP;
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$rows = file( "$IP/maintenance/interwiki.list",
FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
$interwikis = array();
if ( !$rows ) {
return Status::newFatal( 'config-install-interwiki-list' );
diff --git a/includes/installer/DatabaseUpdater.php b/includes/installer/DatabaseUpdater.php
index 70707901..4e5f357e 100644
--- a/includes/installer/DatabaseUpdater.php
+++ b/includes/installer/DatabaseUpdater.php
@@ -73,7 +73,8 @@ abstract class DatabaseUpdater {
'PopulateImageSha1',
'FixExtLinksProtocolRelative',
'PopulateFilearchiveSha1',
- 'PopulateBacklinkNamespace'
+ 'PopulateBacklinkNamespace',
+ 'FixDefaultJsonContentPages'
);
/**
diff --git a/includes/installer/Installer.php b/includes/installer/Installer.php
index 5ae499db..662469b9 100644
--- a/includes/installer/Installer.php
+++ b/includes/installer/Installer.php
@@ -146,7 +146,6 @@ abstract class Installer {
* @var array
*/
protected $envPreps = array(
- 'envPrepExtension',
'envPrepServer',
'envPrepPath',
);
@@ -177,7 +176,6 @@ abstract class Installer {
'wgGitBin',
'IP',
'wgScriptPath',
- 'wgScriptExtension',
'wgMetaNamespace',
'wgDeletedDirectory',
'wgEnableUploads',
@@ -540,9 +538,13 @@ abstract class Installer {
global $wgAutoloadClasses;
$wgAutoloadClasses = array();
- wfSuppressWarnings();
+ // LocalSettings.php should not call functions, except wfLoadSkin/wfLoadExtensions
+ // Define the required globals here, to ensure, the functions can do it work correctly.
+ global $wgExtensionDirectory, $wgStyleDirectory;
+
+ MediaWiki\suppressWarnings();
$_lsExists = file_exists( "$IP/LocalSettings.php" );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$_lsExists ) {
return false;
@@ -830,14 +832,14 @@ abstract class Installer {
* @return bool
*/
protected function envCheckPCRE() {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$regexd = preg_replace( '/[\x{0430}-\x{04FF}]/iu', '', '-АБВГД-' );
// Need to check for \p support too, as PCRE can be compiled
// with utf8 support, but not unicode property support.
// check that \p{Zs} (space separators) matches
// U+3000 (Ideographic space)
$regexprop = preg_replace( '/\p{Zs}/u', '', "-\xE3\x80\x80-" );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $regexd != '--' || $regexprop != '--' ) {
$this->showError( 'config-pcre-no-utf8' );
@@ -1125,12 +1127,12 @@ abstract class Installer {
} elseif ( $c <= 0x7FF ) {
return chr( 0xC0 | $c >> 6 ) . chr( 0x80 | $c & 0x3F );
} elseif ( $c <= 0xFFFF ) {
- return chr( 0xE0 | $c >> 12 ) . chr( 0x80 | $c >> 6 & 0x3F )
- . chr( 0x80 | $c & 0x3F );
+ return chr( 0xE0 | $c >> 12 ) . chr( 0x80 | $c >> 6 & 0x3F ) .
+ chr( 0x80 | $c & 0x3F );
} elseif ( $c <= 0x10FFFF ) {
- return chr( 0xF0 | $c >> 18 ) . chr( 0x80 | $c >> 12 & 0x3F )
- . chr( 0x80 | $c >> 6 & 0x3F )
- . chr( 0x80 | $c & 0x3F );
+ return chr( 0xF0 | $c >> 18 ) . chr( 0x80 | $c >> 12 & 0x3F ) .
+ chr( 0x80 | $c >> 6 & 0x3F ) .
+ chr( 0x80 | $c & 0x3F );
} else {
return false;
}
@@ -1228,19 +1230,6 @@ abstract class Installer {
abstract protected function envGetDefaultServer();
/**
- * Environment prep for setting the preferred PHP file extension.
- */
- protected function envPrepExtension() {
- // @todo FIXME: Detect this properly
- if ( defined( 'MW_INSTALL_PHP5_EXT' ) ) {
- $ext = '.php5';
- } else {
- $ext = '.php';
- }
- $this->setVar( 'wgScriptExtension', $ext );
- }
-
- /**
* Environment prep for setting $IP and $wgScriptPath.
*/
protected function envPrepPath() {
@@ -1289,9 +1278,9 @@ abstract class Installer {
foreach ( $names as $name ) {
$command = $path . DIRECTORY_SEPARATOR . $name;
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$file_exists = file_exists( $command );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $file_exists ) {
if ( !$versionInfo ) {
@@ -1349,7 +1338,7 @@ abstract class Installer {
// it would be good to check other popular languages here, but it'll be slow.
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
foreach ( $scriptTypes as $ext => $contents ) {
foreach ( $contents as $source ) {
@@ -1368,14 +1357,14 @@ abstract class Installer {
unlink( $dir . $file );
if ( $text == 'exec' ) {
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $ext;
}
}
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return false;
}
@@ -1809,8 +1798,8 @@ abstract class Installer {
* Some long-running pages (Install, Upgrade) will want to do this
*/
protected function disableTimeLimit() {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
set_time_limit( 0 );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
}
diff --git a/includes/installer/LocalSettingsGenerator.php b/includes/installer/LocalSettingsGenerator.php
index 162a7897..ddefd673 100644
--- a/includes/installer/LocalSettingsGenerator.php
+++ b/includes/installer/LocalSettingsGenerator.php
@@ -57,7 +57,7 @@ class LocalSettingsGenerator {
$confItems = array_merge(
array(
- 'wgServer', 'wgScriptPath', 'wgScriptExtension',
+ 'wgServer', 'wgScriptPath',
'wgPasswordSender', 'wgImageMagickConvertCommand', 'wgShellLocale',
'wgLanguageCode', 'wgEnableEmail', 'wgEnableUserEmail', 'wgDiff3',
'wgEnotifUserTalk', 'wgEnotifWatchlist', 'wgEmailAuthentication',
@@ -331,13 +331,12 @@ if ( !defined( 'MEDIAWIKI' ) ) {
## (like /w/index.php/Page_title to /wiki/Page_title) please see:
## https://www.mediawiki.org/wiki/Manual:Short_URL
\$wgScriptPath = \"{$this->values['wgScriptPath']}\";
-\$wgScriptExtension = \"{$this->values['wgScriptExtension']}\";
${serverSetting}
-## The relative URL path to the skins directory
-\$wgStylePath = \"\$wgScriptPath/skins\";
+
+## The URL path to static resources (images, scripts, etc.)
\$wgResourceBasePath = \$wgScriptPath;
-## The relative URL path to the logo. Make sure you change this from the default,
+## The URL path to the logo. Make sure you change this from the default,
## or else you'll overwrite your logo when you upgrade!
\$wgLogo = \"{$this->values['wgLogo']}\";
@@ -372,7 +371,7 @@ ${serverSetting}
{$magic}\$wgUseImageMagick = true;
{$magic}\$wgImageMagickConvertCommand = \"{$this->values['wgImageMagickConvertCommand']}\";
-# InstantCommons allows wiki to use images from http://commons.wikimedia.org
+# InstantCommons allows wiki to use images from https://commons.wikimedia.org
\$wgUseInstantCommons = {$this->values['wgUseInstantCommons']};
## If you use ImageMagick (or any other shell command) on a
diff --git a/includes/installer/MssqlInstaller.php b/includes/installer/MssqlInstaller.php
index 5a8403f5..4d79d966 100644
--- a/includes/installer/MssqlInstaller.php
+++ b/includes/installer/MssqlInstaller.php
@@ -537,7 +537,6 @@ class MssqlInstaller extends DatabaseInstaller {
$this->setupSchemaVars();
$dbName = $this->getVar( 'wgDBname' );
$this->db->selectDB( $dbName );
- $server = $this->getVar( 'wgDBserver' );
$password = $this->getVar( 'wgDBpassword' );
$schemaName = $this->getVar( 'wgDBmwschema' );
diff --git a/includes/installer/MssqlUpdater.php b/includes/installer/MssqlUpdater.php
index 5eef3355..164cfab4 100644
--- a/includes/installer/MssqlUpdater.php
+++ b/includes/installer/MssqlUpdater.php
@@ -41,7 +41,7 @@ class MssqlUpdater extends DatabaseUpdater {
array( 'addField', 'mwuser', 'user_password_expires', 'patch-user_password_expires.sql' ),
// 1.24
- array( 'addField', 'page', 'page_lang', 'patch-page-page_lang.sql'),
+ array( 'addField', 'page', 'page_lang', 'patch-page-page_lang.sql' ),
// 1.25
array( 'dropTable', 'hitcounter' ),
diff --git a/includes/installer/MysqlInstaller.php b/includes/installer/MysqlInstaller.php
index 3af08d60..e5c1a1db 100644
--- a/includes/installer/MysqlInstaller.php
+++ b/includes/installer/MysqlInstaller.php
@@ -93,9 +93,7 @@ class MysqlInstaller extends DatabaseInstaller {
public function submitConnectForm() {
// Get variables from the request.
- $newValues = $this->setVarsFromRequest( array(
- 'wgDBserver', 'wgDBname', 'wgDBprefix', '_InstallUser', '_InstallPassword'
- ) );
+ $newValues = $this->setVarsFromRequest( array( 'wgDBserver', 'wgDBname', 'wgDBprefix' ) );
// Validate them.
$status = Status::newGood();
@@ -110,12 +108,6 @@ class MysqlInstaller extends DatabaseInstaller {
if ( !preg_match( '/^[a-z0-9_-]*$/i', $newValues['wgDBprefix'] ) ) {
$status->fatal( 'config-invalid-db-prefix', $newValues['wgDBprefix'] );
}
- if ( !strlen( $newValues['_InstallUser'] ) ) {
- $status->fatal( 'config-db-username-empty' );
- }
- if ( !strlen( $newValues['_InstallPassword'] ) ) {
- $status->fatal( 'config-db-password-empty', $newValues['_InstallUser'] );
- }
if ( !$status->isOK() ) {
return $status;
}
diff --git a/includes/installer/MysqlUpdater.php b/includes/installer/MysqlUpdater.php
index 52a09222..aa60c01b 100644
--- a/includes/installer/MysqlUpdater.php
+++ b/includes/installer/MysqlUpdater.php
@@ -270,6 +270,11 @@ class MysqlUpdater extends DatabaseUpdater {
array( 'doUserNewTalkUseridUnsigned' ),
// note this patch covers other _comment and _description fields too
array( 'modifyField', 'recentchanges', 'rc_comment', 'patch-editsummary-length.sql' ),
+
+ // 1.26
+ array( 'dropTable', 'hitcounter' ),
+ array( 'dropField', 'site_stats', 'ss_total_views', 'patch-drop-ss_total_views.sql' ),
+ array( 'dropField', 'page', 'page_counter', 'patch-drop-page_counter.sql' ),
);
}
diff --git a/includes/installer/PostgresInstaller.php b/includes/installer/PostgresInstaller.php
index b18fe944..cb40f884 100644
--- a/includes/installer/PostgresInstaller.php
+++ b/includes/installer/PostgresInstaller.php
@@ -83,10 +83,7 @@ class PostgresInstaller extends DatabaseInstaller {
function submitConnectForm() {
// Get variables from the request
- $newValues = $this->setVarsFromRequest( array(
- 'wgDBserver', 'wgDBport', 'wgDBname', 'wgDBmwschema',
- '_InstallUser', '_InstallPassword'
- ) );
+ $newValues = $this->setVarsFromRequest( array( 'wgDBserver', 'wgDBport', 'wgDBname', 'wgDBmwschema' ) );
// Validate them
$status = Status::newGood();
@@ -98,12 +95,6 @@ class PostgresInstaller extends DatabaseInstaller {
if ( !preg_match( '/^[a-zA-Z0-9_]*$/', $newValues['wgDBmwschema'] ) ) {
$status->fatal( 'config-invalid-schema', $newValues['wgDBmwschema'] );
}
- if ( !strlen( $newValues['_InstallUser'] ) ) {
- $status->fatal( 'config-db-username-empty' );
- }
- if ( !strlen( $newValues['_InstallPassword'] ) ) {
- $status->fatal( 'config-db-password-empty', $newValues['_InstallUser'] );
- }
// Submit user box
if ( $status->isOK() ) {
diff --git a/includes/installer/PostgresUpdater.php b/includes/installer/PostgresUpdater.php
index 6ac54360..e1063b0f 100644
--- a/includes/installer/PostgresUpdater.php
+++ b/includes/installer/PostgresUpdater.php
@@ -407,6 +407,8 @@ class PostgresUpdater extends DatabaseUpdater {
array( 'addPgField', 'mwuser', 'user_password_expires', 'TIMESTAMPTZ NULL' ),
array( 'changeFieldPurgeTable', 'l10n_cache', 'lc_value', 'bytea',
"replace(lc_value,'\','\\\\')::bytea" ),
+ // 1.23.9
+ array( 'rebuildTextSearch' ),
// 1.24
array( 'addPgField', 'page_props', 'pp_sortkey', 'float NULL' ),
@@ -947,4 +949,12 @@ END;
$this->applyPatch( 'patch-tsearch2funcs.sql', false, "Rewriting tsearch2 triggers" );
}
}
+
+ protected function rebuildTextSearch() {
+ if ( $this->updateRowExists( 'patch-textsearch_bug66650.sql' ) ) {
+ $this->output( "...bug 66650 already fixed or not applicable.\n" );
+ return true;
+ };
+ $this->applyPatch( 'patch-textsearch_bug66650.sql', false, "Rebuilding text search for bug 66650" );
+ }
}
diff --git a/includes/installer/SqliteInstaller.php b/includes/installer/SqliteInstaller.php
index f990ddf5..43b809c9 100644
--- a/includes/installer/SqliteInstaller.php
+++ b/includes/installer/SqliteInstaller.php
@@ -157,9 +157,9 @@ class SqliteInstaller extends DatabaseInstaller {
# Called early on in the installer, later we just want to sanity check
# if it's still writable
if ( $create ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = wfMkdirParents( $dir, 0700, __METHOD__ );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$ok ) {
return Status::newFatal( 'config-sqlite-mkdir-error', $dir );
}
diff --git a/includes/installer/WebInstaller.php b/includes/installer/WebInstaller.php
index 156606a6..8e58e294 100644
--- a/includes/installer/WebInstaller.php
+++ b/includes/installer/WebInstaller.php
@@ -386,15 +386,19 @@ class WebInstaller extends Installer {
}
/**
- * Show an error message in a box. Parameters are like wfMessage().
- * @param string $msg
+ * Show an error message in a box. Parameters are like wfMessage(), or
+ * alternatively, pass a Message object in.
+ * @param string|Message $msg
*/
public function showError( $msg /*...*/ ) {
- $args = func_get_args();
- array_shift( $args );
- $args = array_map( 'htmlspecialchars', $args );
- $msg = wfMessage( $msg, $args )->useDatabase( false )->plain();
- $this->output->addHTML( $this->getErrorBox( $msg ) );
+ if ( !( $msg instanceof Message ) ) {
+ $args = func_get_args();
+ array_shift( $args );
+ $args = array_map( 'htmlspecialchars', $args );
+ $msg = wfMessage( $msg, $args );
+ }
+ $text = $msg->useDatabase( false )->plain();
+ $this->output->addHTML( $this->getErrorBox( $text ) );
}
/**
@@ -696,11 +700,11 @@ class WebInstaller extends Installer {
$text = wfMessage( $msg, $args )->useDatabase( false )->plain();
$html = $this->parse( $text, true );
- return "<div class=\"mw-help-field-container\">\n" .
- "<span class=\"mw-help-field-hint\" title=\"" .
+ return "<div class=\"config-help-field-container\">\n" .
+ "<span class=\"config-help-field-hint\" title=\"" .
wfMessage( 'config-help-tooltip' )->escaped() . "\">" .
wfMessage( 'config-help' )->escaped() . "</span>\n" .
- "<span class=\"mw-help-field-data\">" . $html . "</span>\n" .
+ "<span class=\"config-help-field-data\">" . $html . "</span>\n" .
"</div>\n";
}
@@ -1184,12 +1188,11 @@ class WebInstaller extends Installer {
}
if ( $path !== false ) {
$scriptPath = preg_replace( '{^(.*)/(mw-)?config.*$}', '$1', $path );
- $scriptExtension = $this->getVar( 'wgScriptExtension' );
$this->setVar( 'wgScriptPath', "$scriptPath" );
// Update variables set from Setup.php that are derived from wgScriptPath
- $this->setVar( 'wgScript', "$scriptPath/index$scriptExtension" );
- $this->setVar( 'wgLoadScript', "$scriptPath/load$scriptExtension" );
+ $this->setVar( 'wgScript', "$scriptPath/index.php" );
+ $this->setVar( 'wgLoadScript', "$scriptPath/load.php" );
$this->setVar( 'wgStylePath', "$scriptPath/skins" );
$this->setVar( 'wgLocalStylePath', "$scriptPath/skins" );
$this->setVar( 'wgExtensionAssetsPath', "$scriptPath/extensions" );
diff --git a/includes/installer/WebInstallerPage.php b/includes/installer/WebInstallerPage.php
index 98f3ae8a..151aad0a 100644
--- a/includes/installer/WebInstallerPage.php
+++ b/includes/installer/WebInstallerPage.php
@@ -287,10 +287,10 @@ class WebInstallerLanguage extends WebInstallerPage {
public function getLanguageSelector( $name, $label, $selectedCode, $helpHtml = '' ) {
global $wgDummyLanguageCodes;
- $s = $helpHtml;
+ $output = $helpHtml;
- $s .= Html::openElement( 'select', array( 'id' => $name, 'name' => $name,
- 'tabindex' => $this->parent->nextTabIndex() ) ) . "\n";
+ $select = new XmlSelect( $name, $name, $selectedCode );
+ $select->setAttribute( 'tabindex', $this->parent->nextTabIndex() );
$languages = Language::fetchLanguageNames();
ksort( $languages );
@@ -298,11 +298,11 @@ class WebInstallerLanguage extends WebInstallerPage {
if ( isset( $wgDummyLanguageCodes[$code] ) ) {
continue;
}
- $s .= "\n" . Xml::option( "$code - $lang", $code, $code == $selectedCode );
+ $select->addOption( "$code - $lang", $code );
}
- $s .= "\n</select>\n";
- return $this->parent->label( $label, $name, $s );
+ $output .= $select->getHTML();
+ return $this->parent->label( $label, $name, $output );
}
}
@@ -669,6 +669,8 @@ class WebInstallerUpgrade extends WebInstallerPage {
}
public function showDoneMessage() {
+ global $wgScriptExtension;
+
$this->startForm();
$regenerate = !$this->getVar( '_ExistingDBSettings' );
if ( $regenerate ) {
@@ -682,7 +684,7 @@ class WebInstallerUpgrade extends WebInstallerPage {
wfMessage( $msg,
$this->getVar( 'wgServer' ) .
$this->getVar( 'wgScriptPath' ) . '/index' .
- $this->getVar( 'wgScriptExtension' )
+ $wgScriptExtension
)->plain(), 'tick-32.png'
)
);
@@ -831,6 +833,8 @@ class WebInstallerName extends WebInstallerPage {
* @return bool
*/
public function submit() {
+ global $wgPasswordPolicy;
+
$retVal = true;
$this->parent->setVarsFromRequest( array( 'wgSitename', '_NamespaceType',
'_AdminName', '_AdminPassword', '_AdminPasswordConfirm', '_AdminEmail',
@@ -907,13 +911,21 @@ class WebInstallerName extends WebInstallerPage {
$pwd = $this->getVar( '_AdminPassword' );
$user = User::newFromName( $cname );
if ( $user ) {
- $valid = $user->getPasswordValidity( $pwd );
+ $upp = new UserPasswordPolicy(
+ $wgPasswordPolicy['policies'],
+ $wgPasswordPolicy['checks']
+ );
+ $status = $upp->checkUserPasswordForGroups(
+ $user,
+ $pwd,
+ array( 'bureaucrat', 'sysop' ) // per Installer::createSysop()
+ );
+ $valid = $status->isGood() ? true : $status->getMessage();
} else {
$valid = 'config-admin-name-invalid';
}
if ( strval( $pwd ) === '' ) {
- # $user->getPasswordValidity just checks for $wgMinimalPasswordLength.
- # This message is more specific and helpful.
+ // Provide a more specific and helpful message if password field is left blank
$msg = 'config-admin-password-blank';
} elseif ( $pwd !== $this->getVar( '_AdminPasswordConfirm' ) ) {
$msg = 'config-admin-password-mismatch';
@@ -921,7 +933,7 @@ class WebInstallerName extends WebInstallerPage {
$msg = $valid;
}
if ( $msg !== false ) {
- call_user_func_array( array( $this->parent, 'showError' ), (array)$msg );
+ call_user_func( array( $this->parent, 'showError' ), $msg );
$this->setVar( '_AdminPassword', '' );
$this->setVar( '_AdminPasswordConfirm', '' );
$retVal = false;
@@ -1479,8 +1491,7 @@ class WebInstallerComplete extends WebInstallerPage {
wfMessage( 'config-install-done',
$lsUrl,
$this->getVar( 'wgServer' ) .
- $this->getVar( 'wgScriptPath' ) . '/index' .
- $this->getVar( 'wgScriptExtension' ),
+ $this->getVar( 'wgScriptPath' ) . '/index.php',
'<downloadlink/>'
)->plain(), 'tick-32.png'
)
diff --git a/includes/installer/i18n/ar.json b/includes/installer/i18n/ar.json
index 36136a5e..13755e33 100644
--- a/includes/installer/i18n/ar.json
+++ b/includes/installer/i18n/ar.json
@@ -6,7 +6,8 @@
"OsamaK",
"روخو",
"Claw eg",
- "Kuwaity26"
+ "Kuwaity26",
+ "محمد أحمد عبد الفتاح"
]
},
"config-desc": "مثبت لميدياويكي",
@@ -45,12 +46,16 @@
"config-page-existingwiki": "ويكي موجودة",
"config-help-restart": "هل تريد إزالة البيانات المحفوظة التي قد قمت بإدخالها وإعادة تشغيل عملية التثبيت؟",
"config-restart": "نعم، إعادة التشغيل",
+ "config-env-good": "جرى التحقق من البيئة. يمكنك تنصيب ميدياويكي.",
+ "config-env-bad": "جرى التحقق من البيئة. لا يمكنك تنصيب ميدياويكي.",
"config-env-php": "بي إتش بي $1 مثبت.",
+ "config-env-hhvm": "نصبت HHVM $1.",
"config-db-type": "نوع قاعدة البيانات:",
"config-db-host": "مضيف قاعدة البيانات:",
"config-db-wiki-settings": "حدِّد هذا الويكي",
"config-db-name": "اسم قاعدة البيانات",
"config-db-name-oracle": "سكيما قاعدة البيانات:",
+ "config-db-install-account": "حساب المستخدم للتنصيب",
"config-db-username": "اسم مستخدم قاعدة البيانات:",
"config-db-password": "كلمة سر قاعدة البيانات:",
"config-db-prefix": "بادئة جدول قاعدة البيانات:",
@@ -96,6 +101,7 @@
"config-license-cc-by": "المشاع الإبداعي النسبة للمؤلف",
"config-license-cc-by-nc-sa": "المشاع الإبداعي النسبة للمؤلف غير تجاري المشاركة بالمثل",
"config-license-pd": "ملكية عامة",
+ "config-license-cc-choose": "اختر ترخيص مشاع إبداعي مخصص",
"config-email-settings": "إعدادات البريد الإلكتروني",
"config-email-usertalk": "فعل إخطارات صفحات نقاش المستخدمين",
"config-email-watchlist": "تمكين إشعارات قائمة المراقبة",
@@ -119,6 +125,7 @@
"config-install-user-create-failed": "إنشاء مستخدم \"$1\" فشل:$2",
"config-install-tables": "إنشاء الجداول",
"config-install-keys": "توليد المفاتيح السرية",
+ "config-install-mainpage": "إنشاء صفحة رئيسية بالمحتوى الافتراضي",
"config-help": "مساعدة",
"config-help-tooltip": "اضغط للتوسيع",
"mainpagetext": "'''تم تثبيت ميدياويكي بنجاح.'''",
diff --git a/includes/installer/i18n/ast.json b/includes/installer/i18n/ast.json
index 62f0f036..852982f5 100644
--- a/includes/installer/i18n/ast.json
+++ b/includes/installer/i18n/ast.json
@@ -1,7 +1,8 @@
{
"@metadata": {
"authors": [
- "Xuacu"
+ "Xuacu",
+ "Fitoschido"
]
},
"config-desc": "L'instalador pa MediaWiki",
@@ -47,7 +48,6 @@
"config-env-bad": "Comprobóse l'entornu.\nNun pue instalar MediaWiki.",
"config-env-php": "PHP $1 ta instaláu.",
"config-env-hhvm": "HHVM $1 ta instaláu.",
- "config-unicode-using-utf8": "Usando utf8_normalize.so de Brion Vibber pa la normalización Unicode.",
"config-unicode-using-intl": "Usando la [http://pecl.php.net/intl estensión intl PECL] pa la normalización Unicode.",
"config-unicode-pure-php-warning": "'''Avisu:''' La [http://pecl.php.net/intl estensión intl PECL] nun ta disponible pa xestionar la normalización Unicode; volviendo a la implementación lenta en PHP puru.\nSi xestiona un sitiu con un tráficu altu, tendría de lleer una migaya sobro la [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalización Unicode].",
"config-unicode-update-warning": "'''Avisu:''' La versión instalada del envoltoriu de normalización Unicode usa una versión antigua de la biblioteca [http://site.icu-project.org/ de los proyeutos ICU].\nTendría [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations d'anovala] si ye importante pa vusté usar Unicode.",
@@ -58,6 +58,10 @@
"config-diff3-bad": "Nun s'alcontró GNU diff3.",
"config-git": "Alcontróse'l software de control de versiones Git: <code>$1</code>.",
"config-git-bad": "Nun s'alcontró el software de control de versiones Git.",
+ "config-db-type": "Tipu de base de datos:",
+ "config-db-name": "Nome de base de datos:",
+ "config-type-mysql": "MySQL (o compatible)",
+ "config-type-mssql": "Microsoft SQL Server",
"config-site-name": "Nome de la wiki:",
"config-site-name-help": "Esto apaecerá na barra de títulos del navegador y en dellos sitios más.",
"config-site-name-blank": "Escriba un nome pal sitiu.",
diff --git a/includes/installer/i18n/azb.json b/includes/installer/i18n/azb.json
new file mode 100644
index 00000000..ba0ad68f
--- /dev/null
+++ b/includes/installer/i18n/azb.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mousa",
+ "Koroğlu",
+ "Ebrahimi-amir",
+ "Alp Er Tunqa"
+ ]
+ },
+ "config-desc": "مئدیاویکی قوروجوسو",
+ "config-title": "مئدیاویکی $1 قورماغی",
+ "config-information": "بیلگیلر",
+ "config-localsettings-key": "یوکسلتمک کلیدی:",
+ "config-localsettings-badkey": "وئردیگینیز کیلید دوغرو دئییل.",
+ "config-your-language": "دیلینیز:",
+ "config-wiki-language": "ویکی دیلی:",
+ "config-back": "→ دالی",
+ "config-continue": "سونرا ←",
+ "config-page-language": "دیل",
+ "config-page-welcome": "مئدیاویکی‌یه خوش گلدینیز!",
+ "config-page-name": "آد",
+ "config-page-options": "سئچیملر",
+ "config-page-install": "قور",
+ "config-page-readme": "منی اوخو",
+ "config-env-php": "PHP $1 قورولوبدور.",
+ "config-env-hhvm": "HHVM $1 قورولوبدور.",
+ "config-help": "کؤمک",
+ "config-help-tooltip": "گئنیشلتمک اوچون کلیک ائدین",
+ "config-nofile": "«$1» فایلی تاپیلانمادی. سیلینیبدیرمی؟"
+}
diff --git a/includes/installer/i18n/ba.json b/includes/installer/i18n/ba.json
index e3838e3d..8165da2b 100644
--- a/includes/installer/i18n/ba.json
+++ b/includes/installer/i18n/ba.json
@@ -9,13 +9,19 @@
"config-desc": "MediaWiki йөкләүсе",
"config-title": "MediaWiki $1 йөкләмеше",
"config-information": "Мәғлүмәт",
+ "config-localsettings-upgrade": "<code>LocalSettings.php</code> файлы бар. \nБыл күрһәтмәне яңыртыу өсөн <code>$wgUpgradeKey</code> мәғәнәһен яҙығыҙ.\nУны <code>LocalSettings.php</code> файлында табырға була.",
+ "config-localsettings-cli-upgrade": "<code>LocalSettings.php</code> файлы бар. \nБыл күрһәтмәне яңыртыу өсөн <code>update.php</code> эшләтеп ебәрегеҙ.",
"config-localsettings-key": "Яңыртыу асҡысы:",
"config-localsettings-badkey": "Дөрөҫ булмаған асҡыс күрһәттегеҙ",
+ "config-session-error": "Эш башлағанда сыҡҡан хата: $1",
"config-your-language": "Һеҙҙең тел:",
+ "config-wiki-language": "Вики телдәре:",
"config-back": "← Кире",
"config-continue": "Дауам итергә →",
"config-page-language": "Тел",
"config-page-welcome": "MediaWiki-ға рәхим итегеҙ!",
+ "config-page-dbconnect": "Мәғлүмәт болона тоташыу",
+ "config-page-dbsettings": "Мәғлүмәт болон көйләү",
"config-page-name": "Исем",
"config-page-options": "Көйләүҙәр",
"config-page-complete": "Тамам!",
@@ -24,6 +30,7 @@
"config-page-copying": "Рөхсәтнәмә",
"config-page-upgradedoc": "Яңыртыу",
"config-restart": "Эйе, яңынан башларға",
+ "config-help": "белешмә",
"mainpagetext": "«MediaWiki» уңышлы рәүештә ҡоролдо.",
"mainpagedocfooter": "Был вики менән эшләү тураһында мәғлүмәтте [//meta.wikimedia.org/wiki/Help:Contents ошонда] табып була.\n\n== Файҙалы сығанаҡтар ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Көйләүҙәр исемлеге (инг.)];\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki тураһында йыш бирелгән һорауҙар һәм яуаптар (инг.)];\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki-ның яңы версиялары тураһында хәбәрҙәр алып тороу].\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]"
}
diff --git a/includes/installer/i18n/bcl.json b/includes/installer/i18n/bcl.json
index 533035c3..76a8f37d 100644
--- a/includes/installer/i18n/bcl.json
+++ b/includes/installer/i18n/bcl.json
@@ -27,6 +27,7 @@
"config-page-upgradedoc": "Ipinagpapalangkaw",
"config-page-existingwiki": "Eksistidong wiki",
"config-restart": "Iyo, pakipoon kaini otro",
+ "config-xml-bad": "An XML kan PHP na modyul nawawara.\nAn Mediawiki minakaipo nin mga punksyon sa modyul na ini asin dae matrabaho sa laog kaining konpigurasyon.\nIka minakaipong magmuntar kan php-xml RPM package",
"config-db-wiki-settings": "Bistohon ining wiki",
"config-db-name": "Pangaran kan datos-sarayan:",
"config-db-username": "Ngaran-paragamit nin datos-sarayan:",
diff --git a/includes/installer/i18n/be-tarask.json b/includes/installer/i18n/be-tarask.json
index c131a781..95e2ec4f 100644
--- a/includes/installer/i18n/be-tarask.json
+++ b/includes/installer/i18n/be-tarask.json
@@ -52,7 +52,6 @@
"config-env-bad": "Асяродзьдзе было праверанае.\nУсталяваньне MediaWiki немагчымае.",
"config-env-php": "Усталяваны PHP $1.",
"config-env-hhvm": "HHVM $1 усталяваная.",
- "config-unicode-using-utf8": "Выкарыстоўваецца бібліятэка Unicode-нармалізацыі Браяна Вібэра",
"config-unicode-using-intl": "Выкарыстоўваецца [http://pecl.php.net/intl intl пашырэньне з PECL] для Unicode-нармалізацыі",
"config-unicode-pure-php-warning": "'''Папярэджаньне''': [http://pecl.php.net/intl Пашырэньне intl з PECL] — ня слушнае для Unicode-нармалізацыі, цяпер выкарыстоўваецца марудная PHP-рэалізацыя.\nКалі ў Вас сайт з высокай наведваемасьцю, раім пачытаць пра [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-нармалізацыю].",
"config-unicode-update-warning": "'''Папярэджаньне''': усталяваная вэрсія бібліятэкі для Unicode-нармалізацыі выкарыстоўвае састарэлую вэрсію бібліятэкі з [http://site.icu-project.org/ праекту ICU].\nРаім [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations абнавіць], калі ваш сайт будзе працаваць зь Unicode.",
@@ -65,7 +64,7 @@
"config-magic-quotes-sybase": "'''Фатальная памылка: рэжым [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] уключаны!'''\nГэты рэжым шкодзіць уваходныя зьвесткі непрадказальным чынам.\nПрацяг усталяваньня альбо выкарыстаньне MediaWiki немагчымыя, пакуль рэжым ня будзе выключаны.",
"config-mbstring": "'''Фатальная памылка: рэжым [http://www.php.net/manual/en/ref.info.php#mbstring.overload mbstring.func_overload] уключаны!'''\nГэты рэжым выклікае памылкі і можа шкодзіць зьвесткі непрадказальным чынам.\nПрацяг усталяваньня альбо выкарыстаньне MediaWiki немагчымыя, пакуль рэжым ня будзе выключаны.",
"config-safe-mode": "'''Папярэджаньне:''' [http://www.php.net/features.safe-mode бясьпечны рэжым] PHP уключаны.\nГэта можа выклікаць праблемы, галоўным чынам падчас загрузак файлаў і ў падтрымцы <code>math</code>.",
- "config-xml-bad": "Ня знойдзены модуль XML для PHP.\nMediaWiki патрэбныя функцыі з гэтага модулю, таму MediaWiki ня будзе працаваць у гэтай канфігурацыі.\nКалі Вы выкарыстоўваеце Mandrake, усталюйце пакет php-xml.",
+ "config-xml-bad": "Ня знойдзены модуль XML для PHP.\nMediaWiki патрэбныя функцыі з гэтага модулю, таму MediaWiki ня будзе працаваць у гэтай канфігурацыі.\nМагчыма, вам трэба ўсталяваць RPM-пакет php-xml.",
"config-pcre-old": "<strong>Крытычная памылка:</strong> патрэбны PCRE вэрсіі $1 або пазьнейшай.\nPHP-файл, які выконваецца, зьвязаны з PCRE вэрсіі $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Больш інфармацыі].",
"config-pcre-no-utf8": "'''Фатальная памылка''': модуль PCRE для PHP скампіляваны без падтрымкі PCRE_UTF8.\nMediaWiki патрабуе падтрымкі UTF-8 для слушнай працы.",
"config-memory-raised": "Абмежаваньне на даступную для PHP памяць <code>memory_limit</code> было падвышанае з $1 да $2.",
diff --git a/includes/installer/i18n/bg.json b/includes/installer/i18n/bg.json
index 51fe74f5..2023b64e 100644
--- a/includes/installer/i18n/bg.json
+++ b/includes/installer/i18n/bg.json
@@ -50,37 +50,45 @@
"config-env-bad": "Средата беше проверена.\nНе е възможна инсталация на МедияУики.",
"config-env-php": "Инсталирана е версия на PHP $1.",
"config-env-hhvm": "HHVM $1 е инсталиран.",
- "config-unicode-using-utf8": "Използване на utf8_normalize.so от Brion Vibber за нормализация на Уникод.",
"config-unicode-using-intl": "Използване на разширението [http://pecl.php.net/intl intl PECL] за нормализация на Уникод.",
"config-unicode-pure-php-warning": "'''Предупреждение''': [http://pecl.php.net/intl Разширението intl PECL] не е налично за справяне с нормализацията на Уникод, превключване към по-бавното изпълнение на чист PHP.\nАко сайтът е с голям трафик, препоръчително е запознаването с [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations нормализацията на Уникод].",
"config-unicode-update-warning": "'''Предупреждение''': Инсталираната версия на Обвивката за нормализация на Unicode използва по-старата версия на библиотеката на [http://site.icu-project.org/ проекта ICU].\nНеобходимо е да [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations инсталирате по-нова верия], в случай че сте загрижени за използването на Unicode.",
- "config-no-db": "Не може да бъде открит подходящ драйвер за база данни! Необходимо е да инсталирате драйвер за база данни за PHP.\nПоддържат се следните типове базни данни: $1.\n\nАко сами сте компилирали PHP, преконфигурирайте го с включен клиент за база данни, например чрез използване на <code>./configure --with-mysql</code>.\nАко сте инсталирали PHP от пакет за Debian или Ubuntu, необходимо е също така да инсталирате и модула <code>php5-mysql</code>.",
+ "config-no-db": "Не може да бъде открит подходящ драйвер за база данни! Необходимо е да инсталирате драйвер за база данни за PHP.\n{{PLURAL:$2|Поддържа се следния тип|Поддържат се следните типове}} бази от данни: $1.\n\nАко сами сте компилирали PHP, преконфигурирайте го с включен клиент за база данни, например чрез използване на <code>./configure --with-mysql</code>.\nАко сте инсталирали PHP от пакет за Debian или Ubuntu, необходимо е също така да инсталирате и модула <code>php5-mysql</code>.",
"config-outdated-sqlite": "<strong>Предупреждение:</strong> имате инсталиран SQLite $1, а минималната допустима версия е $2. SQLite ще бъде недостъпна за ползване.",
"config-no-fts3": "'''Предупреждение''': SQLite е компилирана без [//sqlite.org/fts3.html модула FTS3], затова възможностите за търсене няма да са достъпни.",
+ "config-register-globals-error": "<strong>Грешка: Опцията <code>[http://php.net/register_globals register_globals]</code> на PHP е включена.\nЗа да продължи инсталацията, тази опция трябва да бъде изключена.</strong>\nВижте [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] за да видите как да направите това.",
+ "config-magic-quotes-gpc": "<strong>Фатална грешка: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] е включена!</strong>\nТази опция може да повреди данните непредсказуемо.\nМедияУики не може да се инсталира и използва, ако тази опция е включена.",
"config-magic-quotes-runtime": "'''Фатално: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] е активирана!'''\nТова може да повреди непредвидимо въвеждането на данните.\nИнсталацията на МедияУики е невъзможна докато тази настройка не бъде изключена.",
"config-magic-quotes-sybase": "'''Фатално: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] е активирана!'''\nТова може да повреди непредвидимо въвеждането на данните.\nИнсталацията на МедияУики е невъзможна докато тази настройка не бъде изключена.",
"config-mbstring": "'''Фатално: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] е активирана!'''\nТова може да повреди непредвидимо въвеждането на данните.\nИнсталацията на МедияУики е невъзможна докато тази настройка не бъде изключена.",
"config-safe-mode": "'''Предупреждение:''' PHP работи в [http://www.php.net/features.safe-mode безопасен режим].\nТова може да създаде проблеми, особено ако качването на файлове е разрешено, както и при поддръжката на <code>math</code>.",
"config-xml-bad": "Липсва XML модулът на PHP.\nМедияУики се нуждае от някои функции от този модул и няма да работи при наличната конфигурация.\nПри Mandrake, необходимо е да се инсталира пакетът php-xml.",
+ "config-pcre-old": "<strong>Фатална грешка:</strong> Изисква се PCRE версия $1 или по-нова.\nИзпълнимият файл на PHP е свързан с PCRE версия $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/Повече информация за PCRE].",
"config-pcre-no-utf8": "'''Фатално''': Модулът PCRE на PHP изглежда е компилиран без поддръжка на PCRE_UTF8.\nЗа да функционира правилно, МедияУики изисква поддръжка на UTF-8.",
"config-memory-raised": "<code>memory_limit</code> на PHP е $1, увеличаване до $2.",
"config-memory-bad": "'''Предупреждение:''' <code>memory_limit</code> на PHP е $1.\nСтойността вероятно е твърде ниска.\nВъзможно е инсталацията да се провали!",
"config-ctype": "'''Фатално''': Необходимо е PHP да бъде компилиран с поддръжка на [http://www.php.net/manual/en/ctype.installation.php разширението Ctype].",
+ "config-iconv": "<strong>Фатална грешка:</strong> PHP трябва да бъде компилиран с поддръжка на разширението [http://www.php.net/manual/bg/iconv.installation.php iconv].",
+ "config-json": "<strong>Фатална грешка:</strong> PHP е компилирано без поддръжка на JSON.\nТрябва да инсталирате JSON разширението за PHP или разширението [http://pecl.php.net/package/jsonc PECL jsonc] преди да продължите с инсталацията на МедияУики.\n* Разширението за PHP е включено Red Hat Enterprise Linux (CentOS) 5 и 6, но трябва да се включи в <code>/etc/php.ini</code> или <code>/etc/php.d/json.ini</code>.\n* Някои Линукс дистрибуции излезли след май 2013 не включват това PHP разширение, като вместо него в дистрибуцията е включено PECL разширение като <code>php5-json</code> или <code>php-pecl-jsonc</code>.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] е инсталиран",
"config-apc": "[http://www.php.net/apc APC] е инсталиран",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] е инсталиран",
"config-no-cache": "'''Предупреждение:''' Не бяха открити [http://www.php.net/apc APC] [http://xcache.lighttpd.net/ XCache] или [http://www.iis.net/download/WinCacheForPhp WinCache].\nОбектното кеширане не е включено.",
+ "config-mod-security": "<strong>Предупреждение:</strong> [http://modsecurity.org/ mod_security]/mod_security2 е включено на вашия уеб сървър. Много от обичайните му конфигурации пораждат проблеми с МедияУики и друг софтуер, който позволява публикуване на произволно съдържание.\nАко е възможно, моля изключете го. В противен случай се обърнете към [http://modsecurity.org/documentation/ документацията на mod_security] или се свържете с поддръжката на хостинга си, ако се сблъскате със случайни грешки.",
"config-diff3-bad": "GNU diff3 не беше намерен.",
+ "config-git": "Налична е системата за контрол на версиите Git: <code>$1</code>.",
"config-git-bad": "Не е намерен софтуер за контрол на версиите Git.",
"config-imagemagick": "Открит е ImageMagick: <code>$1</code>.\nПреоразмеряването на картинки ще бъде включено ако качването на файлове бъде разрешено.",
"config-gd": "Открита е вградена графичната библиотека GD.\nАко качването на файлове бъде включено, ще бъде включена възможността за преоразмеряване на картинки.",
"config-no-scaling": "Не са открити библиотеките GD или ImageMagick.\nПреоразмеряването на картинки ще бъде изключено.",
"config-no-uri": "'''Грешка:''' Не може да се определи текущия адрес.\nИнсталация беше прекратена.",
+ "config-no-cli-uri": "<strong>Внимание:</strong> Не е зададен параметър <code>--scriptpath</code>, стойност по подразбиране: <code>$1</code>.",
"config-using-server": "Използване на сървърното име \"<nowiki>$1</nowiki>\".",
"config-using-uri": "Използване на сървърния адрес (URL) \"<nowiki>$1$2</nowiki>\".",
"config-uploads-not-safe": "'''Предупреждение:''' Папката по подразбиране за качване <code>$1</code> е уязвима от изпълнение на зловредни скриптове.\nВъпреки че МедияУики извършва проверка за заплахи в сигурността на всички качени файлове, силно препоръчително е да се [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security затвори тази уязвимост в сигурността] преди разрешаване за качване на файлове.",
- "config-brokenlibxml": "Вашата система използа комбинация от версии на PHP и libxml2, които са с много грешки и могат да причинят скрити повреди на данните в МедияУики или други уеб приложения.\nНеобходимо е обновяване до PHP 5.2.9 или по-нова версия и libxml2 2.7.3 или по-нова версия ([//bugs.php.net/bug.php?id=45996 докладвана грешка при PHP]).\nИнсталацията беше прекратена.",
- "config-suhosin-max-value-length": "Suhosin е инсталиран и ограничава дължината на параметъра GET на $1 байта. Компонентът на МедияУики ResourceLoader ще може да пренебрегне частично това ограничение, но това ще намали производителността. По възможност е препоръчително да се настрои <code>suhosin.get.max_value_length</code> на 1024 или по-голяма стойност в <code>php.ini</code> и в LocalSettings.php да се настрои <code>$wgResourceLoaderMaxQueryLength</code> със същата стойност.",
+ "config-no-cli-uploads-check": "<strong>Предупреждение:</strong> Директорията по подразбиране за качване на файлове (<code>$1</code>) не е проверена за уязвимости при изпълнение на произволен скрипт по време на инсталацията от командния ред.",
+ "config-brokenlibxml": "Вашата система използва комбинация от версии на PHP и libxml2, които са с много грешки и могат да причинят скрити повреди на данните в МедияУики или други уеб приложения.\nНеобходимо е обновяване до libxml2 2.7.3 или по-нова версия ([https://bugs.php.net/bug.php?id=45996 докладвана грешка при PHP]).\nИнсталацията беше прекратена.",
+ "config-suhosin-max-value-length": "Suhosin е инсталиран и ограничава дължината GET параметъра <code>length</code> на $1 байта. Компонентът на МедияУики ResourceLoader ще може да пренебрегне частично това ограничение, но това ще намали производителността. По възможност е препоръчително да се настрои <code>suhosin.get.max_value_length</code> на 1024 или по-голяма стойност в <code>php.ini</code> и в LocalSettings.php да се настрои <code>$wgResourceLoaderMaxQueryLength</code> със същата стойност.",
"config-db-type": "Тип на базата от данни:",
"config-db-host": "Хост на базата от данни:",
"config-db-host-help": "Ако базата от данни е на друг сървър, в кутията се въвежда името на хоста или IP адреса.\n\nАко се използва споделен уеб хостинг, доставчикът на услугата би трябвало да е предоставил в документацията си коректния хост.\n\nАко инсталацията протича на Windows-сървър и се използва MySQL, използването на \"localhost\" може да е неприемливо. В такива случаи се използва \"127.0.0.1\" за локален IP адрес.\n\nПри използване на PostgreSQL, това поле се оставя празно, за свързване чрез Unix socket.",
@@ -93,6 +101,7 @@
"config-db-username": "Потребителско име за базата от данни:",
"config-db-password": "Парола за базата от данни:",
"config-db-password-empty": "Въведете парола за новия потребител на базата от данни: $1.\nВъпреки че е допустимо да се създават потребители без пароли, това е незащитено действие.",
+ "config-db-username-empty": "Необходимо е да се въведе стойност за „{{int:config-db-username}}“.",
"config-db-install-username": "Въвежда се потребителско име, което ще се използва за свързване с базата от данни по време на процеса по инсталация.\nТова не е потребителско име за сметка в МедияУики; това е потребителско име за базата от данни.",
"config-db-install-password": "Въвежда се парола, която ще бъде използвана за свързване с базата от данни по време на инсталационния процес.\nТова не е парола за сметка в МедияУики; това е парола за базата от данни.",
"config-db-install-help": "Въвеждат се потребителско име и парола, които ще бъдат използвани за свързване с базата от данни по време на инсталационния процес.",
@@ -101,6 +110,7 @@
"config-db-wiki-help": "Въвежда се потребителско име и парола, които ще се използват при нормалното функциониране на уикито.\nАко сметката не съществува и използваната при инсталацията сметка има необходимите права, тази потребителска сметка ще бъде създадена с минималните необходими права за работа с уикито.",
"config-db-prefix": "Представка за таблиците в базата от данни:",
"config-db-prefix-help": "Ако е необходимо да се сподели базата от данни между няколко уикита или между МедияУики и друго уеб приложение, може да се добави представка пред имената на таблиците, за да се избегнат конфликти.\nНе се използват интервали.\n\nТова поле обикновено се оставя празно.",
+ "config-db-charset": "Набор от знаци на базата от данни:",
"config-charset-mysql5-binary": "MySQL 4.1/5.0 бинарно",
"config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
"config-charset-mysql4": "MySQL 4.0 с обратна съвестимост с UTF-8",
@@ -111,23 +121,26 @@
"config-pg-test-error": "Невъзможно свързване с базата данни '''$1''': $2",
"config-sqlite-dir": "Директория за данни на SQLite:",
"config-sqlite-dir-help": "SQLite съхранява всички данни в един файл.\n\nПо време на инсталацията уеб сървърът трябва да има права за писане в посочената директория.\n\nТя '''не трябва''' да е достъпна през уеб, затова не е там, където са PHP файловете.\n\nИнсталаторът ще съхрани заедно с нея файл <code>.htaccess</code>, но ако този метод пропадне, някой може да придобие даостъп до суровите данни от базата от данни.\nТова включва сурови данни за потребителите (адреси за е-поща, хеширани пароли), както и изтрити версии на страници и друга чувствителна и с ограничен достъп информация от и за уикито.\n\nБазата от данни е препоръчително да се разположи на друго място, например в <code>/var/lib/mediawiki/yourwiki</code>.",
+ "config-oracle-def-ts": "Таблично пространство по подразбиране:",
+ "config-oracle-temp-ts": "Временно таблично пространство:",
"config-type-mysql": "MySQL (или съвместима)",
"config-type-mssql": "Microsoft SQL Сървър",
"config-support-info": "МедияУики поддържа следните системи за бази от данни:\n\n$1\n\nАко не виждате желаната за използване система в списъка по-долу, следвайте инструкциите за активиране на поддръжка по-горе.",
- "config-dbsupport-mysql": "* $1 е най-добре поддържаната система за база от данни, с най-добра поддръжка от МедияУики ([http://www.php.net/manual/en/mysql.installation.php Как се компилира PHP с поддръжка на MySQL])",
- "config-dbsupport-postgres": "* $1 е популярна система за бази от данни с отворен изходен код, която е алтернатива на MySQL ([http://www.php.net/manual/en/pgsql.installation.php как се компилира PHP с поддръжка на PostgreSQL]). Възможно е все още да има грешки, затова не се препоръчва да се използва в общодостъпна среда.",
- "config-dbsupport-sqlite": "* $1 е лека система за база от данни, която е много добре поддържана. ([http://www.php.net/manual/en/pdo.installation.php Как се компилира PHP с поддръжка на SQLite], използва PDO)",
+ "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] е най-важна за МедияУики и се поддържа най-добре. МедияУики работи също така с [{{int:version-db-mariadb-url}} MariaDB] и [{{int:version-db-percona-url}} Percona Server], които са съвместими с MySQL.\n([http://www.php.net/manual/bg/mysqli.installation.php Как се компилира PHP с поддръжка на MySQL])",
+ "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] е популярна система за управление на бази от данни, алтернатива на MySQL. Възможно е все още да има грешки, затова не се препоръчва да се използва в общодостъпна среда.([http://www.php.net/manual/bg/pgsql.installation.php Как се компилира PHP с поддръжка на PostgreSQL])",
+ "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] е олекотена система за бази от данни, която е много добре поддържана. ([http://www.php.net/manual/bg/pdo.installation.php Как се компилира PHP с поддръжка на SQLite], използва PDO)",
"config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] е комерсиална корпоративна база от данни. ([http://www.php.net/manual/en/oci8.installation.php Как се компилира PHP с поддръжка на OCI8])",
+ "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] е комерсиална корпоративна база от данни за Windows. ([http://www.php.net/manual/bg/sqlsrv.installation.php Как да се компилира PHP с поддръжка на SQLSRV])",
"config-header-mysql": "Настройки за MySQL",
"config-header-postgres": "Настройки за PostgreSQL",
"config-header-sqlite": "Настройки за SQLite",
"config-header-oracle": "Настройки за Oracle",
"config-header-mssql": "Настройки за Microsoft SQL Сървър",
"config-invalid-db-type": "Невалиден тип база от данни",
- "config-missing-db-name": "Необходимо е да се въведе стойност за \"Име на базата от данни\"",
- "config-missing-db-host": "Необходимо е да се въведе стойност за \"Хост на базата от данни\"",
- "config-missing-db-server-oracle": "Необходимо е да се въведе стойност за \"Database TNS\"",
- "config-invalid-db-server-oracle": "Невалиден TNS на базата от данни \"$1\".\nДопустими са само ASCII букви (a-z, A-Z), цифри (0-9), символите за долна черта (_) и точка (.).",
+ "config-missing-db-name": "Необходимо е да се въведе стойност за „{{int:config-db-name}}“.",
+ "config-missing-db-host": "Необходимо е да се въведе стойност за „{{int:config-db-host}}“.",
+ "config-missing-db-server-oracle": "Необходимо е да се въведе стойност за „{{int:config-db-host-oracle}}“.",
+ "config-invalid-db-server-oracle": "Невалиден TNS на базата от данни „$1“.\nИзползвайте „TNS Name“ или „Easy Connect“ ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Методи за именуване на Oracle])",
"config-invalid-db-name": "Невалидно име на базата от данни \"$1\".\nИзползват се само ASCII букви (a-z, A-Z), цифри (0-9), долни черти (_) и тирета (-).",
"config-invalid-db-prefix": "Невалидна представка за базата от данни \"$1\".\nПозволени са само ASCII букви (a-z, A-Z), цифри (0-9), долни черти (_) и тирета (-).",
"config-connection-error": "$1.\n\nНеобходимо е да се проверят хостът, потребителското име и паролата, след което да се опита отново.",
@@ -135,6 +148,7 @@
"config-db-sys-create-oracle": "Инсталаторът поддържа само сметка SYSDBA за създаване на нова сметка.",
"config-db-sys-user-exists-oracle": "Потребителската сметка \"$1\" вече съществува. SYSDBA може да се използва само за създаване на нова сметка!",
"config-postgres-old": "Изисква се PostgreSQL $1 или по-нова версия, наличната версия е $2.",
+ "config-mssql-old": "Изисква се Microsoft SQL Server версия $1 или по-нова. Вашата версия е $2.",
"config-sqlite-name-help": "Избира се име, което да идентифицира уикито.\nНе се използват интервали или тирета.\nТова име ще се използва за име на файла за данни на SQLite.",
"config-sqlite-parent-unwritable-group": "Дикректорията за данни <code><nowiki>$1</nowiki></code> не може да бъде създадена, тъй като уеб сървърът няма права за писане в родителската директория <code><nowiki>$2</nowiki></code>.\n\nИнсталаторът разпознава потребителското име, с което работи уеб сървърът.\nУверете се, че той притежава права за писане в директорията <code><nowiki>$3</nowiki></code> преди да продължите.\nВ Unix/Линукс системи можете да използвате:\n\n<pre>cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3</pre>",
"config-sqlite-parent-unwritable-nogroup": "Дикректорията за данни <code><nowiki>$1</nowiki></code> не може да бъде създадена, тъй като уеб сървърът няма права за писане в родителската директория <code><nowiki>$2</nowiki></code>.\n\nИнсталаторът не може да определи потребителското име, с което работи уеб сървърът.\nУверете се, че в директория <code><nowiki>$3</nowiki></code> може да бъде писано от уебсървъра (или от други потребители!) преди да продължите.\nНа Unix/Линукс системи можете да използвате:\n\n<pre>cd $2\nmkdir $3\nchmod a+w $3</pre>",
@@ -164,6 +178,9 @@
"config-mysql-binary": "Бинарен",
"config-mysql-utf8": "UTF-8",
"config-mysql-charset-help": "В '''бинарен режим''' МедияУики съхранява текстовете в UTF-8 в бинарни полета в базата от данни.\nТова е по-ефективно от UTF-8 режима на MySQL и позволява използването на пълния набор от символи в Уникод.\n\nВ '''UTF-8 режим''' MySQL ще знае в кой набор от символи са данните от уикито и ще може да ги показва и променя по подходящ начин, но няма да позволява складиране на символи извън [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Основния многоезичен набор].",
+ "config-mssql-auth": "Тип на удостоверяването:",
+ "config-mssql-sqlauth": "Удостоверяване чрез SQL Server",
+ "config-mssql-windowsauth": "Удостоверяване чрез Windows",
"config-site-name": "Име на уикито:",
"config-site-name-help": "Това име ще се показва в заглавната лента на браузъра и на различни други места.",
"config-site-name-blank": "Необходимо е да се въведе име на уикито.",
@@ -253,6 +270,9 @@
"config-skins": "Облици",
"config-skins-help": "По-горе са посочени облиците, които са открити във вашата директория <code>./skins</code>. Необходимо е да изберете поне един, който да се използва по подразбиране.",
"config-skins-use-as-default": "Използване на този облик по подразбиране",
+ "config-skins-missing": "Не са открити облици; МедияУики ще използва авариен облик, докато инсталирате подходящ.",
+ "config-skins-must-enable-some": "Трябва да изберете поне един облик.",
+ "config-skins-must-enable-default": "Обликът по-подразбиране трябва да бъде включен.",
"config-install-alreadydone": "'''Предупреждение:''' Изглежда вече сте инсталирали МедияУики и се опитвате да го инсталирате отново.\nПродължете към следващата страница.",
"config-install-begin": "Инсталацията на МедияУики ще започне след натискане на бутона „{{int:config-continue}}“.\nВ случай, че е необходимо да се направят промени, използва се бутона „{{int:config-back}}“.",
"config-install-step-done": "готово",
@@ -282,6 +302,7 @@
"config-install-stats": "Инициализиране на статистиките",
"config-install-keys": "Генериране на тайни ключове",
"config-insecure-keys": "'''Предупреждение:''' {{PLURAL:$2|Сигурният ключ, създаден по време на инсталацията, не е напълно надежден|Сигурните ключове, създадени по време на инсталацията, не са напълно надеждни}} $1 . Обмислете да {{PLURAL:$2|го|ги}} смените ръчно.",
+ "config-install-updates": "Предотвратяване стартирането на ненужни актуализации",
"config-install-sysop": "Създаване на администраторска сметка",
"config-install-subscribe-fail": "Невъзможно беше абонирането за mediawiki-announce: $1",
"config-install-subscribe-notpossible": "не е инсталиран cURL и <code>allow_url_fopen</code> не е налична.",
diff --git a/includes/installer/i18n/bn.json b/includes/installer/i18n/bn.json
index 0aecb705..f40bc3e1 100644
--- a/includes/installer/i18n/bn.json
+++ b/includes/installer/i18n/bn.json
@@ -5,12 +5,14 @@
"Wikitanvir",
"Aftab1995",
"Tauhid16",
- "Aftabuzzaman"
+ "Aftabuzzaman",
+ "Hasive"
]
},
"config-desc": "মিডিয়াউইকির জন্য ইন্সটলার",
"config-title": "মিডিয়াউইকি $1 ইন্সটলেশন",
"config-information": "তথ্য",
+ "config-localsettings-upgrade": "<code>LocalSettings.php</code> ফাইলটি মুছে ফেলা হয়েছে। এই ইন্সটলেশনটি আরো উন্নত করতে দয়া করে <code>$wgUpgradeKey</code> কোডটি বক্সে দিন। আপনি এটি <code>LocalSettings.php</code> -এ পাবেন।",
"config-localsettings-key": "হালনাগাদ কি",
"config-localsettings-badkey": "আপনি যেই চাবিটি দিয়েছেন তা সঠিক নয়।",
"config-session-error": "সেশন শুরুতে ত্রুটি: $1",
@@ -21,34 +23,33 @@
"config-continue": "অব্যাহত →",
"config-page-language": "ভাষা",
"config-page-welcome": "মিডিয়াউইকিতে স্বাগতম!",
- "config-page-dbconnect": "ডেটাবেজে সংযোগ দিন",
+ "config-page-dbconnect": "ডেটাবেসে সংযোগ দিন",
"config-page-upgrade": "ইতিমধ্যেই থাকা ইন্সটলেশন হালনাগাদ করুন",
- "config-page-dbsettings": "ডেটাবেজ সেটিংস",
+ "config-page-dbsettings": "ডেটাবেস সেটিংস",
"config-page-name": "নাম",
"config-page-options": "অপশন",
"config-page-install": "ইন্সটল",
"config-page-complete": "সম্পূর্ণ!",
"config-page-restart": "পুনরায় ইন্সটল প্রক্রিয়া চালু করুন",
"config-page-readme": "এটি পড়ুন",
- "config-page-releasenotes": "রিলিজ নোট",
+ "config-page-releasenotes": "প্রকাশ সংক্রান্ত বার্তা",
"config-page-copying": "অনুলেপন",
"config-page-upgradedoc": "হালনাগাদকরণ",
"config-page-existingwiki": "ইতিমধ্যেই থাকা উইকি",
- "config-help-restart": "আপনি কী সকল সংরক্ষিত উপাত্ত পরিষ্কার করতে যা আপনি প্রবেস করিয়েছিলেন এবং ইন্সটালেসন ব্যবস্থা পুনরায় আরম্ভ করতে চান?",
+ "config-help-restart": "আপনি কী সকল সংরক্ষিত উপাত্ত পরিষ্কার করতে যা আপনি প্রবেশ করিয়েছিলেন এবং ইন্সটালেশন ব্যবস্থা পুনরায় আরম্ভ করতে চান?",
"config-restart": "হ্যাঁ, পুনরায় চালু করুন",
"config-env-php": "পিএইচপি $1 ইন্সটল করা হয়েছে।",
"config-env-hhvm": "HHVM $1 ইনস্টল করা হয়েছে।",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] ইনস্টল করা হয়েছে",
"config-apc": "[http://www.php.net/apc এপিসি] ইনস্টল হয়েছে",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] ইনস্টল করা হয়েছে",
- "config-db-type": "ডেটাবেজের ধরন:",
+ "config-db-type": "ডেটাবেসের ধরন:",
"config-db-host": "ডেটাবেজের হোস্ট:",
"config-db-wiki-settings": "এই উইকি সনাক্ত করুন",
- "config-db-name": "উপাত্তসংগ্রহশালা নামঃ",
+ "config-db-name": "ডেটাবেসের নামঃ",
"config-db-install-account": "ইন্সটলের জন্য ব্যবহারকারী অ্যাকাউন্ট",
"config-db-username": "ডেটাবেজের ব্যবহারকারী নাম:",
"config-db-password": "ডেটাবেজের পাসওয়ার্ড:",
- "config-db-username-empty": "আপনাকে অবশ্যই \"{{int:config-db-username}}\"-এর জন্য একটি মান প্রবেশ করাতে হবে।",
"config-db-wiki-account": "সাধারণ অভিযানের জন্য ব্যবহারকারী একাউন্ট",
"config-db-prefix": "উপাত্তশালা ছক প্রিফিক্স:",
"config-db-charset": "ডেটাবেজের অক্ষর সেট",
diff --git a/includes/installer/i18n/bs.json b/includes/installer/i18n/bs.json
index 668fbff7..7a7cfb14 100644
--- a/includes/installer/i18n/bs.json
+++ b/includes/installer/i18n/bs.json
@@ -2,15 +2,21 @@
"@metadata": {
"authors": [
"CERminator",
- "Palapa"
+ "Palapa",
+ "Emir Mujadzic",
+ "Semso98",
+ "Srdjan m"
]
},
"config-desc": "Instalacija za MediaWiki",
"config-title": "MediaWiki $1 instalacija",
"config-information": "Informacija",
"config-localsettings-upgrade": "Otkrivena je datoteka <code>LocalSettings.php</code>.\nDa biste unaprijedili vaš softver, molimo vas upišite vrijednost od <code>$wgUpgradeKey</code> u okvir ispod.\nNaći ćete ga u <code>LocalSettings.php</code>.",
+ "config-localsettings-cli-upgrade": "Datoteka <code>LocalSettings.php</code> file je otkrivena.\nZa nadogradnju ove instalacije, molimo da pokrenete <code>update.php</code> umjesto toga",
"config-localsettings-key": "Ključ za nadgradnju:",
"config-localsettings-badkey": "Ključ koji ste dali je pogrešan.",
+ "config-upgrade-key-missing": "Postojeća instalacije MediaWiki je pronađena.\nZa nadogradnju ove instalacije, molimo da stavite sljedeće liniju na dno vašeg <code>LocalSettings.php</code>:\n\n$1",
+ "config-localsettings-incomplete": "Postojeći <code>LocalSettings.php</code> se čini da je nepotpun.\nVarijabla $1 nije podešena.\nMolimo da zamjenite <code>LocalSettings.php</code> tako da je varijabla podešena, i kliknite \"{{int:Config-continue}}\".",
"config-session-error": "Greška pri pokretanju sesije: $1",
"config-no-session": "Vaši podaci sesije su izgubljeni!\nProvjerite vaš php.ini i provjerite da li je <code>session.save_path</code> postavljen na pravilni direktorijum.",
"config-your-language": "Vaš jezik:",
@@ -30,7 +36,7 @@
"config-page-complete": "Završeno!",
"config-page-restart": "Ponovi instalaciju ispočetka",
"config-page-readme": "Pročitaj me",
- "config-page-releasenotes": "Bilješke izdanja",
+ "config-page-releasenotes": "Napomene izdanja",
"config-page-copying": "Kopiram",
"config-page-upgradedoc": "Nadograđujem",
"config-page-existingwiki": "Postojeća wiki",
@@ -40,7 +46,7 @@
"config-env-good": "Okruženje je provjereno.\nMožete instalirati MediaWiki.",
"config-env-php": "PHP $1 je instaliran.",
"config-env-hhvm": "HHVM $1 je instaliran.",
- "config-no-db": "Nije mogao biti pronađen pogodan driver za bazu podataka! Morate instalirati driver baze podataka za PHP.\nSljedeće vrste baza podataka su podržane: $1.\n\nAko se sami kompajlirali PHP, podesite ga sa omogućenim klijentom baze podataka, koristeći naprimjer, <code>./configure --with-mysqli</code>.\nAko ste instalirali PHP iz Debian ili Ubuntu paketa, tada morate instalirati, naprimjer, i paket <code>php5-mysql</code>.",
+ "config-no-db": "Nije mogao biti pronađen pogodan driver za bazu podataka! Morate instalirati driver baze podataka za PHP.\nSljedeće vrste baza podataka {{PLURAL:$2|type is|types are}}su podržane: $1.\n\nAko se sami kompajlirali PHP, podesite ga sa omogućenim klijentom baze podataka, koristeći naprimjer, <code>./configure --with-mysqli</code>.\nAko ste instalirali PHP iz Debian ili Ubuntu paketa, tada morate instalirati, naprimjer, i paket <code>php5-mysql</code>.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] je instaliran",
"config-apc": "[http://www.php.net/apc APC] je instaliran",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] je instaliran",
@@ -51,14 +57,14 @@
"config-db-name": "Naziv baze podataka:",
"config-db-name-oracle": "Šema baze podataka:",
"config-db-username": "Korisničko ime baze podataka:",
- "config-db-password": "Pasvord baze podataka:",
+ "config-db-password": "Lozinka baze podataka:",
"config-db-port": "Port baze podataka:",
"config-header-mysql": "Postavke MySQL",
"config-header-postgres": "Postavke PostgreSQL",
"config-header-sqlite": "Postavke SQLite",
"config-header-oracle": "Postavke Oracle",
"config-header-mssql": "Postavke za Microsoft SQL Server",
- "config-invalid-db-type": "Nevaljana vrsta baze podataka",
+ "config-invalid-db-type": "Invalidna vrsta baze podataka.",
"config-missing-db-name": "Morate unijeti vrijednost za \"{{int:config-db-name}}\".",
"config-upgrade-done": "Nadogradnja završena.\n\nSada možete [$1 početi koristiti vašu wiki].\n\nAko želite regenerisati vašu datoteku <code>LocalSettings.php</code>, kliknite na dugme ispod.\nOvo '''nije preporučeno''' osim ako nemate problema s vašom wiki.",
"config-mysql-innodb": "InnoDB",
@@ -67,20 +73,21 @@
"config-site-name": "Ime wiki:",
"config-ns-other-default": "MyWiki",
"config-admin-name": "Vaše korisničko ime:",
- "config-admin-password": "Šifra:",
- "config-admin-password-confirm": "Ponovno unesite pasvord:",
- "config-admin-email": "E-mail adresa:",
+ "config-admin-password": "Lozinka:",
+ "config-admin-password-confirm": "Ponovno unesite lozinku:",
+ "config-admin-email": "Adresa e-pošte:",
"config-profile-wiki": "Otvori wiki",
"config-profile-private": "Privatna wiki",
"config-license-pd": "Javno vlasništvo",
"config-logo": "Logo URL:",
"config-cc-again": "Odaberi ponovno...",
+ "config-skins": "Teme",
"config-install-step-done": "završeno",
"config-install-step-failed": "neuspješno",
"config-install-extensions": "Uključujući ekstenzije",
"config-install-tables": "Kreiranje tabela",
"config-help": "pomoć",
"config-help-tooltip": "klikni za proširenje",
- "mainpagetext": "'''MediaViki softver is uspješno instaliran.'''",
- "mainpagedocfooter": "Kontaktirajte [//meta.wikimedia.org/wiki/Help:Contents uputstva za korisnike] za informacije o upotrebi wiki programa.\n\n== Početak ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista postavki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki najčešće postavljana pitanja]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista E-Mail adresa MediaWiki]"
+ "mainpagetext": "'''MediaWiki softver je uspješno instaliran.'''",
+ "mainpagedocfooter": "Kontaktirajte [//meta.wikimedia.org/wiki/Help:Sadržaj uputstva za korisnike] za informacije o upotrebi wiki programa.\n\n== Početak ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista postavki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki najčešće postavljana pitanja]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista E-Mail adresa MediaWiki]"
}
diff --git a/includes/installer/i18n/ca.json b/includes/installer/i18n/ca.json
index 6d28a582..ee33109c 100644
--- a/includes/installer/i18n/ca.json
+++ b/includes/installer/i18n/ca.json
@@ -80,8 +80,6 @@
"config-db-install-account": "Compte d'usuari per a la instal·lació",
"config-db-username": "Nom d'usuari de la base de dades:",
"config-db-password": "Contrasenya de la base de dades:",
- "config-db-password-empty": "Si us plau, introduïu una contrasenya pel nou usuari de la base de dades $1. Tot i que es poden crear usuaris sense contrasenyes, no és segur.",
- "config-db-username-empty": "Heu d'introduir un valor per a «{{int:config-db-username}}»",
"config-db-install-username": "Introduïu el nom d'usuari que s'utilitzarà per connectar a la base de dades durant el procés d'instal·lació. Aquest no és el nom d'usuari de MediaWiki, és el nom d'usuari de la vostra base de dades.",
"config-db-install-password": "Introduïu la contrasenya que s'utilitzarà per connectar a la base de dades durant el procés d'instal·lació. Aquesta no és la contrasenya del vostre compte a MediaWiki, és la contrasenya de la vostra base de dades.",
"config-db-install-help": "Introduïu el nom d'usuari i la contrasenya que s'empraran per connectar a la base de dades durant el procés d'instal·lació.",
@@ -204,6 +202,7 @@
"config-memcached-servers": "Servidors de Memcache:",
"config-memcache-badip": "Heu introduït una adreça IP no vàlida per al Memcached: $1.",
"config-memcache-noport": "No heu especificat un port per utilitzar el servidor Memcached: $1.\nSi no coneixeu el port, per defecte és 11211.",
+ "config-memcache-badport": "Els números de port de Memcached han de ser entre $1 i $2.",
"config-extensions": "Extensions",
"config-skins": "Aparences",
"config-skins-use-as-default": "Utilitza aquest tema per defecte",
diff --git a/includes/installer/i18n/ce.json b/includes/installer/i18n/ce.json
index 0cffa94a..07096654 100644
--- a/includes/installer/i18n/ce.json
+++ b/includes/installer/i18n/ce.json
@@ -31,7 +31,6 @@
"config-no-fts3": "'''Тергам бе''': SQLite гулйина хуттург йоцуш [//sqlite.org/fts3.html FTS3] — лахар болхбеш хир дац оцу бухца.",
"config-no-cli-uri": "'''ДӀахьедар''': <code>--scriptpath</code> параметр язйина яц, иза Ӏад йитарца лелош ю: <code>$1</code> .",
"config-db-name": "Хаамийн базан цӀе:",
- "config-db-username-empty": "Ахьа «{{int:config-db-username}}» параметран маьӀна даздан дезаш ду.",
"config-db-charset": "Базан хаамийн символийн гулам",
"config-charset-mysql5-binary": "MySQL 4.1/5.0 бинаран",
"config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
@@ -41,7 +40,7 @@
"config-missing-db-name": "Ахьа «{{int:config-db-name}}» маьӀна даздан дезаш ду.",
"config-missing-db-host": "Ахьа «{{int:config-db-host}}» параметран маьӀна даздан дезаш ду.",
"config-missing-db-server-oracle": "Ахьа тӀеюза езаш ю «{{int:config-db-host-oracle}}»",
- "config-invalid-db-server-oracle": "Хаамийн базан «$1» нийса йоцу TNS.\nЛелае «TNS Name», я могӀа «Easy Connect» ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm ЦӀераш техкаран кеп Oracle])",
+ "config-invalid-db-server-oracle": "Хаамийн базан «$1» нийса йоцу TNS.\nЛелае «TNS Name», я могӀа «Easy Connect» ([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm ЦӀерш техкаран кеп Oracle])",
"config-sqlite-fts3-downgrade": "PHPн гӀо до FTS3 яц — кхуссу таблицаш",
"config-mysql-utf8": "UTF-8",
"config-mssql-auth": "Аутентификацин тайп:",
@@ -54,7 +53,7 @@
"config-profile-no-anon": "ДӀаяздар кхолла деза",
"config-profile-fishbowl": "ДӀаяздарш долу тадархошна бен",
"config-profile-private": "ДӀачӀаьгӀна вики",
- "config-license": "Авторан бакъонаш а лицензи а:",
+ "config-license": "Авторан бакъонаш а, лицензи а:",
"config-license-cc-by-sa": "Creative Commons Attribution Share Alike",
"config-license-cc-by": "Creative Commons Attribution",
"config-license-cc-by-nc-sa": "Creative Commons Attribution Non-Commercial Share Alike",
@@ -62,7 +61,7 @@
"config-license-gfdl": "GNU Free Documentation License 1.3 я кхин хьалха хиларг",
"config-license-pd": "Юкъараллин хьал",
"config-license-cc-choose": "Харжа цхьа лицензи Creative Commons",
- "config-email-settings": "Электронан почта нисяр",
+ "config-email-settings": "Электронан пошт нисяр",
"config-enable-email": "Латае дӀайохьуьйту e-mail",
"config-upload-deleted": "ДӀаяхна файлийн директори:",
"config-cc-again": "Хьаржа кхин цӀа…",
@@ -87,6 +86,6 @@
"config-download-localsettings": "Чуяккха <code>LocalSettings.php</code>",
"config-help": "гӀо",
"config-nofile": "Файл \"$1\" каро цаелира. И дӀаяьккхина ярий?",
- "mainpagetext": "'''Вики-белха гlирс «MediaWiki» кхочуш дика дlахlоттийна.'''",
+ "mainpagetext": "'''Вики-белхан гӀирс «MediaWiki» кхочуш дика дӀахӀоттийна.'''",
"mainpagedocfooter": "Викийца болх бан хаамаш карор бу хӀокху чохь [//meta.wikimedia.org/wiki/Help:Contents нисвохааман куьйгаллица].\n\n== Цхьаболу пайде гӀирсаш ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings ГӀирс нисбан тарлушболу могӀам];\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Сих сиха лушдолу хаттарш а жоьпаш оцу MediaWiki];\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Хаам бохьуьйту араяларца башхонца керла MediaWiki].\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]"
}
diff --git a/includes/installer/i18n/ckb.json b/includes/installer/i18n/ckb.json
index 202edeff..3e36e95d 100644
--- a/includes/installer/i18n/ckb.json
+++ b/includes/installer/i18n/ckb.json
@@ -38,6 +38,7 @@
"config-db-username": "ناوی بەکارھێنەری بنکەدراوە:",
"config-db-password": "تێپەڕوشەی بنکەدراوە",
"config-site-name": "ناوی ویکی:",
+ "config-site-name-blank": "ناوی پێگە داخڵ بکە.",
"config-ns-generic": "پرۆژە",
"config-admin-name": "ناوی بەکارھێنەرییەکەت:",
"config-admin-password": "تێپەڕوشە:",
diff --git a/includes/installer/i18n/cs.json b/includes/installer/i18n/cs.json
index da2de842..abcb3337 100644
--- a/includes/installer/i18n/cs.json
+++ b/includes/installer/i18n/cs.json
@@ -53,7 +53,6 @@
"config-env-bad": "Prostředí bylo zkontrolováno.\nMediaWiki nelze nainstalovat.",
"config-env-php": "Je nainstalováno PHP $1.",
"config-env-hhvm": "Je nainstalováno HHVM $1.",
- "config-unicode-using-utf8": "Pro normalizaci Unicode se používá utf8_normalize.so Briona Vibbera.",
"config-unicode-using-intl": "Pro normalizaci Unicode se používá [http://pecl.php.net/intl PECL rozšíření intl].",
"config-unicode-pure-php-warning": "'''Upozornění''': Není dostupné [http://pecl.php.net/intl PECL rozšíření intl] pro normalizaci Unicode, bude se využívat pomalá implementace v čistém PHP.\nPokud provozujete wiki s velkou návštěvností, měli byste si přečíst něco o [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalizaci Unicode].",
"config-unicode-update-warning": "'''Upozornění''': Nainstalovaná verze vrstvy pro normalizaci Unicode používá starší verzi knihovny [http://site.icu-project.org/ projektu ICU].\nPokud vám aspoň trochu záleží na používání Unicode, měli byste [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations ji aktualizovat].",
@@ -66,7 +65,7 @@
"config-magic-quotes-sybase": "'''Kritická chyba: Je zapnuto [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase]!'''\nToto nastavení nepředvídatelně poškozuje vstupní data.\nMediaWiki nelze nainstalovat ani používat, dokud není toto nastavení vypnuto.",
"config-mbstring": "'''Kritická chyba: Je zapnuto [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]!'''\nToto nastavení způsobuje chyby a může nepředvídatelně poškozovat vstupní data.\nMediaWiki nelze nainstalovat ani používat, dokud není toto nastavení vypnuto.",
"config-safe-mode": "'''Upozornění:''' Je aktivní [http://www.php.net/features.safe-mode bezpečný režim] PHP.\nMůže způsobovat potíže, zejména při použití načítání souborů a podpory <code>math</code>.",
- "config-xml-bad": "Chybí XML modul pro PHP.\nMediaWiki potřebuje funkce v tomto modulu a v této konfiguraci nebude fungovat.\nPokud běžíte na Mandrake, nainstalujte balíček php-xml.",
+ "config-xml-bad": "Chybí XML modul pro PHP.\nMediaWiki potřebuje funkce v tomto modulu a v této konfiguraci nebude fungovat.\nMožná si budete muset nainstalovat RPM balíček php-xml.",
"config-pcre-old": "'''Kritická chyba:''' Je vyžadováno PCRE verze $1 nebo novější.\nVaše binárka PHP obsahuje PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Více informací.]",
"config-pcre-no-utf8": "'''Kritická chyba''': PHP modul PCRE byl zřejmě přeložen bez podpory PCRE_UTF8.\nMediaWiki vyžaduje ke správné funkci podporu UTF-8.",
"config-memory-raised": "<code>memory_limit</code> v PHP byl nastaven na $1, zvýšen na $2.",
diff --git a/includes/installer/i18n/cu.json b/includes/installer/i18n/cu.json
index 1bd12bb5..0c69d275 100644
--- a/includes/installer/i18n/cu.json
+++ b/includes/installer/i18n/cu.json
@@ -4,7 +4,11 @@
"ОйЛ"
]
},
+ "config-information": "плирофорїꙗ",
+ "config-your-language": "твои ѩꙁꙑкъ :",
"config-page-language": "ѩꙁꙑкъ",
"config-page-name": "имѧ",
+ "config-page-options": "строи",
+ "config-page-complete": "ꙁаврьшєно ѥстъ",
"config-help": "помощь"
}
diff --git a/includes/installer/i18n/da.json b/includes/installer/i18n/da.json
index b9de2cfb..802c8192 100644
--- a/includes/installer/i18n/da.json
+++ b/includes/installer/i18n/da.json
@@ -4,9 +4,18 @@
"Peter Alberti",
"Christian List",
"Tjernobyl",
- "Thomsen"
+ "Thomsen",
+ "MGA73"
]
},
+ "config-desc": "Installationsprogrammet til MediaWiki",
+ "config-title": "Installation af MediaWiki $1",
+ "config-information": "Information",
+ "config-localsettings-upgrade": "En <code>LocalSettings.php</code>-fil er blevet fundet.\nFor at opgradere imstallationen, skriv venligst værdien af <code>$wgUpgradeKey</code> i boksen nedenfor.\nDu finder denne i <code>LocalSettings.php</code>.",
+ "config-localsettings-cli-upgrade": "En <code>LocalSettings.php</code>-fil er blevet fundet.\nFor at opgradere installationen skal du køre <code>update.php</code> i stedet for",
+ "config-localsettings-key": "Opgraderingsnøgle:",
+ "config-localsettings-badkey": "Den nøgle du indtastede er forkert.",
+ "config-upgrade-key-missing": "En eksisterende installation af MediaWiki er blevet fundet.\nFor at opgradere denne installation skal du tilføje følgende linje i bunden af din <code>LocalSettings.php</code>:\n\n$1",
"config-page-language": "Sprog",
"config-page-welcome": "Velkommen til MediaWiki!",
"config-page-dbconnect": "Forbind til database",
diff --git a/includes/installer/i18n/de-ch.json b/includes/installer/i18n/de-ch.json
index 3a73c3ed..b28a40da 100644
--- a/includes/installer/i18n/de-ch.json
+++ b/includes/installer/i18n/de-ch.json
@@ -1,8 +1,12 @@
{
"@metadata": {
"authors": [
- "Geitost"
+ "Geitost",
+ "Das Schäfchen"
]
},
+ "config-copyright": "=== Lizenz und Nutzungsbedingungen ===\n\n$1\n\nDieses Programm ist freie Software, d. h. es kann, gemäss den Bedingungen der von der Free Software Foundation veröffentlichten ''GNU General Public License'', weiterverteilt und/oder modifiziert werden. Dabei kann die Version 2, oder nach eigenem Ermessen, jede neuere Version der Lizenz verwendet werden.\n\nDieses Programm wird in der Hoffnung verteilt, dass es nützlich sein wird, allerdings '''ohne jegliche Garantie''' und sogar ohne die implizierte Garantie einer '''Marktgängigkeit''' oder '''Eignung für einen bestimmten Zweck'''. Hierzu sind weitere Hinweise in der ''GNU General Public License'' enthalten.\n\nEine <doclink href=Copying>Kopie der GNU General Public License</doclink> sollte zusammen mit diesem Programm verteilt worden sein. Sofern dies nicht der Fall war, kann eine Kopie bei der Free Software Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA, schriftlich angefordert oder auf deren Website [http://www.gnu.org/copyleft/gpl.html online gelesen] werden.",
+ "config-unicode-pure-php-warning": "'''Warnung:''' Die [http://pecl.php.net/intl PECL-Erweiterung intl] ist für die Unicode-Normalisierung nicht verfügbar, so dass stattdessen die langsame pure-PHP-Implementierung genutzt wird.\nSofern eine Website mit grosser Benutzeranzahl betrieben wird, sollten weitere Informationen auf der Webseite [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-Normalisierung (en)] gelesen werden.",
+ "config-uploads-not-safe": "'''Warnung:''' Das Standardverzeichnis für hochgeladene Dateien <code>$1</code> ist für die willkürliche Ausführung von Skripten anfällig.\nObwohl MediaWiki die hochgeladenen Dateien auf Sicherheitsrisiken überprüft, wird dennoch dringend empfohlen, diese [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security Sicherheitslücke] zu schliessen, bevor das Hochladen von Dateien aktiviert wird.",
"config-license-help": "Viele öffentliche Wikis publizieren alle Beiträge unter einer [http://freedomdefined.org/Definition/De freien Lizenz.]\nDies trägt dazu bei, ein Gefühl von Gemeinschaft zu schaffen, und ermutigt zu längerfristiger Mitarbeit.\nHingegen ist im Allgemeinen eine freie Lizenz auf geschlossenen Wikis nicht notwendig.\n\nSofern man Texte aus der Wikipedia verwenden möchte und umgekehrt, sollte die ''Creative-Commons''-Lizenz „Namensnennung – Weitergabe unter gleichen Bedingungen“ gewählt werden.\n\nDie Wikipedia nutzte vormals die GNU-Lizenz für freie Dokumentation (GFDL).\nDie GFDL ist eine gültige Lizenz, die allerdings schwer zu verstehen ist.\nEs ist zudem schwierig, gemäss dieser Lizenz lizenzierte Inhalte wiederzuverwenden."
}
diff --git a/includes/installer/i18n/de.json b/includes/installer/i18n/de.json
index b348a1b3..7c683827 100644
--- a/includes/installer/i18n/de.json
+++ b/includes/installer/i18n/de.json
@@ -72,7 +72,7 @@
"config-magic-quotes-sybase": "<strong>Fataler Fehler: Der Parameter <code>[http://www.php.net/manual/de/sybase.configuration.php#ini.magic-quotes-sybase magic_quotes_sybase]</code> von PHP ist aktiviert!</strong>\nDiese Einstellung führt zu unvorhersehbaren Problemen bei der Dateneingabe.\nMediaWiki kann nicht installiert werden, solange dieser Parameter nicht deaktiviert wurde.",
"config-mbstring": "'''Fataler Fehler: Der Parameter <code>[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]</code> von PHP ist aktiviert!'''\nDiese Einstellung verursacht Fehler und führt zu unvorhersehbaren Problemen bei der Dateneingabe.\nMediaWiki kann nicht installiert werden, solange dieser Parameter nicht deaktiviert wurde.",
"config-safe-mode": "'''Warnung:''' Der Funktion <code>[http://www.php.net/features.safe-mode Safe Mode]</code> von PHP ist aktiviert.\nDies kann zu Problemen führen, insbesondere wenn das Hochladen von Dateien möglich sein, bzw. der Auszeichner <code>math</code> genutzt werden soll.",
- "config-xml-bad": "Das XML-Modul von PHP fehlt.\nMediaWiki benötigt Funktionen, die dieses Modul bereitstellt und wird in der bestehenden Konfiguration nicht funktionieren.\nSofern Mandriva genutzt wird, muss noch das „php-xml“-Paket installiert werden.",
+ "config-xml-bad": "Das XML-Modul von PHP fehlt.\nMediaWiki benötigt Funktionen, die dieses Modul bereitstellt und wird in der bestehenden Konfiguration nicht funktionieren.\nDu musst vielleicht das „php-xml“-RPM-Paket installieren.",
"config-pcre-old": "<strong>Fataler Fehler:</strong> PCRE $1 oder neuer ist erforderlich!\nDie vorhandene PHP-Binärdatei ist mit PCRE $2 verknüpft.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Weitere Informationen].",
"config-pcre-no-utf8": "'''Fataler Fehler:''' Das PHP-Modul PCRE scheint ohne PCRE_UTF8-Unterstützung kompiliert worden zu sein.\nMediaWiki benötigt die UTF-8-Unterstützung, um fehlerfrei lauffähig zu sein.",
"config-memory-raised": "Der PHP-Parameter <code>memory_limit</code> betrug $1 und wurde auf $2 erhöht.",
diff --git a/includes/installer/i18n/el.json b/includes/installer/i18n/el.json
index 27b930a7..8109c2e5 100644
--- a/includes/installer/i18n/el.json
+++ b/includes/installer/i18n/el.json
@@ -4,7 +4,9 @@
"Glavkos",
"Protnet",
"ZaDiak",
- "Astralnet"
+ "Astralnet",
+ "Geraki",
+ "Stam.nikos"
]
},
"config-desc": "Το πρόγραμμα εγκατάστασης για το MediaWiki",
@@ -13,8 +15,11 @@
"config-localsettings-key": "Κλειδί αναβάθμισης:",
"config-localsettings-badkey": "Το κλειδί που δώσατε είναι εσφαλμένο.",
"config-upgrade-key-missing": "Έχει εντοπιστεί μια υπάρχουσα εγκατάσταση του MediaWiki.\nΓια να αναβαθμίσετε αυτήν την εγκατάσταση, παρακαλούμε να βάλετε την ακόλουθη γραμμή στο κάτω μέρος του <code>LocalSettings.php</code> σας:\n\n$1",
+ "config-session-error": "Σφάλμα κατά την εκκίνηση συνεδρίας: $1",
"config-your-language": "Η γλώσσα σας:",
+ "config-your-language-help": "Επιλέξτε μία γλώσσα για τη διαδικασία της εγκατάστασης.",
"config-wiki-language": "Γλώσσα του wiki:",
+ "config-wiki-language-help": "Επιλέξτε τη γλώσσα που θα γραφεί το wiki πρωταρχικά.",
"config-back": "← Πίσω",
"config-continue": "Συνέχεια →",
"config-page-language": "Γλώσσα",
@@ -34,10 +39,18 @@
"config-page-existingwiki": "Υπάρχον wiki",
"config-help-restart": "Θέλετε να καταργήσετε όλα τα αποθηκευμένα δεδομένα που έχετε εισαγάγει και να επανεκκινήσετε τη διαδικασία εγκατάστασης;",
"config-restart": "Ναι, κάντε επανεκκίνηση",
+ "config-welcome": "=== Περιβαλλοντικοί έλεγχοι ===\nΤώρα θα γίνουν βασικοί έλεγχοι για να δούμε αν αυτό το περιβάλλον είναι κατάλληλο για την εγκατάσταση του MediaWiki.\nΘυμηθείτε να συμπεριλάβετε αυτές τις πληροφορίες εάν αναζητήσετε υποστήριξη για το πώς να ολοκληρώσετε την εγκατάσταση.",
+ "config-copyright": "=== Πνευματικά δικαιώματα και Όροι ===\n\n$1\n\nΑυτό το πρόγραμμα είναι ελεύθερο λογισμικό• μπορείτε να το αναδιανείμετε ή και να το τροποποιήσετε υπό τους όρους της Γενικής Άδειας Δημόσιας Χρήσης GNU, όπως αυτή δημοσιεύεται από το Ίδρυμα Ελεύθερου Λογισμικού• είτε της έκδοσης 2 της Άδειας, είτε (κατά την επιλογή σας) οποιασδήποτε μεταγενέστερης έκδοσης.\n\nΑυτό το πρόγραμμα διανέμεται με την ελπίδα ότι θα είναι χρήσιμο, αλλά <strong>χωρίς καμία εγγύηση</strong>• χωρίς καν την υπονοούμενη εγγύηση της <strong>εμπορευσιμότητας</strong> ή της <strong>καταλληλοτότητας για συγκεκριμένο σκοπό</strong>.\nΔείτε την Γενική Άδεια Δημόσιας Χρήσης GNU για περισσότερες λεπτομέρειες.\n\nΘα πρέπει να έχετε λάβει <doclink href=\"Copying\">ένα αντίγραφο της Γενικής Άδειας Δημόσιας Χρήσης GNU</doclink> μαζί με αυτό το πρόγραμμα• αν όχι, γράψτε στο Free Software Foundation,\n51 Franklin Street, Fifth Floor,\nBoston, MA 02110-1335\nUSA ή [http://www.gnu.org/copyleft/gpl.html διαβάστε online].",
+ "config-sidebar": "* [//www.mediawiki.org Αρχική MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Οδηγός Χρήστη]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Οδηγός Διαχειριστή]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Συχνές ερωτήσεις]\n----\n* <doclink href=\"Readme\">Διαβάστε με</doclink>\n* <doclink href=\"ReleaseNotes\">Σημειώσεις έκδοσης</doclink>\n* <doclink href=\"Copying\">Αντιγραφή</doclink>\n* <doclink href=\"UpgradeDoc\">Αναβάθμιση</doclink>",
"config-env-good": "Το περιβάλλον έχει ελεγχθεί.\nΜπορείτε να εγκαταστήσετε το MediaWiki.",
"config-env-bad": "Το περιβάλλον έχει ελεγχθεί.\nΔεν μπορείτε να εγκαταστήσετε το MediaWiki.",
"config-env-php": "H PHP $1 είναι εγκατεστημένη.",
+ "config-env-hhvm": "Το HHVM $1 είναι εγκατεστημένο.",
+ "config-unicode-using-intl": "Χρησιμοποιώντας την [http://pecl.php.net/intl επέκταση intl PECL] για κανονικοποίηση Unicode.",
+ "config-unicode-pure-php-warning": "<strong>Προειδοποίηση:</strong> Η [http://pecl.php.net/intl επέκταση intl PECL] δεν είναι διαθέσιμη για να χειριστεί την κανονικοποίηση Unicode, επιστρέφουμε στην αργή αμιγώς PHP εφαρμογή.\nΕάν λειτουργείτε έναν ιστότοπο υψηλής επισκεψιμότητας, θα πρέπει να ρίξετε μια ματιά στην [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations κανονικοποίηση Unicode].",
+ "config-xcache": "[http://xcache.lighttpd.net/ Το XCache] είναι εγκατεστημένο",
"config-apc": "Το [http://www.php.net/apc APC] είναι εγκατεστημένο",
+ "config-wincache": "[http://www.iis.net/download/WinCacheForPhp Το WinCache] είναι εγκατεστημένο",
"config-diff3-bad": "Το GNU diff3 δεν βρέθηκε.",
"config-db-type": "Τύπος βάσης δεδομένων:",
"config-db-host": "Φιλοξενία βάσης δεδομένων:",
@@ -49,9 +62,14 @@
"config-db-username": "Όνομα χρήστη βάσης δεδομένων:",
"config-db-password": "Κωδικός πρόσβασης βάσης δεδομένων:",
"config-db-wiki-account": "Λογαριασμός χρήστη για κανονική λειτουργία",
+ "config-db-prefix": "Πρόθεμα πίνακα βάσης δεδομένων:",
+ "config-db-charset": "Σύνολο χαρακτήρων βάσης δεδομένων",
"config-charset-mysql5-binary": "MySQL 4.1/5.0 δυαδικό",
"config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
+ "config-charset-mysql4": "UTF-8 συμβατό προς τα πίσω με MySQL 4.0",
"config-db-port": "Θύρα βάσης δεδομένων:",
+ "config-type-mysql": "MySQL (ή συμβατό)",
+ "config-type-mssql": "Microsoft SQL Server",
"config-header-mysql": "Ρυθμίσεις MySQL",
"config-header-postgres": "Ρυθμίσεις PostgreSQL",
"config-header-sqlite": "Ρυθμίσεις SQLite",
@@ -62,11 +80,19 @@
"config-missing-db-host": "Πρέπει να εισαγάγετε μια τιμή για \"{{int:config-db-host}}\".",
"config-missing-db-server-oracle": "Πρέπει να εισαγάγετε μια τιμή για \"{{int:config-db-host-oracle}}\".",
"config-connection-error": "$1.\n\nΕλέγξτε τη διεύθυνση, το όνομα χρήστη και τον κωδικό πρόσβασης και προσπαθήστε ξανά.",
+ "config-mssql-old": "Απαιτείται Microsoft SQL Server $1 ή νεώτερο. Εσείς έχετε $2.",
"config-sqlite-readonly": "Το αρχείο <code>$1</code> δεν είναι εγγράψιμο.",
+ "config-sqlite-cant-create-db": "Δεν ήταν δυνατή η δημιουργία του αρχείου βάσης δεδομένων <code>$1</code>.",
"config-regenerate": "Αναδημιουργία LocalSettings.php →",
+ "config-db-web-account": "Λογαριασμός βάσης δεδομένων για πρόσβαση ιστού",
"config-mysql-engine": "Μηχανή αποθήκευσης:",
+ "config-mysql-innodb": "InnoDB",
+ "config-mysql-myisam": "MyISAM",
+ "config-mysql-charset": "Σύνολο χαρακτήρων βάσης δεδομένων:",
+ "config-mysql-binary": "Δυαδικό",
"config-mysql-utf8": "UTF-8",
"config-mssql-auth": "Τύπος ελέγχου ταυτότητας:",
+ "config-mssql-sqlauth": "Έλεγχος ταυτότητας του SQL Server",
"config-mssql-windowsauth": "Έλεγχος ταυτότητας των Windows",
"config-site-name": "Όνομα του wiki:",
"config-site-name-help": "Αυτό θα εμφανίζεται στη γραμμή τίτλου του προγράμματος περιήγησης και σε διάφορα άλλα μέρη.",
@@ -80,6 +106,7 @@
"config-admin-name": "Το όνομα χρήστη σας:",
"config-admin-password": "Κωδικός πρόσβασης:",
"config-admin-password-confirm": "Επανάληψη κωδικού πρόσβασης:",
+ "config-admin-name-blank": "Εισαγάγετε όνομα χρήστη διαχειριστή.",
"config-admin-password-mismatch": "Οι δύο κωδικοί πρόσβασης που εισηγάγατε δεν ταιριάζουν.",
"config-admin-email": "Διεύθυνση ηλεκτρονικού ταχυδρομείου:",
"config-admin-error-bademail": "Έχετε εισαγάγει μη έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου.",
@@ -90,32 +117,64 @@
"config-profile-no-anon": "Απαιτείται η δημιουργία λογαριασμού",
"config-profile-fishbowl": "Εξουσιοδοτημένοι συντάκτες μόνο",
"config-profile-private": "Ιδιωτικό wiki",
+ "config-license": "Πνευματικά δικαιώματα και άδεια χρήσης:",
+ "config-license-none": "Χωρίς άδεια χρήσης στο υποσέλιδο",
+ "config-license-cc-by-sa": "Creative Commons Αναφορά Δημιουργού-Παρόμοια Διανομή",
+ "config-license-cc-by": "Creative Commons Αναφορά Δημιουργού",
+ "config-license-cc-by-nc-sa": "Creative Commons Αναφορά Δημιουργού-Μη Εμπορική Χρήση-Παρόμοια Διανομή",
+ "config-license-cc-0": "Creative Commons Μηδέν (Κοινό Κτήμα)",
+ "config-license-gfdl": "Αδειοδότηση Ελεύθερης Τεκμηρίωσης GNU 1.3 ή μεταγενέστερη",
"config-license-pd": "Κοινό Κτήμα",
"config-license-cc-choose": "Επιλέξτε μια προσαρμοσμένη άδεια Creative Commons",
"config-email-settings": "Ρυθμίσεις ηλεκτρονικού ταχυδρομείου",
+ "config-email-user": "Ενεργοποίηση ηλεκτρονικού ταχυδρομείου από χρήστη σε χρήστη",
"config-email-usertalk": "Ενεργοποίηση ειδοποίησης σελίδας συζήτησης χρήστη",
"config-email-auth": "Ενεργοποίηση ταυτοποίησης μέσω ηλεκτρονικού ταχυδρομείου",
+ "config-email-sender": "Διεύθυνση ηλεκτρονικού ταχυδρομείου επιστροφής:",
"config-upload-settings": "Ανέβασμα εικόνων και άλλων αρχείων",
"config-upload-enable": "Ενεργοποιήστε το ανέβασμα αρχείων",
+ "config-upload-help": "Το ανέβασμα αρχείων εκθέτει πιθανώς το διακομιστή σας σε κινδύνους ασφαλείας.\nΓια περισσότερες πληροφορίες, διαβάστε την [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security ενότητα περί ασφάλειας] στο εγχειρίδιο.\n\nΓια να ενεργοποιήσετε το ανέβασμα αρχείων, αλλάξτε την κατάσταση του υποκαταλόγου <code>εικόνες</code> που βρίσκεται κάτω από τον ριζικό κατάλογο του MediaWiki έτσι ώστε ο διακομιστής ιστού να μπορεί να γράψει σε αυτόν.\nΣτη συνέχεια ενεργοποιήσετε αυτή την επιλογή.",
"config-upload-deleted": "Καταλόγος για διαγραφέντα αρχεία:",
"config-logo": "Διεύθυνση URL λογότυπου:",
"config-instantcommons": "Ενεργοποίηση Instant Commons",
"config-cc-again": "Επιλέξτε ξανά...",
"config-advanced-settings": "Προηγμένες ρυθμίσεις παραμέτρων",
+ "config-cache-options": "Ρυθμίσεις για την προσωρινή αποθήκευση αντικειμένου:",
"config-extensions": "Επεκτάσεις",
"config-skins": "Θέματα εμφάνισης",
"config-skins-help": "Τα θέματα εμφάνισης που αναφέρονται παραπάνω εντοπίστηκαν στον κατάλογο <code>./skins</code>. Πρέπει να ενεργοποιήσετε τουλάχιστον ένα και να επιλέξτε ποιο θα είναι το προεπιλεγμένο.",
"config-skins-use-as-default": "Χρήση αυτού του θέματος εμφάνισης ως προεπιλογή",
+ "config-skins-must-enable-some": "Πρέπει να επιλέξετε τουλάχιστον μία εμφάνιση να την ενεργοποιήσετε.",
"config-skins-must-enable-default": "Το θέμα εμφάνισης που επιλέχθηκε ως προεπιλεγμένο πρέπει να είναι ενεργοποιημένο.",
+ "config-install-alreadydone": "<strong>Προειδοποίηση:</strong> Φαίνεται πως έχετε ήδη εγκατεστημένο το MediaWiki και προσπαθείτε να το εγκαταστήσετε ξανά.\nΠαρακαλώ προχωρήστε στην επόμενη σελίδα.",
+ "config-install-begin": "Πατώντας «{{int:config-continue}}» θα ξεκινήσει η εγκατάσταση του MediaWiki.\nΕάν θέλετε ακόμα να κάνετε αλλαγές, πατήστε «{{int:config-back}}».",
"config-install-step-done": "έγινε",
"config-install-step-failed": "απέτυχε",
+ "config-install-extensions": "Γίνεται συμπερίληψη των επεκτάσεων",
"config-install-database": "Ρύθμιση βάσης δεδομένων",
+ "config-install-schema": "Γίνεται δημιουργία του σχήματος της βάσης δεδομένων",
+ "config-install-pg-commit": "Γίνονται οι αλλαγές",
+ "config-install-pg-plpgsql": "Γίνεται έλεγχος για τη γλώσσα PL/pgSQL",
+ "config-pg-no-plpgsql": "Πρέπει να εγκαταστήσετε τη γλώσσα PL/pgSQL στη βάση δεδομένων $1",
+ "config-install-user": "Γίνεται η δημιουργία του χρήστη της βάσης δεδομένων",
"config-install-user-alreadyexists": "Ο χρήστης \"$1\" υπάρχει ήδη",
+ "config-install-user-create-failed": "Η δημιουργία του χρήστη «$1» απέτυχε: $2",
+ "config-install-user-grant-failed": "Η παροχή άδειας στο χρήστη «$1» απέτυχε: $2",
+ "config-install-user-missing": "Ο χρήστης «$1» που καθορίστηκε δεν υπάρχει.",
"config-install-tables": "Γίνεται δημιουργία πινάκων",
"config-install-tables-failed": "<strong>Σφάλμα:</strong>Η δημιουργία πινάκων απέτυχε με το ακόλουθο μήνυμα λάθους: $1",
"config-install-interwiki": "Γίνεται συμπλήρωση του προεπιλεγμένου πίνακα interwiki",
"config-install-interwiki-list": "Αδυναμία ανάγνωσης του αρχείου <code>interwiki.list</code>.",
+ "config-install-stats": "Γίνεται αρχικοποίηση των στατιστικών",
+ "config-install-keys": "Γίνεται δημιουργία των μυστικών κλειδιών",
+ "config-install-sysop": "Γίνεται δημιουργία του λογαριασμού χρήστη του διαχειριστή",
+ "config-install-mainpage": "Γίνεται δημιουργία της αρχικής σελίδας με προεπιλεγμένο περιεχόμενο",
+ "config-install-extension-tables": "Γίνεται δημιουργία πινάκων για τις εγκατεστημένες επεκτάσεις",
+ "config-install-mainpage-failed": "Δεν ήταν δυνατή η εισαγωγή της αρχικής σελίδας: $1",
+ "config-download-localsettings": "Λήψη του <code>LocalSettings.php</code>",
"config-help": "βοήθεια",
+ "config-help-tooltip": "κλικ για ανάπτυξη",
+ "config-nofile": "Το αρχείο «$1» δεν μπορεί να βρεθεί. Μήπως έχει διαγραφεί;",
"mainpagetext": "<strong>To MediaWiki εγκαταστάθηκε με επιτυχία.</strong>",
- "mainpagedocfooter": "Περισσότερες πληροφορίες σχετικά με τη χρήση και με τη ρύθμιση παραμέτρων θα βρείτε στους συνδέσμους: [//meta.wikimedia.org/wiki/MediaWiki_localisation Οδηγίες για τροποποίηση του περιβάλλοντος εργασίας] και [//meta.wikimedia.org/wiki/MediaWiki_User%27s_Guide Εγχειρίδιο χρήστη]."
+ "mainpagedocfooter": "Συμβουλευτείτε το [//meta.wikimedia.org/wiki/Help:Contents Εγχειρίδιο χρήστη] για πληροφορίες σχετικά με τη χρήση του λογισμικού wiki.\n\n== Ξεκινώντας ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Κατάλογος ρυθμίσεων]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Λίστα ταχυδρομείου εκδόσεων MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Τοπικοποιήστε το MediaWiki για τη γλώσσα σας]"
}
diff --git a/includes/installer/i18n/en-gb.json b/includes/installer/i18n/en-gb.json
index a79282a2..b5794bf0 100644
--- a/includes/installer/i18n/en-gb.json
+++ b/includes/installer/i18n/en-gb.json
@@ -9,7 +9,6 @@
"config-title": "MediaWiki $1 installation",
"config-information": "Information",
"config-copyright": "=== Copyright and Terms ===\n\n$1\n\nThis program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public Licence as published by the Free Software Foundation; either version 2 of the Licence, or (at your option) any later version.\n\nThis 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'''.\nSee the GNU General Public Licence for more details.\n\nYou should have received <doclink href=Copying>a copy of the GNU General Public Licence</doclink> along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. or [http://www.gnu.org/copyleft/gpl.html read it online].",
- "config-unicode-using-utf8": "Using Brion Vibber's utf8_normalize.so for Unicode normalisation.",
"config-unicode-using-intl": "Using the [http://pecl.php.net/intl intl PECL extension] for Unicode normalisation.",
"config-unicode-pure-php-warning": "'''Warning:''' The [http://pecl.php.net/intl intl PECL extension] is not available to handle Unicode normalisation, falling back to slow pure-PHP implementation.\nIf you run a high-traffic site, you should read a little on [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalisation].",
"config-unicode-update-warning": "'''Warning:''' The installed version of the Unicode normalisation wrapper uses an older version of [http://site.icu-project.org/ the ICU project's] library.\nYou should [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations upgrade] if you are at all concerned about using Unicode.",
diff --git a/includes/installer/i18n/en.json b/includes/installer/i18n/en.json
index c19e3ee6..1eb8e033 100644
--- a/includes/installer/i18n/en.json
+++ b/includes/installer/i18n/en.json
@@ -97,8 +97,6 @@
"config-db-install-account": "User account for installation",
"config-db-username": "Database username:",
"config-db-password": "Database password:",
- "config-db-password-empty": "Please enter a password for the new database user: $1.\nWhile it may be possible to create users with no passwords, it is not secure.",
- "config-db-username-empty": "You must enter a value for \"{{int:config-db-username}}\".",
"config-db-install-username": "Enter the username that will be used to connect to the database during the installation process.\nThis is not the username of the MediaWiki account; this is the username for your database.",
"config-db-install-password": "Enter the password that will be used to connect to the database during the installation process.\nThis is not the password for the MediaWiki account; this is the password for your database.",
"config-db-install-help": "Enter the username and password that will be used to connect to the database during the installation process.",
diff --git a/includes/installer/i18n/eo.json b/includes/installer/i18n/eo.json
index 250816a3..0653a72d 100644
--- a/includes/installer/i18n/eo.json
+++ b/includes/installer/i18n/eo.json
@@ -3,7 +3,10 @@
"authors": [
"Airon90",
"Yekrats",
- "KuboF"
+ "KuboF",
+ "Fitoschido",
+ "Ochilov",
+ "Tlustulimu"
]
},
"config-desc": "Instalilo de MediaWiki",
@@ -32,6 +35,7 @@
"config-env-good": "La medio estis kontrolita.\nVi povas instali MediaWiki.",
"config-env-bad": "La medio estis kontrolita.\nNe eblas instali MediaWiki.",
"config-env-php": "PHP $1 estas instalita.",
+ "config-env-hhvm": "HHVM $1 instalatas.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] estas instalita.",
"config-apc": "[http://www.php.net/apc APC] estas instalita",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] estas instalita",
@@ -41,6 +45,10 @@
"config-db-name": "Nomo de datumbazo:",
"config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
"config-type-mysql": "MySQL (aŭ kongrua)",
+ "config-mysql-utf8": "UTF-8",
+ "config-site-name": "Nomo de vikio:",
+ "config-ns-generic": "Projekto",
+ "config-admin-name": "Via uzantonomo:",
"config-admin-password": "Pasvorto:",
"config-admin-password-confirm": "Retajpu pasvorton:",
"config-admin-name-blank": "Enigu salutnomon de administranto.",
diff --git a/includes/installer/i18n/es.json b/includes/installer/i18n/es.json
index a9836514..7e34f968 100644
--- a/includes/installer/i18n/es.json
+++ b/includes/installer/i18n/es.json
@@ -66,7 +66,7 @@
"config-help-restart": "¿Deseas borrar todos los datos guardados que has escrito y reiniciar el proceso de instalación?",
"config-restart": "Sí, reiniciarlo",
"config-welcome": "=== Comprobación del entorno ===\nAhora se van a realizar comprobaciones básicas para ver si el entorno es adecuado para la instalación de MediaWiki.\nRecuerda suministrar los resultados de tales comprobaciones si necesitas ayuda para completar la instalación.",
- "config-copyright": "=== Derechos de autor y Términos de uso ===\n\n$1\n\nEste programa es software libre; puedes redistribuirlo y/o modificarlo en los términos de la Licencia Pública General de GNU, tal como aparece publicada por la Fundación para el Software Libre, tanto la versión 2 de la Licencia, como cualquier versión posterior (según prefiera).\n\nEste programa es distribuido en la esperanza de que sea útil, pero '''sin cualquier garantía'''; inclusive, sin la garantía implícita de la '''posibilidad de ser comercializado''' o de '''idoneidad para cualquier finalidad específica'''.\nConsulte la licencia *GNU General *Public *License para más detalles.\n\nEn conjunto con este programa debe haber recibido <doclink href=Copying>una copia de la Licencia Pública General de GNU</doclink>; si no la recibió, pídala por escrito a Fundación para el Software Libre, Inc., 51 Franklin Street, Fifth Floor, Boston, ME La 02110-1301, USA o [http://www.gnu.org/copyleft/gpl.html léala en internet].",
+ "config-copyright": "=== Derechos de autor y Términos de uso ===\n\n$1\n\nEste programa es software libre; puedes redistribuirlo y/o modificarlo en los términos de la Licencia Pública General de GNU, tal como aparece publicada por la Fundación para el Software Libre, tanto la versión 2 de la Licencia, como cualquier versión posterior (según prefieras).\n\nEste programa es distribuido con la esperanza de que sea útil, pero <strong>sin ninguna garantía</strong>; inclusive, sin la garantía implícita de la <strong>posibilidad de ser comercializado</strong> o de <strong>idoneidad para cualquier finalidad específica</strong>.\nConsulta la Licencia Pública General de GNU para más detalles.\n\nEn conjunto con este programa debes haber recibido <doclink href=Copying>una copia de la Licencia Pública General de GNU</doclink>; caso contrario, pídela por escrito a la Fundación para el Software Libre, Inc., 51 Franklin Street, Fifth Floor, Boston, ME La 02110-1301, USA o [http://www.gnu.org/copyleft/gpl.html léela en Internet].",
"config-sidebar": "* [//www.mediawiki.org Página principal de MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Guía del usuario]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Guía del administrador]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Preguntas frecuentes]\n----\n* <doclink href=Readme>Léeme</doclink>\n* <doclink href=ReleaseNotes>Notas de la versión</doclink>\n* <doclink href=Copying>Copia</doclink>\n* <doclink href=UpgradeDoc>Actualización</doclink>",
"config-env-good": "El entorno ha sido comprobado.\nPuedes instalar MediaWiki.",
"config-env-bad": "El entorno ha sido comprobado.\nNo puedes instalar MediaWiki.",
@@ -79,15 +79,15 @@
"config-outdated-sqlite": "<strong>Advertencia:</strong> tienes SQLite $1, que es inferior a la mínima versión requerida: $2. SQLite no estará disponible.",
"config-no-fts3": "<strong>Advertencia:</strong> SQLite está compilado sin el [//sqlite.org/fts3.html módulo FTS3]. Las funcionalidades de búsqueda no estarán disponibles en esta instalación.",
"config-register-globals-error": "<strong>Error: la opción de PHP <code>[http://php.net/register_globals register_globals]</code> está activada.\nDebe estar desactivada para continuar con la instalación.</strong>\nVéase [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] para obtener ayuda sobre cómo hacerlo.",
- "config-magic-quotes-gpc": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] está activa!</strong>\nEsta opción corrompe la entrada de datos de forma impredecible.\nUsted no puede instalar o utilizar MediaWiki a menos que esta opción esté deshabilitada.",
+ "config-magic-quotes-gpc": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] está activa!</strong>\nEsta opción corrompe la entrada de datos de forma impredecible.\nNo puedes instalar o utilizar MediaWiki a menos que esta opción esté desactivada.",
"config-magic-quotes-runtime": "'''Fatal: ¡[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] está activada!'''\nEsta opción causa la imprevisible corrupción de la entrada de datos.\nNo puedes instalar o utilizar MediaWiki a menos que esta opción esté inhabilitada.",
"config-magic-quotes-sybase": "'''Fatal: ¡[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] está activada!'''\nEsta opción causa la imprevisible corrupción de la entrada de datos.\nNo puedes instalar o utilizar MediaWiki a menos que esta opción esté inhabilitada.",
"config-mbstring": "'''Fatal: La opción [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] está activada!'''\nEsta opción causa errores y puede corromper los datos de una forma imprevisible.\nNo se puede instalar o usar MediaWiki a menos que esta opción sea desactivada.",
"config-safe-mode": "<strong>Advertencia:</strong> el [http://www.php.net/features.safe-mode modo seguro] de PHP está activado.\nEste modo puede causar problemas, especialmente en la carga de archivos y en compatibilidad con <code>math</code>.",
- "config-xml-bad": "Falta el módulo XML de PHP.\nMediaWiki necesita funciones en este módulo y no funcionará con esta configuración.\nSi estás usando Mandrake, instala el paquete php-xml.",
+ "config-xml-bad": "Falta el módulo XML de PHP.\nMediaWiki requiere funciones de este módulo y no funcionará en esta configuración.\nPuede que necesites instalar el el paquete RPM llamado php-xml.",
"config-pcre-old": "'''Fatal:''' Se requiere PCRE $1 o posterior.\nSu PHP binario está enlazado con PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Más información].",
"config-pcre-no-utf8": "'''Error fatal ''': Parece que el módulo PCRE de PHP fue compilado sin el soporte PCRE_UTF8.\nMediaWiki requiere compatibilidad con UTF-8 para funcionar correctamente.",
- "config-memory-raised": "el parámetro <code>memory_limit</code> de PHP es $1, aumentada a $2.",
+ "config-memory-raised": "El parámetro <code>memory_limit</code> de PHP es $1. Se aumenta a $2.",
"config-memory-bad": "<strong>Advertencia:</strong> el parámetro <code>memory_limit</code> de PHP es $1.\nProbablemente sea demasiado bajo.\n¡La instalación puede fallar!",
"config-ctype": "'''Fatal''': Se necesita compilar PHP con compatibilidad para la [http://www.php.net/manual/en/ctype.installation.php extensión Ctype].",
"config-iconv": "<strong>Fatal:</strong> PHP debe ser compilado con soporte para la [http://www.php.net/manual/en/iconv.installation.php extensión iconv].",
@@ -115,7 +115,7 @@
"config-db-host": "Servidor de la base de datos:",
"config-db-host-help": "Si tu servidor de base de datos está en otro servidor, escribe el nombre del equipo o su dirección IP aquí.\n\nSi estás utilizando alojamiento web compartido, tu proveedor debería darte el nombre correcto del servidor en su documentación.\n\nSi vas a instalar en un servidor Windows y a utilizar MySQL, el uso de \"localhost\" como nombre del servidor puede no funcionar. Si es así, intenta poner \"127.0.0.1\" como dirección IP local.\n\nSi utilizas PostgreSQL, deja este campo vacío para conectarse a través de un socket de Unix.",
"config-db-host-oracle": "TNS de la base de datos:",
- "config-db-host-oracle-help": "Introduzca un [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm nombre de conexión local] válido; un archivo tnsnames.ora debe ser visible para esta instalación.<br />Si está utilizando bibliotecas de cliente 10g o más recientes también puede utilizar el método de asignación de nombres [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect].",
+ "config-db-host-oracle-help": "Escribe un [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm nombre de conexión local] válido; un archivo tnsnames.ora debe ser visible para esta instalación.<br />Si estás utilizando bibliotecas de cliente 10g o más recientes también puedes utilizar el método de asignación de nombres [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect].",
"config-db-wiki-settings": "Identifica este wiki",
"config-db-name": "Nombre de la base de datos:",
"config-db-name-help": "Elige un nombre que identifique tu wiki.\nNo debe contener espacios.\n\nSi estás utilizando alojamiento web compartido, tu proveedor te dará un nombre específico de base de datos para que lo utilices, o bien te permitirá crear bases de datos a través de un panel de control.",
@@ -124,8 +124,6 @@
"config-db-install-account": "Cuenta de usuario para instalación",
"config-db-username": "Nombre de usuario de la base de datos:",
"config-db-password": "Contraseña de la base de datos:",
- "config-db-password-empty": "Escribe una contraseña para el nuevo usuario de base de datos: $1.\nAunque es posible crear usuarios sin contraseña, esto no es seguro.",
- "config-db-username-empty": "Debes introducir un valor para \"{{int:config-db-username}}\"",
"config-db-install-username": "Escribe el nombre de usuario que se utilizará para conectarse a la base de datos durante el proceso de instalación.\nEste no es el nombre de usuario de la cuenta de MediaWiki, sino el nombre de usuario para la base de datos.",
"config-db-install-password": "Escribe la contraseña que se utilizará para conectarse a la base de datos durante el proceso de instalación.\nEsta no es la contraseña para la cuenta de MediaWiki, sino la contraseña para la base de datos.",
"config-db-install-help": "Escribe el nombre de usuario y la contraseña que se utilizarán para conectarse a la base de datos durante el proceso de instalación.",
@@ -158,7 +156,7 @@
"config-dbsupport-postgres": "[{{int:version-db-postgres-url}} PostgreSQL] es un sistema de base de datos popular de código abierto, alternativa a MySQL. Pueden haber algunos fallos menores destacables, y no es recomendable para su uso en un entorno de producción. ([http://www.php.net/manual/es/pgsql.installation.php Cómo compilar PHP con compatibilidad PostgreSQL]).",
"config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] es un sistema de base de datos ligero con gran compatibilidad con MediaWiki. ([http://www.php.net/manual/es/pdo.installation.php Cómo compilar PHP con compatibilidad SQLite], usando PDO)",
"config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] es una base de datos comercial a nivel empresarial. ([http://www.php.net/manual/es/oci8.installation.php Cómo compilar PHP con compatibilidad con OCI8])",
- "config-dbsupport-mssql": "* [{{int:version-db-oracle-url}} Oracle] es una base de datos comercial a nivel empresarial. ([http://www.php.net/manual/es/oci8.installation.php Cómo compilar PHP con compatibilidad con OCI8])",
+ "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] es una base de datos comercial a nivel empresarial para Windows. ([http://www.php.net/manual/en/sqlsrv.installation.php Cómo compilar PHP con soporte para SQLSRV])",
"config-header-mysql": "Configuración de MySQL",
"config-header-postgres": "Configuración de PostgreSQL",
"config-header-sqlite": "Configuración de SQLite",
@@ -178,8 +176,8 @@
"config-postgres-old": "Se requiere PostgreSQL $1 o posterior. Tienes la versión $2.",
"config-mssql-old": "Se requiere Microsoft SQL Server $1 o posterior. Tienes la versión $2.",
"config-sqlite-name-help": "Elige el nombre que identificará a tu wiki.\nNo uses espacios o guiones.\nEste nombre se usará como nombre del archivo de datos de SQLite.",
- "config-sqlite-parent-unwritable-group": "No se puede crear el directorio de datos <code><nowiki>$1</nowiki></code> , porque el directorio padre <code><nowiki>$2</nowiki></code> no es accesible en escritura por el servidor Web.\n\nEl instalador ha determinado el usuario cuyo servidor Web se está ejecutando.\nConceda permisos de escritura en el directorio <code><nowiki>$3</nowiki></code> para continuar.\nEn un sistema Unix/Linux haga:\n\n<pre>cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3</pre>",
- "config-sqlite-parent-unwritable-nogroup": "No se puede crear el directorio de datos <code><nowiki>$1</nowiki></code> , porque el directorio padre <code><nowiki>$2</nowiki></code> no es accesible en escritura por el servidor Web.\n\nEl programa de instalación no pudo determinar el usuario que se ejecuta en el servidor Web\nConceda permisos de escritura en el directorio <code><nowiki>$3</nowiki></code> para continuar.\nEn un sistema Unix/Linux haga:\n\n<pre>cd $2\nmkdir $3\nchmod a+w $3</pre>",
+ "config-sqlite-parent-unwritable-group": "No se puede crear el directorio de datos <code><nowiki>$1</nowiki></code>, porque el servidor web no tiene permiso de escribir en el directorio padre <code><nowiki>$2</nowiki></code>.\n\nEl instalador ha determinado el usuario con el que se ejecuta tu servidor web.\nConcede permisos de escritura a él en el directorio <code><nowiki>$3</nowiki></code> para continuar.\nEn un sistema Unix/Linux haz:\n\n<pre>cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3</pre>",
+ "config-sqlite-parent-unwritable-nogroup": "No se puede crear el directorio de datos <code><nowiki>$1</nowiki></code>, porque el servidor web no tiene permiso de escribir en el directorio padre <code><nowiki>$2</nowiki></code>.\n\nEl instalador no pudo determinar el usuario con el que se ejecuta tu servidor web.\nConcede permisos de escritura a él (¡y a otros!) en el directorio <code><nowiki>$3</nowiki></code> para continuar.\nEn un sistema Unix/Linux haz:\n\n<pre>cd $2\nmkdir $3\nchmod a+w $3</pre>",
"config-sqlite-mkdir-error": "Error al crear el directorio de datos \"$1\".\nComprueba la ubicación e inténtalo de nuevo.",
"config-sqlite-dir-unwritable": "No se puede escribir en el directorio \"$1\".\nModifica sus permisos para que el servidor web pueda escribir en él, y vuelve a intentarlo.",
"config-sqlite-connection-error": "$1.\n\nVerifica el directorio de datos y el nombre de la base de datos mostrada a continuación, e inténtalo nuevamente.",
@@ -208,8 +206,8 @@
"config-mysql-utf8": "UTF-8",
"config-mysql-charset-help": "En '''modo binario''', MediaWiki almacena texto UTF-8 para la base de datos en campos binarios.\nEsto es más eficiente que el modo UTF-8 de MySQL y le permite utilizar la gama completa de caracteres Unicode.\n\nEn '''modo UTF-8''', MySQL sabrá qué conjunto de caracteres emplean sus datos y puede presentarlos y convertirlos adecuadamente, pero no le permitirá almacenar caracteres por encima del [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes plano multilingüe básico].",
"config-mssql-auth": "Tipo de autenticación:",
- "config-mssql-install-auth": "Seleccione el tipo de autenticación que se utilizará para conectarse a la base de datos durante el proceso de instalación.\nSi selecciona \"{{int:config-mssql-windowsauth}}\", las credenciales de cualquier usuario de el servidor web que se está ejecutando van a ser utilizadas.",
- "config-mssql-web-auth": "Seleccione el tipo de autenticación que utilizará el servidor web para conectarse al servidor de base de datos, durante el funcionamiento normal de la wiki.\nSi selecciona \"{{int:config-mssql-windowsauth}}\", las credenciales del usuario que sea cual sea el servidor Web se ejecuta como será utilizado.",
+ "config-mssql-install-auth": "Selecciona el tipo de autenticación que se utilizará para conectarse a la base de datos durante el proceso de instalación.\nSi seleccionas \"{{int:config-mssql-windowsauth}}\", se usarán las credenciales del usuario con el que se ejecuta el servidor web.",
+ "config-mssql-web-auth": "Selecciona el tipo de autenticación que utilizará el servidor web para conectarse al servidor de base de datos, durante el funcionamiento normal de la wiki.\nSi seleccionas \"{{int:config-mssql-windowsauth}}\", se usarán las credenciales del usuario con el cual se ejecuta el servidor web.",
"config-mssql-sqlauth": "Autenticación de SQL Server",
"config-mssql-windowsauth": "Autentificación de Windows",
"config-site-name": "Nombre del wiki:",
@@ -239,7 +237,7 @@
"config-admin-error-bademail": "Has escrito una dirección de correo electrónico no válida.",
"config-subscribe": "Suscribirse a la [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce lista de correo de anuncios de versiones].",
"config-subscribe-help": "Esta es una lista de divulgación de bajo volumen para anuncios de lanzamiento de versiones nuevas, incluyendo anuncios de seguridad importantes.\nTe recomendamos suscribirte y actualizar tu instalación MediaWiki cada vez que se lance una nueva versión.",
- "config-subscribe-noemail": "Ha intentado suscribirse a la lista de correo de anuncios de nuevos lanzamientos sin proporcionar una dirección de correo electrónico.\nProporcione una dirección de correo electrónico si desea suscribirse a la lista de correo.",
+ "config-subscribe-noemail": "Has intentado suscribirte a la lista de correo de anuncios de nuevos lanzamientos sin proporcionar una dirección de correo electrónico.\nProporciona una dirección de correo electrónico si quieres suscribirte a la lista de correo.",
"config-almost-done": "¡Ya casi has terminado!\nAhora puedes saltarte el resto de los pasos e instalar el wiki ya.",
"config-optional-continue": "Hazme más preguntas.",
"config-optional-skip": "Ya estoy aburrido, sólo instala el wiki.",
@@ -266,19 +264,19 @@
"config-email-user-help": "Permitir que todos los usuarios intercambien correos electrónicos si lo han activado en sus preferencias.",
"config-email-usertalk": "Activar notificaciones de páginas de discusión de usuarios",
"config-email-usertalk-help": "Permitir a los usuarios recibir notificaciones de cambios en la página de discusión de usuario, si lo han activado en sus preferencias.",
- "config-email-watchlist": "Activar notificación de alteraciones a la páginas vigiladas",
+ "config-email-watchlist": "Activar la notificación de la lista de seguimiento",
"config-email-watchlist-help": "Permitir a los usuarios recibir notificaciones de cambios en la páginas que vigilan, si lo han activado en sus preferencias.",
"config-email-auth": "Activar autenticación del correo electrónico",
"config-email-auth-help": "Si esta opción está habilitada, los usuarios tienen que confirmar su dirección de correo electrónico mediante un enlace que se les envía a ellos cuando éstos lo establecen o lo cambian.\nSolo las direcciones de correo electrónico autenticadas pueden recibir correos electrónicos de otros usuarios o correos electrónicos de notificación de cambios.\nEsta opción está '''recomendada''' para wikis públicos debido a posibles abusos de las características del correo electrónico.",
"config-email-sender": "Dirección de correo electrónico de retorno:",
- "config-email-sender-help": "Introduce la dirección de correo electrónico que será usada como dirección de retorno en los mensajes electrónicos de salida.\nAquí llegarán los correos electrónicos que no lleguen a su destino.\nMuchos servidores de correo electrónico exigen que por lo menos la parte del nombre del dominio sea válida.",
+ "config-email-sender-help": "Escribe la dirección de correo electrónico que se usará como dirección de retorno en los mensajes electrónicos de salida.\nAquí llegarán los correos electrónicos que no lleguen a su destino.\nMuchos servidores de correo electrónico exigen que por lo menos la parte del nombre del dominio sea válida.",
"config-upload-settings": "Cargas de imágenes y archivos",
"config-upload-enable": "Habilitar la subida de archivos",
"config-upload-help": "La carga de archivos expone potencialmente su servidor a riesgos de seguridad.\nPara obtener más información, lea la [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security sección de seguridad] en el manual.\n\nPara habilitar la carga de archivos, cambie el modo en el subdirectorio <code>images</code> bajo el directorio raíz de MediaWiki para que el servidor web pueda escribir en él.\nA continuación, habilite esta opción.",
- "config-upload-deleted": "*Directorio para los archivos eliminados:",
+ "config-upload-deleted": "Directorio para los archivos eliminados:",
"config-upload-deleted-help": "Elige un directorio en el que guardar los archivos eliminados.\nLo ideal es una carpeta no accesible desde la red.",
"config-logo": "URL del logo :",
- "config-logo-help": "La apariencia por defecto de MediaWiki incluye espacio para un logotipo de 135x160 píxeles encima del menú de la barra lateral.\nCargua una imagen de tamaño adecuado e introduce la dirección URL aquí.\n\nPuedes usar <code>$wgStylePath</code> o <code>$wgScriptPath</code> si tu logotipo es relativo a esas rutas.\n\nSi no deseas un logotipo, deja esta casilla en blanco.",
+ "config-logo-help": "La apariencia predeterminada de MediaWiki incluye espacio para un logotipo de 135x160 píxeles encima del menú de la barra lateral.\nCarga una imagen de tamaño adecuado y escribe la dirección URL aquí.\n\nPuedes usar <code>$wgStylePath</code> o <code>$wgScriptPath</code> si tu logotipo es relativo a esas rutas.\n\nSi no deseas un logotipo, deja esta casilla en blanco.",
"config-instantcommons": "Habilitar Instant Commons",
"config-instantcommons-help": "[//www.mediawiki.org/wiki/InstantCommons Instant Commons] es una característica que permite que los wikis puedan utilizar imágenes, sonidos y otros archivos multimedia que se encuentran en el sitio [//commons.wikimedia.org/ Wikimedia Commons].\nPara ello, MediaWiki requiere acceso a Internet.\n\nPara obtener más información sobre esta función, incluidas las instrucciones sobre cómo configurarlo para otras wikis distintas de Wikimedia Commons, consulte [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos el manual].",
"config-cc-error": "El selector de licencia de Creative Commons no dio resultado.\nEscribe el nombre de la licencia manualmente.",
@@ -304,35 +302,35 @@
"config-skins-missing": "No se encontró ninguna apariencia; MediaWiki utilizará una apariencia anterior hasta que instales unas apariencias adecuadas.",
"config-skins-must-enable-some": "Debes seleccionar al menos una apariencia para activar.",
"config-skins-must-enable-default": "La apariencia elegida como predeterminada debe estar habilitada.",
- "config-install-alreadydone": "'''Aviso:''' Parece que ya habías instalado MediaWiki y estás intentando instalarlo nuevamente.\nPasa a la próxima página, por favor.",
+ "config-install-alreadydone": "<strong>Advertencia:</strong> parece que ya habías instalado MediaWiki y estás intentando instalarlo nuevamente.\nPasa a la próxima página.",
"config-install-begin": "Al pulsar en «{{int:config-continue}}» comenzará el proceso de instalación de MediaWiki.\nSi quieres realizar algún cambio, pulsa en «{{int:config-back}}».",
"config-install-step-done": "hecho",
"config-install-step-failed": "falló",
- "config-install-extensions": "Extensiones inclusive",
+ "config-install-extensions": "Incluyendo extensiones",
"config-install-database": "Configurando la base de datos",
"config-install-schema": "Creando el esquema",
"config-install-pg-schema-not-exist": "El esquema PostgreSQL no existe.",
- "config-install-pg-schema-failed": "La creación de las tablas ha fallado.\nAsegúrate de que el usuario \"$1\" puede escribir en el esquema \"$2\".",
+ "config-install-pg-schema-failed": "Falló la creación de las tablas.\nAsegúrate de que la cuenta «$1» tiene permiso de escritura para el esquema «$2».",
"config-install-pg-commit": "Validando los cambios",
"config-install-pg-plpgsql": "Comprobación de lenguaje PL/pgSQL",
- "config-pg-no-plpgsql": "Necesita instalar el lenguaje PL/pgSQL en la base de datos $1",
+ "config-pg-no-plpgsql": "Necesitas instalar el lenguaje PL/pgSQL en la base de datos $1",
"config-pg-no-create-privs": "La cuenta especificada para la instalación no tiene suficientes privilegios para crear una cuenta.",
- "config-pg-not-in-role": "La cuenta especificada para el usuario web ya existe.\nLa cuenta especificada para la instalación no es de un superusuario y no es miembro del grupo de usuarios con acceso a la web, por lo que es incapaz de crear objetos pertenecientes al usuario web.\n\nMediaWiki requiere actualmente que las tablas sean propiedad del usuario web. Especifique otro nombre de cuenta web, o haga clic en \"atrás\" y especifique un usuario de instalación con los privilegios convenientes.",
+ "config-pg-not-in-role": "La cuenta especificada para el usuario web ya existe.\nLa cuenta especificada para la instalación no es de un superusuario y no es miembro del grupo de usuarios con acceso a la web, por lo que es incapaz de crear objetos pertenecientes al usuario web.\n\nMediaWiki requiere actualmente que las tablas sean propiedad del usuario web. Especifica otro nombre de cuenta web, o haz clic en \"atrás\" y especifica un usuario de instalación con los privilegios convenientes.",
"config-install-user": "Creando el usuario de la base de datos",
"config-install-user-alreadyexists": "El usuario \"$1\" ya existe",
"config-install-user-create-failed": "La creación del usuario \"$1\" falló: $2",
"config-install-user-grant-failed": "La concesión de permisos al usuario \"$1\" falló: $2",
"config-install-user-missing": "El usuario especificado \"$1\" no existe.",
- "config-install-user-missing-create": "El usuario especificado \"$1\" no existe.\nPor favor, haga clic en la casilla \"Crear cuenta\" que aparece a continuación si desea crearlo.",
+ "config-install-user-missing-create": "El usuario especificado \"$1\" no existe.\nHaz clic en la casilla \"Crear cuenta\" debajo si quieres crearlo.",
"config-install-tables": "Creando tablas",
- "config-install-tables-exist": "'''Advertencia''': Al parecer, las tablas de MediaWiki ya existen. Saltándose su creación.",
- "config-install-tables-failed": "'''Error''': La creación de las tablas falló con el siguiente error: $1",
+ "config-install-tables-exist": "<strong>Advertencia:</strong> al parecer, las tablas de MediaWiki ya existen. Saltándose su creación.",
+ "config-install-tables-failed": "<strong>Error:</strong> la creación de las tablas falló con el siguiente error: $1",
"config-install-interwiki": "Llenando la tabla interwiki predeterminada",
- "config-install-interwiki-list": "No se pudo encontrar el archivo <code>interwiki.list</code>.",
- "config-install-interwiki-exists": "'''Advertencia''': La tabla de interwikis parece ya contener entradas.\nSe omitirá la lista predeterminada.",
+ "config-install-interwiki-list": "No se pudo leer el archivo <code>interwiki.list</code>.",
+ "config-install-interwiki-exists": "<strong>Advertencia:</strong> la tabla de interwikis parece ya contener entradas.\nSe omitirá la lista predeterminada.",
"config-install-stats": "Iniciando las estadísticas",
"config-install-keys": "Generando claves secretas",
- "config-insecure-keys": "''' Atención:'' ' {{PLURAL:$2|Una clave de seguridad generada|Las claves de seguridad generadas}} ($1) durante la instalación no {{PLURAL:$2|es totalmente segura|son totalmente seguras}}. Considere {{PLURAL:$2| cambiarla|cambiarlas}} manualmente.",
+ "config-insecure-keys": "<strong>Advertencia:</strong> {{PLURAL:$2|una clave de seguridad generada|las claves de seguridad generadas}} ($1) durante la instalación no {{PLURAL:$2|es totalmente segura|son totalmente seguras}}. Considera {{PLURAL:$2| cambiarla|cambiarlas}} manualmente.",
"config-install-updates": "Evitar ejecutar actualizaciones innecesarias",
"config-install-updates-failed": "<strong>Error:</strong> falló la inserción de claves de actualización en las tablas con el siguiente error: $1",
"config-install-sysop": "Creando la cuenta de usuario del administrador",
@@ -342,7 +340,7 @@
"config-install-extension-tables": "Creando las tablas para las extensiones habilitadas",
"config-install-mainpage-failed": "No se pudo insertar la página principal: $1",
"config-install-done": "<strong>¡Felicidades!</strong>\nHas instalado MediaWiki correctamente.\n\nEl instalador ha generado un archivo <code>LocalSettings.php</code>.\nEste contiene toda su configuración.\n\nDeberás descargarlo y ponerlo en la base de la instalación de wiki (el mismo directorio que index.php). La descarga debería haber comenzado automáticamente.\n\nSi no comenzó la descarga, o si se ha cancelado, puedes reiniciar la descarga haciendo clic en el siguiente enlace:\n\n$3\n\n<strong>Nota</strong>: Si no haces esto ahora, este archivo de configuración generado no estará disponible más tarde si sales de la instalación sin descargarlo.\n\nCuando lo hayas hecho, podrás <strong>[$2 entrar en tu wiki]</strong>.",
- "config-download-localsettings": "Descargar archivo <code>LocalSettings.php</code>",
+ "config-download-localsettings": "Descargar <code>LocalSettings.php</code>",
"config-help": "ayuda",
"config-help-tooltip": "haz clic para ampliar",
"config-nofile": "El archivo \"$1\" no se pudo encontrar. ¿Se ha eliminado?",
diff --git a/includes/installer/i18n/et.json b/includes/installer/i18n/et.json
index a3732a80..31441e08 100644
--- a/includes/installer/i18n/et.json
+++ b/includes/installer/i18n/et.json
@@ -5,9 +5,12 @@
"Pikne",
"Boxmein",
"Cumbril",
- "Roland"
+ "Roland",
+ "Postituvi"
]
},
+ "config-desc": "MediaWiki paigaldaja",
+ "config-title": "MediaWiki $1 install",
"config-information": "Teave",
"config-upgrade-key-missing": "Tuvastati olemasolev MediaWiki install.\nSelle installi täiendamiseks lisa palun järgmine rida faili <code>LocalSettings.php</code> lõppu:\n\n$1",
"config-session-error": "Tõrge seansi alustamisel: $1",
@@ -66,7 +69,7 @@
"config-license-cc-by": "Creative Commonsi litsents \"Autorile viitamine\"",
"config-license-cc-by-nc-sa": "Creative Commonsi litsents \"Autorile viitamine + mitteäriline eesmärk + jagamine samadel tingimustel\"",
"config-email-settings": "E-posti sätted",
- "config-email-sender": "Saatja e-aadress:",
+ "config-email-sender": "Saatja e-posti aadress:",
"config-logo": "Logo internetiaadress:",
"config-cc-again": "Vali uuesti...",
"config-extensions": "Lisad",
diff --git a/includes/installer/i18n/eu.json b/includes/installer/i18n/eu.json
index baab24aa..57140d31 100644
--- a/includes/installer/i18n/eu.json
+++ b/includes/installer/i18n/eu.json
@@ -3,7 +3,8 @@
"authors": [
"An13sa",
"පසිඳු කාවින්ද",
- "Subi"
+ "Subi",
+ "Sator"
]
},
"config-desc": "MediaWiki instalatzailea",
@@ -74,6 +75,7 @@
"config-email-settings": "E-posta hobespenak",
"config-logo": "Logo URL:",
"config-extensions": "Luzapenak",
+ "config-skins": "Itxurak",
"config-install-step-done": "egina",
"config-help": "Laguntza",
"mainpagetext": "'''MediaWiki arrakastaz instalatu da.'''",
diff --git a/includes/installer/i18n/fa.json b/includes/installer/i18n/fa.json
index 6452fc6e..de264994 100644
--- a/includes/installer/i18n/fa.json
+++ b/includes/installer/i18n/fa.json
@@ -8,7 +8,8 @@
"Pouyana",
"Reza1615",
"Alirezaaa",
- "Danialbehzadi"
+ "Danialbehzadi",
+ "Leyth"
]
},
"config-desc": "نصب کنندهٔ ویکی‌مدیا",
@@ -66,7 +67,7 @@
"config-magic-quotes-sybase": "'''مخرب: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] فعال است.\nاین گزینه اطلاعات داده شده به رایانه را به طور غیر‌قابل پیش‌بینی از بین می‌برد.\nشما نمی‌توانید مدیاویکی را نصب یا استفاده کنید مگر اینکه این گزینه غیر‌فعال باشد.",
"config-mbstring": "''' مخرب:[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] فعال است.\nاین گزینه باعث ایجاد خطا می‌شود و ممکن است اطلاعات را به طور غیر‌قابل پیش‌بینی از بین ببرد.\nشما نمی‌توانید مدیاویکی را نصب یا استفاده کنید مگر اینکه این گزینه غیر‌فعال باشد.",
"config-safe-mode": "'''هشدار:''' PHP's [http://www.php.net/features.safe-mode safe mode] فعال است.\nممکن است باعث ایجاد مشکلاتی شود، مخصوصاً اگر از ارسال پرونده استفاده شود و <code>math</code> پشتیبانی شود.",
- "config-xml-bad": "ماژول اکس‌ام‌ال پی‌اچ‌پی کار نمی‌کند.\nمدیاویکی نیازمند عملیاتی در این ماژول است و در این پیکربندی کار نخواهد‌کرد.\nاگر مان‌دریک را اجرا می‌کنید, بستهٔ نرم افزاری پی‌اچ‌پی-ایکس‌ام‌ال را نصب کنید.",
+ "config-xml-bad": "ماژول اکس‌ام‌ال پی‌اچ‌پی کار نمی‌کند.\nمدیاویکی نیازمند عملیاتی در این ماژول است و در این پیکربندی کار نخواهد‌کرد.\nشاید نیاز باشد که بستهٔ نرم افزاریِ آرپی‌ام پی‌اچ‌پی-ایکس‌ام‌ال را نصب کنید.",
"config-pcre-old": "''' خطای اساسی:'' ' PCRE $1 یا بعدا مورد نیاز است.\nکد باینری پی‌اچ‌پی‌تان با PCRE $2 پیوند دارد.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE اطلاعات بیشتر].",
"config-pcre-no-utf8": "'''مخرب:''' به‌ نظر می‌رسد ماژول پی‌سی‌آرایی پی‌اچ‌پی بدون پشتیبانی پی‌سی‌آرایی_یو‌تی‌اف۸ تهیه شده‌است.\nمدیاویکی برای درست عمل کردن نیازمند پشتیبانی یوتی‌اف-۸ است.",
"config-memory-raised": "PHP's <code>memory_limit</code>, نسخهٔ $1 است، به نسخهٔ $2 ارتقاء داده شده‌است.",
@@ -132,7 +133,7 @@
"config-oracle-temp-ts": "جدول موقت:",
"config-type-mysql": "مای‌اس‌کیو‌ال (یا سازگار)",
"config-type-mssql": "سرور مایکروسافت اس‌کیو‌ال",
- "config-support-info": "مدیاویکی سامانه‌های پایگاه اطلاعاتی زیر را حمایت می‌کند:\n$1\nاگر متوجه سامانه پایگاه اطلاعاتی که سعی دارید از فهرست زیر استفاده کنید، نمی‌شوید، بنابراین دستورالعمل‌های مرتبط در بالا را برای فعال‌کردن پشتیبانی دنبال کنید.",
+ "config-support-info": "مدیاویکی سامانه‌های پایگاه اطلاعاتی زیر را حمایت می‌کند:\n$1\nاگر متوجه سامانه پایگاه اطلاعاتی که سعی دارید از فهرست زیر استفاده کنید، نمی‌شوید، بنابراین دستورالعمل‌های مرتبط در بالا را برای فعال کردن پشتیبانی دنبال کنید.",
"config-dbsupport-mysql": "*[{{int:version-db-mysql-url}} MySQL] مهم‌ترین هدف برای مدیاویکی است و بهترین پشتیبانی. مدیاویکی همچنین کار می‌کند با [{{int:version-db-mariadb-url}} MariaDB] و [{{int:version-db-percona-url}} Percona Server] که با MySQL سازگار هستند.([http://www.php.net/manual/en/mysqli.installation.php چگونه php را با MySQL کامپایل کنیم])",
"config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] یک منبع آزاد پر‌طرفدار دستگاه پایگاه اطلاعاتی به عنوان یک غیرمتعارف برای مای‌اس‌کیوال است.ممکن است عیوب بارز مختصری باشد، و برای استفاده در یک محیط تولیدی توصیه نمی‌شود.([http://www.php.net/manual/en/pgsql.installation.php how to compile PHP with PostgreSQL support])",
"config-dbsupport-sqlite": "*[{{int:version-db-sqlite-url}} اس‌کیولایت] یک سامانه پایگاه اطلاعاتی کم حجمی است که بسیار خوب پشتیبانی شده‌است.\n([http://www.php.net/manual/en/pdo.installation.php چگونگی کامپایل پی‌اچ‌پی با اس‌کیولایت]، از PDO استفاده می‌کند)",
@@ -211,7 +212,7 @@
"config-admin-name-invalid": "نام کاربری تعیین شدهٔ \"<nowiki>$1</nowiki>\" نامعتبر است.\nیک نام کاربری دیگر تعیین کنید.",
"config-admin-password-blank": "برای حساب سرپرست یک رمز عبور وارد کنید.",
"config-admin-password-mismatch": "دو رمز عبوری که وارد کرده‌اید با هم مطابقت ندارند.",
- "config-admin-email": "آدرس ایمیل:",
+ "config-admin-email": "نشانی ایمیل:",
"config-admin-email-help": "یک آدرس ایمیل برای اجازهٔ دریافت ایمیل از دیگر کاربران ویکی، اینجا وارد کنید، رمز عبور خود را دوباره تنظیم کنید، و از تغییرات صفحه در فهرست پیگیری‌ها مطلع باشید. می‌توانید این بخش را خالی بگذارید.",
"config-admin-error-user": "خطای داخلی هنگام ایجاد یک مدیر با نام \"<nowiki>$1</nowiki>\".",
"config-admin-error-password": "خطای داخلی هنگام تنظیم یک رمز عبور برای مدیر \"<nowiki>$1</nowiki>\": <pre>$2</pre>",
@@ -241,14 +242,14 @@
"config-email-settings": "تنظیمات ایمیل",
"config-enable-email": "فعال‌سازی ایمیل خروجی",
"config-enable-email-help": "اگر می‌خواهید ارسال ایمیل کار کند، [http://www.php.net/manual/en/mail.configuration.php PHP's mail settings] نیازمند پیکربندی صحیح است.\nاگر هیچ قابلیت ایمیلی نمی‌خواهید، می‌توانید آنها را اینجا غیر‌فعال کنید.",
- "config-email-user": "فعال‌کردن ایمیل کاربر به کاربر",
+ "config-email-user": "فعال کردن ایمیل کاربر به کاربر",
"config-email-user-help": "به همهٔ کاربرانی که ارسال ایمیل را در ترجیحات خود فعال کرده‌اند، اجازه داده خواهد شد که به یکدیگر ایمیل ارسال کنند.",
- "config-email-usertalk": "فعال‌کردن اطلاع‌رسانی صفحهٔ بحث کاربر",
+ "config-email-usertalk": "فعال کردن اطلاع‌رسانی صفحهٔ بحث کاربر",
"config-email-usertalk-help": "به همهٔ کاربرانی که دریافت اطلاعیه را در اولویت‌های خود فعال کرده‌اند،اجازه خواهد داده‌شد که اطلاعیه‌ها را در صفحهٔ تغییر گفت‌وگوی کاربر دریافت کنند.",
- "config-email-watchlist": "فعال‌کردن اطلاع‌رسانی فهرست پیگیری‌ها",
+ "config-email-watchlist": "فعال کردن اطلاع‌رسانی فهرست پیگیری‌ها",
"config-email-watchlist-help": "به همهٔ کاربرانی که مشاهدهٔ صفحه را در اولویت‌های خود فعال کرده‌اند،اجازه خواهد داده‌شد که اطلاعیه‌های در رابطه با صفحات مشاهده شده را دریافت کنند.",
"config-email-auth": "فعال کردن احراز هویت توسط ایمیل",
- "config-email-auth-help": "اگر این گزینه را فعال کنید، کاربران باید ایمیل خود را با استفاده از پیوند تأیید که به ایمیلشان ارسال می‌شود، تأیید کنند. \nدر این صورت تنها ایمیل‌هایی که تأیید شده باشند، می‌توانند از سیستم در هنگام تغییرات، ایمیل دریافت کنند.\nبرای ویکی‌هایی که به صورت عمومی استفاده می‌شوند، فعال‌کردن این گزینه پیشنهاد می‌شود.",
+ "config-email-auth-help": "اگر این گزینه را فعال کنید، کاربران باید ایمیل خود را با استفاده از پیوند تأیید که به ایمیلشان ارسال می‌شود، تأیید کنند. \nدر این صورت تنها ایمیل‌هایی که تأیید شده باشند، می‌توانند از سیستم در هنگام تغییرات، ایمیل دریافت کنند.\nبرای ویکی‌هایی که به صورت عمومی استفاده می‌شوند، فعال کردن این گزینه پیشنهاد می‌شود.",
"config-email-sender": "آدرس ایمیل بازگشت:",
"config-email-sender-help": "آدرس ایمیلی را وارد کنید که هنگام ارسال ایمیل خارج از محدوده از آن به عنوان ایمیل بازگشت استفاده شود.\nبه جایی که پیام‌ها برگشت داده می‌شوند، فرستاده خواهد شد.\nبسیاری از سرورهای پستی حداقل به بخش نام عمومی معتبر نیاز دارند.",
"config-upload-settings": "بارگذاری‌های پرونده و تصویر",
@@ -258,7 +259,7 @@
"config-upload-deleted-help": "فهرستی برای بایگانی کردن پوشه‌های حذف شده انتخاب کنید.\nبه طور مطلوب،از شبکه نباید در دسترس باشد.",
"config-logo": "نشانی نامواره:",
"config-logo-help": "پوستهٔ پیش‌فرض مدیاویکی شامل مکانی برای یک آرم ۱۳۵x۱۶۰ پیکسلی بالای منوی نوارکناری است.\nیک عکس با اندازهٔ مناسب ارسال کنید، و یوآرال را اینجا وارد کنید.\nاگر آرم شما با آن راه‌ها مزتبط است،می‌توانید از <code>$wgStylePath</code> یا <code>$wgScriptPath</code> استفاده کنید.\nاگر آرم نمی‌خواهید، این جعبه را خالی رها کنید.",
- "config-instantcommons": "فعال‌کردن فوری کامنز",
+ "config-instantcommons": "فعال کردن فوری ویکی‌انبار",
"config-instantcommons-help": "[//www.mediawiki.org/ ویکی و InstantCommons ویکی‌انبار فوری] یک ویژگی‌است که به شما اجازه می‌دهد تا تصاویر، صداها یا سایر رسانه‌های یافته شده بر روی [//commons.wikimedia.org/ انبار ویکی مدیا] را استفاده کنید.\n\nبرای استفاده از این ویژگی مدیاویکی نیازمند دسترسی به اینترنت است.\n\nبرای کسب اطلاعات بیشتر درباره این ویژگی٬ شامل دستورالعمل‌های برای چگونگی نصب آن برای سایر ویکی‌های بجز ویکی‌انبار لطفاً از [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos the نصب دستی] استفاده کنید.",
"config-cc-error": "مجوز چوزر عوام سازنده بی‌نتیجه ماند.\nنام مجوز را دستی وارد کنید.",
"config-cc-again": "انتخاب دوباره...",
diff --git a/includes/installer/i18n/fo.json b/includes/installer/i18n/fo.json
index d40c45a2..0a147d2e 100644
--- a/includes/installer/i18n/fo.json
+++ b/includes/installer/i18n/fo.json
@@ -35,6 +35,19 @@
"config-help-restart": "Ynskir tú at sletta øll goymd dáta sum tú hevur skrivað og byrja umaftur at installera?",
"config-restart": "Ja, byrja umaftur",
"config-env-php": "PHP $1 er innstallerað.",
- "config-env-php-toolow": "PHP $1 er installerað.\nMen, MediaWiki krevur PHP $2 ella hægri.",
+ "config-env-hhvm": "HHVM $1 er lagt inn.",
+ "config-unicode-using-intl": "Brúkar [http://pecl.php.net/intl intl PECL ískoytið] til Unicode normalisering.",
+ "config-unicode-pure-php-warning": "<strong>Ávaring:</strong> [http://pecl.php.net/intl intl PECL ískoytið] er ikki tøkt at handfara Unicode normalisering, fellur aftur til eina spakuligari reina-PHP verkseting.\nUm tú koyrir eina netsíðu við høgari ferðslu, so eigur tú at lesa eitt sindur um [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalisering].",
+ "config-unicode-update-warning": "<strong>Ávaring:</strong> Tann innlagda versjónin av Unicode normalisering wrapper nýtir eina eldri versjón av [http://site.icu-project.org/ bókasavninum hjá ICU verkætlanini].\nTú eigur at [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations fremja uppstigning] um tú stúrir fyri at nýta Unicode.",
+ "config-diff3-bad": "GNU diff3 ikki funnið.",
+ "config-git": "Fann Git version control forritið: <code>$1</code>.",
+ "config-git-bad": "Git version control forritið varð ikki funnið.",
+ "config-imagemagick": "Fann ImageMagick: <code>$1</code>.\nTað at velja smámynd verður gjørt virkið um tú aktiverar møgulleikan at leggja myndir út.",
+ "config-using-server": "Brúkar servaranavnið \"<nowiki>$1</nowiki>\".",
+ "config-using-uri": "Nýtir servara URL \"<nowiki>$1$2</nowiki>\".",
+ "config-db-type": "Slag av dátugrunni:",
+ "config-db-host": "Dátugrunn vertur:",
+ "config-db-username": "Dátugrunn brúkaranavn:",
+ "config-db-password": "Dátugrunn loyniorð:",
"mainpagetext": "'''Innlegging av Wiki-ritbúnaði væleydnað.'''"
}
diff --git a/includes/installer/i18n/fr.json b/includes/installer/i18n/fr.json
index c9750903..87f3374d 100644
--- a/includes/installer/i18n/fr.json
+++ b/includes/installer/i18n/fr.json
@@ -68,7 +68,6 @@
"config-env-bad": "L’environnement a été vérifié.\nVous ne pouvez pas installer MediaWiki.",
"config-env-php": "PHP $1 est installé.",
"config-env-hhvm": "HHVM $1 est installé.",
- "config-unicode-using-utf8": "Utilisation de utf8_normalize.so par Brion Vibber pour la normalisation Unicode.",
"config-unicode-using-intl": "Utilisation de [http://pecl.php.net/intl l'extension PECL intl] pour la normalisation Unicode.",
"config-unicode-pure-php-warning": "<strong>Attention</strong> : L'[http://pecl.php.net/intl extension PECL intl] n'est pas disponible pour la normalisation d’Unicode, retour à la version lente implémentée en PHP.\nSi votre site web sera très fréquenté, vous devriez lire ceci : [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations ''Unicode normalization''] (en anglais).",
"config-unicode-update-warning": "'''Attention''': La version installée du ''wrapper'' de normalisation Unicode utilise une vieille version de la [http://site.icu-project.org/ bibliothèque logicielle ''ICU Project''].\nVous devriez faire une [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations mise à jour] si vous êtes tout à fait concerné par l'usage d'Unicode.",
@@ -81,7 +80,7 @@
"config-magic-quotes-sybase": "'''Erreur fatale : [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybasee] est activé !'''\nCette option corrompt les données de manière imprévisible.\nVous ne pouvez pas installer ou utiliser MediaWiki tant que cette option est activée.",
"config-mbstring": "'''Erreur fatale : [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] est activé !'''\nCette option provoque des erreurs et peut corrompre les données de manière imprévisible.\nVous ne pouvez pas installer ou utiliser MediaWiki tant que cette option est activée.",
"config-safe-mode": "'''Attention : le « [http://www.php.net/features.safe-mode safe mode] » est activé !'''\nCeci peut causer des problèmes, en particulier si vous utilisez le téléversement de fichiers et le support de <code>math</code>.",
- "config-xml-bad": "Le module XML de PHP est manquant.\nMediaWiki requiert des fonctions de ce module et ne fonctionnera pas avec cette configuration.\nSi vous êtes sous Mandrake, installez le paquet php-xml.",
+ "config-xml-bad": "Le module XML de PHP est manquant.\nMediaWiki requiert des fonctions de ce module et ne fonctionnera pas avec cette configuration.\nVous pourrez avoir besoin d’installer le paquet RPM php-xml.",
"config-pcre-old": "'''Fatal :''' PCRE $1 ou ultérieur est nécessaire.\nVotre binaire PHP est lié avec PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/Plus d’information sur PCRE].",
"config-pcre-no-utf8": "'''Erreur fatale''': Le module PCRE de PHP semble être compilé sans le support PCRE_UTF8.\nMédiaWiki nécessite la gestion d’UTF-8 pour fonctionner correctement.",
"config-memory-raised": "Le paramètre <code>memory_limit</code> de PHP était à $1, porté à $2.",
diff --git a/includes/installer/i18n/fy.json b/includes/installer/i18n/fy.json
index 39c46b53..f84063b2 100644
--- a/includes/installer/i18n/fy.json
+++ b/includes/installer/i18n/fy.json
@@ -13,6 +13,7 @@
"config-mysql-binary": "Binêr",
"config-ns-generic": "Projekt",
"config-admin-password": "Wachtwurd:",
+ "config-admin-email": "E-mailadres:",
"config-help": "help",
"mainpagetext": "'''MediaWiki-program goed ynstallearre.'''",
"mainpagedocfooter": "Rieplachtsje de [//meta.wikimedia.org/wiki/Help:Contents Ynhâldsopjefte hantlieding] foar ynformaasje oer it gebrûk fan 'e wikisoftware.\n\n== Mear help oer Mediawiki ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings List mei ynstellingen]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Faak stelde fragen (FAQ)]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Mailinglist foar oankundigings fan nije ferzjes]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]"
diff --git a/includes/installer/i18n/gl.json b/includes/installer/i18n/gl.json
index 940b4c01..544b852e 100644
--- a/includes/installer/i18n/gl.json
+++ b/includes/installer/i18n/gl.json
@@ -13,7 +13,7 @@
"config-localsettings-upgrade": "Detectouse un ficheiro <code>LocalSettings.php</code>.\nPara actualizar esta instalación, introduza o valor de <code>$wgUpgradeKey</code> na caixa.\nPode atopalo en <code>LocalSettings.php</code>.",
"config-localsettings-cli-upgrade": "Detectouse un ficheiro <code>LocalSettings.php</code>.\nPara actualizar esta instalación, execute <code>update.php</code>",
"config-localsettings-key": "Clave de actualización:",
- "config-localsettings-badkey": "A clave dada é incorrecta",
+ "config-localsettings-badkey": "A clave dada é incorrecta.",
"config-upgrade-key-missing": "Detectouse unha instalación existente de MediaWiki.\nPara actualizar esta instalación, inclúa esta liña ao final do ficheiro <code>LocalSettings.php</code>:\n\n$1",
"config-localsettings-incomplete": "Semella que o ficheiro <code>LocalSettings.php</code> existente está incompleto.\nA variable $1 non está establecida.\nModifique o ficheiro <code>LocalSettings.php</code> de xeito que a variable quede establecida e prema en \"{{int:Config-continue}}\".",
"config-localsettings-connection-error": "Atopouse un erro ao conectar coa base de datos empregando a configuración especificada no ficheiro <code>LocalSettings.php</code>. Corrixa esta configuración e inténteo de novo.\n\n$1",
@@ -50,7 +50,6 @@
"config-env-bad": "Rematou a comprobación da contorna.\nNon pode instalar MediaWiki.",
"config-env-php": "Está instalado o PHP $1.",
"config-env-hhvm": "Está instalado o HHVM $1.",
- "config-unicode-using-utf8": "Usando utf8_normalize.so de Brion Vibber para a normalización Unicode.",
"config-unicode-using-intl": "Usando a [http://pecl.php.net/intl extensión intl PECL] para a normalización Unicode.",
"config-unicode-pure-php-warning": "<strong>Atención:</strong> A [http://pecl.php.net/intl extensión intl PECL] non está dispoñible para manexar a normalización Unicode; volvendo á implementación lenta de PHP puro.\nSe o seu sitio posúe un alto tráfico de visitantes, debería ler un chisco sobre a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalización Unicode].",
"config-unicode-update-warning": "<strong>Atención:</strong> A versión instalada da envoltura de normalización Unicode emprega unha versión vella da biblioteca [http://site.icu-project.org/ do proxecto ICU].\nDebería [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations actualizar] se o uso de Unicode é importante para vostede.",
@@ -63,7 +62,7 @@
"config-magic-quotes-sybase": "<strong>Erro fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] está activado!</strong>\nEsta opción corrompe os datos de entrada de xeito imprevisible.\nNon pode instalar ou empregar MediaWiki a menos que esta opción estea desactivada.",
"config-mbstring": "<strong>Erro fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] está activado!</strong>\nEsta opción causa erros e pode corromper os datos de xeito imprevisible.\nNon pode instalar ou empregar MediaWiki a menos que esta opción estea desactivada.",
"config-safe-mode": "<strong>Atención:</strong> O [http://www.php.net/features.safe-mode safe mode] do PHP está activado.\nIsto pode causar problemas, particularmente se emprega cargas de ficheiros e soporte de <code>math</code>.",
- "config-xml-bad": "Falta o módulo XML do PHP.\nMediaWiki necesita funcións neste módulo e non funcionará con esta configuración.\nSe está executando o Mandrake, instale o paquete php-xml.",
+ "config-xml-bad": "Falta o módulo XML do PHP.\nMediaWiki necesita funcións neste módulo e non funcionará con esta configuración.\nPode que necesite instalar o php-xml no paquete RPM.",
"config-pcre-old": "<strong>Erro fatal:</strong> Necesítase PCRE $1 ou posterior.\nO seu PHP binario está ligado con PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Máis información].",
"config-pcre-no-utf8": "<strong>Erro fatal:</strong> Semella que o módulo PCRE do PHP foi compilado sen o soporte PCRE_UTF8.\nMediaWiki necesita soporte UTF-8 para funcionar correctamente.",
"config-memory-raised": "O parámetro <code>memory_limit</code> do PHP é $1. Aumentado a $2.",
@@ -103,8 +102,6 @@
"config-db-install-account": "Conta de usuario para a instalación",
"config-db-username": "Nome de usuario da base de datos:",
"config-db-password": "Contrasinal da base de datos:",
- "config-db-password-empty": "Introduza un contrasinal para o novo usuario da base de datos: $1.\nMalia que é posible crear usuarios sen contrasinal, esta práctica non é segura.",
- "config-db-username-empty": "Debe introducir un valor para \"{{int:config-db-username}}\"",
"config-db-install-username": "Escriba o nome de usuario que empregará para conectarse á base de datos durante o proceso de instalación. Este non é o nome de usuario da conta de MediaWiki, trátase do nome de usuario para a súa base de datos.",
"config-db-install-password": "Escriba o contrasinal que empregará para conectarse á base de datos durante o proceso de instalación. Este non é o contrasinal da conta de MediaWiki, trátase do contrasinal para a súa base de datos.",
"config-db-install-help": "Introduza o nome de usuario e contrasinal que se usará para conectar á base de datos durante o proceso de instalación.",
diff --git a/includes/installer/i18n/he.json b/includes/installer/i18n/he.json
index 34190891..9b5a3221 100644
--- a/includes/installer/i18n/he.json
+++ b/includes/installer/i18n/he.json
@@ -52,7 +52,6 @@
"config-env-bad": "הסביבה שלכם נבדקה.\nאי־אפשר להתקין מדיה־ויקי.",
"config-env-php": "מותקנת <span dir=\"ltr\">PHP $1</span>.",
"config-env-hhvm": "מותקנת <span dir=\"ltr\">HHVM $1</span>.",
- "config-unicode-using-utf8": "משתמש ב־utf8_normalize.so של בריון ויבר לנרמול יוניקוד.",
"config-unicode-using-intl": "משתמש ב[http://pecl.php.net/intl הרחבת intl PECL] לנרמול יוניקוד.",
"config-unicode-pure-php-warning": "'''אזהרה''': [http://pecl.php.net/intl הרחבת intl PECL] אינה זמינה לטיפול בנרמול יוניקוד. משתמש ביישום PHP טהור ואטי יותר.\nאם זהו אתר בעל תעבורה גבוהה, כדאי לקרוא את המסמך הבא: [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization].",
"config-unicode-update-warning": "'''אזהרה''': הגרסה המותקנת של מעטפת נרמול יוניקוד משתמשת בגרסה ישנה של הספרייה של [http://site.icu-project.org/ פרויקט ICU].\nכדאי [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations לעדכן] אם הטיפול ביוניקוד חשוב לך.",
@@ -65,7 +64,7 @@
"config-magic-quotes-sybase": "'''שגיאה סופנית''': האפשרות [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] פעילה!'''\nהאפשרות הזאת מעוותת את נתוני הקלט באופן בלתי־צפוי.\nלא ניתן להתקין את מדיה־ויקי או להשתמש בה אלא אם האפשרות הזאת תכובה.",
"config-mbstring": "'''שגיאה סופנית''': האפשרות [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] פעילה!'''\nהאפשרות הזאת גורמת לשגיאות ומעוותת את נתוני הקלט באופן בלתי־צפוי.\nלא ניתן להתקין את מדיה־ויקי או להשתמש בה אלא אם האפשרות הזאת תכובה.",
"config-safe-mode": "'''אזהרה:''' האפשרות [http://www.php.net/features.safe-mode safe mode] של PHP פעילה.\nהיא יכולה לגרום לבעיות, במיוחד אם אתם משתמשים בהעלאת קבצים או ב־<code>math</code>.",
- "config-xml-bad": "מודול XML של PHP חסר.\nמדיה־ויקי דורשת פונקציות של המודול ולא תעבוד עם הגדרות כאלו.\nאם מערכת ההפעלה שלהם היא Mandrake, התקינו את החבילה php-xml.",
+ "config-xml-bad": "מודול XML של PHP חסר.\nמדיה־ויקי דורשת פונקציות של המודול ולא תעבוד עם הגדרות כאלו.\nייתכן שצריך להתקין באמצעות RPM את חבילת php-xml.",
"config-pcre-old": "<strong>שגיאה סופנית:</strong> חובה להתקין PCRE מגרסה $1 או גרסה חדשה יותר.\nקובץ הרצת ה־PHP שלך מקושר עם PCRE מגרסה $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE מידע נוסף].",
"config-pcre-no-utf8": "'''שגיאה סופנית''': נראה שמודול PCRE של PHP מקומפל ללא תמיכה ב־PCRE_UTF8.\nמדיה־ויקי דורשת תמיכה ב־UTF-8 לפעילות נכונה.",
"config-memory-raised": "ערך האפשרות <code>memory_limit</code> של PHP הוא $1, הועלה ל־$2.",
diff --git a/includes/installer/i18n/hi.json b/includes/installer/i18n/hi.json
index 629b53b5..42dbd4f1 100644
--- a/includes/installer/i18n/hi.json
+++ b/includes/installer/i18n/hi.json
@@ -4,7 +4,8 @@
"Smtchahal",
"Vivek Rai",
"Phoenix303",
- "संजीव कुमार"
+ "संजीव कुमार",
+ "Sahilrathod"
]
},
"config-desc": "साँचा लिए इंस्टॉलर",
@@ -36,13 +37,17 @@
"config-restart": "हाँ, इसे पुनः आरंभ करें",
"config-env-php": "PHP $1 स्थापित किया गया है।",
"config-db-wiki-settings": "इस विकि को पहचानें",
+ "config-db-install-account": "इंस्टालेशन के लिए उपयोगकर्ता खाता",
"config-mssql-auth": "प्रमाणन प्रकार:",
"config-mssql-sqlauth": "SQL सर्वर प्रमाणन",
"config-site-name": "विकि का नाम:",
+ "config-site-name-blank": "एक साइट का नाम लिखें",
"config-project-namespace": "प्रकल्प नामस्थान:",
"config-ns-generic": "प्रकल्प",
"config-ns-other": "अन्य (निर्दिष्ट करें)",
"config-ns-other-default": "मेरा विकि",
+ "config-admin-box": "व्यवस्थापक खाता",
+ "config-admin-name": "आपका उपयोगकर्ता नाम:",
"config-admin-password": "कूटशब्द:",
"config-admin-password-confirm": "फिर से कूटशब्द:",
"config-admin-email": "ईमेल पता:",
@@ -52,6 +57,7 @@
"config-profile-no-anon": "खाता बनाने की आवश्यकता",
"config-profile-fishbowl": "केवल प्रमाषित संपादक ही",
"config-profile-private": "निजी विकि",
+ "config-license-cc-by": "क्रिएटिव कॉमन्स ऍट्रीब्यूशन",
"config-email-watchlist": "ध्यानसूची अधिसूचना को सक्षम करें",
"config-extensions": "एक्सटेंशन",
"config-help": "सहायता",
diff --git a/includes/installer/i18n/hu.json b/includes/installer/i18n/hu.json
index cf5ad454..b460f602 100644
--- a/includes/installer/i18n/hu.json
+++ b/includes/installer/i18n/hu.json
@@ -57,31 +57,36 @@
"config-unicode-pure-php-warning": "'''Figyelmeztetés''': Az Unicode normalizáláshoz szükséges [http://pecl.php.net/intl intl PECL kiterjesztés] nem érhető el, helyette a lassú, PHP alapú implementáció lesz használva.\nHa nagy látogatottságú oldalt üzemeltetsz, itt találhatsz további információkat [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations a témáról].",
"config-unicode-update-warning": "'''Figyelmeztetés''': Az Unicode normalizáláshoz szükséges burkolókönyvtár [http://site.icu-project.org/ ICU projekt] függvénykönyvtárának régebbi változatát használja.\nHa ügyelni kívánsz a Unicode használatára, fontold meg a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations frissítését].",
"config-no-db": "Nem sikerült egyetlen használható adatbázis-illesztőprogramot sem találni. Telepítened kell egyet a PHP-hez.\nA következő {{PLURAL:$2|adatbázistípus támogatott|adatbázistípusok támogatottak}}: $1.\n\nHa a PHP-t magad fordítottad, konfiguráld újra úgy, hogy engedélyezve legyen egy adatbáziskliens, pl. a <code>./configure --with-mysql</code> parancs használatával.\nHa a PHP-t Debian vagy Ubuntu csomaggal telepítetted, akkor szükséged lesz például a php5-mysql csomagra is.",
+ "config-outdated-sqlite": "<strong>Figyelmeztetés:</strong> SQLite $1 verziód van, ami alacsonyabb a legalább szükséges $2 verziónál. Az SQLite nem lesz elérhető.",
"config-no-fts3": "'''Figyelmeztetés''': Az SQLite [//sqlite.org/fts3.html FTS3 modul] nélkül lett fordítva, a keresési funkciók nem fognak működni ezen a rendszeren.",
"config-magic-quotes-runtime": "'''Kritikus hiba: a [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] aktív!'''\nEz a beállítás kiszámíthatatlan károkat okoz a bevitt adatokban.\nA MediaWiki csak akkor telepíthető, ha ki van kapcsolva.",
"config-magic-quotes-sybase": "'''Kritikus hiba: a [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_sybase] aktív!'''\nEz a beállítás kiszámíthatatlan károkat okoz a bevitt adatokban.\nA MediaWiki csak akkor telepíthető, ha ki van kapcsolva.",
"config-mbstring": "'''Kritikus hiba: az [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime mbstring.func_overload] aktív!'''\nEz a beállítás hibákat okoz és kiszámíthatatlanul károsíthatja bevitt adatokat.\nA MediaWiki csak akkor telepíthető, ha ki van kapcsolva.",
"config-safe-mode": "'''Figyelmeztetés:''' A PHP [http://www.php.net/features.safe-mode safe mode]-ja be van kapcsolva.\nProblémákat okozhat, különösen a fájlfeltöltéseknél és a <code>math</code>-támogatás használatánál.",
- "config-xml-bad": "A PHP XML-modulja hiányzik.\nEgyes MediaWiki-funkciók, melyek ezt a modult igénylik, nem fognak működni ilyen beállítások mellett.\nHa Madrake-et futtatsz, telepítsd a php-xml csomagot.",
+ "config-xml-bad": "A PHP XML-modulja hiányzik.\nEgyes MediaWiki-funkciók, melyek ezt a modult igénylik, nem fognak működni ilyen konfigurációban.\nSzükséges lehet a php-xml RPM-csomag telepítése.",
"config-pcre-old": "<strong>Kritikus hiba:</strong> PCRE $1 vagy későbbi szükséges.\nA Te PHP binárisod PCRE $2-vel lett linkelve.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE További információ].",
"config-pcre-no-utf8": "'''Kritikus hiba''': Úgy tűnik, hogy a PHP PRCE modulja PRCE_UTF8 támogatás nélkül lett fordítva.\nA MediaWikinek UTF-8-támogatásra van szüksége a helyes működéshez.",
"config-memory-raised": "A PHP <code>memory_limit</code> beállításának értéke: $1. Meg lett növelve a következő értékre: $2.",
"config-memory-bad": "'''Figyelmeztetés:''' A PHP <code>memory_limit</code> beállításának értéke $1.\nEz az érték valószínűleg túl kevés, a telepítés sikertelen lehet.",
"config-ctype": "<strong>Kritikus hiba:</strong> A PHP-t [http://www.php.net/manual/en/ctype.installation.php Ctype kiterjesztés] támogatással kell fordítani.",
+ "config-iconv": "<strong>Kritikus hiba:</strong> a PHP-t az [http://www.php.net/manual/en/iconv.installation.php iconv kiterjesztést] támogatva kell fordítani.",
"config-xcache": "Az [http://xcache.lighttpd.net/ XCache] telepítve van",
"config-apc": "Az [http://www.php.net/apc APC] telepítve van",
"config-wincache": "A [http://www.iis.net/download/WinCacheForPhp WinCache] telepítve van",
"config-no-cache": "'''Figyelmeztetés:''' Nem található [http://www.php.net/apc APC], [http://xcache.lighttpd.net/ XCache] és [http://www.iis.net/download/WinCacheForPhp WinCache] sem.\nObjektum-gyorsítótárazás nem lesz engedélyezve.",
"config-diff3-bad": "GNU diff3 nem található.",
+ "config-git": "Megtaláltam a Git verziókezelő szoftvert: <code>$1</code>.",
+ "config-git-bad": "A Git verziókezelő rendszer nem található.",
"config-imagemagick": "Az ImageMagick megtalálható a rendszeren: <code>$1</code>.\nA bélyegképek készítése engedélyezve lesz a feltöltések engedélyezése esetén.",
"config-gd": "A GD grafikai könyvtár elérhető.\nBélyegképek készítése működni fog, miután engedélyezted a fájlfeltöltést.",
"config-no-scaling": "Nem található a GD könyvtár és az ImageMagick.\nA bélyegképek készítése le lesz tiltva.",
"config-no-uri": "'''Hiba:''' Nem sikerült megállapítani a jelenlegi URI-t.\nTelepítés megszakítva.",
+ "config-no-cli-uri": "<strong>Figyelmeztetés:</strong> Nincs <code>--scriptpath</code> megadva, használom az alapértelmezettet: <code>$1</code>.",
"config-using-server": "A következő szervernév használata: „<nowiki>$1</nowiki>”.",
"config-using-uri": "A következő szerver URL-cím használata: „<nowiki>$1$2</nowiki>”.",
"config-uploads-not-safe": "'''Figyelmeztetés:''' a feltöltésekhez használt alapértelmezett könyvtárban (<code>$1</code>) tetszőleges külső szkript futtatható.\nHabár a MediaWiki ellenőrzi a feltöltött fájlokat az efféle biztonsági veszélyek megtalálása érdekében, a feltöltés engedélyezése előtt erősen ajánlott a [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security a sérülékenység megszüntetése].",
"config-brokenlibxml": "A rendszereden a PHP és libxml2 verziók olyan kombinációja található meg, ami hibásan működik, és észrevehetetlen adatkárosodást okoz a MediaWikiben és más webalkalmazásokban.\nFrissíts a libxml2 2.7.3 vgy újabb verziójára ([https://bugs.php.net/bug.php?id=45996 A hiba bejelentése a PHP-nél]).\nTelepítés megszakítva.",
- "config-suhosin-max-value-length": "A Suhosin telepítve van, és a GET paraméter hosszát $1 bájtra korlátozza. A MediaWiki erőforrásbetöltő összetevője megkerüli a problémát, de így csökkenni fog a teljesítmény. Ha lehetséges, állítsd be a <code>suhosin.get.max_value_length</code> értékét legalább 1024-re a <code>php.ini</code>ben, és állítsd be a <code>$wgResourceLoaderMaxQueryLength</code> változót ugyanerre az értékre a LocalSettings.php-ben.",
+ "config-suhosin-max-value-length": "A Suhosin telepítve van, és a GET <code>length</code> paraméterét $1 bájtra korlátozza.\nA MediaWiki ResourceLoader (erőforrásbetöltő) összetevője megkerüli a problémát, de így csökkenni fog a teljesítmény.\nHa lehetséges, állítsd be a <code>suhosin.get.max_value_length</code> értékét legalább 1024-re a <code>php.ini</code>-ben, és állítsd be a <code>$wgResourceLoaderMaxQueryLength</code> változót ugyanerre az értékre a <code>LocalSettings.php</code>-ban.",
"config-db-type": "Adatbázis típusa:",
"config-db-host": "Adatbázis hosztneve:",
"config-db-host-help": "Ha az adatbázisszerver másik szerveren található, add meg a hosztnevét vagy az IP-címét.\n\nHa megosztott webtárhelyet használsz, a szolgáltató dokumentációjában megtalálható a helyes hosztnév.\n\nHa Windows-alapú szerverre telepítesz, és MySQL-t használsz, a „localhost” nem biztos, hogy működni fog. Ha így van, próbáld meg a „127.0.0.1” helyi IP-cím használatát.\n\nHa PostgreSQL-t használsz, hagyd ezt a mezőt üresen a Unix-socketon keresztül történő csatlakozáshoz.",
@@ -95,6 +100,7 @@
"config-db-username": "Felhasználónév:",
"config-db-password": "Jelszó:",
"config-db-password-empty": "Írd be az új adatbázis-felhasználó jelszavát: $1\nVan lehetőség jelszó nélküli felhasználók létrehozására, azonban ez nem ajánlott.",
+ "config-db-username-empty": "A „{{int:config-db-username}}” mező kitöltése kötelező.",
"config-db-install-username": "Írd be az adatbázisrendszerhez való csatlakozáshoz használt felhasználónevet.\nEz nem a MediaWiki fiók felhasználóneve; ez az adatbázisrendszeren használt felhasználóneved.",
"config-db-install-password": "Írd be az adatbázisrendszerhez való csatlakozáshoz használt jelszót.\nEz nem a MediaWiki-fiók jelszava; ez az adatbázisrendszeren használt jelszavad.",
"config-db-install-help": "Add meg a felhasználónevet és jelszót, amivel a telepítő csatlakozhat az adatbázishoz.",
@@ -124,6 +130,7 @@
"config-dbsupport-postgres": "* A [{{int:version-db-postgres-url}} PostgreSQL] népszerű, nyílt forráskódú adatbázisrendszer, a MySQL alternatívája ([http://www.php.net/manual/en/pgsql.installation.php Hogyan fordítható a PHP PostgreSQL-támogatással]). Több apró, javítatlan hiba is előfordulhat, így nem ajánlott éles környezetben használni. ([http://www.php.net/manual/en/pgsql.installation.php Hogyan fordítható a PHP PostgreSQL-támogatással])",
"config-dbsupport-sqlite": "* Az [{{int:version-db-sqlite-url}} SQLite] egy könnyű, nagyon jól támogatott adatbázisrendszer. ([http://www.php.net/manual/en/pdo.installation.php Hogyan fordítható a PHP SQLite-támogatással], PDO-t használ)",
"config-dbsupport-oracle": "* Az [{{int:version-db-oracle-url}} Oracle] kereskedelmi, vállalati adatbázisrendszer. ([http://www.php.net/manual/en/oci8.installation.php Hogyan fordítható a PHP OCI8-támogatással])",
+ "config-dbsupport-mssql": "* A [{{int:version-db-mssql-url}} Microsoft SQL Server] kereskedelmi, vállalati adatbázisrendszer. ([http://www.php.net/manual/en/sqlsrv.installation.php Hogyan fordítható a PHP SQLSRV-támogatással])",
"config-header-mysql": "MySQL-beállítások",
"config-header-postgres": "PostgreSQL-beállítások",
"config-header-sqlite": "SQLite-beállítások",
@@ -206,7 +213,7 @@
"config-optional-continue": "További információk megadása.",
"config-optional-skip": "Épp elég volt, települjön a wiki!",
"config-profile": "Felhasználói jogosultságok profilja:",
- "config-profile-wiki": "Wiki megnyitása",
+ "config-profile-wiki": "Nyílt wiki",
"config-profile-no-anon": "Felhasználói fiók létrehozása szükséges",
"config-profile-fishbowl": "Csak engedélyezett szerkesztők",
"config-profile-private": "Privát wiki",
@@ -261,7 +268,10 @@
"config-extensions": "Kiterjesztések",
"config-extensions-help": "A fent felsorolt kiterjesztések találhatóak meg az <code>./extensions</code> könyvtárban.\n\nLehetséges, hogy további beállításra lesz szükség hozzájuk, de már most engedélyezheted őket.",
"config-skins": "Felületek",
+ "config-skins-help": "A fent felsorolt felületek a <code>./skins</code> könyvtáradban találhatóak. Legalább egyet engedélyezned kell, és ki kell választanod az alapértelmezettet.",
"config-skins-use-as-default": "Felület használata alapértelmezettként",
+ "config-skins-must-enable-some": "Legalább egy felületet engedélyezned kell.",
+ "config-skins-must-enable-default": "Az alapértelmezett felületnek engedélyezettnek kell lennie.",
"config-install-alreadydone": "'''Figyelmeztetés:''' Úgy tűnik, hogy a MediaWiki telepítve van, és te ismét megpróbálod telepíteni.\nFolytasd a következő oldalon.",
"config-install-begin": "A „{{int:config-continue}}” gomb megnyomása elindítja a MediaWiki telepítését.\nHa szeretnél módosítani a beállításokon, kattints a \"{{int:config-back}}\" gombra.",
"config-install-step-done": "kész",
@@ -290,6 +300,7 @@
"config-install-stats": "Statisztika inicializálása",
"config-install-keys": "Titkos kulcsok generálása",
"config-insecure-keys": "'''Figyelmeztetés:''' A telepítés során generált $1 {{PLURAL:$2|biztonsági kulcs|biztonsági kulcsok}} nem teljesen $1 {{PLURAL:$2|biztonságos|biztonságosak}}. Érdemes {{PLURAL:$2||őket}} manuálisan megváltoztatni.",
+ "config-install-updates": "Nem szükséges frissítések futtatásának megakadályozása",
"config-install-sysop": "Az adminisztrátor felhasználói fiókjának létrehozása",
"config-install-subscribe-fail": "Nem sikerült feliratkozni a mediawiki-announce levelezőlistára: $1",
"config-install-subscribe-notpossible": "A cURL nincs telepítve és az <code>allow_url_fopen</code> nem érhető el.",
@@ -299,7 +310,9 @@
"config-install-done": "'''Gratulálunk!'''\nA MediaWiki telepítése sikeresen befejeződött.\n\nA telepítő elkészítette a <code>LocalSettings.php</code> fájlt, amely tartalmazza az összes beállítást.\n\nEzt le kell tölteni, majd elhelyezni a wiki telepítési könyvtárába (az a könyvtár, ahol az index.php is található).\n\nA letöltés automatikusan elindul. Ha mégsem indulna el, vagy megszakítottad, az alábbi linkre kattintva újra letöltheted:\n\n$3\n\n'''Megjegyzés''': Ha ezt most nem teszed meg, és kilépsz a telepítésből, az elkészített konfigurációs fájlt nem tudod elérni a későbbiekben.\n\nHa végeztél a fájl elhelyezésével, '''[$2 beléphetsz a wikibe]'''.",
"config-download-localsettings": "<code>LocalSettings.php</code> letöltése",
"config-help": "segítség",
+ "config-help-tooltip": "kattints a kibontáshoz",
"config-nofile": "\"$1\" fájl nem található. Törölve lett?",
+ "config-extension-link": "Tudtad, hogy a wikid támogat [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions kiterjesztéseket]?\n\nBöngészhetsz [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category kiterjesztéseket kategóriánként] vagy válogathatsz a [//www.mediawiki.org/wiki/Extension_Matrix kiterjesztésmátrixból] az összes kiterjesztés áttekintéséhez.",
"mainpagetext": "'''A MediaWiki telepítése sikeresen befejeződött.'''",
"mainpagedocfooter": "Ha segítségre van szükséged a wikiszoftver használatához, akkor keresd fel a [//meta.wikimedia.org/wiki/Help:Contents User's Guide] oldalt.\n\n== Alapok (angol nyelven) ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Beállítások listája]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki GyIK]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki-kiadások levelezőlistája]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources A MediaWiki fordítása a saját nyelvedre]"
}
diff --git a/includes/installer/i18n/hy.json b/includes/installer/i18n/hy.json
index 76179420..a1f91546 100644
--- a/includes/installer/i18n/hy.json
+++ b/includes/installer/i18n/hy.json
@@ -1,5 +1,38 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": [
+ "Vahe Gharakhanyan"
+ ]
+ },
+ "config-title": "ՄեդիաՎիքի $1-ի տեղադրում",
+ "config-information": "Տեղեկատվություն",
+ "config-localsettings-key": "Թարմացման բանալի`",
+ "config-your-language": "Ձեր լեզուն`",
+ "config-wiki-language": "Վիքի լեզու`",
+ "config-back": "← Վերադառնալ",
+ "config-continue": "Շարունակել →",
+ "config-page-language": "Լեզու",
+ "config-page-welcome": "Բարի գալուստ ՄեդիաՎիքի:",
+ "config-page-dbconnect": "Միացում տվյալների բազային",
+ "config-page-name": "Անվանում",
+ "config-page-options": "Ընտրանքներ",
+ "config-page-install": "Տեղադրում",
+ "config-page-complete": "Պատրաստ է:",
+ "config-page-readme": "Կարդա ինձ",
+ "config-page-releasenotes": "Տեղեկություն տարբերակի մասին",
+ "config-page-existingwiki": "Գոյություն ունեցող վիքի",
+ "config-restart": "Այո, նորից սկսել",
+ "config-admin-password": "Գաղտնաբառ՝",
+ "config-admin-password-confirm": "Գաղտնաբառը կրկին`",
+ "config-admin-email": "Էլ-փոստի հասցեն՝",
+ "config-license": "Հեղինակային իրավունք և արտոնագիր`",
+ "config-license-cc-by-sa": "Creative Commons Attribution-ShareAlike",
+ "config-license-cc-by": "Creative Commons Attribution",
+ "config-license-cc-by-nc-sa": "Creative Commons Attribution-NonCommercial-ShareAlike",
+ "config-license-cc-0": "Creative Commons Zero (հանրային սեփականություն)",
+ "config-license-gfdl": "GNU Free Documentation License 1.3 կամ ավելի ուշ",
+ "config-license-pd": "Հանրային սեփականություն",
+ "config-help": "օգնություն",
"mainpagetext": "'''«MediaWiki» ծրագիրը հաջողությամբ տեղադրվեց։'''",
"mainpagedocfooter": "Այցելեք [//meta.wikimedia.org/wiki/Help:Contents User's Guide]՝ վիքի ծրագրային ապահովման օգտագործման մասին տեղեկությունների համար։\n\n== Որոշ օգտակար ռեսուրսներ ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki release mailing list]"
}
diff --git a/includes/installer/i18n/ia.json b/includes/installer/i18n/ia.json
index 0e8f5973..9c7acd66 100644
--- a/includes/installer/i18n/ia.json
+++ b/includes/installer/i18n/ia.json
@@ -48,11 +48,10 @@
"config-env-bad": "Le ambiente ha essite verificate.\nTu non pote installar MediaWiki.",
"config-env-php": "PHP $1 es installate.",
"config-env-hhvm": "HHVM $1 es installate.",
- "config-unicode-using-utf8": "utf8_normalize.so per Brion Vibber es usate pro le normalisation Unicode.",
"config-unicode-using-intl": "Le [http://pecl.php.net/intl extension PECL intl] es usate pro le normalisation Unicode.",
"config-unicode-pure-php-warning": "'''Aviso''': Le [http://pecl.php.net/intl extension PECL intl] non es disponibile pro exequer le normalisation Unicode; le systema recurre al implementation lente in PHP pur.\nSi tu sito ha un alte volumine de traffico, tu deberea informar te un poco super le [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalisation Unicode].",
"config-unicode-update-warning": "'''Aviso''': Le version installate del bibliotheca inveloppante pro normalisation Unicode usa un version ancian del bibliotheca del [http://site.icu-project.org/ projecto ICU].\nTu deberea [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations actualisar lo] si le uso de Unicode importa a te.",
- "config-no-db": "Non poteva trovar un driver appropriate pro le base de datos! Es necessari installar un driver de base de datos pro PHP.\nLe sequente typos de base de datos es supportate: $1.\n\nSi tu compilava PHP tu mesme, reconfigura lo con un cliente de base de datos activate, per exemplo usante <code>./configure --with-mysqli</code>.\nSi tu installava PHP ex un pacchetto Debian o Ubuntu, tu debe installar equalmente, per exemplo, le modulo <code>php5-mysql</code>.",
+ "config-no-db": "Non poteva trovar un driver appropriate pro le base de datos! Es necessari installar un driver de base de datos pro PHP.\nLe sequente {{PLURAL:$2|typo|typos}} de base de datos es supportate: $1.\n\nSi tu compilava PHP tu mesme, reconfigura lo con un cliente de base de datos activate, per exemplo, usante <code>./configure --with-mysqli</code>.\nSi tu installava PHP ex un pacchetto Debian o Ubuntu, tu debe etiam installar, per exemplo, le modulo <code>php5-mysql</code>.",
"config-outdated-sqlite": "'''Attention''': tu ha SQLite $1, que es inferior al version minimal requirite, $2. SQLite essera indisponibile.",
"config-no-fts3": "'''Attention''': SQLite es compilate sin [//sqlite.org/fts3.html modulo FTS3]; functionalitate de recerca non essera disponibile in iste back-end.",
"config-register-globals-error": "<strong>Error: Le option <code>[http://php.net/register_globals register_globals]</code> de PHP es active.\nIllo debe esser disactivate pro continuar le installation.</strong>\nVide [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] pro obtener adjuta sur como facer lo.",
@@ -61,7 +60,7 @@
"config-magic-quotes-sybase": "'''Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] es active!'''\nIste option corrumpe le entrata de datos imprevisibilemente.\nTu non pote installar o usar MediaWiki si iste option non es disactivate.",
"config-mbstring": "'''Fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] es active!'''\nIste option causa errores e pote corrumper datos imprevisibilemente.\nTu non pote installar o usar MediaWiki si iste option non es disactivate.",
"config-safe-mode": "'''Aviso:''' Le [http://www.php.net/features.safe-mode modo secur] de PHP es active.\nIsto pote causar problemas, particularmente si es usate le incargamento de files e le supporto de <code>math</code>.",
- "config-xml-bad": "Le modulo XML de PHP es mancante.\nMediaWiki require functiones de iste modulo e non functionara in iste configuration.\nSi tu usa Mandrake, installa le pacchetto php-xml.",
+ "config-xml-bad": "Le modulo XML de PHP es mancante.\nMediaWiki require functiones de iste modulo e non functionara in iste configuration.\nEs possibile que tu debe installar le pacchetto RPM php-xml.",
"config-pcre-old": "<strong>Fatal:</strong> PCRE $1 o plus tarde es necessari.\nTu binario de PHP binary es ligate con PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Plus information].",
"config-pcre-no-utf8": "'''Fatal''': Le modulo PCRE de PHP pare haber essite compilate sin supporto de PCRE_UTF8.\nMediaWiki require supporto de UTF-8 pro functionar correctemente.",
"config-memory-raised": "Le <code>memory_limit</code> de PHP es $1, elevate a $2.",
@@ -101,8 +100,6 @@
"config-db-install-account": "Conto de usator pro installation",
"config-db-username": "Nomine de usator del base de datos:",
"config-db-password": "Contrasigno del base de datos:",
- "config-db-password-empty": "Per favor entra un contrasigno pro le nove usator del base de datos: $1.\nBen que il es possibile crear usatores sin contrasigno, isto non es secur.",
- "config-db-username-empty": "Es necessari entrar un valor pro \"{{int:config-db-username}}\".",
"config-db-install-username": "Entra le nomine de usator que essera usate pro connecter al base de datos durante le processo de installation. Isto non es le nomine de usator del conto MediaWiki; isto es le nomine de usator pro tu base de datos.",
"config-db-install-password": "Entra le contrasigno que essera usate pro connecter al base de datos durante le processo de installation. Isto non es le contrasigno del conto MediaWiki; isto es le contrasigno pro tu base de datos.",
"config-db-install-help": "Entra le nomine de usator e contrasigno que essera usate pro connecter al base de datos durante le processo de installation.",
diff --git a/includes/installer/i18n/id.json b/includes/installer/i18n/id.json
index e85e735a..c430d601 100644
--- a/includes/installer/i18n/id.json
+++ b/includes/installer/i18n/id.json
@@ -55,7 +55,6 @@
"config-env-bad": "Kondisi telah diperiksa.\nAnda tidak dapat menginstal MediaWiki.",
"config-env-php": "PHP $1 diinstal.",
"config-env-hhvm": "HHVM $1 telah dipasang.",
- "config-unicode-using-utf8": "Menggunakan utf8_normalize.so Brion Vibber untuk normalisasi Unicode.",
"config-unicode-using-intl": "Menggunakan [http://pecl.php.net/intl ekstensi PECL intl] untuk normalisasi Unicode.",
"config-unicode-pure-php-warning": "'''Peringatan''': [http://pecl.php.net/intl Ekstensi intl PECL] untuk menangani normalisasi Unicode tidak tersedia, kembali menggunakan implementasi murni PHP yang lambat.\nJika Anda menjalankan situs berlalu lintas tinggi, Anda harus sedikit membaca [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalisasi Unicode].",
"config-unicode-update-warning": "'''Peringatan''': Versi terinstal dari pembungkus normalisasi Unicode menggunakan versi lama pustaka [http://site.icu-project.org/ proyek ICU].\nAnda harus [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations memutakhirkannya] jika Anda ingin menggunakan Unicode.",
diff --git a/includes/installer/i18n/it.json b/includes/installer/i18n/it.json
index b9aab3ac..96c9fd3e 100644
--- a/includes/installer/i18n/it.json
+++ b/includes/installer/i18n/it.json
@@ -11,11 +11,15 @@
"Ontsed",
"Seb35",
"Nemo bis",
- "Ricordisamoa"
+ "Ricordisamoa",
+ "Fpugliajno",
+ "The Polish",
+ "Sannita",
+ "C.R."
]
},
- "config-desc": "Il programma di installazione per MediaWiki",
- "config-title": "Installazione MediaWiki $1",
+ "config-desc": "Programma di installazione per MediaWiki",
+ "config-title": "Installazione di MediaWiki $1",
"config-information": "Informazioni",
"config-localsettings-upgrade": "È stato rilevato un file <code>LocalSettings.php</code>.\nPer aggiornare questa installazione, si prega di inserire il valore di <code>$wgUpgradeKey</code> nella casella qui sotto.\nLo potete trovare in <code>LocalSettings.php</code>.",
"config-localsettings-cli-upgrade": "È stato rilevato un file <code>LocalSettings.php</code>.\nPer aggiornare questa installazione, eseguire <code>update.php</code>",
@@ -57,7 +61,6 @@
"config-env-bad": "L'ambiente è stato controllato.\nNon è possibile installare MediaWiki.",
"config-env-php": "PHP $1 è installato.",
"config-env-hhvm": "HHVM $1 è installato.",
- "config-unicode-using-utf8": "Usa Brion Vibber's utf8_normalize.so per la normalizzazione Unicode.",
"config-unicode-using-intl": "Usa [http://pecl.php.net/intl l'estensione PECL intl] per la normalizzazione Unicode.",
"config-unicode-pure-php-warning": "'''Attenzione:''' [http://pecl.php.net/intl l'estensione PECL intl] non è disponibile per gestire la normalizzazione Unicode, così si usa la lenta implementazione in puro PHP.\nSe esegui un sito ad alto traffico, dovresti leggere alcune considerazioni sulla [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalizzazione Unicode].",
"config-unicode-update-warning": "'''Attenzione:''' La versione installata del gestore per la normalizzazione Unicode usa una vecchia versione della libreria [http://site.icu-project.org/ del progetto ICU].\nDovresti [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations aggiornare] se ti interessa usare l'Unicode.",
@@ -70,7 +73,7 @@
"config-magic-quotes-sybase": "'''Errore: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] è attivato!''' Questa opzione interferisce in modo imprevedibile con l'inserimento dei dati. Non è possibile installare o utilizzare MediaWiki a meno che questa opzione non sia disabilitata.",
"config-mbstring": "'''Errore: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] è attivato!''' Questa opzione causa errori e può interferire in modo imprevedibile coi dati. Non è possibile installare o utilizzare MediaWiki a meno che questa opzione non sia disabilitata.",
"config-safe-mode": "'''Attenzione:''' [http://www.php.net/features.safe-mode safe mode] è attivato!\nQuesta opzione potrebbe causare problemi, in particolare nel caricamento di documenti e nel supporto delle funzioni <code>math</code>.",
- "config-xml-bad": "Il modulo XML di PHP è mancante.\nMediaWIki necessita di funzioni presenti in questo modulo e non funzionerà con la configurazione corrente.\nSe si sta eseguendo Mandrake, installare il paccketto php-xml.",
+ "config-xml-bad": "Manca il modulo XML di PHP.\nMediaWIki ha bisogno di funzionalità presenti in questo modulo e non funzionerà con la configurazione corrente.\nSe stai eseguendo Mandrake, installa il paccketto php-xml.",
"config-pcre-old": "<strong>Errore fatale:</strong> si richiede PCRE $1 o successivo.\nIl tuo file binario PHP è collegato con PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/Maggiori informazioni su PCRE].",
"config-pcre-no-utf8": "'''Errore''': Il modulo PCRE di PHP sembra essere stato compilato senza il supporto PCRE_UTF8, ma MediaWiki lo richiede per funzionare correttamente.",
"config-memory-raised": "Il valore <code>memory_limit</code> di PHP è $1, aumentato a $2.",
@@ -110,8 +113,6 @@
"config-db-install-account": "Account utente per l'installazione",
"config-db-username": "Nome utente del database:",
"config-db-password": "Password del database:",
- "config-db-password-empty": "Inserire una password per il nuovo utente del database: $1.\nAnche se può essere possibile creare utenti senza password, questo non è sicuro.",
- "config-db-username-empty": "È necessario immettere un valore per \"{{int:config-db-username}}\"",
"config-db-install-username": "Inserisci il nome utente che verrà utilizzato per connettersi al database durante il processo di installazione.\nQuesto non è il nome utente dell'account MediaWiki; ma quello per il tuo database.",
"config-db-install-password": "Inserisci la password che verrà utilizzato per connettersi al database durante il processo di installazione.\nQuesta non è la password dell'account MediaWiki; ma quella per il tuo database.",
"config-db-install-help": "Inserire il nome utente e la password che verranno usate per la connessione al database durante il processo d'installazione.",
@@ -189,7 +190,7 @@
"config-mysql-charset": "Set di caratteri del database:",
"config-mysql-binary": "Binario",
"config-mysql-utf8": "UTF-8",
- "config-mysql-charset-help": "In <strong>modalità binaria</strong>, MediaWiki archivia il testo UTF-8 nel database in cambi binari.\nQuesto è più efficiente rispetto alla modalità UTF-8 di MySQL, e consente di utilizzare la gamma completa di caratteri Unicode.\n\nIn <strong>modalità UTF-8</strong>, MySQL conoscerà in quale set di caratteri sono i tuoi dati, e può presentarli e convertirli in modo appropriato, ma non ti permetterà di memorizzare i caratteri al di sopra del [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Basic Multilingual Plane].",
+ "config-mysql-charset-help": "In <strong>modalità binaria</strong>, MediaWiki archivia il testo UTF-8 nel database in campi binari.\nQuesto è più efficiente rispetto alla modalità UTF-8 di MySQL, e consente di utilizzare la gamma completa di caratteri Unicode.\n\nIn <strong>modalità UTF-8</strong>, MySQL conoscerà in quale set di caratteri sono i tuoi dati, e può presentarli e convertirli in modo appropriato, ma non ti permetterà di memorizzare i caratteri al di sopra del [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Basic Multilingual Plane].",
"config-mssql-auth": "Tipo di autenticazione:",
"config-mssql-install-auth": "Seleziona il tipo di autenticazione che verrà utilizzato per connettersi al database durante il processo di installazione.\nSe si seleziona \"{{int:config-mssql-windowsauth}}\", saranno utilizzate le credenziali dell'utente con cui viene eseguito il server web, qualunque esso sia.",
"config-mssql-web-auth": "Seleziona il tipo di autenticazione che il server web utilizzerà per connettersi al database, durante il normale funzionamento del wiki.\nSe si seleziona \"{{int:config-mssql-windowsauth}}\", saranno utilizzate le credenziali dell'utente con cui viene eseguito il server web, qualunque esso sia.",
diff --git a/includes/installer/i18n/ja.json b/includes/installer/i18n/ja.json
index dedc3c20..6020bdce 100644
--- a/includes/installer/i18n/ja.json
+++ b/includes/installer/i18n/ja.json
@@ -13,7 +13,8 @@
"青子守歌",
"아라",
"Shield-9",
- "Takot"
+ "Takot",
+ "Sujiniku"
]
},
"config-desc": "MediaWiki のインストーラー",
@@ -59,11 +60,10 @@
"config-env-bad": "環境を確認しました。\nMediaWiki のインストールはできません。",
"config-env-php": "PHP $1がインストールされています。",
"config-env-hhvm": "HHVM $1 がインストールされています。",
- "config-unicode-using-utf8": "Unicode正規化に、Brion Vibberのutf8_normalize.soを使用。",
"config-unicode-using-intl": "Unicode正規化に[http://pecl.php.net/intl intl PECL 拡張機能]を使用。",
"config-unicode-pure-php-warning": "<strong>警告:</strong> Unicode 正規化の処理に [http://pecl.php.net/intl intl PECL 拡張機能]を利用できないため、処理が遅いピュア PHP の実装を代わりに使用しています。\n高トラフィックのサイトを運営する場合は、[//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode 正規化]をお読みください。",
"config-unicode-update-warning": "<strong>警告:</strong> インストールされているバージョンの Unicode 正規化ラッパーは、[http://site.icu-project.org/ ICU プロジェクト]のライブラリの古いバージョンを使用しています。\nUnicode を少しでも利用する可能性がある場合は、[//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations アップグレード]してください。",
- "config-no-db": "適切なデータベース ドライバーが見つかりませんでした! PHP にデータベース ドライバーをインストールする必要があります。\n以下の種類のデータベースに対応しています: $1\n\nPHP を自分でコンパイルした場合は、例えば <code>./configure --with-mysqli</code> を実行して、データベース クライアントを使用できるように再設定してください。\nDebian または Ubuntu のパッケージから PHP をインストールした場合は、モジュール (例: <code>php5-mysql</code>) もインストールする必要があります。",
+ "config-no-db": "適切なデータベース ドライバーが見つかりませんでした! PHP にデータベース ドライバーをインストールする必要があります。\n以下の種類のデータベース{{PLURAL:$2|のタイプ}}に対応しています: $1\n\nPHP を自分でコンパイルした場合は、例えば <code>./configure --with-mysqli</code> を実行して、データベース クライアントを使用できるように再設定してください。\nDebian または Ubuntu のパッケージから PHP をインストールした場合は、モジュール (例: <code>php5-mysql</code>) もインストールする必要があります。",
"config-outdated-sqlite": "<strong>警告:</strong> あなたは SQLite $1 を使用していますが、最低限必要なバージョン $2 より古いバージョンです。SQLite は利用できません。",
"config-no-fts3": "<strong>警告:</strong> SQLite は [//sqlite.org/fts3.html FTS3] モジュールなしでコンパイルされており、このバックエンドでは検索機能は利用できなくなります。",
"config-register-globals-error": "<strong>エラー: PHPの <code>[http://php.net/register_globals register_globals]</code> オプションが有効になっています。\nインストールを進めるには無効にしなければなりません。</strong>\nやり方については[https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] をご覧ください。",
@@ -72,7 +72,7 @@
"config-magic-quotes-sybase": "<strong>致命的エラー: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] が動作しています!</strong>\nこのオプションは、予期せずデータ入力を破壊します。\nこのオプションを無効化しない限り、MediaWiki のインストールや使用はできません。",
"config-mbstring": "<strong>致命的エラー: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] が動作しています!</strong>\nこのオプションは、エラーを引き起こし、予期せずデータを破壊するおそれがあります。\nこのオプションを無効化しない限り、MediaWiki のインストールや使用はできません。",
"config-safe-mode": "<strong>警告:</strong> PHPの[http://www.php.net/features.safe-mode セーフモード]が有効になっています。\n特に、ファイルのアップロードや<code>math</code>機能で、問題が発生するおそれがあります。",
- "config-xml-bad": "PHPのXMLモジュールが不足しています。\nMediaWikiは、このモジュールの関数を必要としているため、この構成では動作しません。\nMandrakeを実行している場合、php-xmlパッケージをインストールしてください。",
+ "config-xml-bad": "PHPのXMLモジュールが不足しています。\nMediaWikiは、このモジュールの関数を必要としているため、この構成では動作しません。\nphp-xml RPM パッケージをインストールする必要があります。",
"config-pcre-old": "<strong>致命的エラー:</strong> PCRE $1 以降が必要です。\nご使用中の PHP のバイナリは PCRE $2 とリンクされています。\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE 詳細情報]",
"config-pcre-no-utf8": "<strong>致命的エラー:</strong> PHP の PCRE が PCRE_UTF8 対応なしでコンパイルされているようです。\nMediaWiki を正しく動作させるには、UTF-8 対応が必要です。",
"config-memory-raised": "PHPの<code>memory_limit</code>は$1で、$2に引き上げられました。",
@@ -112,8 +112,6 @@
"config-db-install-account": "インストールで使用する利用者アカウント",
"config-db-username": "データベースのユーザー名:",
"config-db-password": "データベースのパスワード:",
- "config-db-password-empty": "新しいデータベースの利用者名 $1 のパスワードを入力してください。\nパスワードを設定せずにユーザーを作成できる場合もありますが、安全ではありません。",
- "config-db-username-empty": "「{{int:config-db-username}}」を入力してください。",
"config-db-install-username": "インストール中にデータベースへの接続で使用するユーザー名を入力してください。\nこれは MediaWiki アカウントの利用者名のことではありません。あなたのデータベースでのユーザー名です。",
"config-db-install-password": "インストール中にデータベースへの接続で使用するパスワードを入力してください。\nこれは MediaWiki アカウントのパスワードのことではありません。あなたのデータベースでのパスワードです。",
"config-db-install-help": "インストール作業中にデータベースに接続するための利用者名とパスワードを入力してください。",
@@ -322,6 +320,7 @@
"config-install-keys": "秘密鍵の生成",
"config-insecure-keys": "<strong>警告:</strong> インストール中に生成されたセキュアキー ($1) は完璧に安全ではありません。手動で変更することを検討してください。",
"config-install-updates": "不要な更新を実行するのを防ぐ",
+ "config-install-updates-failed": "<strong>エラー:</strong> 更新キーをテーブルに挿入する際に失敗しました。以下のエラーが起こっています: $1",
"config-install-sysop": "管理者のアカウントの作成",
"config-install-subscribe-fail": "mediawiki-announce を購読できませんでした: $1",
"config-install-subscribe-notpossible": "cURL がインストールされていないため、<code>allow_url_fopen</code> を利用できません。",
diff --git a/includes/installer/i18n/jut.json b/includes/installer/i18n/jut.json
index 10119bea..be3da586 100644
--- a/includes/installer/i18n/jut.json
+++ b/includes/installer/i18n/jut.json
@@ -1,9 +1,10 @@
{
"@metadata": {
"authors": [
- "Huslåke"
+ "Huslåke",
+ "Jyllanj"
]
},
- "mainpagetext": "'''MediaWiki er nu installeret.'''",
+ "mainpagetext": "'''MediaWiki ä nu installiirtj.'''",
"mainpagedocfooter": "Se vores engelskspråĝede [//meta.wikimedia.org/wiki/MediaWiki_localisation dokumentåsje tilpasnenge'm åf æ brugergrænseflade] og [//meta.wikimedia.org/wiki/MediaWiki_User%27s_Guide æ brugervejlednenge] før åplysnenger åpsætnenge'm og anvendelse."
}
diff --git a/includes/installer/i18n/km.json b/includes/installer/i18n/km.json
index 8318e9cc..f5dff47e 100644
--- a/includes/installer/i18n/km.json
+++ b/includes/installer/i18n/km.json
@@ -26,7 +26,10 @@
"config-page-install": "តំលើង",
"config-page-complete": "បញ្ចប់!",
"config-page-restart": "តំលើងឡើងវិញ",
+ "config-install-sysop": "កំពុងបង្កើតគណនីអភិបាល",
"config-help": "ជំនួយ",
+ "config-help-tooltip": "ចុចដើម្បីពន្លាត",
+ "config-nofile": "រកមិនឃើញឯកសារ \"$1\" ទេ។ វាប្រហែលជាត្រូវបានលុបចោលហើយ។",
"mainpagetext": "'''មេឌាវិគីត្រូវបានដំឡើងសំរេចហើយ​។'''",
"mainpagedocfooter": "សូមពិនិត្យមើល [//meta.wikimedia.org/wiki/Help:Contents ខ្លឹមសារ​ណែនាំ​ប្រើប្រាស់]សម្រាប់​ព័ត៌មាន​​បន្ថែមអំពី​ការប្រើប្រាស់សូហ្វវែរវិគី​។\n\n== ការចាប់ផ្ដើម ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings បញ្ជីការកំណត់នានា]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/km សំណួរញឹកញាប់​ក្នុងមេឌាវិគី]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce បញ្ជី​អ៊ីមែលផ្សព្វផ្សាយ​របស់​មេឌាវិគី]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources ការប្រែសម្រួលមេឌាវិគីសម្រាប់ភាសារបស់អ្នក]"
}
diff --git a/includes/installer/i18n/kn.json b/includes/installer/i18n/kn.json
index 2c84dc3c..b7f71b11 100644
--- a/includes/installer/i18n/kn.json
+++ b/includes/installer/i18n/kn.json
@@ -1,9 +1,11 @@
{
"@metadata": {
"authors": [
- "VASANTH S.N."
+ "VASANTH S.N.",
+ "Pavanaja"
]
},
+ "config-title": "ಮೀಡಿಯಾವಿಕಿ ಆವೃತ್ತಿ $1 ರ ಅನುಸ್ಥಾಪನೆ",
"config-information": "ಮಾಹಿತಿ",
"config-localsettings-key": "ಉನ್ನತೀಕರಣ ಕೀಲಿ",
"config-localsettings-badkey": "ನೀವು ನೀಡಿದ ಕೀಲಿ ಸರಿಯಾಗಿಲ್ಲ",
diff --git a/includes/installer/i18n/ko.json b/includes/installer/i18n/ko.json
index 10ca898e..573172d7 100644
--- a/includes/installer/i18n/ko.json
+++ b/includes/installer/i18n/ko.json
@@ -6,7 +6,8 @@
"Hym411",
"Priviet",
"Namoroka",
- "Revi"
+ "Revi",
+ "Alex00728"
]
},
"config-desc": "미디어위키를 위한 설치 관리자",
@@ -46,50 +47,49 @@
"config-help-restart": "입력한 모든 저장된 데이터를 지우고 설치 과정을 다시 시작하겠습니까?",
"config-restart": "예, 다시 시작합니다",
"config-welcome": "=== 사용 환경 검사 ===\n기본 검사는 지금 이 환경이 미디어위키 설치에 적합한지 수행합니다.\n설치를 완료하는 방법에 대한 지원을 찾는다면 이 정보를 포함해야 하는 것을 기억하세요.",
- "config-copyright": "=== 저작권 및 약관 ===\n\n$1\n\n이 프로그램은 자유 소프트웨어입니다. 당신은 자유 소프트웨어 재단이 발표한 GNU 일반 공중 사용 허가서 버전 2나 그 이후 버전에 따라 이 프로그램을 재배포하거나 수정할 수 있습니다.\n\n이 프로그램이 유용하게 사용될 수 있기를 바라지만 '''상용으로 사용'''되거나 '''특정 목적에 맞을 것'''이라는 것을 '''보증하지 않습니다'''.\n자세한 내용은 GNU 일반 공중 사용 허가서를 참고하십시오.\n\n당신은 이 프로그램을 통해 <doclink href=Copying>GNU 일반 공중 사용 허가서 전문</doclink>을 받았습니다. 그렇지 않다면, Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA로 편지를 보내주시거나 [http://www.gnu.org/copyleft/gpl.html 온라인으로 읽어보시기] 바랍니다.",
+ "config-copyright": "=== 저작권 및 약관 ===\n\n$1\n\n이 프로그램은 자유 소프트웨어입니다. 당신은 자유 소프트웨어 재단이 발표한 GNU 일반 공중 사용 허가서 버전 2나 그 이후 버전에 따라 이 프로그램을 재배포하거나 수정할 수 있습니다.\n\n이 프로그램이 유용하게 사용될 수 있기를 바라지만 <strong>상용으로 사용</strong>되거나 <strong>특정 목적에 맞을 것</strong>이라는 것을 <strong>보증하지 않습니다</strong>.\n자세한 내용은 GNU 일반 공중 사용 허가서를 참조하십시오.\n\n당신은 이 프로그램을 통해 <doclink href=Copying>GNU 일반 공중 사용 허가서 전문</doclink>을 받았습니다. 그렇지 않다면, Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA로 편지를 보내주시거나 [http://www.gnu.org/copyleft/gpl.html 온라인으로 읽어보시기] 바랍니다.",
"config-sidebar": "* [//www.mediawiki.org 미디어위키 홈]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents 사용자 가이드]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents 관리자 가이드]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]\n----\n* <doclink href=Readme>읽어보기</doclink>\n* <doclink href=ReleaseNotes>릴리스 노트</doclink>\n* <doclink href=Copying>전문</doclink>\n* <doclink href=UpgradeDoc>업그레이드하기</doclink>",
"config-env-good": "환경이 확인되었습니다.\n미디어위키를 설치할 수 있습니다.",
"config-env-bad": "환경이 확인되었습니다.\n미디어위키를 설치할 수 없습니다.",
"config-env-php": "PHP $1이(가) 설치되어 있습니다.",
- "config-env-hhvm": "HHMV $1이(가) 설치되어 있습니다.",
- "config-unicode-using-utf8": "유니코드 정규화에 Brion Vibber의 utf8_normalize.so를 사용합니다.",
+ "config-env-hhvm": "HHVM $1이(가) 설치되어 있습니다.",
"config-unicode-using-intl": "유니코드 정규화에 [http://pecl.php.net/intl intl PECL 확장 기능]을 사용합니다.",
- "config-unicode-pure-php-warning": "<strong>경고</strong>: 유니코드 정규화를 처리할 [http://pecl.php.net/intl intl PECL 확장 기능]을 사용할 수 없기 때문에 느린 pure-PHP 구현을 대신 사용합니다.\n트래픽이 높은 사이트에서 실행하시려면 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations 유니코드 정규화]를 읽어보셔야 합니다.",
- "config-unicode-update-warning": "<strong>경고</strong>: 유니코드 정규화 래퍼의 설치된 버전은 [http://site.icu-project.org/ ICU 프로젝트]의 라이브러리의 이전 버전을 사용합니다.\n만약 유니코드를 사용하는 것에 대해 우려가 된다면 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations 업그레이드]해야합니다.",
+ "config-unicode-pure-php-warning": "<strong>경고:</strong> 유니코드 정규화를 처리할 [http://pecl.php.net/intl intl PECL 확장 기능]을 사용할 수 없기 때문에 느린 pure-PHP 구현을 대신 사용합니다.\n트래픽이 높은 사이트에서 실행하시려면 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations 유니코드 정규화]를 읽어보셔야 합니다.",
+ "config-unicode-update-warning": "<strong>경고:</strong> 유니코드 정규화 래퍼의 설치된 버전은 [http://site.icu-project.org/ ICU 프로젝트]의 라이브러리의 이전 버전을 사용합니다.\n만약 유니코드를 사용하는 것에 대해 우려가 된다면 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations 업그레이드]해야합니다.",
"config-no-db": "적절한 데이터베이스 드라이버를 찾을 수 없습니다! PHP용 데이터베이스 드라이버를 설치해야 합니다.\n다음 데이터베이스 {{PLURAL:$2|유형을 지원합니다}}: $1.\n\nPHP를 직접 컴파일했다면, 예를 들어 <code>./configure --with-mysql</code>을 사용하여, 데이터베이스 클라이언트를 활성화하도록 다시 설정하세요.\n데비안이나 우분투 패키지에서 PHP를 설치했다면 <code>php5-mysql</code> 모듈도 설치해야 합니다.",
- "config-outdated-sqlite": "<strong>경고</strong>: 최소인 $2 버전보다 낮은 SQLite $1(이)가 있습니다. SQLite를 사용할 수 없습니다.",
- "config-no-fts3": "<strong>경고</strong>: SQLite를 [//sqlite.org/fts3.html FTS3 모듈] 없이 컴파일하며, 검색 기능은 백엔드에 사용할 수 없습니다.",
+ "config-outdated-sqlite": "<strong>경고:</strong> 최소인 $2 버전보다 낮은 SQLite $1(이)가 있습니다. SQLite를 사용할 수 없습니다.",
+ "config-no-fts3": "<strong>경고:</strong> SQLite를 [//sqlite.org/fts3.html FTS3 모듈] 없이 컴파일하며, 검색 기능은 백엔드에 사용할 수 없습니다.",
"config-register-globals-error": "<strong>오류: PHP의 <code>[http://php.net/register_globals register_globals]</code> 옵션이 활성화되어 있습니다.\n설치를 계속하려면 비활성화해야 합니다.</strong>\n어떻게 하는지에 대한 도움말에 대해서는 [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals]를 보세요.",
"config-magic-quotes-gpc": "<strong>치명: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc]이 활성화되어 있습니다!</strong>\n이 옵션은 데이터를 입력하는 데 예기치 않는 손상을 일으킵니다.\n이 옵션을 비활성화하지 않는 한 미디어위키를 설치하고 사용할 수 없습니다.",
"config-magic-quotes-runtime": "<strong>치명: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime]이 활성화되어 있습니다!</strong>\n이 옵션은 데이터를 입력하는 데 예기치 않는 손상이 일으킵니다.\n이 옵션을 비활성화하지 않는 한 미디어위키를 설치하고 사용할 수 없습니다.",
"config-magic-quotes-sybase": "<strong>치명: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase]이 활성화되어 있습니다!</strong>\n이 옵션은 데이터를 입력하는 데 예기치 않는 손상을 일으킵니다.\n이 옵션을 비활성화하지 않는 한 미디어위키를 설치하고 사용할 수 없습니다.",
"config-mbstring": "<strong>치명: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]이 활성화되어 있습니다!</strong>\n이 옵션은 오류가 발생하고 데이터를 입력하는 데 예기치 않는 손상을 일으킬 수 있습니다.\n이 옵션을 비활성화하지 않는 한 미디어위키를 설치하고 사용할 수 없습니다.",
"config-safe-mode": "<strong>경고:</strong> PHP의 [http://www.php.net/features.safe-mode 안전 모드]가 활성화되어 있습니다!\n특히 파일을 올리거나 <code>math</code>를 지원하는 데 문제가 발생할 수 있습니다.",
- "config-xml-bad": "PHP의 XML 모듈이 없습니다.\n미디어위키는 이 모듈의 기능이 필요하며 이 설정에서는 작동하지 않습니다.\nMandrake를 실행하고 있다면 php-xml 패키지를 설치하세요.",
+ "config-xml-bad": "PHP의 XML 모듈이 없습니다.\n미디어위키는 이 모듈의 기능이 필요하며 이 설정에서는 작동하지 않습니다.\nphp-xml 패키지를 설치해야할 수도 있습니다.",
"config-pcre-old": "<strong>치명:</strong> PCRE $1 또는 그 이상이 필요합니다.\nPHP 바이너리는 PCRE $2에 연결되어 있습니다. [https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE 자세한 정보].",
"config-pcre-no-utf8": "<strong>치명:</strong> PHP의 PCRE 모듈은 RCRE_UTF8 지원 없이 컴파일된 것 같습니다.\n미디어위키가 올바르게 작동하려면 UTF-8을 지원해야 합니다.",
"config-memory-raised": "PHP의 <code>memory_limit</code>는 $1이며 $2(으)로 늘렸습니다.",
- "config-memory-bad": "'''경고:''' PHP의 <code>memory_limit</code>는 $1입니다.\n아마도 너무 낮은 것 같습니다.\n설치가 실패할 수 있습니다!",
- "config-ctype": "'''치명''': PHP는 [http://www.php.net/manual/en/ctype.installation.php Ctype 확장 기능]을 지원하도록 하여 컴파일해야 합니다.",
+ "config-memory-bad": "<strong>경고:</strong> PHP의 <code>memory_limit</code>는 $1입니다.\n아마도 너무 낮은 것 같습니다.\n설치가 실패할 수 있습니다!",
+ "config-ctype": "<strong>치명</strong>: PHP는 [http://www.php.net/manual/en/ctype.installation.php Ctype 확장 기능]을 지원하도록 하여 컴파일해야 합니다.",
"config-iconv": "<strong>치명</strong>: PHP는 [http://www.php.net/manual/en/iconv.installation.php iconv 확장 기능]을 지원하도록 하여 컴파일해야 합니다.",
- "config-json": "'''치명:''' PHP가 JSON 지원이 없이 컴파일되었습니다.\n미디어위키를 설치하기 전에 PHP JSON 확장 기능이나 [http://pecl.php.net/package/jsonc PECL jsonc] 확장 기능 중 하나를 설치해야 합니다.\n* PHP 확장 기능은 Red Hat Enterprise Linux (CentOS) 5와 6에 포함되어 있지만, <code>/etc/php.ini</code>나 <code>/etc/php.d/json.ini</code>에서 활성화해야 합니다.\n* 2013년 5월 이후에 출시된 일부 리눅스 배포판은 PHP 확장 기능이 생략된 대신, <code>php5-json</code>이나 <code>php-pecl-jsonc</code>로 PECL 확장 기능이 포장되어 있습니다.",
+ "config-json": "<strong>치명:</strong> PHP가 JSON 지원이 없이 컴파일되었습니다.\n미디어위키를 설치하기 전에 PHP JSON 확장 기능이나 [http://pecl.php.net/package/jsonc PECL jsonc] 확장 기능 중 하나를 설치해야 합니다.\n* PHP 확장 기능은 Red Hat Enterprise Linux (CentOS) 5와 6에 포함되어 있지만, <code>/etc/php.ini</code>나 <code>/etc/php.d/json.ini</code>에서 활성화해야 합니다.\n* 2013년 5월 이후에 출시된 일부 리눅스 배포판은 PHP 확장 기능이 생략된 대신, <code>php5-json</code>이나 <code>php-pecl-jsonc</code>로 PECL 확장 기능이 포장되어 있습니다.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache]가 설치되었습니다",
"config-apc": "[http://www.php.net/apc APC]가 설치되었습니다",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache]가 설치되었습니다",
- "config-no-cache": "'''경고:''' [http://www.php.net/apc APC], [http://xcache.lighttpd.net/ XCache] 또는 [http://www.iis.net/download/WinCacheForPhp WinCache]를 찾을 수 없습니다.\n개체 캐싱을 활성화하지 않습니다.",
- "config-mod-security": "'''경고''': 웹 서버에 [http://modsecurity.org/ mod_security]가 허용되었습니다. 잘못 설정된 경우 미디어위키나 사용자가 임의의 내용을 게시할 수 있는 다른 소프트웨어에 대한 문제를 일으킬 수 있습니다.\n[http://modsecurity.org/documentation/ mod_security] 문서를 참고하거나 임의의 오류가 발생할 경우 호스트의 지원 요청에 문의하십시오.",
+ "config-no-cache": "<strong>경고:</strong> [http://www.php.net/apc APC], [http://xcache.lighttpd.net/ XCache] 또는 [http://www.iis.net/download/WinCacheForPhp WinCache]를 찾을 수 없습니다.\n개체 캐싱을 활성화하지 않습니다.",
+ "config-mod-security": "<strong>경고:</strong> 웹 서버에 [http://modsecurity.org/ mod_security]가 허용되었습니다. 잘못 설정된 경우 미디어위키나 사용자가 임의의 내용을 게시할 수 있는 다른 소프트웨어에 대한 문제를 일으킬 수 있습니다.\n[http://modsecurity.org/documentation/ mod_security] 문서를 참고하거나 임의의 오류가 발생할 경우 호스트의 지원 요청에 문의하십시오.",
"config-diff3-bad": "GNU diff3를 찾을 수 없습니다.",
"config-git": "Git 버전 관리 소프트웨어를 찾았습니다: <code>$1</code>.",
"config-git-bad": "Git 버전 관리 소프트웨어를 찾을 수 없습니다.",
"config-imagemagick": "ImageMagick를 찾았습니다: <code>$1</code>.\n올리기를 활성화할 경우 그림 섬네일이 활성화됩니다.",
"config-gd": "내장된 GD 그래픽 라이브러리를 찾았습니다.\n올리기를 활성화할 경우 그림 섬네일이 활성화됩니다.",
"config-no-scaling": "GD 라이브러리나 ImageMagick를 찾을 수 없습니다.\n그림 섬네일이 비활성화됩니다.",
- "config-no-uri": "'''오류:''' 현재 URI를 확인할 수 없습니다.\n설치가 중단되었습니다.",
- "config-no-cli-uri": "'''경고''': 기본값을 사용하여 <code>--scriptpath</code>를 지정하지 않았습니다: <code>$1</code>.",
+ "config-no-uri": "<strong>오류:</strong> 현재 URI를 확인할 수 없습니다.\n설치가 중단되었습니다.",
+ "config-no-cli-uri": "<strong>경고:</strong> 기본값을 사용하여 <code>--scriptpath</code>를 지정하지 않았습니다: <code>$1</code>.",
"config-using-server": "\"<nowiki>$1</nowiki>\"(을)를 서버 이름으로 사용합니다.",
"config-using-uri": "\"<nowiki>$1$2</nowiki>\"(을)를 서버 URL로 사용합니다.",
- "config-uploads-not-safe": "'''경고:''' 올리기에 대한 기본 디렉터리(<code>$1</code>)는 임의의 스크립트 실행에 취약합니다.\n미디어위키는 보안 위협 때문에 모든 올려진 파일을 검사하지만, 올리기를 활성화하기 전에 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security 이 보안 취약점을 해결할 것]을 매우 권장합니다.",
- "config-no-cli-uploads-check": "'''경고:''' 올리기를 위한 기본 디렉터리(<code>$1</code>)는 CLI를 설치하는 동안 임의의 스크립트 실행에 대한 취약점에 대해 검사되지 않습니다.",
+ "config-uploads-not-safe": "<strong>경고:</strong> 올리기에 대한 기본 디렉터리(<code>$1</code>)는 임의의 스크립트 실행에 취약합니다.\n미디어위키는 보안 위협 때문에 모든 올려진 파일을 검사하지만, 올리기를 활성화하기 전에 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security 이 보안 취약점을 해결할 것]을 매우 권장합니다.",
+ "config-no-cli-uploads-check": "<strong>경고:</strong> 올리기를 위한 기본 디렉터리(<code>$1</code>)는 CLI를 설치하는 동안 임의의 스크립트 실행에 대한 취약점에 대해 검사되지 않습니다.",
"config-brokenlibxml": "시스템에 버그가 있는 PHP와 libxml2의 조합이 있으며 미디어위키나 다른 웹 어플리케이션에 숨겨진 데이터 손상을 일으킬 수 있습니다.\nlibxml2 2.7.3 이후 버전으로 업그레이드하세요. ([https://bugs.php.net/bug.php?id=45996 PHP에 제기한 버그])\n설치가 중단되었습니다.",
"config-suhosin-max-value-length": "수호신(Suhosin)이 설치되고 $1 바이트로 GET 매개 변수 <code>length</code>를 제한하고 있습니다.\n미디어위키의 ResourceLoader 구성 요소는 이 제한을 회피하지만 성능이 저하됩니다.\n가능하면 <code>php.ini</code>의 <code>suhosin.get.max_value_length</code>를 1024 이상으로 설정하고 <code>LocalSettings.php</code>의 <code>$wgResourceLoaderMaxQueryLength</code>를 같은 값으로 설정해야 합니다.",
"config-db-type": "데이터베이스 종류:",
@@ -105,8 +105,6 @@
"config-db-install-account": "설치를 위한 사용자 계정",
"config-db-username": "데이터베이스 사용자 이름:",
"config-db-password": "데이터베이스 비밀번호:",
- "config-db-password-empty": "새 데이터베이스 사용자의 비밀번호를 입력하세요: $1.\n비밀번호 없이 사용자를 만들 수도 있지만 안전하지 않습니다.",
- "config-db-username-empty": "\"{{int:config-db-username}}\"에 대한 값을 입력해야 합니다.",
"config-db-install-username": "설치 과정 도중 데이터베이스에 연결할 때 사용할 사용자 이름을 입력하세요.\n미디어위키 계정의 사용자 이름이 아닌 데이터베이스의 사용자 이름입니다.",
"config-db-install-password": "설치 과정 도중 데이터베이스에 연결할 때 사용할 비밀번호을 입력하세요.\n미디어위키 계정의 비밀번호가 아닌 데이터베이스의 비밀번호입니다.",
"config-db-install-help": "설치 과정 중에 데이터베이스에 연결할 때 사용할 사용자 이름과 비밀번호를 입력하세요.",
@@ -119,12 +117,12 @@
"config-charset-mysql5-binary": "MySQL 4.1/5.0 바이너리",
"config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
"config-charset-mysql4": "MySQL 4.0 UTF-8 하위 호환성",
- "config-charset-help": "'''경고:''' MySQL 4.1에서 '''하위 호환 가능 UTF-8'''을 사용하고 나서 <code>mysqldump</code>로 데이터베이스를 백업하면 ASCII가 아닌 모든 문자를 파괴하고 손상된 백업을 되돌릴 수 없습니다!\n\n'''바이너리 모드'''에서 미디어위키는 바이너리 필드의 데이터베이스에 UTF-8 텍스트를 저장합니다.\nMySQL의 UTF-8 모드를 보다 더 효율적이고 유니코드 문자의 전체 범위를 사용할 수 있습니다.\n'''UTF-8 모드'''에서는 MySQL이 데이터를 사용하는 문자 집합을 알고 있기 때문에 적절하게 표현하고 변환할 수 있지만\n[//ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%ED%8F%89%EB%A9%B4#.EA.B8.B0.EB.B3.B8_.EB.8B.A4.EA.B5.AD.EC.96.B4_.ED.8F.89.EB.A9.B4 기본 다국어 평면] 밖에 있는 문자를 저장할 수 없습니다.",
+ "config-charset-help": "<strong>경고:</strong> MySQL 4.1에서 <strong>하위 호환 가능 UTF-8</strong>을 사용하고 나서 <code>mysqldump</code>로 데이터베이스를 백업하면 ASCII가 아닌 모든 문자를 파괴하고 손상된 백업을 되돌릴 수 없습니다!\n\n<strong>바이너리 모드</strong>에서 미디어위키는 바이너리 필드의 데이터베이스에 UTF-8 텍스트를 저장합니다.\nMySQL의 UTF-8 모드를 보다 더 효율적이고 유니코드 문자의 전체 범위를 사용할 수 있습니다.\n<strong>UTF-8 모드</strong>에서는 MySQL이 데이터를 사용하는 문자 집합을 알고 있기 때문에 적절하게 표현하고 변환할 수 있지만\n[//ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%ED%8F%89%EB%A9%B4#.EA.B8.B0.EB.B3.B8_.EB.8B.A4.EA.B5.AD.EC.96.B4_.ED.8F.89.EB.A9.B4 기본 다국어 평면] 밖에 있는 문자를 저장할 수 없습니다.",
"config-mysql-old": "MySQL $1 이상이 필요하나 $2(이)가 있습니다.",
"config-db-port": "데이터베이스 포트:",
"config-db-schema": "미디어위키에 대한 스키마:",
"config-db-schema-help": "보통 이 스키마는 문제가 없습니다.\n필요한 경우에만 바꾸세요.",
- "config-pg-test-error": "'''$1''' 데이터베이스에 연결할 수 없습니다: $2",
+ "config-pg-test-error": "<strong>$1</strong> 데이터베이스에 연결할 수 없습니다: $2",
"config-sqlite-dir": "SQLite 데이터 디렉터리:",
"config-sqlite-dir-help": "SQLite는 하나의 파일에 모든 데이터를 저장합니다.\n\n입력한 디렉토리는 설치하는 동안 웹 서버가 쓸 수 있어야 합니다.\n\n이 디렉토리는 웹을 통해 접근할 수 <strong>없어야</strong> 합니다. PHP 파일이 있는 곳에 넣을 수 없는 것은 이 때문입니다.\n\n설치 관리자는 <code>.htaccess</code> 파일을 작성하지만, 이것이 실패하면 누군가가 원본 데이터베이스에 접근할 수 있습니다.\n데이터베이스는 원본 사용자 데이터(이메일 주소, 해시한 비밀번호)뿐만 아니라 삭제된 판과 위키의 다른 제한된 데이터를 포함합니다.\n\n예를 들어 <code>/var/lib/mediawiki/yourwiki</code>와 같이 다른 곳에 데이터베이스를 넣는 것이 좋습니다.",
"config-oracle-def-ts": "기본 테이블공간:",
@@ -165,12 +163,12 @@
"config-sqlite-readonly": "<code>$1</code> 파일은 쓸 수 없습니다.",
"config-sqlite-cant-create-db": "<code>$1</code> 데이터베이스 파일을 만들 수 없습니다.",
"config-sqlite-fts3-downgrade": "PHP가 FTS3 지원이 없어졌습니다. 테이블을 다운그레이드합니다",
- "config-can-upgrade": "이 데이터베이스에 미디어위키 테이블이 있습니다.\n미디어위키 $1(으)로 업그레이드하려면 '''계속'''을 클릭하세요.",
- "config-upgrade-done": "업그레이드가 완료되었습니다.\n\n이제 [$1 위키를 시작]할 수 있습니다.\n\n만약 <code>LocalSettings.php</code> 파일을 다시 만들고 싶다면 아래의 버튼을 클릭하세요.\n위키에 문제가 있지 않는 한 '''권장하지 않습니다'''.",
+ "config-can-upgrade": "이 데이터베이스에 미디어위키 테이블이 있습니다.\n미디어위키 $1(으)로 업그레이드하려면 <strong>계속</strong>을 클릭하세요.",
+ "config-upgrade-done": "업그레이드가 완료되었습니다.\n\n이제 [$1 위키를 시작]할 수 있습니다.\n\n만약 <code>LocalSettings.php</code> 파일을 다시 만들고 싶다면 아래의 버튼을 클릭하세요.\n위키에 문제가 있지 않는 한 <strong>권장하지 않습니다</strong>.",
"config-upgrade-done-no-regenerate": "업그레이드가 완료되었습니다.\n\n이제 [$1 위키를 시작]할 수 있습니다.",
"config-regenerate": "LocalSettings.php 다시 생성 →",
"config-show-table-status": "<code>SHOW TABLE STATUS</code> 쿼리를 실패했습니다!",
- "config-unknown-collation": "'''경고:''' 데이터베이스가 인식하지 않는 정렬을 사용하고 있습니다.",
+ "config-unknown-collation": "<strong>경고:</strong> 데이터베이스가 인식하지 않는 집합을 사용하고 있습니다.",
"config-db-web-account": "웹 접근을 위한 데이터베이스 계정",
"config-db-web-help": "위키의 일반적인 작업을 수행하는 동안 데이터베이스 서버에 연결하는 데 사용할 웹 서버의 계정 이름과 비밀번호를 선택하세요.",
"config-db-web-account-same": "설치를 위해 같은 계정 사용",
@@ -179,13 +177,13 @@
"config-mysql-engine": "저장소 엔진:",
"config-mysql-innodb": "InnoDB",
"config-mysql-myisam": "MyISAM",
- "config-mysql-myisam-dep": "'''경고''': MySQL을 위한 저장소 엔진으로 MyISAM을 선택하였습니다. MyISAM을 미디어위키에 사용하는 것은 좋지 않습니다. 이유는:\n* 테이블 잠금 때문에 동시 실행을 지원하지 않습니다\n* 다른 엔진보다 더 손상되는 경향이 있습니다\n* 미디어위키 코드베이스가 항상 정상적으로 MyISAM을 처리하지 않습니다\n\nMySQL이 InnoDB를 지원한다면, InnoDB를 선택할 것을 매우 권장합니다.\nMySQL이 InnoDB를 지원하지 않는다면, 업그레이드를 하시는 편이 좋습니다.",
- "config-mysql-only-myisam-dep": "'''경고''': MyISAM은 이 기계에 유일하게 사용할 수 있는 MySQL용 저장소 엔진이며, 미디어위키에 사용하는 것은 좋지 않습니다. 이유는:\n* 테이블 잠금 때문에 동시 실행을 지원하지 않습니다\n* 다른 엔진보다 더 손상시키는 경향이 있습니다\n* 미디어위키 코드베이스가 항상 정상적으로 MyISAM을 처리하지 않습니다\n\n당신의 MySQL은 InnoDB를 지원하지 않으며, 업그레이드를 하는 것이 좋습니다.",
- "config-mysql-engine-help": "'''InnoDB'''는 동시 실행 지원이 우수하기 때문에 대부분의 경우 최고의 옵션입니다.\n\n'''MyISAM'''은 단일 사용자나 읽기 전용 설치에서 더 빠를 수 있습니다.\nMyISAM 데이터베이스는 InnoDB 데이터베이스보다 더 자주 손실될 수 있습니다.",
+ "config-mysql-myisam-dep": "<strong>경고:</strong> MySQL을 위한 저장소 엔진으로 MyISAM을 선택하였습니다. MyISAM을 미디어위키에 사용하는 것은 좋지 않습니다. 이유는:\n* 테이블 잠금 때문에 동시 실행을 지원하지 않습니다\n* 다른 엔진보다 더 손상되는 경향이 있습니다\n* 미디어위키 코드베이스가 항상 정상적으로 MyISAM을 처리하지 않습니다\n\nMySQL이 InnoDB를 지원한다면, InnoDB를 선택할 것을 매우 권장합니다.\nMySQL이 InnoDB를 지원하지 않는다면, 업그레이드를 하시는 편이 좋습니다.",
+ "config-mysql-only-myisam-dep": "<strong>경고:</strong> MyISAM은 이 기계에 유일하게 사용할 수 있는 MySQL용 저장소 엔진이며, 미디어위키에 사용하는 것은 좋지 않습니다. 이유는:\n* 테이블 잠금 때문에 동시 실행을 지원하지 않습니다\n* 다른 엔진보다 더 손상시키는 경향이 있습니다\n* 미디어위키 코드베이스가 항상 정상적으로 MyISAM을 처리하지 않습니다\n\n당신의 MySQL은 InnoDB를 지원하지 않으며, 업그레이드를 하는 것이 좋습니다.",
+ "config-mysql-engine-help": "<strong>InnoDB</strong>는 동시 실행 지원이 우수하기 때문에 대부분의 경우 최고의 옵션입니다.\n\n<strong>MyISAM</strong>은 단일 사용자나 읽기 전용 설치에서 더 빠를 수 있습니다.\nMyISAM 데이터베이스는 InnoDB 데이터베이스보다 더 자주 손실될 수 있습니다.",
"config-mysql-charset": "데이터베이스 문자 집합:",
"config-mysql-binary": "바이너리",
"config-mysql-utf8": "UTF-8",
- "config-mysql-charset-help": "'''바이너리 모드'''에서 미디어위키는 바이너리 필드의 데이터베이스에 UTF-8 텍스트를 저장합니다.\nMySQL의 UTF-8 모드보다 더 효율적이고, 유니코드 문자의 전체 범위를 사용할 수 있습니다.\n'''UTF-8 모드'''에서는 MySQL이 데이터를 사용하는 문자 집합을 알고 있기 때문에 적절하게 표현하고 변환할 수 있지만\n[//ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%ED%8F%89%EB%A9%B4#.EA.B8.B0.EB.B3.B8_.EB.8B.A4.EA.B5.AD.EC.96.B4_.ED.8F.89.EB.A9.B4 기본 다국어 평면] 밖에 있는 문자를 저장할 수 없습니다.",
+ "config-mysql-charset-help": "<strong>바이너리 모드</strong>에서 미디어위키는 바이너리 필드의 데이터베이스에 UTF-8 텍스트를 저장합니다.\nMySQL의 UTF-8 모드보다 더 효율적이고, 유니코드 문자의 전체 범위를 사용할 수 있습니다.\n<strong>UTF-8 모드</strong>에서는 MySQL이 데이터를 사용하는 문자 집합을 알고 있기 때문에 적절하게 표현하고 변환할 수 있지만\n[//ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%ED%8F%89%EB%A9%B4#.EA.B8.B0.EB.B3.B8_.EB.8B.A4.EA.B5.AD.EC.96.B4_.ED.8F.89.EB.A9.B4 기본 다국어 평면] 밖에 있는 문자를 저장할 수 없습니다.",
"config-mssql-auth": "인증 형식:",
"config-mssql-install-auth": "설치 과정 중 데이터베이스에 연결하는 데 사용할 인증 형식을 선택하세요.\n\"{{int:config-mssql-windowsauth}}\"을 선택하시면 웹서버를 실행 중인 아무 사용자의 자격 증명이 사용됩니다.",
"config-mssql-web-auth": "위키가 일반적인 작업을 수행하는 동안 데이터베이스 서버에 연결하는 데 사용할 인증 형식을 선택하세요.\n\n\"{{int:config-mssql-windowsauth}}\"을 선택하시면 웹서버를 실행 중인 아무 사용자의 자격 증명이 사용됩니다.",
@@ -227,7 +225,7 @@
"config-profile-no-anon": "계정 만들기 필요",
"config-profile-fishbowl": "승인된 편집자만",
"config-profile-private": "비공개 위키",
- "config-profile-help": "위키는 가능한 많은 사람들이 편집할 수 있도록 할 때 가장 뛰어난 역할을 합니다.\n미디어위키에서는 최근 바뀜을 검토하기 쉽고, 미숙하거나 악의적인 사용자의 어떠한 손실을 되돌리는 것이 쉽습니다.\n\n그러나 많은 사람이 미디어위키가 다양한 역할을 수행하는 데 유용하다는 것을 알고 있지만, 때로는 모든 사람에게 위키 방식의 장점을 설득하기 쉽지 않을 지도 모릅니다.\n그래서 선택할 수 있습니다.\n\n'''{{int:config-profile-wiki}}''' 모델은 로그인하지 않고도 누구나 편집할 수 있습니다.\n'''{{int:config-profile-no-anon}}'''인 위키에서는 편집자에게 추가적인 책임을 부여하지만, 부담 없는 기여를 저해할 수도 있습니다.\n\n'''{{int:config-profile-fishbowl}}''' 시나리오에서는 승인된 사용자만 편집할 수 있지만, 일반 사용자도 문서(문서 역사 포함)는 볼 수 있습니다.\n'''{{int:config-profile-private}}'''는 승인된 사용자만 문서를 볼 수 있으며, 승인된 사용자 그룹이 편집할 수 있습니다.\n\n더 복잡한 사용자 권한 설정은 설치한 후 사용할 수 있으며 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights 관련 설명서 항목]을 참고하세요.",
+ "config-profile-help": "위키는 가능한 많은 사람들이 편집할 수 있도록 할 때 가장 뛰어난 역할을 합니다.\n미디어위키에서는 최근 바뀜을 검토하기 쉽고, 미숙하거나 악의적인 사용자의 어떠한 손실을 되돌리는 것이 쉽습니다.\n\n그러나 많은 사람이 미디어위키가 다양한 역할을 수행하는 데 유용하다는 것을 알고 있지만, 때로는 모든 사람에게 위키 방식의 장점을 설득하기 쉽지 않을 지도 모릅니다.\n그래서 선택할 수 있습니다.\n\n<strong>{{int:config-profile-wiki}}/<strong> 모델은 로그인하지 않고도 누구나 편집할 수 있습니다.\n<strong>{{int:config-profile-no-anon}}</strong>인 위키에서는 편집자에게 추가적인 책임을 부여하지만, 부담 없는 기여를 저해할 수도 있습니다.\n\n<strong>{{int:config-profile-fishbowl}}</strong> 시나리오에서는 승인된 사용자만 편집할 수 있지만, 일반 사용자도 문서(문서 역사 포함)는 볼 수 있습니다.\n<strong>{{int:config-profile-private}}</strong>는 승인된 사용자만 문서를 볼 수 있으며, 승인된 사용자 그룹이 편집할 수 있습니다.\n\n더 복잡한 사용자 권한 설정은 설치한 후 사용할 수 있으며 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights 관련 설명서 항목]을 참조하세요.",
"config-license": "저작권 및 라이선스:",
"config-license-none": "라이선스 바닥글 없음",
"config-license-cc-by-sa": "크리에이티브 커먼즈 저작자표시-동일조건변경허락",
@@ -248,18 +246,18 @@
"config-email-watchlist": "주시문서 목록 알림 활성화",
"config-email-watchlist-help": "환경 설정에서 활성화한 경우 사용자가 주시한 문서에 대한 알림을 받도록 활성화합니다.",
"config-email-auth": "이메일 인증 활성화",
- "config-email-auth-help": "이 설정이 활성화되어 있으면 사용자는 이메일 주소를 설정하거나 바꿀 때마다 링크를 사용하여 이메일 주소를 확인해야 합니다.\n인증된 이메일 주소만 다른 사용자로부터의 이메일이나 바뀜 알림 이메일을 받을 수 있습니다.\n이메일 기능의 남용 가능성이 있기 때문에 공개 위키에서는 이 옵션을 설정할 것을 '''권장'''합니다.",
+ "config-email-auth-help": "이 설정이 활성화되어 있으면 사용자는 이메일 주소를 설정하거나 바꿀 때마다 링크를 사용하여 이메일 주소를 확인해야 합니다.\n인증된 이메일 주소만 다른 사용자로부터의 이메일이나 바뀜 알림 이메일을 받을 수 있습니다.\n이메일 기능의 남용 가능성이 있기 때문에 공개 위키에서는 이 옵션을 설정할 것을 <strong>권장</strong>합니다.",
"config-email-sender": "반송 이메일 주소",
"config-email-sender-help": "발신한 이메일에 대한 반송 주소로 사용할 이메일 주소를 입력하세요.\n반송할 때 보내는 주소입니다.\n대부분의 메일 서버는 적어도 도메인 이름 부분은 유효합니다.",
"config-upload-settings": "그림과 파일 올리기",
"config-upload-enable": "파일 올리기 활성화",
- "config-upload-help": "파일 올리기는 서버에 잠재적인 보안 위험에 쉽게 노출될 수 있습니다.\n자세한 내용은 매뉴얼의 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security 보안 문단]을 참고하세요.\n\n파일 올리기를 활성화하려면 미디어위키의 루트 디렉토리에 있는 <code>images</code> 하위 디렉토리에서 웹 서버가 기록할 수 있도록 모드를 바꿉니다.\n그 다음 이 옵션을 활성화합니다.",
+ "config-upload-help": "파일 올리기는 서버에 잠재적인 보안 위험에 쉽게 노출될 수 있습니다.\n자세한 내용은 매뉴얼의 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security 보안 문단]을 참조하세요.\n\n파일 올리기를 활성화하려면 미디어위키의 루트 디렉토리에 있는 <code>images</code> 하위 디렉토리에서 웹 서버가 기록할 수 있도록 모드를 바꿉니다.\n그 다음 이 옵션을 활성화합니다.",
"config-upload-deleted": "삭제된 파일에 대한 디렉터리:",
"config-upload-deleted-help": "삭제된 파일을 보관할 디렉토리를 선택하세요.\n이상적으로 웹에서 접근할 수 없게 해야 합니다.",
"config-logo": "로고 URL:",
"config-logo-help": "미디어위키의 기본 스킨은 사이드바 메뉴 위에 135×160 픽셀의 로고의 공간을 포함하고 있습니다.\n적당한 크기로 그림을 올리고 여기에 URL을 입력하세요.\n\n로고가 상대적인 경로에 있으면 <code>$wgStylePath</code>나 <code>$wgScriptPath</code>를 사용할 수 있습니다.\n\n로고 사용을 원하지 않으면 이 상자를 비우세요.",
"config-instantcommons": "인스턴트 공용 기능 활성화",
- "config-instantcommons-help": "[//www.mediawiki.org/wiki/InstantCommons 인스턴트 공용]은 [//commons.wikimedia.org/ 위키미디어 공용] 사이트에서 찾을 수 있는 그림, 소리 및 다른 미디어를 위키에서 사용할 수 있도록 하는 기능입니다.\n이렇게 하려면 미디어위키가 인터넷에 접근해야합니다.\n\n위키미디어 공용 외에 기타 위키를 설정하는 방법에 대한 지침을 포함한, 기능에 대한 자세한 내용은 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos 매뉴얼]을 참고하세요.",
+ "config-instantcommons-help": "[//www.mediawiki.org/wiki/InstantCommons 인스턴트 공용]은 [//commons.wikimedia.org/ 위키미디어 공용] 사이트에서 찾을 수 있는 그림, 소리 및 다른 미디어를 위키에서 사용할 수 있도록 하는 기능입니다.\n이렇게 하려면 미디어위키가 인터넷에 접근해야합니다.\n\n위키미디어 공용 외에 기타 위키를 설정하는 방법에 대한 지침을 포함한, 기능에 대한 자세한 내용은 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos 매뉴얼]을 참조하세요.",
"config-cc-error": "크리에이티브 커먼즈 라이선스 선택기에 결과가 없습니다.\n수동으로 라이선스 이름을 입력하세요.",
"config-cc-again": "다시 선택...",
"config-cc-not-chosen": "원하는 크리에이티브 커먼즈 라이선스를 선택하고 \"진행\"을 클릭하세요.",
@@ -283,7 +281,7 @@
"config-skins-missing": "스킨을 찾을 수 없습니다; 미디어위키는 당신이 적절한 스킨을 설치할 때까지 대체 스킨을 사용합니다.",
"config-skins-must-enable-some": "적어도 활성화활 스킨 하나를 선택해야 합니다.",
"config-skins-must-enable-default": "기본값으로 설정한 스킨은 반드시 활성화해야 합니다.",
- "config-install-alreadydone": "'''경고:''' 이미 미디어위키를 설치했고 다시 설치하려고 합니다.\n다음 페이지로 진행하세요.",
+ "config-install-alreadydone": "<strong>경고:</strong> 이미 미디어위키를 설치했고 다시 설치하려고 합니다.\n다음 페이지로 진행하세요.",
"config-install-begin": "\"{{int:config-continue}}\"을 누르면 미디어위키의 설치를 시작합니다.\n그래도 바꾸는 것을 원한다면 \"{{int:config-back}}\"를 누르세요.",
"config-install-step-done": "완료",
"config-install-step-failed": "실패",
@@ -304,14 +302,14 @@
"config-install-user-missing": "지정한 \"$1\" 사용자가 존재하지 않습니다.",
"config-install-user-missing-create": "지정된 \"$1\" 사용자가 존재하지 않습니다.\n사용자를 만드려면 아래의 \"계정 만들기\" 확인 상자를 클릭하세요.",
"config-install-tables": "테이블을 만드는 중",
- "config-install-tables-exist": "'''경고''': 미디어위키 테이블이 이미 있는 것 같습니다.\n테이블 만들기를 생략합니다.",
- "config-install-tables-failed": "'''오류''': 다음 오류로 인해 테이블 만들기에 실패했습니다: $1",
+ "config-install-tables-exist": "<strong>경고:</strong> 미디어위키 테이블이 이미 있는 것 같습니다.\n테이블 만들기를 생략합니다.",
+ "config-install-tables-failed": "<strong>오류</strong>: 다음 오류로 인해 테이블 만들기에 실패했습니다: $1",
"config-install-interwiki": "기본 인터위키 테이블을 채우는 중",
"config-install-interwiki-list": "<code>interwiki.list</code> 파일을 불러올 수 없습니다.",
- "config-install-interwiki-exists": "'''경고''': 인터위키 테이블이 이미 항목을 갖고 있는 것 같습니다.\n기본 목록을 건너뜁니다.",
+ "config-install-interwiki-exists": "<strong>경고:</strong> 인터위키 테이블이 이미 항목을 갖고 있는 것 같습니다.\n기본 목록을 건너뜁니다.",
"config-install-stats": "통계를 초기화하는 중",
"config-install-keys": "보안 키를 만드는 중",
- "config-insecure-keys": "'''경고:''' 설치 중에 생성한 {{PLURAL:$2|보안 키}} ($1)는 완전히 안전하지 {{PLURAL:$2|않습니다}}. 직접 바꾸는 것을 고려하세요.",
+ "config-insecure-keys": "<strong>경고:</strong> 설치 중에 생성한 {{PLURAL:$2|보안 키}} ($1)는 완전히 안전하지 {{PLURAL:$2|않습니다}}. 직접 바꾸는 것을 고려하세요.",
"config-install-updates": "불필요한 업데이트 실행 방지",
"config-install-updates-failed": "<strong>오류:</strong> 다음 오류로 테이블 안에 업데이트 키를 넣기에 실패했습니다: $1",
"config-install-sysop": "관리자 사용자 계정을 만드는 중",
@@ -326,6 +324,6 @@
"config-help-tooltip": "확장하려면 클릭",
"config-nofile": "\"$1\" 파일을 찾을 수 없습니다. 이미 삭제되었나요?",
"config-extension-link": "당신의 위키가 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions 확장 기능]을 지원한다는 것을 알고 계십니까?\n\n[//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category 분류별 확장 기능]을 찾아보실 수 있습니다.",
- "mainpagetext": "'''미디어위키가 성공적으로 설치되었습니다.'''",
+ "mainpagetext": "<strong>미디어위키가 성공적으로 설치되었습니다.</strong>",
"mainpagedocfooter": "[//meta.wikimedia.org/wiki/Help:Contents 이곳]에서 위키 소프트웨어에 대한 정보를 얻을 수 있습니다.\n\n== 시작하기 ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings 설정하기 목록]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ 미디어위키 FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce 미디어위키 릴리스 메일링 리스트]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources 내 언어로 미디어위키 지역화]"
}
diff --git a/includes/installer/i18n/ksh.json b/includes/installer/i18n/ksh.json
index 367db406..bffdf057 100644
--- a/includes/installer/i18n/ksh.json
+++ b/includes/installer/i18n/ksh.json
@@ -7,7 +7,7 @@
]
},
"config-desc": "Et Projramm för Mediwiki opzesäze.",
- "config-title": "MediaWiki $1 opsäze",
+ "config-title": "MehdijaWikki $1 opsäze",
"config-information": "Enfomazjuhn",
"config-localsettings-upgrade": "De Dattei <code lang=\"en\"><code>LocalSettings.php</code></code> es ald doh.\nDe Projramme vum Wiki künne op der neußte Shtand jebraat wääde:\nDonn doför dä Wäät vum <code lang=\"en\">$wgUpgradeKey</code> en dat heh Feld enjävve.\nDo fenggs_et en dä Dattei <code lang=\"en\"><code>LocalSettings.php</code></code> om ẞööver.",
"config-localsettings-cli-upgrade": "En Dattei <code lang=\"en\"><code>LocalSettings.php</code></code> es jefonge woode.\nÖm et Wiki_Projramm op ene neue Shtand ze bränge, donn <code lang=\"en\">update.php</code> oproofe.",
@@ -17,52 +17,51 @@
"config-localsettings-incomplete": "Mer han en Dattei <code lang=\"en\"><code>LocalSettings.php</code>:</code> jefonge, ävver di schingk nit kumplätt ze sin.\nDe Varijable <code lang=\"en\">$1</code> es nit jesatz.\nBes esu joot, un donn di Dattei esu aanpaße, dat se jesaz ea, un dann donn op „{{int:config-continue}}“ klecke.",
"config-localsettings-connection-error": "Ene Fähler es opjetrodde wi mer en Verbendong noh de Datebangk opmaache wullte met dä Enschtällonge uß dä Dattei <code lang=\"en\">LocalSettings</code> un et hät nit jeflupp. Bes esu joot un don dat repareere un versöhg et dann norr_ens.\n\n$1\n\n$1",
"config-session-error": "Ene Fähler es opjetrodde beim Aanmelde för en Sezung: $1",
- "config-session-expired": "De Daate för Ding Setzung sinn wall övverholld of afjeloufe.\nDe Setzungunge sin esu enjeshtallt, nit mieh wi $1 ze doore.\nDat kanns De verlängere, endämm dat De de <code lang=\"en\">session.gc_maxlifetime</code> en dä Dattei <code>php.ini</code> jrüüßer määß.\nDon dat Projramm för et Opsäze norr_ens aanschmiiße.",
+ "config-session-expired": "De Daate för Ding Setzung sinn wall övverholld of afjeloufe.\nDe Setzungunge sin esu enjeshtallt, nit mih wi $1 ze doore.\nDat kanns De verlängere, endämm dat De de <code lang=\"en\">session.gc_maxlifetime</code> en dä Dattei <code>php.ini</code> jrüüßer määß.\nDon dat Projramm för et Opsäze norr_ens aanschmiiße.",
"config-no-session": "De Daate för Ding Setzung sinn verschött jejange.\nDonn en dä Dattei <code>php.ini</code> nohloore, ov dä <code lang=\"en\">session.save_path</code> op e zopaß Verzeijschneß zeisch.",
"config-your-language": "De Schprohch beim Enreeschte:",
"config-your-language-help": "Donn heh di Schprohch ußsöhke, di dat Enschtallzjuhnsprojramm kalle sull.",
"config-wiki-language": "Dem Wiki sing Schprohch:",
"config-wiki-language-help": "Donn heh di Schprohch ußsöhke, di et Wiki schtandattmääßesch kalle sull.",
- "config-back": "← Retuur",
+ "config-back": "← Retuhr",
"config-continue": "Wigger →",
"config-page-language": "Schprohch",
- "config-page-welcome": "Wellkumme beim MediaWiki!",
+ "config-page-welcome": "Wellkumme beim MehdijaWikki!",
"config-page-dbconnect": "Met dä Daatebangk Verbenge",
"config-page-upgrade": "En Inshtallzjuhn op der neuste Shtand bränge",
"config-page-dbsettings": "Parrameeter för de Daatebangk",
- "config-page-name": "Name",
+ "config-page-name": "Nahme",
"config-page-options": "Ennställunge",
"config-page-install": "Opsäzze",
- "config-page-complete": "Fäädesch!",
+ "config-page-complete": "Fähdesch!",
"config-page-restart": "Et Opsäze norr_ens neu aanfange",
"config-page-readme": "Donn mesch lässe! (<i lang=\"en\">read me</i>)",
"config-page-releasenotes": "Henwies för heh di Version vum Projramm (<i lang=\"en\">Release notes</i>)",
"config-page-copying": "Ben aam Kopeere",
"config-page-upgradedoc": "Ben op der neuste Stand aam bränge",
"config-page-existingwiki": "Mer han ald e Wiki!",
- "config-help-restart": "Wells De all Ding enjejovve Sachee fottjeschmesse han, un dä janze Vörjang vun fürre aan neu aanfange?",
+ "config-help-restart": "Wells De all Ding enjejovve Saache fottjeschmeße han, un dä janze Vörjang vun fürre aan neu aanfange?",
"config-restart": "Joh, neu aanfange!",
"config-welcome": "=== Ömjevong Pröhfe ===\nMer maache en Aanzahl jrundlääje Pröhvunge, öm erus ze fenge, ov di Ömjävvong heh paß för Mediawiki opzesäze.\nWann de Hölp bem Opsäze hölls, saach wigger, wat heh erus kohm, alsu wat heh schteiht.",
"config-copyright": "=== Urhävverrääsch un Lizänzbedengunge ===\n\n$1\n\nDat Projramm heh es frei, mer kann et wiggerjävve un verdeijle un och verändere onger dä Bedengunge vun de GNU <i lang=\"en\">General Public License</i> (Alljemeine öffentlesche Lizänz) wi se vun de <i lang=\"en\">Free Software Foundation</i> (de Schteftung för frei Projramme) veröffentlesch woode es. Dobei kanns De Der de Version 2 vun dä Lizanz ußsöhke, udder jeede Version donoh, wi et Der jefällt.\n\nDat Projramm weed wigger jejovve met dä Hoffnung, dat et jät nöz, ävver <strong>der ohne Jarrantie</strong>, sujaa der ohne de onußjeshproche Jarantie, <strong>verkoufbaa</strong> ze sin, udder <strong>för öhnds_ene beshtemmpte Zweck ze bruche</strong> ze sin.\nLiß de GNU <i lang=\"en\">General Public License</i> sellver, öm mieh ze erfahre.\n\nDo sullts en <doclink href=Copying>Kopie vun dä alljemene öffentlesche Lizänz vun dä GNU</doclink> (<i lang=\"en\">GNU General Public License</i>) zosamme met heh däm Projramm krääje han. Wann dat nit esu es, schrief aan de <i lang=\"en\">Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA</i>, udder [http://www.gnu.org/copyleft/gpl.html liß se online övver et Internet].",
- "config-sidebar": "* [//www.mediawiki.org MediaWiki sing Hompäjdsch]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Handbooch för Aanwender]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Handbooch för Administratore un Wiki_Köbesse]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Öff jeshtallte Froore met Antwoote]\n----\n* <doclink href=Readme>Liß Mesch! (<i lang=\"en\">Read me</i>)</doclink>\n* <doclink href=ReleaseNotes><i lang=\"en\">Release notes</i> Övver heh di Projrammversion</doclink>\n* <doclink href=Copying><i lang=\"en\">Copying</i> — Lizänzbeshtemmunge</doclink>\n* <doclink href=UpgradeDoc><i lang=\"en\">Upgrading</i> — Ob en neu Projrammversion jonn</doclink>",
- "config-env-good": "De Ömjävung es jeprööf.\nDo kanns MediaWiki opsäze.",
- "config-env-bad": "De Ömjävung es jeprööf.\nDo kanns MediaWiki nit opsäze.",
+ "config-sidebar": "* [//www.mediawiki.org MediaWiki sing Hompäjdsch]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Handbohch för Aanwänder]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Handbohch för Administratohre un Wiki_Köbesse]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Öff jeschtallte Frohre met Antwoote]\n----\n* <doclink href=Readme>Liß Mesch! (<i lang=\"en\">Read me</i>)</doclink>\n* <doclink href=ReleaseNotes><i lang=\"en\">Release notes</i> Övver heh di Projrammversion</doclink>\n* <doclink href=Copying><i lang=\"en\">Copying</i> — Lizänzbeshtemmunge</doclink>\n* <doclink href=UpgradeDoc><i lang=\"en\">Upgrading</i> — Ob en neu Projrammversion jonn</doclink>",
+ "config-env-good": "De Ömjävvöng es jepröhf.\nDo kanns MehdijaWikki opsäze.",
+ "config-env-bad": "De Ömjävong es jeprööf.\nDo kanns MehdijaWikki nit opsäze.",
"config-env-php": "PHP $1 es doh.",
"config-env-hhvm": "HHVM $1 es enschtalleerd.",
- "config-unicode-using-utf8": "För et <i lang=\"en\">Unicode</i>-Nommaliseere dom_mer däm <i lang=\"en\">Brion Vibber</i> sing Projramm <code lang=\"en\">utf8_normalize.so</code> nämme.",
"config-unicode-using-intl": "För et <i lang=\"en\">Unicode</i>-Nommaliseere dom_mer dä [http://pecl.php.net/intl Zohsaz <code lang=\"en\">intl</code> uss em <code lang=\"en\">PECL</code>] nämme.",
- "config-unicode-pure-php-warning": "'''Opjepaß:''' Mer kunnte dä [http://pecl.php.net/intl Zohsaz <code lang=\"en\">intl</code> uss em <code lang=\"en\">PECL</code>] för et <i lang=\"en\">Unicode</i>-Nommaliseere nit fenge. Dröm nämme mer dat eijfache, ävver ärsh lahme, <i lang=\"en\">PHP</i>-Projrammshtöck doför.\nFör jruuße Wikis met vill Metmaachere doht Üsch die Sigg övver et [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations <i lang=\"en\">Unicode</i>-Nommaliseere] (es op Änglesch) aanloore.",
+ "config-unicode-pure-php-warning": "'''Opjepaß:''' Mer kunnte dä [http://pecl.php.net/intl Zohsaz <code lang=\"en\">intl</code> uss em <code lang=\"en\">PECL</code>] för et <i lang=\"en\">Unicode</i>-Nommaliseere nit fenge. Dröm nämme mer dat eijfache, ävver ärsh lahme, <i lang=\"en\">PHP</i>-Projrammshtöck doför.\nFör jruuße Wikis met vill Metmaachere doht Üsch di Sigg övver et [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations <i lang=\"en\">Unicode</i>-Nommaliseere] (es op Änglesch) aanloore.",
"config-unicode-update-warning": "'''Opjepaß:''' Dat Projramm för der <i lang=\"en\">Unicode</i> zo normaliseere boud em Momang op en ählter Version vun dä Bibliothek vum [http://site.icu-project.org/ ICU-Projäk] op.\nDoht di [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations op der neuste Shtand bränge], wann auf dat Wiki em Äänz <i lang=\"en\">Unicode</i> bruche sull.",
- "config-no-db": "Mer kunnte kei zopaß Daatebangk-Driiverprojamm fenge.\nMer bruche e Daatebangk-Driiverprojamm för PHP. Dat moß enjeresht wääde.\nMer künne met heh dä Daatebangke ömjonn: $1.\n\nWann De nit om eijene Rääshner bes, moß De Dinge <i lang=\"en\">provider</i> bedde, dat hä Der ene zopaß Driiver enresht.\nWann de PHP sellver övversaz häs, donn e Zohjangsprojramm för en Daatebangk enbenge, för e Beishpell met: <code lang=\"en\">./configure --with-mysql</code>.\nWann De PHP uss enem <i lang=\"en\">Debian</i> udder <i lang=\"en\">Ubuntu</i> Pakätt enjeresht häs, moß De dann och noch et <code lang=\"en\">php5-mysql</code> op Dinge Räschner bränge.",
+ "config-no-db": "Mer kunnte kei zopaß Daatebangk-Driiverprojamm fenge.\nMer bruche e Daatebangk-Driiverprojamm för PHP. Dat moß enjeresht wääde.\nMer künne met heh dä {{PLURAL:$2|Daatebangk|Daatebangke|Daatebangk}} ömjonn: $1.\n\nWann De nit om eijene Rääshner bes, moß De Dinge <i lang=\"en\">provider</i> bedde, dat hä Der ene zopaß Driiver enresht.\nWann de PHP sellver övversaz häs, donn e Zohjangsprojramm för en Daatebangk enbenge, för e Beishpell met: <code lang=\"en\">./configure --with-mysql</code>.\nWann De PHP uss enem <i lang=\"en\">Debian</i> udder <i lang=\"en\">Ubuntu</i> Pakätt enjeresht häs, moß De dann och noch et <code lang=\"en\">php5-mysql</code> op Dinge Räschner bränge.",
"config-outdated-sqlite": "'''Opjepaß:''' <i lang=\"en\">SQLite</i> $1 es enschtaleert. Avver MediaWiki bruch <i lang=\"en\">SQLite</i> $2 udder hühter. <i lang=\"en\">SQLite</i> kann dröm nit enjesaz wääde.",
"config-no-fts3": "'''Opjepaß:''' De Projramme vum <i lang=\"en\">SQLite</i> sin der ohne et [//sqlite.org/fts3.html FTS3-Modul] övversaz, dröm wääde de Funxjohne för et Söhke fähle.",
"config-register-globals-error": "<strong>Fähler: dem PHP sing Enschtällong <code>[http://php.net/register_globals register_globals]</code> es aanjeschalldt.\nSe moß ußjeschalldt sin, domet mer heh wigger maache kann.</strong>\nLoor op dä Sigg [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] wi mer se ußschallde kann.",
- "config-magic-quotes-gpc": "'''Dä!''' Dem PHP singe Schallder <code lang=\"en\">[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc]</code> es enjeschalldt.\nDä määt enjejovve Daate kapott, un doh draan kam_mer dann nix mieh repareere.\nDomet kam_mer MediaWiki nit ennreeshte un och nit loufe lohße.\nDat heiß, mer moß en affschallde, söns jeiht nix.",
- "config-magic-quotes-runtime": "'''Dä!''' Dem PHP singe Schallder <code lang=\"en\">[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime]</code> es enjeschalldt.\nDä määt enjejovve Daate kapott, un doh draan kam_mer dann nix mieh repareere.\nDomet kam_mer MediaWiki nit ennreeshte un och nit loufe lohße.\nDat heiß, mer moß en affschallde, söns jeiht nix.",
+ "config-magic-quotes-gpc": "<strong>Dä!</strong> Dem PHP singe Schallder <code lang=\"en\">[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc]</code> es enjeschalldt.\nDä määt enjejovve Daate kapott, un doh draan kam_mer dann nix mih repareere.\nDomet kam_mer MediaWiki nit ennreeshte un och nit loufe lohße.\nDat heiß, mer moß en affschallde, söns jeiht nix.",
+ "config-magic-quotes-runtime": "<strong>Dä!</strong> Dem PHP singe Schallder <code lang=\"en\">[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime]</code> es enjeschalldt.\nDä määt enjejovve Daate kapott, un doh draan kam_mer dann nix mieh repareere.\nDomet kam_mer MediaWiki nit ennreeshte un och nit loufe lohße.\nDat heiß, mer moß en affschallde, söns jeiht nix.",
"config-magic-quotes-sybase": "'''Dä!''' Dem PHP singe Schallder <code lang=\"en\">[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase]</code> es enjeschalldt.\nDä määt enjejovve Daate kapott, un doh draan kam_mer dann nix mieh repareere.\nDomet kam_mer MediaWiki nit ennreeshte un och nit loufe lohße.\nDat heiß, mer moß en affschallde, söns jeiht nix.",
- "config-mbstring": "'''Dä!''' Dem PHP singe Schallder <code lang=\"en\">[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]</code> es enjeschalldt.\nDat sorresch för Fähler un kann enjejovve Daate esu kapott maach, dat doh draan nix mieh ze repareere es.\nDomet kam_mer MediaWiki nit ennreeshte un och nit loufe lohße.\nDat heiß, mer moß en affschallde, söns jeiht nix.",
+ "config-mbstring": "<strong>Dä!</strong> Dem PHP singe Schallder <code lang=\"en\">[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]</code> es enjeschalldt.\nDat sorresch för Fähler un kann enjejovve Daate esu kapott maach, dat doh draan nix mih ze repareere es.\nDomet kam_mer MediaWiki nit ennreeshte un och nit loufe lohße.\nDat heiß, mer moß en affschallde, söns jeiht nix.",
"config-safe-mode": "'''Opjepaß:''' Dem PHP singe <code lang=\"en\">[http://www.php.net/features.safe-mode safe mode]</code> es aanjeschalldt. Dat kann Ärjer maache, besönders beim Datteie Huhlaade bei de Ongershtözung för <code lang=\"en\">math</code>-Befähle.",
- "config-xml-bad": "Dem PHP sing XML-Modul es nit ze fenge.\nMediaWiki bruch Funxjohne en däm Modul un deiht et esu nit.\nWann De <i lang=\"en\">Mandrake</i> aam loufehäs, donn dat Pakätt <code lang=\"en\">php-xml</code> enstalleere.",
+ "config-xml-bad": "Dem <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"PHP Hypertext Preprocessor\">PHP</i> sing <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Extensible Markup Language\">XML</i>-Moduhl es nit ze fenge.\nMediaWiki bruch Funxjohne en däm Moduhl un deiht et esu nit.\nDe künns et nühdesch han, dat Pakätt \n„<code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">php-xml</code>“ ze enschtallehre.",
"config-pcre-old": "<strong>Fähler:</strong> PCRE $1 udder neuer es nüüdesch.\nPHP es jäz ävver met PCRE $2 zesamme jebonge.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Mieh dohzoh].",
"config-pcre-no-utf8": "'''Dä:''' Et PHP-Modul <i lang=\"en\">PCRE</i> schingk ohne de <i lang=\"en\">PCRE_UTF8</i>-Aandeile övversaz ze sin.\nMediaWiki bruch dä UTF-8-Krohm ävver, öm ohne Fähler loufe ze künne.",
"config-memory-raised": "Der jrühzte zohjelasse Shpeisherbedarf vum PHP, et <code lang=\"en\">memory_limit</code>, shtund op $1 un es op $2 erop jesaz woode.",
@@ -74,7 +73,7 @@
"config-apc": "Dä <code lang=\"en\">[http://www.php.net/apc APC]</code> es ennjeresht.",
"config-wincache": "Dä <code lang=\"en\">[http://www.iis.net/download/WinCacheForPhp WinCache]</code> es ennjeresht.",
"config-no-cache": "'''Opjepaß:''' Mer kunnte dä <code lang=\"en\">[http://www.php.net/apc APC]</code>, dä <code lang=\"en\">[http://xcache.lighttpd.net/ XCache]</code> un dä <code lang=\"en\">[http://www.iis.net/download/WinCacheForPhp WinCache]</code> nit fenge.\nEt <i lang=\"en\">object caching</i> es nit müjjelesh un ußjeschalldt.",
- "config-mod-security": "'''Opjepaß''': Dinge Webßööver hät <code lang=\"en\">[http://modsecurity.org/ mod_security]</code> enjeschalldt. Wann doh derbei en Enschtällong nit janz akeraat paßß, dann kann et goot sin, dat mer Probleme met MeedijaWiki un oc met ander Projramme kritt, die zohlööt, dat vun ußerhallef öhndsene Krohm op dä Webßööver jebraat wääde künnt.Beloor Der di Sigg <code lang=\"en\">[http://modsecurity.org/documentation/ mod_security documentation]</code> udder donn met dä Fachlück för Dinge Webßööver kalle, wann zohfälleje un koomijje Fähler bemerke deihß.",
+ "config-mod-security": "<strong>Opjepaß</strong>: Dinge Wäbßööver hät <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[http://modsecurity.org/ mod_security]</code> enjeschalldt. Jenohch schtandattmähßejje Enschtällonge heh em Wikki künne Problehme met MehdijaWikki un och met ander Projramme aanschtivvelle, di zohlohße, dat vun ußerhallef öhndsene Krohm op dä Webßööver jebraat wähde künnt.\nWann müjjelesch sullt mer dat affschallde. Söns beloor Der di Sigg <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[http://modsecurity.org/documentation/ mod_security documentation]</code> udder donn met dä Fachlück för Dinge Webßööver kalle, wann zohfälleje un koomijje Fähler bemärke deihß.",
"config-diff3-bad": "Mer han <i lang=\"en\">GNU</i> <code lang=\"en\">diff3</code> nit jefonge.",
"config-git": "Mer han de Väsjohn <code>$1</code> vun däm Väsjohnsverwalldongsprojamm <i lang=\"en\">Git</i> jefonge.",
"config-git-bad": "Dat Väsjohnsverwalldongsprojamm <i lang=\"en\">Git</i> ham_mer nit jefonge.",
@@ -95,31 +94,29 @@
"config-db-host-oracle": "Dä Daatebangk ier <i lang=\"en\" title=\"Transparent Network Substrate\">TNS</i>:",
"config-db-host-oracle-help": "Donn ene jöltije [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm „<i lang=\"en\">Local Connect</i>“-Name] aanjävve. De Dattei „<code lang=\"en\">tnsnames.ora</code>“ moß för heh dat Projamm seschbaa un ze Lässe sin.<br />Wann heh de Projamm_Biblijoteeke für de Aanwänderprojramme för de Version 10g udder neuer enjesaz wääde, kam_mer och et [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm „<i lang=\"en\">Easy Connect</i>“] jenumme wääde för der Name ze verjävve.",
"config-db-wiki-settings": "De Daate vum Wiki",
- "config-db-name": "Dä Name vun dä Daatebangk:",
+ "config-db-name": "Dä Nahme vun dä Daatebangk:",
"config-db-name-help": "Jiff ene Name aan, dä för Ding Wiki passe deiht.\nDoh sullte kei Zweschrereum un kein Stresche dren sin.\n\nWann De nit op Dingem eije Rääschner bes, künnt et sin, dat Dinge Provaider Der extra ene beshtemmpte Name för de Daatebangk jejovve hät, uffr dat de dä drom froore moß udder dat De de Daatebangke övver e Fommulaa selver enreeschte moß.",
"config-db-name-oracle": "Schema för de Daatebangk:",
- "config-db-account-oracle-warn": "Mer han drei Aate, wi mer <i lang=\"en\">Oracle</i> als Daatebangk aanbenge künne.\n\nWann De ene neue Zohjang op de Daatenbangk met Naame un Paßwoot mem Projramm för et Opsäze aanlääje wells, dann jif ene Zohjang met däm Rääsch „<i lang=\"en\">SYSDBA</i>“ aan, dä et alld jitt, un jif däm di Daate aan för dä neue Zohjang aanzelääje.\nDo kanns och dä neue Zohjang vun Hand aanlääje un heh beim Opsäze nur dää aanjävve — wann dä dat Rääsch hät, en de Daatebangk Schema_Objäkte aanzelääje.\nUdder De jiß zwei ongerscheidlijje Zohjäng op de Daatenbangk aan, woh eine vun dat Rääsch zom Aanlääje hät un dä andere moß dat nit un es för der nomaale Bedrief zohshtändesch.\n\nEn Skrep, wat ene Zohjang op de Daatenbangk aanlääsch met all dä nüüdejje Rääschde, fengks De em Verzeishneß <code lang=\"en\">maintenance/oracle/</code> vun Dingem MediaWiki. Donn draan dengke, dat ene Zohjang met beschrängkte Rääschde all di Müjjeleschkeite för et Waade un Repareere nit hät, di de jewöhnlejje Zoot Zohjang met sesh brängk.",
+ "config-db-account-oracle-warn": "Mer han drei Aate, wi mer <i lang=\"en\">Oracle</i> als Dahtebangk aanbenge künne.\n\nWann De ene neue Zohjang op de Dahtenbangk met Nahme un Paßwoot mem Projramm för et Opsäze aanlääje wells, dann jif ene Zohjang met däm Rääsch „<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"SYS - Database Administrator Authentication\">SYSDBA</i>“ aan, dä et alld jitt, un jif däm di Daate aan för dä neue Zohjang aanzelääje.\nDo kanns och dä neue Zohjang vun Hand aanlääje un heh beim Opsäze nur dää aanjävve — wann dä dat Rääsch hät, en de Daatebangk Schema_Objäkte aanzelääje.\nUdder De jiß zwei ongerscheidlijje Zohjäng op de Daatenbangk aan, woh eine vun dat Rääsch zom Aanlääje hät un dä andere moß dat nit un es för der nomaale Bedrief zohshtändesch.\n\nEn Skrep, wat ene Zohjang op de Dahtenbangk aanlääsch met all dä nüüdejje Rääschde, fengks De em Verzeishneß <code lang=\"en\">maintenance/oracle/</code> vun Dingem MediaWiki. Donn draan dengke, dat ene Zohjang met beschrängkte Rääschde all di Müjjeleschkeite för et Waade un Repareere nit hät, di de jewöhnlejje Zoot Zohjang met sesh brängk.",
"config-db-install-account": "Der Zohjang för en Enreeschte",
"config-db-username": "Dä Name vun däm Aanwender för dä Zohjref op de Daatebangk:",
"config-db-password": "Et Paßwoot vun däm Aanwender för dä Zohjref op de Daatebangk:",
- "config-db-password-empty": "Jiv e Paßwoot aan, för dä neue Aanwender för dä Zohjref op de Daatebangk, $1.\nEd es zwa müjjelesch, Aanwender för dä Zohjref op de Daatebangk der ohne e Paßwoot aanzelääje,\nävver dat wöhr en schwere Jevah för de Sescherheit vum Wiki.",
- "config-db-username-empty": "Do moß jäd aanjävve för \"{{int:config-db-username}}\".",
- "config-db-install-username": "Jiv ene Name aan för dä Aanwender för dä Zohjref op de Daatebangk beim Enshtalleere.\nDat es keine Metmaacher_Name em Wiki — heh dä Name es alleins en der Daatebangk bikannt.",
+ "config-db-install-username": "Jiv ene Nahme aan för dä Aanwender för dä Zohjref op de Datebangk beim Enshtallehre.\nDat es keine Metmaacher_Nahme em Wikki — heh dä Nahme es alleins en der Dahtebangk bikannt.",
"config-db-install-password": "Jiv e Paßwoot aan för dä Aanwender för dä Zohjref op de Daatebangk beim Enshtalleere.\nDat es kei Paßwoot för ene Metmaacher em Wiki — et es alleins en der Daatebangk bikannt.",
"config-db-install-help": "Donn dä Name un et Paßwoot vun däm Aanwänder för der Zohjreff op de Daatebangk jäz för et Enreeshte aanjävve.",
"config-db-account-lock": "Donn dersälve Name un et sälve Paßwoot för der nomaale Bedrief vum Wiki bruche",
"config-db-wiki-account": "Dä Name vun däm Aanwender för dä Zohjref op de Daatebangk em nomaale Bedrief:",
- "config-db-wiki-help": "Jiv ene Name un e Paßwoot aan, för dä Aanwender för dä Zohjref op de Daatebangk, wann et wiki nommaal aam Loufe es.\nWan et dä Name en der Daatebangk noch it jit, un dä Aanwender för dä Zohjref op de Daatebangk beim Enshtalleere\njenooch Beräschtijunge hät, läät dä heh dä Aanwender en der Daatebangk aan un jidd_em di Rääschde, di dä nüüdesch hät, ävver nit mieh.",
+ "config-db-wiki-help": "Jiv ene Nahme un e Paßwoot aan, för dä Aanwänder för dä Zohjref op de Dahtebangk, wann et Wikki nommahl aam Loufe es.\nWann et dä Nahme en der Dahtebangk noch nit jit, un dä Aanwender för dä Zohjrevv op de Dahtebangk beim Enschtallehre jenohch Berääschtejonge hät, läht dä heh dä Aanwänder en der Dahtebangk aan un jidd_em di Rääschde, di dä nühdesch hät, ävver nit mih.",
"config-db-prefix": "Vörsaz för de Name vun de Tabälle en de Daatebangk:",
- "config-db-prefix-help": "Wann ein Daatebangk för mieh wi ein Wiki udder e Wiki uns söns jät zosamme jebruch weed, dann kam_mer noch jet vör de Tabälle ier Name säze. Esu ene Vörsaz sull dubblte Tabällename vermeide hälfe.\nDonn kein Zwescheräum enjävve!\n\nJewöhnlesch bliev dat Feld heh ävver läddesch.",
+ "config-db-prefix-help": "Wann ein Daatebangk för mih wi ein Wiki udder e Wiki uns söns jät zosamme jebruch weed, dann kam_mer noch jet vör de Tabälle ier Name säze. Esu ene Vörsaz sull dubblte Tabällename vermeide hälfe.\nDonn kein Zwescheräum enjävve!\n\nJewöhnlesch bliev dat Feld heh ävver läddesch.",
"config-db-charset": "Dä Daatebangk iere Zeischesaz",
"config-charset-mysql5-binary": "MySQL (4.1 udder 5.0) binär",
"config-charset-mysql5": "MySQL (4.1 udder 5.0) UTF-8",
"config-charset-mysql4": "MySQL 4.0 röckwääts kompatibel UTF-8",
- "config-charset-help": "<strong>Opjepaß:</strong>\nWann De et <strong>röckwääts kompatibel UTF-8 Fommaht</strong> nemmps, met dem <i lang=\"en\">MySQL</i> singe Väsjohn 4.1 udder hüüter, dann künnt dat all di Zeische kappott maache, die nit em <i lang=\"en\" title=\"American Standard Code for Information Interchange\">ASCII</i> sen, un domet all Ding Sescherungskopieje kapott maache, wat mer nieh mieh retuur krijje kann.\n\nBeim Schpeischere em <strong>binäre Fomaat</strong> deiht MediaWiki de Täx, dä em UTF-8 Fommaht küt, en dä Dahtebangk en binähr kodehrte Dahtefälder faßhallde.\nDat es flöcker un spaasahmer wi et UTF-8 Fommaht vum <i lang=\"en\">MySQL</i> un määd_et müjjelesch, jehdes <i lang=\"en\">Unicode</i>-Zeische met faßzehallde.\n\nBeim Schpeischere em <strong>UTF-8 Fomaht</strong> deihd_et <i lang=\"en\">MySQL</i> der Zeischesaz un de Kodehrung vun dä Dahte känne, un kann se akeraht aanzeije un ömwandelle,\nallerdengs künne kein Zeische ußerhalv vum [//de.wikipedia.org/wiki/Basic_Multilingual_Plane#Gliederung_in_Ebenen_und_Bl.C3.B6cke jrondlähje Knubbel för vill Schprohche (<i lang=\"en\">Basic Multilingual Plane — BMP</i>)] afjeschpeischert wähde.",
+ "config-charset-help": "<strong>Opjepaß:</strong>\nWann De et <strong>röckwääts kompatibel UTF-8 Fommaht</strong> nemmps, met dem <i lang=\"en\">MySQL</i> singe Väsjohn 4.1 udder hüüter, dann künnt dat all di Zeische kappott maache, di nit em <i lang=\"en\" title=\"American Standard Code for Information Interchange\">ASCII</i> sen, un domet all Ding Sescherungskopieje kapott maache, wat mer nieh mieh retuur krijje kann.\n\nBeim Schpeischere em <strong>binäre Fomaat</strong> deiht MediaWiki de Täx, dä em UTF-8 Fommaht küt, en dä Dahtebangk en binähr kodehrte Dahtefälder faßhallde.\nDat es flöcker un spaasahmer wi et UTF-8 Fommaht vum <i lang=\"en\">MySQL</i> un määd_et müjjelesch, jehdes <i lang=\"en\">Unicode</i>-Zeische met faßzehallde.\n\nBeim Schpeischere em <strong>UTF-8 Fomaht</strong> deihd_et <i lang=\"en\">MySQL</i> der Zeischesaz un de Kodehrung vun dä Dahte känne, un kann se akeraht aanzeije un ömwandelle,\nallerdengs künne kein Zeische ußerhalv vum [//de.wikipedia.org/wiki/Basic_Multilingual_Plane#Gliederung_in_Ebenen_und_Bl.C3.B6cke jrondlähje Knubbel för vill Schprohche (<i lang=\"en\">Basic Multilingual Plane — BMP</i>)] afjeschpeischert wähde.",
"config-mysql-old": "Mer bruche <i lang=\"en\">MySQL</i> $1 udder neuer. Em Momang es <i lang=\"en\">MySQL</i> $2 aam Loufe.",
"config-db-port": "De Pooz-Nommer (<i lang=\"en\">port</i>) för de Daatebangk:",
- "config-db-schema": "Et Schema en de Datebangk för MediaWiki:",
+ "config-db-schema": "Et Schehma en de Datebangk för MehdijaWikki:",
"config-db-schema-help": "För jewöhnlesch es dat Schema en Odenong.\nDonn bloß jät draan ändere, wann De sescher weiß, dat dat nüüdesch es.",
"config-pg-test-error": "Mer krijje kein Verbendung zor Daatebank '''$1''': $2",
"config-sqlite-dir": "Dem <i lang=\"en\">SQLite</i> sing Daateverzeishnes:",
@@ -132,11 +129,11 @@
"config-type-oracle": "<i lang=\"en\">Oracle</i>",
"config-type-mssql": "Dä <i lang=\"en\" xml:lang=\"en\">SQL</i>-ẞööver vun <i lang=\"en\" xml:lang=\"en\">Microsoft</i>",
"config-support-info": "MediaWiki kann met heh dä Daatebangk_Süßteeme zosamme jonn:\n\n$1\n\nWann dat Daatebangk_Süßteem, wat De nämme wells, onge nit dobei es, dann donn desch aan di Aanleidonge hallde, di bovve verlengk sen, öm et op Dingem ẞööver singem Süßteem müjjelesh ze maache, se aan et Loufe ze krijje.",
- "config-dbsupport-mysql": "* <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mysql-url}} MySQL]</i> es dat vum MediaWiki et eets un et bäß ongerschtöz Daatebangksüßtehm. Et leuf ävver och met <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mariadb-url}} MariaDB]</i> un <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-percona-url}} Percona Server]</i>. Di sin kumpatihbel mem <i lang=\"en\" xml:lang=\"en\">MySQL</i>. ([http://www.php.net/manual/de/mysql.installation.php Aanleidung för et Övversäze un Enreeschte von PHP met <i lang=\"en\">MySQL</i> dobei, op Deutsch])",
+ "config-dbsupport-mysql": "* <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mysql-url}} MySQL]</i> es dat vum MediaWiki et eets un et bäß ongerschtöz Daatebangksüßtehm. Et leuf ävver och met <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mariadb-url}} MariaDB]</i> un <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-percona-url}} Percona Server]</i>. Di sin kumpatihbel mem <i lang=\"en\" xml:lang=\"en\">MySQL</i>. ([http://www.php.net/manual/de/mysql.installation.php Aanleidung för et Övversäze un Enreeschte von <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"PHP Hypertext Preprocessor\">PHP</i> met <i lang=\"en\">MySQL</i> dobei, op Deutsch])",
"config-dbsupport-postgres": "* <i lang=\"en\">[{{int:version-db-postgres-url}} PostgreSQL]</i> es e bikannt Daatebangksüßtehm met offe Quälltäxde, un ed es och en Wahl nävve <i lang=\"en\">MySQL</i>. Et sinn_er ävver paa klein Fählersche bekannt, um mer künne et em Momang för et reschtijje Werke nit ämfähle. ([http://www.php.net/manual/de/pgsql.installation.php Aanleidung för et Övversäze un Enreeschte von PHP met <i lang=\"en\">PostgreSQL</i> dobei, op Deutsch])",
"config-dbsupport-sqlite": "* <i lang=\"en\">[{{int:version-db-sqlite-url}} SQLite]</i> es e eijfach Daatebangksüßtehm, wat joot en Schoß jehallde weed. ([http://www.php.net/manual/de/pdo.installation.php Aanleidong för et Övversäze un Enreeschte von PHP met <i lang=\"en\">SQLite</i> dobei, op Deutsch])",
"config-dbsupport-oracle": "* <i lang=\"en\">[{{int:version-db-oracle-url}} Oracle]</i> es e jeschäfflesch Daatebangksüßtehm för Ferme. ([http://www.php.net/manual/de/oci8.installation.php Aanleidong för et Övversäze un Enreeschte von PHP met <i lang=\"en\" xml:lang=\"en\">OCI8</i> dobei, op Deutsch])",
- "config-dbsupport-mssql": "* Dä <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mssql-url}} Microsoft SQL Server]</i> es e jeschäfflesch Daatebangksüßtehm för Rääschner met <i lang=\"en\" xml:lang=\"en\">Windows</i>. ([http://www.php.net/manual/de/sqlsrv.installation.php Aanleidong för et Övversäze un Enreeschte von PHP met <i lang=\"en\" xml:lang=\"en\">SQLSRV </i> dobei, op Deutsch])",
+ "config-dbsupport-mssql": "* Dä <i lang=\"en\" xml:lang=\"en\">[{{int:version-db-mssql-url}} Microsoft SQL Server]</i> es e jeschäfflesch Dahtebangksüßtehm för Rääschner met <i lang=\"en\" xml:lang=\"en\">Windows</i>. ([http://www.php.net/manual/de/sqlsrv.installation.php Aanleidong för et Övversäze un Enreeschte von <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"PHP Hypertext Preprocessor\">PHP</i> met <i lang=\"en\" xml:lang=\"en\">SQLSRV </i> dobei, op Deutsch])",
"config-header-mysql": "De Enshtällunge för de <i lang=\"en\">MySQL</i> Daatebangk",
"config-header-postgres": "De Enshtällunge för de <i lang=\"en\">PostgreSQL</i> Daatebangk",
"config-header-sqlite": "De Enshtällunge för de <i lang=\"en\">SQLite</i> Daatebangk",
@@ -151,11 +148,11 @@
"config-invalid-db-prefix": "Dä Vörsaz för de Name vun de Tabälle en de Daatebangk kann nit „$1“ sin, dä es esu nit jöltesch.\nDöh dörve bloß <i lang=\"en\" title=\"American Standard Code for Information Interchange\">ASCII</i> Boochshtaabe (a-z, A-Z), Zahle (0-9), Ongerstreshe (_), un Bendeshtreshe (-) dren vörkumme.",
"config-connection-error": "$1.\n\nDonn de Name för dä Rääschner, vun däm Aanwender för dä Zohjref op de Daatebangk, un et Paßwoot prööfe, repareere, un dann versöhg et norr_ens.",
"config-invalid-schema": "Dat Schema för MediaWiki kann nit „$1“ sin, dä Name wöhr esu nit jöltesch.\nDöh dörve bloß <i lang=\"en\" title=\"American Standard Code for Information Interchange\">ASCII</i> Boochshtaabe (a-z, A-Z), Zahle (0-9), un Ongerstreshe (_) dren vörkumme.",
- "config-db-sys-create-oracle": "Dat Projramm för MediaWiki opzesäze kann bloß <i lang=\"en\">SYSDBA</i> bruche för ene neue Zohjang zor Daatebangk enzereeschte!",
- "config-db-sys-user-exists-oracle": "Dä Aanwender „$1“ för dä Zohjref op de Daatebangk jidd_et ald. <i lang=\"en\">SYSDBA</i> kam_mer bloß bruche, för ene neue Zohjang enzereeschte!",
+ "config-db-sys-create-oracle": "Dat Projramm för MehdijaWikki opzesäze kann blohß ene <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"SYS - Database Administrator Authentication\">SYSDBA</i>-Zohjang bruche för ene neuje Zohjang zor Dahtebangk ennzereeschte.",
+ "config-db-sys-user-exists-oracle": "Dä Aanwender „$1“ för dä Zohjref op de Daatebangk jidd_et ald. <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"SYS - Database Administrator Authentication\">SYSDBA</i> kam_mer bloß bruche, för ene neue Zohjang enzereeschte!",
"config-postgres-old": "Mer bruche <i lang=\"en\">PostgreSQL</i> $1 udder neuer. Em Momang es <i lang=\"en\">PostgreSQL</i> $2 aam Loufe.",
"config-mssql-old": "Dä <i lang=\"en\" xml:lang=\"en\">SQL</i>-ẞööver vun <i lang=\"en\" xml:lang=\"en\">Microsoft</i> aff de Väsjohn $1 es nüüdesch. Heh es bloß d Väsjohn $2 ze fenge.",
- "config-sqlite-name-help": "Söhk enen Name uß, dä Ding Wiki beschrief.\nDonn kein Bendeschresch un Zweschräum en däm Name bruche.\nDä Name weed för der Dateiname för de <i lang=\"en\">SQLite</i> Daatebangk jenumme.",
+ "config-sqlite-name-help": "Söhk ene Nahme uß, dä Ding Wikki beschrief.\nDonn kein Bendeschresch un Zweschräum en däm Name bruche.\nDä Name weed för der Datteinahme för de <i lang=\"en\">SQLite</i> Dahtebangk jenumme.",
"config-sqlite-parent-unwritable-group": "Mer kunnte dat Verzeischneß för de Daate, <code lang=\"en\"><nowiki>$1</nowiki></code>, nit enreeschte, weil dat Projramm fö dä Web_ẞööver en dat Verzeischneß doh drövver, <code><nowiki>$2</nowiki></code>, nix erin donn darref.\n\nMer han dä Name vun däm Zohjang op et Süßteem eruß jefonge, onger dämm dat Web_ẞööver_Projramm läuf. Jez moß De bloß doför sorrje, dat dä en dat Verzeischneß <code><nowiki>$3</nowiki></code> schrieve kann, öm heh wigger maache ze künne.\nOb enem Süßteem met <i lang=\"en\">Unix</i>- oder <i lang=\"en\">Linux</i> jeiht dat esu:\n<pre>cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3</pre>",
"config-sqlite-parent-unwritable-nogroup": "Mer kunnte dat Verzeischneß för de Daate, <code lang=\"en\"><nowiki>$1</nowiki></code>, nit enreeschte, weil dat Projramm fö dä Web_ẞööver en dat Verzeischneß doh drövver, <code><nowiki>$2</nowiki></code>, nix erin donn darref.\n\nMer han dä Name vun däm Zohjang op et Süßteem nit eruß fenge künne, onger dämm dat Web_ẞööver_Projramm läuf. Jez moß De bloß doför sorrje, dat dä en dat Verzeischneß <code><nowiki>$3</nowiki></code> schrieve kann, öm heh wigger maache ze künne. Wann De dä Name och nit weiß, maach, dat jeeder_ein doh schrieve kann.\nOb enem Süßteem met <i lang=\"en\">Unix</i>- oder <i lang=\"en\">Linux</i> jeiht dat esu:\n<pre>cd $2\nmkdir $3\nchmod a+w $3</pre>",
"config-sqlite-mkdir-error": "Ene Fähler es opjetrodde beim Aanlääje vum Daate_Verzeishneß „$1“.\nDon dä Plaz för et Shpeishere prööfe un Repareere, dann versöhg et norr_ens.",
@@ -164,7 +161,7 @@
"config-sqlite-readonly": "En di Dattei <code lang=\"en\">$1</code> künne mer nit schrieve.",
"config-sqlite-cant-create-db": "Mer kunnte di Dattei <code lang=\"en\">$1</code> för de Daatebangk nit aanlääje.",
"config-sqlite-fts3-downgrade": "Dat PHP heh hät kein Ongershtözong för FTS3, dröm donn mer de Daatebangktabälle eronger shtoofe.",
- "config-can-upgrade": "Et sinn-er ald Daatebangktabelle vum MediaWiki en dä Daatebangk.\nÖm di op der Shtand vum MediaWiki $1 ze bränge, donn jäz op „{{int:config-continue}}“ klecke.",
+ "config-can-upgrade": "Et sinn-er ald Dahtebangktabälle vum MehdijaWikki en dä Dahtebangk.\nÖm di op der Schtand vum MehdijaWikki $1 ze bränge, donn jäz op „{{int:config-continue}}“ klecke.",
"config-upgrade-done": "Alles es jäz om neue Schtand.\n\nMer kann dat Wiki jäz [$1 bruche].\n\nWann De Ding Dattei <code lang=\"en\">LocalSettings.php</code> neu schrieve wells, donn onge op dä Knopp kleke.\nDat dom_mer ävver '''nit vörschlonn''' — em Jääjedeil — ußer, wann et Problehme mem Wiki jitt.",
"config-upgrade-done-no-regenerate": "Alles es jäz om neue Shtand.\n\nMer kann dat Wiki jäz [$1 bruche].",
"config-regenerate": "Donn de Dattei <code lang=\"en\">LocalSettings.php</code> neu opsäze →",
@@ -180,7 +177,7 @@
"config-mysql-myisam": "MyISAM",
"config-mysql-myisam-dep": "'''Opjepaß:''' <i lang=\"en\">MyISAM</i> es als Speicher för <i lang=\"en\">MySQL</i> nit besönders joot för et Zosammeschpell met MediaWiki zo bruche:\n* Dorj_et kumplätte Sperre vun Tabälle, künne koum ens Saache parrallel en dä Daatebangk jedonn wääde.\n* Dat Fomaat es anfällesch för Probleme met de Daate.\n* Et weed vun MediaWiki nit ėmmer zopaß ongerschtöz.\n\nWann Ding <i lang=\"en\">MySQL</i> et Schpeischere en <i lang=\"en\">InnoDB</i>-Datteije ongerschtöze deiht, dom_mer dat nohdröcklesch ämfähle.\nKann dä ẞööver dat nit, künnd et joode jelääjeheit sin, dä ens op der neuste Schtand ze bränge.",
"config-mysql-only-myisam-dep": "'''Opjepaß:''' <i lang=\"en\" xml:lang=\"en\">MyISAM</i> es de einzeje Zoot Schpeischerprojramm för <i lang=\"en\" xml:lang=\"en\">MySQL</i> op dä Maschiin. Di es nit för MediaWiki ze ämfähle es, weil:\n* wääje dem Schpärre vun jannze Tabälle sin koum paralleele Axjuhne en dä Daatebangk möjjelesch,\n* ed es aanfällesch för Probleeme met de Daate es, un\n* et weed vun MediaWiki nit emmer jood ongerschtöz.\n\nDing Enschtallazjuhn vum <i lang=\"en\" xml:lang=\"en\">MySQL</i> kann nit met <i lang=\"en\" xml:lang=\"en\">InnoDB</i> ömjonn.\nWi wöhr et med ene neuere Väsjohn vum <i lang=\"en\" xml:lang=\"en\">MySQL</i>?",
- "config-mysql-engine-help": "'''InnoDB''' es fö jewöhnlesch et beß, weil vill Zohjreffe op eijmohl joot ongershtöz wääde.\n\n'''MyISAM''' es flöcker op Rääschnere met bloß einem Minsch draan, un bei Wikis, di mer bloß lässe un nit schrieeve kann.\nMyISAM-Daatebangke han em Schnett mieh Fähler un jon flöcker kappott, wi InnoDB-Daatebangke.",
+ "config-mysql-engine-help": "<strong>InnoDB</strong> es fö jewöhnlesch et beß, weil vill Zohjreffe op eijmohl joot ongershtöz wääde.\n\n<strong>MyISAM</strong> es flöcker op Rääschnere met bloß einem Minsch draan, un bei Wikis, di mer bloß lässe un nit schrieeve kann.\nMyISAM-Daatebangke han em Schnett mih Fähler un jon flöcker kappott, wi InnoDB-Daatebangke.",
"config-mysql-charset": "Dä Daatebangk iere Zeischesaz:",
"config-mysql-binary": "binär",
"config-mysql-utf8": "UTF-8",
@@ -190,8 +187,8 @@
"config-mssql-web-auth": "Söhk us, wi dat Aanmälde aan dä Daatebangk vör sesch jonn sull för de nommaale Ärbeid vum Wiki.\nWann De <em>{{int:Config-mssql-windowsauth}}</em> nemms, weed dat jenumme, wohmet dä Wäbßööver aam loufe es.",
"config-mssql-sqlauth": "De Aanmäldong bemm <i lang=\"en\" xml:lang=\"en\">SQL</i>-ẞööver vun <i lang=\"en\" xml:lang=\"en\">Microsoft</i>",
"config-mssql-windowsauth": "De Annmäldong bemm <i lang=\"en\" xml:lang=\"en\">Windows</i>",
- "config-site-name": "Däm Wiki singe Name:",
- "config-site-name-help": "Dä douch em Tettel vun de Brauserfinstere un aan ätlije andere Schtälle op.",
+ "config-site-name": "Däm Wikki singe Nahme:",
+ "config-site-name-help": "Dä douch en dä Övverschreff vun de Brauserfinstere un aan ätlije andere Schtälle op.",
"config-site-name-blank": "Donn ene Name för di Sait aanjävve.",
"config-project-namespace": "Dä Name för et Appachtemang övver et Projäk:",
"config-ns-generic": "Projäk",
@@ -202,12 +199,12 @@
"config-ns-invalid": "Dat aanjejovve Appachtemang „<nowiki>$1</nowiki>“ es nit jöltesch.\nNemm ene andere Name för däm Wiki sing eije Appachtemang.",
"config-ns-conflict": "Dat aanjejovve Appachtemang „<nowiki>$1</nowiki>“ kütt ald als Standatt-Appachtemang em MediaWiki vör.\nNemm ene andere Name för däm Wiki sing eije Appachtemang.",
"config-admin-box": "Der Zohjang för der eezte Wiki_Köbes",
- "config-admin-name": "Dinge Metmaacher_Name:",
+ "config-admin-name": "Dinge Metmaacher_Nahme:",
"config-admin-password": "Et Paßwoot:",
"config-admin-password-confirm": "Norrens dat Paßwoot:",
"config-admin-help": "Jif Dinge leevste Name als Metmaacher för Desch aan, för e Beishpell „Schmitzens Pitter“\n— Dat weed dä Name wääde, met dämm De Desch enlogge deihs.",
- "config-admin-name-blank": "Jiv ene Metmaacher_Name en för dä Wiki-Köbes.",
- "config-admin-name-invalid": "„<nowiki>$1</nowiki>“ es keine jöltijje Metmaacher_Name.\nJiv ene joode Name en!",
+ "config-admin-name-blank": "Jiv ene Metmaacher_Nahme en för dä Wikki-Köhbes.",
+ "config-admin-name-invalid": "„<nowiki>$1</nowiki>“ es keine jöltijje Metmaacher_Nahme.\nJiv ene johde Nahme en!",
"config-admin-password-blank": "Do mos_e Paßwoot för dä Wiki_Köbes aanjävve!",
"config-admin-password-mismatch": "Di Paßwööter sin ongerscheidlesh!",
"config-admin-email": "Addräß för de <i lang=\"en\">e-mail</i>:",
@@ -215,18 +212,18 @@
"config-admin-error-user": "Beim Enreeshte vum Zohjang för dä Wiki_Köbes „<nowiki>$1</nowiki>“ es ene Fähler em Wiki opjetrodde.",
"config-admin-error-password": "Beim Paßwoot-Säze för dä Wiki_Köbes „<nowiki>$1</nowiki>“ es ene Fähler em Wiki opjetrodde.: <pre>$2</pre>",
"config-admin-error-bademail": "Do häs_en onjöltijje Addräß för de <i lang=\"en\">e-mail</i> aanjejovve.",
- "config-subscribe": "Donn de [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce <i lang=\"en\">e-mail</i>-Leß met de Aanköndijunge vum MediaWiki] abonnere.",
+ "config-subscribe": "Donn de [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce \n<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i>-Leß met de Aanköndijonge vum MehdijaWikki] abonnehre.",
"config-subscribe-help": "Do kumme bloß winnish Meddeilunge un di jonn övver neu Versiohne vom MediaWiki un weeshtejje Saache vun däm sing Sesherheit.\nDo sullts se abbonneere, un Ding MediWiki_Projramme op der neue Shtand bränge, wann neu Version eruß kumme.",
"config-subscribe-noemail": "Do has versöhk, der ohne en Addräß för Ding <i lang=\"en\">e-mail<i> aanzejävve, de Aanköndijonge för Aanköndijunge för neue Versione ze abboneere. Jivv en Addräß aan, wann De di Aanköndijonge hann wells.",
- "config-almost-done": "Do bes beinah dorsh!\nDo künnts jez der Räß vun de einzel Enshtellunge övverjonn, un et Wiki tiräktemang fäädesch opsäze.",
- "config-optional-continue": "De wells noch mieh Frore jeshtallt krijje un noch mieh Enshtällunge maache?",
+ "config-almost-done": "Do bes beinah dorsch!\nDo künnts jez der Räß vun de einzel Enschtällonge övverjonn, un et Wiki tiräktemang fähdesch opsäze.",
+ "config-optional-continue": "De wells noch mih Frohre jeschtallt krijje un noch mih Enschtällonge maache?",
"config-optional-skip": "Nä, lohß dä Ömshtand, donn eifarr_et Wiki opsäze.",
"config-profile": "Enshtällunge för de Metmaacher ier Rääschte:",
"config-profile-wiki": "En offe Wiki",
"config-profile-no-anon": "Schriever möße enlogge",
"config-profile-fishbowl": "Bloß ußdröcklesch zohjelohße Schriever",
"config-profile-private": "E jeschloße Privat_Wiki",
- "config-profile-help": "Wikis loufe et bäß, wam_mer esu vill Lück wi möjjelesch draan metmaache un schrieve löht.\nMet MediaWiki es et ejfach, de neuste Änderonge ze beloore un wat ahnungslose udder fiese Lück kapott jemaat han wider retuur ze maache.\n\nBloß, mänsch eine häd_eruß jefonge, dat mer MediaWiki jood en en jruuße Zahl ongerscheidlijje Rolle bruche kann, un nit emmer es et leisch, ene vum onverfälschte Wiki_Wääsch ze övverzeuje.\nEsu häß De de Wahl:\n\n'''{{int:config-profile-wiki}}''' löht jeder_ein metschrieve, och ohne sesch enzelogge.\n\n'''{{int:config-profile-no-anon}}''', dat sorsch för mieh seeschbaa Verantwootlischkeite, künnt ävver zohfällije Methellefer verschrecke.\n\n'''{{int:config-profile-fishbowl}}''' löht nor de ußjesöhk Metmaacher schrieve, ävver de janze Öffentleshkeit kann et lässe un süht och de ällder Versione, un wat wää wann draan jedonn hät.\n\n'''{{int:config-profile-private}}''' kann nur lässe, wäh en et Wiki zohjelohße es, un desellve Jropp kann uch schrieve.\n\nNoch ander un un opwändijere Enschtellunge för de Rääschte sin möjjelesch, wann et Wiki ens aam Loufe es. Loor Der doför de [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights zopaß Hölp em Handbooch] aan.",
+ "config-profile-help": "Wikkis loufe et bäß, wam_mer esu vill Lück wi möjjelesch draan metmaache un schrieve löht.\nMet MehdijaWikki es et ejfach, de neuste Änderonge ze beloore un wat ahnungslose udder fiese Lück kapott jemaat han wider retuur ze maache.\n\nBloß, mänsch eine häd_eruß jefonge, dat mer MediaWiki jood en en jruuße Zahl ongerscheidlijje Rolle bruche kann, un nit emmer es et leisch, ene vum onverfälschte Wiki_Wääsch ze övverzeuje.\nEsu häß De de Wahl:\n\n'''{{int:config-profile-wiki}}''' löht jeder_ein metschrihve, och ohne sesch enzelogge.\n\n'''{{int:config-profile-no-anon}}''', dat sorsch för mieh seeschbaa Verantwootlischkeite, künnt ävver zohfällije Methellefer verschrecke.\n\n'''{{int:config-profile-fishbowl}}''' löht nor de ußjesöhk Metmaacher schrieve, ävver de janze Öffentleshkeit kann et lässe un süht och de ällder Versione, un wat wää wann draan jedonn hät.\n\n'''{{int:config-profile-private}}''' kann nur lässe, wäh en et Wikki zohjelohße es, un desellve Jropp kann och schrieve.\n\nNoch ander un un opwändijere Enschtällonge för de Rääschte sin müjjelesch, wann et Wikki ens aam Loufe es. Loor Der doför de [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights zopaß Hölp em Handbooch] aan.",
"config-license": "Urhävverrääsch un Lizänz:",
"config-license-none": "Kein Fooßreih övver de Lizänz",
"config-license-cc-by-sa": "<i lang=\"en\">Creative Commons</i> Der Name moß jenannt sin, et Wiggerjävve es zohjelohße onger dersellve Bedengunge",
@@ -239,11 +236,11 @@
"config-license-help": "Ättlijje öffentleje Wikis donn iehr Beidrääsch onger en [http://freedomdefined.org/Definition freije Lizänz] schtelle.\nDat hellef, e Jeföhl vun Jemeinsamkeid opzeboue, un op lange Seesch emmer wider Beidrääsch ze krijje.\nDat es nit onbedengk nüüdesh för e Jeschäffs- udder Privaat_Wiki.\n\nWä Stöcke uß de Wikipedia bruche well, un dröm han well, dat mer för Wikipedia uss_em eije Wiki jät övvernämme kann, sullt „'''<i lang=\"en\">Creative Commons</i>, dem Schriever singe Name moß jenannt wääde, un Wiggerjävve zoh dersellve Bedengunge es zohjelohße'''“ ußwähle.\n\nDe su jenannte '''<i lang=\"en\">GNU Free Documentation License</i>''' (de freije Lizänz för Dokemäntazjuhne vun dä GNU) sen de ahle Lizänzbedenonge vun de Wikipedia. Se es emmer noch in Odenong un jöltesch, ävver se es schwer ze verschtonn un et Wiggerjävve un widder Bruche es ens schwieerejer domet.",
"config-email-settings": "Enschtellunge för de <i lang=\"en\">e-mail</i>",
"config-enable-email": "De <i lang=\"en\">e-mail</i> noh druße zohlohße",
- "config-enable-email-help": "Sulle <i lang=\"en\">e-mails</i> zohjelohße sin, moß mer, domet et noher flupp, de [http://www.php.net/manual/en/mail.configuration.php Enschtellunge em PHP för de <i lang=\"en\">e-mails</i>] zopaß jemaat han.\nWann kein <i lang=\"en\">e-mails</i> nüüdesch sin, kam_mer se heh afschallde.",
+ "config-enable-email-help": "Sulle \n<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mails</i> zohjelohße sin, moß mer, domet et noher flupp, dä Datteij <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">[http://www.php.net/manual/en/mail.configuration.php</code> Enschtällonge em PHP för de <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mail</i>] zopaß jemaat han.\nWann kein <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mails</i> nüüdesch sin, kam_mer se heh afschallde.",
"config-email-user": "<i lang=\"en\">e-mails</i> zwesche de Metmaacher zohlohße",
- "config-email-user-help": "Määt et müjjelesch, dat sesch de Metmaacher jääjesiggesch <i lang=\"en\">e-mails</i> schecke künne, wann se dat en iehre eije Enschtellunge och enjeschalldt han.",
+ "config-email-user-help": "Määt et müjjelesch, dat sesch de Metmaacher jääjesiggesch \n<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mails</i> scheke künne, wann se dat en iehre eije Enschtällonge och enjeschalldt han.",
"config-email-usertalk": "<i lang=\"en\">e-mails</i> mem Bescheid zohlohße, dat einem sing Klaafsigg verändert woodt",
- "config-email-usertalk-help": "Maach et müjjelesch, dat Metmaaacher en iere Enstellunge <i lang=\"en\">e-mails</i> mem Bescheid zohlohße, dat einem sing Klaafsigg verändert woodt.",
+ "config-email-usertalk-help": "Maach et müjjelesch, dat Metmaaacher en iere Enschtällonge <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"„de eläktrohnesche Poß“\">e-mails</i>mem Bescheid zohlohße, dat einem sing Klaafsigg veränndert woodt.",
"config-email-watchlist": "Nohreeschte övver Änderonge aan Sigg op de Opaßleßte zohlohße",
"config-email-watchlist-help": "Lohß Metmaacher Nohreeshte övver de Sigge op dänne iehr Oppaßleß krijje, wann se et en iehre Enschtellonge ußjewählt han.",
"config-email-auth": "Donn de Övverprööfung för Zohjangsberääschtejunge övver de <i lang=\"en\">e-mail</i> zohlohße",
@@ -251,14 +248,14 @@
"config-email-sender": "De Adräß för de Antwoote op <i lang=\"en\">e-mails</i>:",
"config-email-sender-help": "Jiff de Adräß för de <i lang=\"en\">e-mail</i> en, woh Antwoote ob em Wiki singe <i lang=\"en\">e-mails</i> hen jonn sulle.\nDat es och de Adräß, woh de <i lang=\"en\">e-mails</i> met Fählermäldonge hen jon.\nVill ẞöövere för de <i lang=\"en\">e-mail</i> welle winnischßdens ene jöltijje Domain en dä Adräß han.",
"config-upload-settings": "Belder un Datteie huh laade",
- "config-upload-enable": "Belder un Datteie huh laade zohlohße",
+ "config-upload-enable": "Et Belder un Datteie Huhlahde zohlohße",
"config-upload-help": "Datteije huh ze laade künnt e Risiko för dem ẞööver singe Sescherheit sin.\nMieh doh drövver kam_mer em [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security Kapitel övver de Sescherheit] em Handbooch lässe.\n\nÖm et Huhlaade zohzelohße donn de Rääschde för der Zohjreff op dat Ongerverzeischneß <code lang=\"en\">images</code> em MediaWiki singem Houpverzeischneß esu enshtälle, dat et Webßööverprojramm doh Datteije un Verzeischneße eren schrieve kann.\nDonoh donn heh di Saach zohlohße.",
"config-upload-deleted": "Dat Verzeishneß för fottjeschmeße Datteije:",
"config-upload-deleted-help": "Söhk e Verzeijschneß uß för de fottjeschmeße Datteije vum Wiki dren afzelääje.\nEt bäß es, wam_mer vum <i lang=\"en\">world wide web</i> doh nit drahn kumme kann.",
"config-logo": "Dem Wiki singem Logo sing <i lang=\"en\">URL</i>:",
"config-logo-help": "De Schtandart_Bedeen_Bovverfläsch vum MediaWiki hät e Logo bovve en der Eck met 135x160 Pixele.\nDonn e zopaß Logo huh laade, un donn däm sing URL heh endraare.\n\nDo kanns <code lang=\"en\">$wgStylePath</code> udder <code lang=\"en\">$wgScriptPath</code> nämme, wann Ding Logo en einem vun dänne Pahde litt.\n\nWells De kei Logo han, draach heh nix en.",
"config-instantcommons": "Donn <i lang=\"en\">InstantCommons</i> zohlohße.",
- "config-instantcommons-help": "<i lang=\"en\">[//www.mediawiki.org/wiki/InstantCommons InstantCommons]</i> es en Eijeschaff, di et för Wikis müjjelesch määt, Belder, Tondatteie un ander Meedijedatteie enzebenge, di op dä Webßait vun de <i lang=\"en\">[//commons.wikimedia.org/ Wikimedia Commons]</i> ongerjebraat sin. Öm dat noze ze künne, moß dä ẞööver vum MediaWiki en Verbendung nohm Internet opnämme künne.\n\nMieh Aanjaabe doh drövver un en Aanleidung, wi mer och ander Wikis ußer de <i lang=\"en\">Wikimedia Commons</i> doför enreeschte kann, fengk mer em [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos Handbooch].",
+ "config-instantcommons-help": "<i lang=\"en\">[//www.mediawiki.org/wiki/InstantCommons InstantCommons]</i> es en Eijeschaff, di et för Wikis müjjelesch määt, Belder, Tondatteie un ander Meedijedatteie enzebenge, di op dä Webßait vun de <i lang=\"en\">[//commons.wikimedia.org/ Wikimedia Commons]</i> ongerjebraat sin. Öm dat noze ze künne, moß dä ẞööver vum MediaWiki en Verbendung nohm Internet opnämme künne.\n\nMih Aanjahbe doh drövver un en Aanleidong, wi mer och ander Wikis ußer de <i lang=\"en\">Wikimedia Commons</i> doför enreeschte kann, fengk mer em [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos Handbooch].",
"config-cc-error": "Et Ußsöhke övver de <i lang=\"en\">Creative Commons</i> iehr Projramm zum Lizänzbeshtemme hät nix jebraat.\nDonn de Lizänz sellver beshtemme.",
"config-cc-again": "Noch ens neu ußsöhke&nbsp;…",
"config-cc-not-chosen": "Söhk uß, wat för en Lizänz vun de <i lang=\"en\">Creative Commons</i> De han wells, un donn dann op „<i lang=\"en\">proceed</i>“ klecke.",
@@ -303,7 +300,7 @@
"config-install-user-missing": "Dä aanjejovve Metmaacher „$1“ jidd_et nit.",
"config-install-user-missing-create": "{{int:Config-install-user-missing}}<!-- $1 -->\nDonn e Höhksche en et Käßje „{{int:Createaccount}}“ onge, wann De dä aanlääje wells.",
"config-install-tables": "Ben de Daatebangk-Tabälle aam aanlääje.",
- "config-install-tables-exist": "'''Opjepaß''': Et schingk, dem MediaWiki sing Tabälle sin alt doh.\nDoh dom_mer nix aanlääje.",
+ "config-install-tables-exist": "'''Opjepaß''': Et schingk, dem MehdijaWikki sing Tabälle sin alt doh.\nDoh dom_mer nix aanlääje.",
"config-install-tables-failed": "'''Fähler''': De Tabälle kunnte nit aanjelaat wääde, wääje: $1",
"config-install-interwiki": "Ben de Engerwiki-Tabäll met de shtandattmääßejje Daate aam fölle.",
"config-install-interwiki-list": "Mer kunnte de Dattei <code lang=\"en\">interwiki.list</code> nit fenge.",
@@ -320,11 +317,11 @@
"config-install-extension-tables": "Ben Datebangk-Tabälle för de Zohsazprojramme aam ennreschte",
"config-install-mainpage-failed": "Kunnt de Houpsigg nit afshpeishere: $1",
"config-install-done": "'''Jlöckwonsch!'''\nMediaWiki es jetz enstalleet.\n\nEt Projramm zom Enreeschte hät en Dattei <code lang=\"en\">LocalSettings.php</code> aanjelaat.\nDoh sin de Enstellunge vum Wiki dren.\n\nDo weeß se eronge laade möße un dann en dem Wiki sing Aanfangsverzeishnes donn möße, et sellve Verzeisneß, woh di Dattei <code lang=\"en\">index.php</code> dren litt. Dat Erongerlaade sullt automattesch aanjefange han.\n\nWann domet jet nit jeflupp hät, udder De di Dattei norr_ens han wells, donn op dä Lengk heh dronger klecke:\n\n$3\n\n'''Opjepaß''': Wann De dat jez nit deihß, es alles verschött, wat De bes jöz enjejovve häs, weil di Dattei fott es en däm Momang, woh heh dat Projamm aam Engk es.\n\nWann De mem Ronger- un widder Huhlaade fäädesh bes, kanns De '''[$2 en Ding Wiki jonn]'''.",
- "config-download-localsettings": "Donn di Dattei <code lang=\"en\">LocalSettings.php</code> eronger laade",
+ "config-download-localsettings": "Donn di Dattei <code lang=\"en\" xml:lang=\"en\" dir=\"ltr\">LocalSettings.php</code> eronger lahde",
"config-help": "Hölp",
"config-help-tooltip": "Donn Hölp heh aan däm Plaaz enblände.",
"config-nofile": "De Dattei „$1“ ham_mer nit jefonge. Es di fottjeschmeße?",
"config-extension-link": "Häs De jewoß, dat et Wiki [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions Zohsazprojramme] hann kann?\n\nDo kanns [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category Zohsazprojramme noh Saachjroppe] söhke udder en de [//www.mediawiki.org/wiki/Extension_Matrix Tabäll met de Zohsazprojramme] kike, öm de kumplätte Leß met de Zohsazprojramme ze krijje.",
- "mainpagetext": "'''MediaWiki es jäz enschtalleht.'''",
+ "mainpagetext": "'''MehdijaWikki es jäz enschtalleht.'''",
"mainpagedocfooter": "Luur en et (änglesche) [//meta.wikimedia.org/wiki/Help:Contents Handbooch] wann De wesse wells wie de Wiki-Soffwär jebruch un bedeent wääde moß.\n\nLuur en et (änglesche) [//meta.wikimedia.org/wiki/Help:Contents Handbooch] wann De weße wells wi de Wiki-Soffwähr jebruch un bedehnt wääde moß.\n\n== För der Aanfang ==\nDat es och all op Änglesch:\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Configuration settings list]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki release mailing list]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Donn MediaWiki op Ding Schprohch aanpaße]"
}
diff --git a/includes/installer/i18n/ku-latn.json b/includes/installer/i18n/ku-latn.json
index 920d9ae2..9bbb635e 100644
--- a/includes/installer/i18n/ku-latn.json
+++ b/includes/installer/i18n/ku-latn.json
@@ -1,16 +1,62 @@
{
"@metadata": {
"authors": [
- "George Animal"
+ "George Animal",
+ "Ghybu",
+ "Bikarhêner"
]
},
+ "config-desc": "Barkera MediaWikiyê",
+ "config-title": "Barkirina MediaWiki $1",
"config-information": "Agahî",
"config-your-language": "Zimanê te:",
"config-wiki-language": "Zimanê wîkiyê:",
+ "config-back": "← Paş",
+ "config-continue": "Bidomîne →",
"config-page-language": "Ziman",
+ "config-page-welcome": "Bi xêr hatî MediaWikiyê!",
+ "config-page-dbsettings": "Eyarên danegehê",
"config-page-name": "Nav",
"config-page-options": "Vebijêrk",
+ "config-page-install": "Ava bike",
+ "config-page-complete": "Qedîya!",
+ "config-page-restart": "Barkirinê jinûve dest pê bide kirin",
+ "config-page-readme": "Min bixwîne",
+ "config-page-copying": "Kopîkirin",
+ "config-page-upgradedoc": "Bilindkirin",
+ "config-page-existingwiki": "Wîkiya heye",
+ "config-restart": "Erê, jinûve bide destpêkirin",
+ "config-xcache": "[http://xcache.lighttpd.net/ XCache] hate avakirin",
+ "config-apc": "[http://www.php.net/apc APC] hate avakirin",
+ "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] hate avakirin",
+ "config-diff3-bad": "GNU diff3 nehate dîtin.",
+ "config-db-type": "Cureya danegehê:",
+ "config-db-wiki-settings": "Vî wîkîyê bide danasîn",
+ "config-db-name": "Navê danagehê:",
+ "config-db-install-account": "Hesabê bikarhêner bo avakirinê",
+ "config-db-username": "Navê bikarhêner bo danagehê:",
+ "config-db-password": "Şîfreya danegehê:",
+ "config-db-web-account": "Hesabê danegehê bô têgihiştina tora înternetê",
+ "config-mysql-myisam": "MyISAM",
+ "config-mysql-utf8": "UTF-8",
+ "config-site-name": "Navê wîkiyê:",
+ "config-site-name-blank": "Navê malperek têkeve.",
"config-ns-generic": "Proje",
+ "config-ns-other-default": "MyWiki",
+ "config-admin-box": "Hesabê rêveberiyê",
+ "config-admin-name": "Navê bikarhêner:",
+ "config-admin-password": "Şîfre:",
+ "config-admin-password-confirm": "Şîfreyê dîsa binivîse:",
+ "config-admin-email": "Navnîşana e-nameyê:",
+ "config-optional-continue": "Bêhtir pirsan ji min bike.",
+ "config-profile": "Profîla mafên bikarhêner:",
+ "config-profile-wiki": "Wîkiya vekirî",
+ "config-email-settings": "Eyarên e-nameyê",
+ "config-email-usertalk": "Agahdariyên rûpela gotûbêjê ya bikarhêner gengaz bike",
+ "config-upload-settings": "Barkirina wêne û dosyeyan",
+ "config-upload-enable": "Barkirina dosyeyan gengaz bike",
+ "config-logo": "URL'ya logoyêː",
+ "config-cc-again": "Dîsa hilbijêre...",
"config-install-step-done": "çêbû",
"config-help": "alîkarî",
"mainpagetext": "'''MediaWiki serketî hate çêkirin.'''",
diff --git a/includes/installer/i18n/lb.json b/includes/installer/i18n/lb.json
index 2dccc50c..ac54d87f 100644
--- a/includes/installer/i18n/lb.json
+++ b/includes/installer/i18n/lb.json
@@ -37,7 +37,7 @@
"config-page-copying": "Kopéieren",
"config-page-upgradedoc": "Aktualiséieren",
"config-page-existingwiki": "Wiki déi et gëtt",
- "config-help-restart": "Wëllt dir all gespäichert Donnéeë läschen déi dir bis elo aginn hutt an den Installatiounsprozess nei starten?",
+ "config-help-restart": "Wëllt Dir all gespäichert Donnéeë läschen déi Dir bis elo aginn hutt an den Installatiounsprozess nei starten?",
"config-restart": "Jo, neistarten",
"config-welcome": "=== Iwwerpréifung vum Installatiounsenvironnement ===\nEt gi grondsätzlech Iwwerpréifunge gemaach fir ze kucken ob den Environnment gëeegent ass fir MediaWiki z'installéieren.\nDir sollt d'Resultater vun dëser Iwwerpréifung ugi wann Dir während der Installatioun Hëllef frot wéi Dir D'Installatioun ofschléisse kënnt.",
"config-sidebar": "* [//www.mediawiki.org MediaWiki Haaptsäit]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Benotzerguide]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Guide fir Administrateuren]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ FAQ]\n----\n* <doclink href=Readme>Liest dëst</doclink>\n* <doclink href=ReleaseNotes>Informatioune vun der aktueller Versioun</doclink>\n* <doclink href=Copying>Lizenzbedingungen</doclink>\n* <doclink href=UpgradeDoc>Aktualisatioun</doclink>",
@@ -45,7 +45,6 @@
"config-env-bad": "Den Environnement gouf iwwerpréift.\nDir kënnt MediWiki net installéieren.",
"config-env-php": "PHP $1 ass installéiert.",
"config-env-hhvm": "HHVM $1 ass installéiert.",
- "config-unicode-using-utf8": "Fir d'Unicode-Normalisatioun gëtt dem Brion Vibber säin <code>utf8_normalize.so</code> benotzt.",
"config-no-db": "Et konnt kee passenden Datebank-Driver fonnt ginn! Dir musst een Datebank-Driver fir PHP installéieren.\n{{PLURAL:$2|Dësn Datebank-Typ gëtt|Dës Datebank-Type ginn}} ënnerstëtzt: $1.\n\nWann Dir PHP selwer compiléiert hutt, da rekonfiguréiert en mat dem ageschalten Datebank-Client, zum Beispill an deem Dir <code>./configure --with-mysql</code> benotzt.\nWann Dir PHP vun engem Debian oder Ubuntu Package aus installéiert hutt, da musst Dir och den php5-mysql Modul installéieren.",
"config-outdated-sqlite": "'''Warnung:''' SQLite $1 ass installéiert. Allerdengs brauch MediaWiki SQLite $2 oder méi nei. SQLite ass dofir net disponibel.",
"config-memory-bad": "'''Opgepasst:''' De Parameter <code>memory_limit</code> vu PHP ass $1.\nDat ass wahrscheinlech ze niddreg.\nD'Installatioun kéint net funktionéieren.",
diff --git a/includes/installer/i18n/lrc.json b/includes/installer/i18n/lrc.json
index 607fc404..6d93a5c5 100644
--- a/includes/installer/i18n/lrc.json
+++ b/includes/installer/i18n/lrc.json
@@ -8,8 +8,12 @@
"config-information": "دونسمنيا",
"config-your-language": "زون شما:",
"config-wiki-language": "زون ویکی:",
+ "config-back": "← ڤادئما",
+ "config-continue": "نئها گئرئتئن →",
"config-page-language": "زون",
"config-page-welcome": "د ویکی رسانه خوش اومایت!",
+ "config-page-dbconnect": "ڤأصل بییئن د رئسینە جا",
+ "config-page-dbsettings": "میزوٙنکاری رئسینە جا",
"config-page-name": "نوم",
"config-page-options": "گزينه يا هنی:",
"config-page-install": "پورنیئن",
diff --git a/includes/installer/i18n/lv.json b/includes/installer/i18n/lv.json
index eb66bbb6..69bbc835 100644
--- a/includes/installer/i18n/lv.json
+++ b/includes/installer/i18n/lv.json
@@ -2,7 +2,8 @@
"@metadata": {
"authors": [
"GreenZeb",
- "Papuass"
+ "Papuass",
+ "Silraks"
]
},
"config-information": "Informācija",
@@ -23,8 +24,11 @@
"config-page-readme": "Lasīt mani",
"config-page-releasenotes": "Informācija par laidienu",
"config-page-copying": "Kopē",
+ "config-restart": "Jā, restartēt",
"config-env-php": "PHP $1 ir uzstādīts.",
"config-diff3-bad": "GNU diff3 nav atrasts.",
+ "config-db-username": "Datubāzes lietotājvārds:",
+ "config-db-password": "Datubāzes parole:",
"config-db-charset": "Datubāzes rakstzīmju kopa",
"config-charset-mysql5-binary": "MySQL 4.1/5.0 binārs",
"config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
@@ -40,6 +44,15 @@
"config-header-mssql": "Microsoft SQL servera iestatījumi",
"config-mysql-innodb": "InnoDB",
"config-mysql-myisam": "MyISAM",
+ "config-admin-name": "Tavs lietotājvārds:",
+ "config-admin-password": "Parole:",
+ "config-admin-password-confirm": "Parole vēlreiz:",
+ "config-admin-name-blank": "Ievadiet administratora lietotājvārdu.",
+ "config-admin-email": "E-pasta adrese:",
+ "config-cc-again": "Izvēlies vēlreiz...",
+ "config-install-step-done": "Gatavs",
+ "config-help": "palīdzība",
+ "config-help-tooltip": "uzspiediet, lai izvērstu",
"mainpagetext": "'''MediaWiki veiksmīgi ieinstalēts'''",
"mainpagedocfooter": "Izlasi [//meta.wikimedia.org/wiki/Help:Contents Lietotāja pamācību], lai iegūtu vairāk informācijas par Wiki programmatūras lietošanu.\n\n== Pirmie soļi ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Konfigurācijas iespēju saraksts]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki J&A]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Parakstīties uz paziņojumiem par jaunām MediaWiki versijām]"
}
diff --git a/includes/installer/i18n/mai.json b/includes/installer/i18n/mai.json
index 8302c03c..8c6cb8ba 100644
--- a/includes/installer/i18n/mai.json
+++ b/includes/installer/i18n/mai.json
@@ -2,9 +2,11 @@
"@metadata": {
"authors": [
"Umeshberma",
- "बिप्लब आनन्द"
+ "बिप्लब आनन्द",
+ "Bijay chaurasia"
]
},
+ "config-desc": "मेडिया-विकी के लेल इंस्टॉलर",
"config-information": "जानकारी",
"config-your-language": "अहाँक भाषा:",
"config-your-language-help": "प्रतिस्थापन होएतकाल भाषाके चयन करू",
diff --git a/includes/installer/i18n/mg.json b/includes/installer/i18n/mg.json
index 53324c6c..39162336 100644
--- a/includes/installer/i18n/mg.json
+++ b/includes/installer/i18n/mg.json
@@ -19,6 +19,7 @@
"config-page-language": "Fiteny",
"config-page-welcome": "Tonga soa eto amin'i MediaWiki !",
"config-page-dbconnect": "Hiditra eo amin'i banky angona",
+ "config-page-dbsettings": "Parametatry ny banky angona",
"config-page-name": "Anarana",
"config-page-options": "Safidy",
"config-page-install": "Apetraka",
@@ -31,8 +32,19 @@
"config-page-existingwiki": "Wiki efa misy",
"config-help-restart": "Tianao hofafana avokoa ve ny data voaangona natsofokao ary hamerina ny fizotran'ny fametrahana ?",
"config-restart": "Eny, avereno atao",
+ "config-welcome": "=== Fanamarinana mikasika ny tontolo ===\nNy fanamarihana tsotsotra dia atao hijerena raha mety ho ana rindrankajy Mediawiki ny tontolo.\nTadidio ny mametraka ireto torohay ireo raha mitady fanohanana mikasika ny fomba famaranana ny fametrahana ianao.",
+ "config-env-good": "Voamarina ny tontolo.\nAfaka apetrakao i MediaWiki.",
+ "config-env-bad": "Voamarina ny tontolo.\nTsy afaka mametraka an'i MediaWiki ianao.",
+ "config-env-php": "Misy ato PHP $1.",
+ "config-env-hhvm": "Misy ato HHVM $1.",
+ "config-unicode-using-intl": "Mampiasa ny [http://pecl.php.net/intl itatra PECL intl] ho an'ny fampifenerana Unicode.",
+ "config-unicode-pure-php-warning": "<strong>Fampitandremana: </strong> Ny [http://pecl.php.net/intl itatra PECL intl] dia tsy misy mba hahazakana ny fampifenerana Unicode, ka mitontona amin'ny implementasiona PHP ranoray noho ny tsifisiany.\nRaha hametraka tranonkala be mpamangy ianao dia tokony mamaky ny [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations ''Unicode normalization''] (amin'ny teny anglisy)",
"config-db-username": "Anaram-pikamban'ny banky angona :",
"config-db-password": "Tenimiafin'ny banky angona :",
+ "config-charset-mysql5-binary": "roafototra MySQL 4.1/5.0",
+ "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
+ "config-charset-mysql4": "MySQL 4.0 miverinjaka UTF-8",
+ "config-db-port": "Seranam-banky angona:",
"config-header-mysql": "Parametatr'i MySQL",
"config-header-sqlite": "Parametatr'i SQLite",
"config-header-oracle": "Parametatr'i Oracle",
diff --git a/includes/installer/i18n/mk.json b/includes/installer/i18n/mk.json
index 86494844..76bfc042 100644
--- a/includes/installer/i18n/mk.json
+++ b/includes/installer/i18n/mk.json
@@ -60,7 +60,7 @@
"config-magic-quotes-sybase": "'''Кобно: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] е активно!'''\nОваа можност непредвидливо го расипува вносот на податоци.\nОваа можност мора да е исклучена. Во спротивно нема да можете да го воспоставите и користите МедијаВики.",
"config-mbstring": "'''Кобно: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] е активно!'''\nОваа можност предизвикува грешки и може непредвидиво да го расипува вносот на податоци.\nОваа можност мора да е исклучена. Во спротивно нема да можете да го воспоставите и користите МедијаВики.",
"config-safe-mode": "'''Предупредување:''' [http://www.php.net/features.safe-mode безбедниот режим] на PHP е активен.\nОва може да предизвика проблеми, особено ако користите подигања и поддршка за <code>math</code>.",
- "config-xml-bad": "XML-модулот за PHP недостасува.\nМедијаВики има потреба од функции во овој модул и нема да работи со овие поставки.\nАко работите со Mandrake, воспоставете го пакетот php-xml.",
+ "config-xml-bad": "XML-модулот за PHP недостасува.\nМедијаВики има потреба од функции во овој модул и нема да работи со овие поставки.\nМоже да треба да го воспоставите RPM-пакетот „php-xml“.",
"config-pcre-old": "'''Кобно:''' Се бара PCRE $1 или понова верзија.\nВашиот PHP-бинарен е сврзан со PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Повеќе информации].",
"config-pcre-no-utf8": "'''Фатално''': PCRE-модулот на PHP е составен без поддршка за PCRE_UTF8.\nМедијаВики бара поддршка за UTF-8 за да може да работи правилно.",
"config-memory-raised": "<code>memory_limit</code> за PHP изнесува $1, зголемен на $2.",
@@ -89,7 +89,7 @@
"config-suhosin-max-value-length": "Suhosin е воспоставен и ја ограничува должината на параметарот GET на $1 бајти. Делот ResourceLoader на МедијаВики ќе ја заобиколува ова граница, но со тоа ќе се влоши делотворноста. Ако е воопшто можно, на <code>suhosin.get.max_value_length</code> треба да го наместите на 1024 или повеќе во <code>php.ini</code>, и да му ја зададете истата вредност на <code>$wgResourceLoaderMaxQueryLength</code> во <code>LocalSettings.php</code>.",
"config-db-type": "Тип на база:",
"config-db-host": "Домаќин на базата:",
- "config-db-host-help": "Ако вашата база е на друг опслужувач, тогаш тука внесете го името на домаќинот или IP-адресата.\n\nАко користите заедничко (споделено) вдомување, тогаш вашиот вдомител треба да го наведе точното име на домаќинот во неговата документација.\n\nАко воспоставувате на опслужувач на Windows и користите MySQL, можноста „localhost“ може да не функционира за опслужувачкото име. Во тој случај, обидете се со внесување на „127.0.0.1“ како локална IP-адреса.\n\nАко користите PostgreSQL, оставете го полево празно за да се поврзете преку Unix-приклучок.",
+ "config-db-host-help": "Ако вашата база е на друг опслужувач, тогаш тука внесете го името на домаќинот или IP-адресата.\n\nАко користите заедничко (споделено) вдомување, тогаш вашиот вдомител треба да го наведе точното име на домаќинот во неговата документација.\n\nАко воспоставувате на опслужувач на Windows и користите MySQL, можноста „localhost“ може да не функционира за опслужувачкото име. Во тој случај, обидете се со внесување на „127.0.0.1“ како месна IP-адреса.\n\nАко користите PostgreSQL, оставете го полево празно за да се поврзете преку Unix-приклучок.",
"config-db-host-oracle": "TNS на базата:",
"config-db-host-oracle-help": "Внесете важечко [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm месно име за поврзување]. На оваа воспоставка мора да ѝ биде видлива податотеката tnsnames.ora.<br />Ако користите клиентски библиотеки 10g или понови, тогаш можете да го користите и методот на иметнување на [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect].",
"config-db-wiki-settings": "Идентификувај го викиво",
@@ -100,8 +100,6 @@
"config-db-install-account": "Корисничка смета за воспоставка",
"config-db-username": "Корисничко име за базата:",
"config-db-password": "Лозинка за базата:",
- "config-db-password-empty": "Внесете лозинка за новиот корисник на базата: $1.\nИако може да се создаваат корисници без лозинка, тоа не е безбедно.",
- "config-db-username-empty": "Мора да внесете вредност за „{{int:config-db-username}}“.",
"config-db-install-username": "Внесете корисничко име што ќе се користи за поврзување со базата во текот на воспоставката. Ова не е корисничкото име од сметката на МедијаВики, туку посебно корисничко име за вашата база на податоци.",
"config-db-install-password": "Внесете клозинка што ќе се користи за поврзување со базата во текот на воспоставката. Ова не е лозинката од сметката на МедијаВики, туку посебна лозинка за вашата база на податоци.",
"config-db-install-help": "Внесете го корисничкото име и лозинката што ќе се користи за поврзување со базата на податоци во текот на воспоставката.",
diff --git a/includes/installer/i18n/mr.json b/includes/installer/i18n/mr.json
index 632951b7..78683ad8 100644
--- a/includes/installer/i18n/mr.json
+++ b/includes/installer/i18n/mr.json
@@ -1,7 +1,8 @@
{
"@metadata": {
"authors": [
- "V.narsikar"
+ "V.narsikar",
+ "Suyog"
]
},
"config-information": "माहिती",
@@ -11,6 +12,7 @@
"config-your-language": "आपली भाषा:",
"config-your-language-help": "उभारणी प्रक्रियेत वापरावयाची भाषा निवडा.",
"config-wiki-language": "विकी भाषा:",
+ "config-wiki-language-help": "तुमची लेखन भाषा निवडा",
"config-back": "← परत",
"config-continue": "चालू ठेवा →",
"config-page-language": "भाषा",
@@ -23,6 +25,7 @@
"config-page-readme": "हे वाचा",
"config-page-releasenotes": "विमोचन टिप्पण्या",
"config-page-existingwiki": "साध्याचा विकि",
+ "config-restart": "हो, परत चालू करा",
"config-pg-test-error": "विदागाराशी अनुबंधन करता येत नाही <strong>$1</strong>: $2",
"config-type-mssql": "मायक्रोसॉफ्ट एसक्युएल सर्व्हर",
"config-header-mssql": "मायक्रोसॉफ्ट एसक्युएल सर्व्हर मांडणावळ",
diff --git a/includes/installer/i18n/nan.json b/includes/installer/i18n/nan.json
index fbc2bbc1..70addf91 100644
--- a/includes/installer/i18n/nan.json
+++ b/includes/installer/i18n/nan.json
@@ -1,7 +1,8 @@
{
"@metadata": {
"authors": [
- "Ianbu"
+ "Ianbu",
+ "唐吉訶德的侍從"
]
},
"config-desc": "MediaWiki的安裝程式",
@@ -9,8 +10,8 @@
"config-information": "資訊",
"config-localsettings-upgrade": "有一个<code>LocalSettings.php</code>檔案佇咧。若欲升級,請佇下面的框內底拍<code>$wgUpgradeKey</code>的內容。你會使佇<code>LocalSettings.php</code>內底揣著彼項。",
"config-localsettings-cli-upgrade": "有一个<code>LocalSettings.php</code>檔案。若欲升級,請直接執行<code>update.php</code>。",
- "config-localsettings-key": "升級的密碼:",
- "config-localsettings-badkey": "你提供的密碼無正確。",
+ "config-localsettings-key": "Seng-kip--ê bi̍t-bé:",
+ "config-localsettings-badkey": "Lí phah--ê bi̍t-bé bô chèng-khak.",
"config-upgrade-key-missing": "已經有一个MediaWiki矣。若要升級,請共下面這逝加去<code>LocalSettings.php</code>的下跤:\n\n$1",
"config-localsettings-incomplete": "這馬的<code>LocalSettings.php</code>可能無齊全,因為無設變量$1。請佇<code>LocalSettings.php</code>設彼个變量,並且揤「{{int:Config-continue}}」。",
"config-localsettings-connection-error": "An error was encountered when connecting to the database 用<code>LocalSettings.php</code>的設定去連接資料庫的時陣有一个錯誤發生,請改遮的設定了,才閣試。\n\n$1",
@@ -28,7 +29,7 @@
"config-page-dbconnect": "連接去資料庫",
"config-page-upgrade": "共這馬的安裝升級",
"config-page-dbsettings": "資料庫的設定",
- "config-page-name": "名稱",
+ "config-page-name": "Miâ",
"config-page-options": "選項",
"config-page-install": "安裝",
"config-page-complete": "完成",
@@ -46,8 +47,6 @@
"config-env-good": "環境檢查已完成。\n你會當安裝 MediaWiki。",
"config-env-bad": "環境檢查已完成。\n你無法度安裝 MediaWiki。",
"config-env-php": "PHP $1 已經安裝。",
- "config-env-php-toolow": "已經安裝 PHP $1。\n但是 MediaWiki 愛 PHP $2 抑較新的版本。",
- "config-unicode-using-utf8": "用 Brion Vibber 的 utf8_normalize.so 做 Unicode 正規化。",
"config-unicode-using-intl": "用 [http://pecl.php.net/intl intl PECL 擴充套件] 做 Unicode 正規化。",
"config-unicode-pure-php-warning": "<strong>警告:</strong> 無法度用 [http://pecl.php.net/intl intl PECL 擴充套件] 處理 Unicode 正規化,所以退回用純 PHP 實作的正規化程式,這種方式處理速度較慢。\n\n若你的網站瀏覽人數誠濟,你應該先看 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations/zh Unicode 正規化]。",
"config-unicode-update-warning": "<strong>警告</strong>:這馬安裝的 Unicode 正規化包裝程式用舊版 [http://site.icu-project.org/ ICU 計劃] 的程式庫。\n若你需要用 Unicode,你應該先進行 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations 升級]。",
diff --git a/includes/installer/i18n/nap.json b/includes/installer/i18n/nap.json
index 3a43d901..fd0ab3ef 100644
--- a/includes/installer/i18n/nap.json
+++ b/includes/installer/i18n/nap.json
@@ -48,11 +48,10 @@
"config-env-bad": "L'ambiente è stato cuntrullato.\nNun se può installà MediaWiki.",
"config-env-php": "PHP $1 è installato.",
"config-env-hhvm": "HHVM $1 è installato.",
- "config-unicode-using-utf8": "Aúsa Brion Vibber's utf8_normalize.so pe' ne fà 'a normalizzazione Unicode.",
"config-unicode-using-intl": "Aúsa [http://pecl.php.net/intl l'estensione PECL intl] pe' ne fà 'a normalizzazione Unicode.",
"config-unicode-pure-php-warning": "<strong>Attenziò:</strong> L' [http://pecl.php.net/intl estensione intl PECL] nun è a disposizione pe' gestire 'a normalizzazione Unicode, accussì se ausasse n'imprementazziona llenta 'n puro PHP.\nSi state a gestire nu pizzo ad alto traffico, avisseve a lieggere cocche considerazione ncopp' 'a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalizzaziona Unicode].",
"config-unicode-update-warning": "<strong>Attenziò:</strong> 'A verziona installata 'e normalizzazione Unicode aùsa 'a verziona viecchia d' 'o [http://site.icu-project.org/ pruggetto ICU].\nV'avite 'a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations agghiurnà] si state a penzà ncopp' 'o fatto d'ausà Unicode.",
- "config-no-db": "Nun se può truvà nu driver adatto p' 'o database! È necessario installare nu driver p' 'o PHP.\n{{PLURAL:$2|'O furmatto suppurtato|'E furmatte suppurtate}} 'e database ccà annanze: $1.\n\nSi cumpilate PHP autonomamente, riaccunciatevello attivando nu client database, p'esempio ausannoo <code>./configure --with-mysqli</code>.\nQuanno fosse installato PHP pe' bbìa 'e nu pacchetto Debian o Ubuntu, allora avite 'a installà pure 'o pacchetto <code>php5-mysql</code>.",
+ "config-no-db": "Nun se può truvà nu driver adatto p' 'o database! È necessario installare nu driver p' 'o PHP.\n{{PLURAL:$2|'O furmato suppurtato|'E furmate suppurtate}} 'e database ccà annanze: $1.\n\nSi cumpilate PHP autonomamente, riaccunciatevello attivando nu client database, p'esempio ausannoo <code>./configure --with-mysqli</code>.\nQuanno fosse installato PHP pe' bbìa 'e nu pacchetto Debian o Ubuntu, allora avite 'a installà pure 'o pacchetto <code>php5-mysql</code>.",
"config-outdated-sqlite": "'''Attenziò''': tenite 'o SQLite $1 pe' tramente ca ce vulesse 'a verziona $2, SQLite nun sarrà a disposizione.",
"config-no-fts3": "'''Attenziò''': SQLite è cumpilato senza 'o [//sqlite.org/fts3.html modulo FTS3], 'e funziune 'e p'ascià dinto nun sarranno a disposizione ncopp'a stu backend.",
"config-register-globals-error": "<strong>Errore: l'opzione PHP <code>[http://php.net/register_globals register_globals]</code> è apicciata.\nS'avesse 'a stutà pe' cuntinuà c' 'a installazione.</strong>\nVide [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] pe' n'avé n'aiuto ncopp'a comme s'avess'a ffà.",
@@ -61,7 +60,7 @@
"config-magic-quotes-sybase": "<strong>Fatale: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] è attivo!'</strong>\nSt'opzione scassa 'e date 'e na manera scanusciuta.\nNun se può installà o ausà MediaWiki si nun se stuta st'opzione.",
"config-mbstring": "<strong>Fatale: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] è attivo!'</strong>\nSt'opzione scassa 'e date 'e na manera scanusciuta.\nNun se può installà o ausà MediaWiki si nun se stuta st'opzione.",
"config-safe-mode": "<strong>Warning:</strong> PHP's [http://www.php.net/features.safe-mode safe mode] è attivato.\nPutesse fà cocche probblema, specialmente si state ausanno 'a funziona 'e carrecà file e 'o supporto d' ' e funziune <code>math</code>.",
- "config-xml-bad": "'O modulo XML 'e PHP è mancante.\nA MediaWiki servessero 'e funziune prisente dint'a stu modulo e nun faticarrà c' 'a configurazione 'e mò.\nSi se sta eseguenno Mandrake, installare 'o pacco php-xml.",
+ "config-xml-bad": "'O modulo XML 'e PHP è mancante.\nA MediaWiki servessero 'e funziune prisente dint'a stu modulo e nun faticarrà c' 'a configurazione 'e mò.\nSi se sta eseguenno Mandrake, installare 'o pacco php-xml RPM.",
"config-pcre-old": "<strong>Errore fatale:</strong> s'addimanna PCRE $1 o succiessivo.\n'O file vuosto binario PHP è acucchiato c' 'o PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Cchiù nfurmaziune].",
"config-pcre-no-utf8": "<strong>Fatale:</strong> 'E module PCRE d' 'o PHP pare ca se so' compilate senza PCRE_UTF8 supporto.\nA MediaWiki serve nu supporto UTF-8 pe' putè funziunà apposto.",
"config-memory-raised": "'O valore 'e PHP <code>memory_limit</code> è $1, aumentato a $2.",
@@ -101,13 +100,11 @@
"config-db-install-account": "Cunto utente pe' l'installazione",
"config-db-username": "Nomme utente p' 'o database:",
"config-db-password": "Password d' 'o database:",
- "config-db-password-empty": "Avita nzertà na password pe' l'utente nuovo d' 'o database: $1.\nPure si fosse possibbele 'e crià ll'utente senza password chisto nun fosse sicuro.",
- "config-db-username-empty": "Avita miette nu valore p' 'o \"{{int:config-db-username}}\"",
"config-db-install-username": "Nzertate 'o nomme utente ca s'aussarrà pe' ve cullegà ô database pe' tramente ca se fà l'installazione. Chistu nun è 'o nomme utente d' 'o cunto MediaWiki; ma chillo p' 'o database vuosto.",
"config-db-install-password": "Nzertate 'a password che s'ausarrà pe' ve putè cullegà ô database pe' tramente ca se fa l'installazione.\nChista nun è 'a password d' 'o cunto 'e MediaWiki; ma chilla p' 'o database vuosto.",
"config-db-install-help": "Miette 'o nomme utente e 'a password ca sarrà usata quanno ve cullegate ô database pe' tramente ca facite 'a installazione.",
"config-db-account-lock": "Aúsa 'o stisso nomme utente e password pe' l'operazione normale.",
- "config-db-wiki-account": "Account utente p' 'o funzionamento nurmale",
+ "config-db-wiki-account": "Cunto utente p' 'o funzionamento nurmale",
"config-db-wiki-help": "Miette 'o nomme utente e 'a password ca sarrà ausata pe' se cullegà ô database pe' l'operazione normale d' 'o wiki. Si 'o cunto nun esiste, e 'o cunto e installazione téne diritte sufficiente, sarrà criato ch' 'e diritte minime necessarie pe' putè faticà ncopp' 'o wiki.",
"config-db-prefix": "Prefisso d' 'a tavolozza d' 'o database:",
"config-db-prefix-help": "Si tenite abbesuogno 'e spartì nu database nfra cchiù wiki, o nfra MediaWiki e n'at'apprecazione web, putite scegliere d'azzeccà nu prefisso a tutte 'e nomme 'e tabbella, pe putè evità cunflitte.\nNun ausate abbacante.\n\n'O solito, stu campo se lassasse abbacante.",
@@ -130,6 +127,9 @@
"config-support-info": "MediaWiki supporta 'e sisteme 'e database ccà abbascio:\n\n$1\n\nSi nfra chiste ccà nun vedite 'o sistema 'e database ca vulite ausà, allora avite liegge 'e instruziune ccà ncoppa pe' ne dà supporto.",
"config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] è 'a configurazione cchiù mmeglio p' 'o MediaWiki e è chilla meglio suppurtata. MediaWiki può faticà pure cu' [{{int:version-db-mariadb-url}} MariaDB] e [{{int:version-db-percona-url}} Percona Server], ca fossero MySQL cumpatibbele. ([http://www.php.net/manual/en/mysqli.installation.php Comme s'adda fà pe' cumpilà PHP cu suppuorto MySQL])",
"config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] è nu sistema canusciuto 'e database open source ca fosse n'alternativa a MySQL. Putess'avé cocch'errore p'arricettà, e nun è cunzigliato 'e ll'ausà dint'a n'ambiente 'e produziona. ([http://www.php.net/manual/en/pgsql.installation.php Comme s'avess'a cumpilà PHP cu suppuorto PostgreSQL])",
+ "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] è nu sistema 'e database leggero, ca fosse assaje buono suppurtato. ([http://www.php.net/manual/en/pdo.installation.php Comme cumpilà PHP cu suppuorto SQLite], aùsa PDO)",
+ "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] è nu database 'e na fraveca commerciale. ([http://www.php.net/manual/en/oci8.installation.php Comme cumpilà PHP cu suppuorto OCI8])",
+ "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] è nu database 'e na fraveca commerciale p' 'o Windows. ([http://www.php.net/manual/en/sqlsrv.installation.php Comme cumpilà PHP cu suppuorto SQLSRV])",
"config-header-mysql": "Mpustaziune MySQL",
"config-header-postgres": "Mpustaziune PostgreSQL",
"config-header-sqlite": "Mpustaziune SQLite",
@@ -140,13 +140,19 @@
"config-missing-db-host": "Avita miette nu valore p' 'o \"{{int:config-db-host}}\"",
"config-missing-db-server-oracle": "Avita miette nu valore p' 'o \"{{int:config-db-host-oracle}}\"",
"config-invalid-db-server-oracle": "'O database 'e TNS \"$1\" nun è buono.\nAusate 'o \"TNS Name\" o na catena d' \"Easy Connect\"([http://docs.oracle.com/cd/E11882_01/network.112/e10836/naming.htm Metude 'e Nommena Oracle]).",
+ "config-invalid-db-name": "Nomme 'e database \"$1\" nun valido.\nAúsa surtanto carattere ASCII comme lettere (a-z, A-Z), nummere (0-9), sottolineatura (_) e trattine (-).",
+ "config-invalid-db-prefix": "Prefisso database \"$1\" nun valido.\nAúsa surtanto carattere ASCII comme lettere (a-z, A-Z), nummere (0-9), sottolineatura (_) e trattine (-).",
"config-connection-error": "$1.\n\nCuntrullate 'o host, nomme utente e password e tentate n'ata vota.",
"config-invalid-schema": "Schema MediaWiki \"$1\" nun è buono.\nAusate surtanto 'e lettere ASCII (a-z, A-Z), nummere (0-9) e carattere 'e sottolineatura (_).",
"config-db-sys-create-oracle": "'O prugramma 'e installazione supporta surtanto l'uso 'e nu cunto SYSDBA pe' putè crià nu cunto nuovo.",
+ "config-db-sys-user-exists-oracle": "'O cunto utente \"$1\" esiste già. SYSDBA se pò ausà surtanto pe' crià cunte nuove!",
"config-postgres-old": "PostgreSQL $1 o cchiù muderno è necessario. Vuje tenite $2.",
"config-mssql-old": "Microsoft SQL Server $1 o cchiù muderno è necessario. Vuje tenite $2.",
"config-sqlite-name-help": "Sciglite nu nomme ca identificasse 'o wiki vuosto.\nNun ausà spazie o trattine.\nChesto serverrà pe' putè miettere 'o nomme ro file 'e date SQLite.",
"config-sqlite-parent-unwritable-group": "Nun se pò crià 'a cartella 'e date <code><nowiki>$1</nowiki></code>, pecché 'a cartella supiriore <code><nowiki>$2</nowiki></code> nun se pò scrivere 'a 'o webserver.\n\n'O prugramma d'installazione ha determinato l'utente c' 'o quale 'o server web se stà a esecutà.\nDàte 'a pussibbelità 'e scrivere dint' 'a cartella <code><nowiki>$3</nowiki></code> pe' cuntinuà\nNcopp'a nu sistema Unix/Linux:\n\n<pre>cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3</pre>",
+ "config-sqlite-parent-unwritable-nogroup": "Nun se può crià na cartella 'e date <code><nowiki>$1</nowiki></code>, pecché 'a cartella patre <code><nowiki>$2</nowiki></code> nun è scrivibbele p' 'o server web.\n\n'O prugramma 'e installazione nun ave pututo determinà l'utente c' 'o quale se stà ausanno 'o server web.\nFacite 'a cartella <code><nowiki>$3</nowiki></code> screvibbele globbalmente pe chisto (e ll'ati!) pe' putè cuntinuà:\nDint'a nu sistema Unix/Linux facite:\n\n<pre>cd $2\nmkdir $3\nchmod a+w $3</pre>",
+ "config-sqlite-mkdir-error": "Errore pe' tramente ca se faceva 'a criazione d' 'o directory date \"$1\".\nCuntrullate 'a posizione e pruvate n'ata vota.",
+ "config-sqlite-dir-unwritable": "Nun se pò scrivere dint' 'a directory \"$1\".\nCagnate ll'autorizzaziune 'n modo ca 'o webserver pozza scrivere ncoppa e pruvate n'ata vota.",
"config-sqlite-connection-error": "$1.\n\nCuntrullate 'a cartella 'e date e 'o nomme d' 'o database ccà abbascio e pruvate n'ata vota.",
"config-sqlite-readonly": "'O file <code>$1</code> nun è scrivibbele.",
"config-sqlite-cant-create-db": "Nun se può crià 'o file database <code>$1</code>.",
@@ -157,7 +163,7 @@
"config-regenerate": "Rigennera LocalSettings.php →",
"config-show-table-status": "'A query <code>SHOW TABLE STATUS</code> è fallita!",
"config-unknown-collation": "<strong>Attenziò:</strong> 'O database sta ausanno reule 'e cunfronto nun ricanusciute.",
- "config-db-web-account": "Account d' 'o database pe' ne fà acciesso web",
+ "config-db-web-account": "Cunto d' 'o database pe' ne fà acciesso web",
"config-db-web-help": "Scigliete 'o nomme utente e passwrod ca 'o web server ausarrà pe' se cullegà 'o server database, pe' tramente ca se fa' operazione normale d' 'o wiki.",
"config-db-web-account-same": "Aúsa 'o stisso cunto comme quanno s'è fatta 'a installazione",
"config-db-web-create": "Crìa 'o cunto si nun esiste ancora",
@@ -165,9 +171,13 @@
"config-mysql-engine": "Mutore d'astipo:",
"config-mysql-innodb": "InnoDB",
"config-mysql-myisam": "MyISAM",
+ "config-mysql-myisam-dep": "<strong>Attenziò:</strong> avite scigliuto MyISAM comm' 'o mutore 'archiviaziona MySQL, ca nun è raccummannato pe' l'ausà cu MediaWiki, pecché:\n* supporta debolmente 'a concorrenza p' 'o blocco d' 'a tabbella\n* è cchiù inchine 'a corruzione 'e l'ati mutore\n* 'o codece 'e base 'e MediaWiki nun gestisce sempe MyISAM comme l'avess'a gistiunà\n\nSi ll'installazione vosta MySQL suppuorta InnoDB, è autamente raccummandato ca si scigliesse a 'o posto suo.\nSi 'a installazione MySQL nun suppurtasse InnoDB, forse è 'o mumento 'e ll'agghiurnà.",
+ "config-mysql-only-myisam-dep": "<strong>Attenziò:</strong> MyISAM è l'uneco mutore p'astipà date ca se trova mo' a disposizione p' 'o MySQL dint'a sta macchina, e nun fosse raccumandato 'e s'ausà cu MediaWiki, pecché:\n* suppurtasse minimamente concorrenza pe' bbìa 'e bluccà tabbelle\n* è cchiù facile ca jesse a se scassà cchiù 'e l'ati mutore\n* 'o codece MediaWiki nun maniasse sempe MyISAM comme l'avesse 'e manià\n\nL'installazione MySQL nun suppurtasse InnoDB, può darse ca chist'è 'o mumento pe' ve ll'agghiurnà.",
+ "config-mysql-engine-help": "<strong>InnoDB</strong> è quase sempe 'a meglia opzione, pecché ave nu buono suppuorto concorrente.\n\n<strong>MyISAM</strong> putesse ghì cchiù ampressa int'a na installazione mono-utente e liegge-surtanto.\n'E database MyISAM se scassano cchiù spisso d' 'e database InnoDB.",
"config-mysql-charset": "Nzieme 'e carattere d' 'o database:",
"config-mysql-binary": "Binario",
"config-mysql-utf8": "UTF-8",
+ "config-mysql-charset-help": "Int'a <strong>modalità binaria</strong>, MediaWiki archiviasse 'o testo UTF-8 dint' 'o database a campe binarie.\nChest'è cchiù efficiente rispetto 'a modalità UTF-8 'e MySQL, e ve cunzente d'ausà 'a gamma cumpreta 'e carattere Unicode.\n\nInt'a <strong>modalità UTF-8</strong>, MySQL canoscesse dint'a quale set 'e carattere ce stanno 'e date vuoste, e putesse presentà e scagnà sti date int'a nu modo appropriato, ma nun ve premmettesse 'e dà memoria a 'e carattere ncopp' 'o [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes Piano base Multilengua].",
"config-mssql-auth": "Tipo d'autenticazione:",
"config-mssql-install-auth": "Sceglie 'o tipo d'autenticazziona ca s'ausarrà pe cunnettà â database, durante ll'operazziona d'istallazziona. Si piglie \"{{int:config-mssql-windowsauth}}\", 'e credenziale 'e qualunque fosse ll'utenza ca 'o webserver sta pruciessanno sarranno ausate.",
"config-mssql-web-auth": "Sceglie 'o tipo d'autenticazziona ca 'o web server pigliarrà pe se cunnettà a 'o server 'e bbase 'e dati, durante ll'operazziona nurmale d' 'a wiki.\nSi piglie \"{{int:config-mssql-windowsauth}}\", 'e credenziale 'e qualunque fosse ll'utenza ca 'o webserver sta pruciessanno sarranno ausate.",
@@ -181,6 +191,7 @@
"config-ns-site-name": "'O stesso ch' 'o nomme d' 'o wiki: $1",
"config-ns-other": "Ati (specificà)",
"config-ns-other-default": "MyWiki",
+ "config-project-namespace-help": "Secutanno l'esempio 'e Wikipedia, tante wiki teneno 'e paggene lloro ch' 'e regole spartute d' 'e paggene 'e cuntenute, dint'a nu \"'''namespace 'e pruggetto'''\". Tuttuquante 'e titule d' 'e paggene dint'a stu namespace accummenciano cu nu certo prefisso ca se putesse nzegnà ccà.\n'O solito, stu prefisso vene d' 'o nomme d' 'o wiki, ma nun adda cuntenè carattere 'e punteggiatura comme fossero \"#\" o \":\".",
"config-ns-invalid": "'O namespace specificato \"<nowiki>$1</nowiki>\" nun è buono.\nSpecificate nu namespace 'e pruggetto differente.",
"config-ns-conflict": "'O namespace innecato \"<nowiki>$1</nowiki>\" tràse ncunflitto cu nu namespace predefinito 'e MediaWiki.\nSpecifiate n'atu nomme divierzo 'e namespace 'e pruggetto.",
"config-admin-box": "Cunto ammenistratore",
@@ -191,18 +202,91 @@
"config-admin-name-blank": "Mettite nu nomme utente p' 'ammenistratore.",
"config-admin-name-invalid": "'O namespace specificato \"<nowiki>$1</nowiki>\" nun è buono.\nSpecificate nu namespace differente.",
"config-admin-password-blank": "Miette na password p' 'o cunto d'ammenistratore.",
+ "config-admin-password-mismatch": "'E dduje password c'avite miso nun songhe eguale.",
"config-admin-email": "Indirizzo e-mail:",
+ "config-admin-email-help": "Azzecate ccà nu nderizzo e-mail pe' pute ricevere 'e mmasciate mail 'a ll'at'utente d' 'o wiki, mpustà n'ata vota 'a password vuosta, e ve nfurmà d' 'e cagnamiente fatte a 'e paggene dint'a ll'elenco 'e paggene cuntrullate. Putite lassà stu campo abbacante.",
+ "config-admin-error-user": "Errore interno quanno se steva a crià n'ammenistratore c' 'o nomme \"<nowiki>$1</nowiki>\".",
+ "config-admin-error-password": "Errore interno quanno se steva a mpustà na password pe ll'ammenistratore \"<nowiki>$1</nowiki>\": <pre>$2</pre>",
"config-admin-error-bademail": "Avite miso n'indirizzo e-mail invalido.",
+ "config-subscribe": "Mettiteve dint' 'a [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce mailing list 'e ll'annunciazione 'e verziune d' 'o software rilassate].",
+ "config-subscribe-help": "Chest'è na mailing list a basso traffeco ca se dedicasse a se ffà annunzie 'e verziune nove, piglianno pure mpurtante nutarelle ca riguardassero 'a sicurezza.\nFosse cunzigliato 'e se nzegnà e s'agghiurnà l'installazione 'e MediaWiki quanno na verziona nova fosse pubbreca.",
+ "config-subscribe-noemail": "Vuje avite tentato 'e ve trasì dint' 'a mailing list addedecata a se fà annunzie ncopp' 'e verziune nove senza ve dà n'indirizzo email.\nNzertanno n'indirizzo email se vulite affettuà l'iscrizione dint'a mailing list.",
+ "config-almost-done": "Avite quase fernuto!\nMo' putite zumpà 'a parta r' 'a configurazione e sempricemente installà 'a wiki.",
"config-optional-continue": "Spiate cchiù dimanne.",
+ "config-optional-skip": "Me so' scucciato già, installa surtanto 'o wiki.",
"config-profile": "Profilo 'e deritte utente:",
"config-profile-wiki": "Wiki araputo",
"config-profile-no-anon": "Cunto utente obbligatorio",
"config-profile-fishbowl": "Surtanto ll'editure premmesse",
"config-profile-private": "Wiki privato",
+ "config-profile-help": "'E wiki funzionano meglio si se lassa ca tante perzone 'e putessero cagnà.\nInt'a MediaWiki, è semprice cuntrullà sti cagnamiente cchiù ricente, e arrepiglià 'e danne causate d' 'e prove o male ntenziune.\n\nAncora, nu cuofeno 'utente hanno truvato ca MediaWiki fosse utile int'a tante ruole, e cocche vota nun è facile 'e cunvencere tuttuquante ncopp' 'e vantagge d' 'a modalità wiki. Picciò facite 'a scelta vosta. Sciglite vuje.\n\n'O mudello <strong>{{int:config-profile-wiki}}</strong> cunzente a chiunque 'e cagnà, pure senza trasì.\nNu wiki cu <strong>{{int:config-profile-no-anon}}</strong> uffrisse na responsabilità maggiore, ma putesse scuraggià cocche cuntribbutore occasionale.\n\n'O scenario <strong>{{int:config-profile-fishbowl}}</strong> cunzente l'utente autorizzate 'e cagnà, ma 'o pubbreco putesse vedé 'e paggene vedenno pure tutta quanta 'a cronologgia.\nNu <strong>{{int:config-profile-private}}</strong> cunzente ll'utente autorizzate surtanto 'e se vedé 'e paggene, 'o stesso gruppo 'e putesse cagnà.\n\nMpustaziune 'e deritte utente cchiù cumplesse songo a disposizione aropp'a l'installazione, vedite 'a [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights parte relativa d' 'o manuale].",
+ "config-license": "Copyright e licienza:",
+ "config-license-none": "Nisciuno piede 'e paggena p' 'a licienza",
+ "config-license-cc-by-sa": "Creative Commons Attribuziona-SparteEguale",
+ "config-license-cc-by": "Creative Commons Attribuziona",
+ "config-license-cc-by-nc-sa": "Creative Commons Attribuziona-NunCommerciale-SparteEguale",
+ "config-license-cc-0": "Creative Commons Zero (Pubbreco dumminio)",
+ "config-license-gfdl": "GNU Free Documentation License 1.3 o verziune aroppo",
"config-license-pd": "Pubbreco duminio",
+ "config-license-cc-choose": "Sciglite na licienza Creative Commons ca vulite",
+ "config-license-help": "Nu cuofeno 'e wiki pubbrece lassano 'e cuntribbute lloro cu na [http://freedomdefined.org/Definition licienza libbera]. Chesto aiutasse a crià nu senso 'e pruprietà spartuta dint'a communità e ncuraggiasse a cuntribbuiì a nu tèrmene luongo. Nun è generalmente necessario pe' nu wiki privato o aziendale.\n\nSi vulite ausà testi 'a Wikipedia, o vulite ca Wikipedia se pozza miette 'n grado d'accettà teste cupiate d' 'o wiki vuosto, avissev'a scegiere <strong>{{int:config-license-cc-by-sa}}</strong>.\n\nApprimma Wikipedia aveva ausato 'a GNU Free Documentation License. 'A GFDL è una licienza valida, ma è di difficile comprensiona e complica 'o riutilizzo 'e cuntenute.",
+ "config-email-settings": "Mpustaziune email",
+ "config-enable-email": "Premmette mmasciate elettroniche r'asciuta",
+ "config-email-user": "Premmette email utente-utente",
+ "config-email-user-help": "Cunzente a ll'utente 'e mannà uno a ll'ato le mail si 'e teneno appicciate dint' 'e preferenze lloro.",
+ "config-email-usertalk": "Premmette notifiche p' 'e paggene 'e chiacchiera utente",
+ "config-email-usertalk-help": "Premmette ll'utente 'e ricevere notifiche p' 'e cagnamiente r' 'e paggene 'e chiacchiera lloro, si l'avessero appicciato dint' 'e preferenze lloro.",
+ "config-email-watchlist": "Appiccia notifica 'osservati speciale",
+ "config-email-auth": "Appiccia autenticaziona via email",
+ "config-email-sender": "Innerizo email e ritorno:",
+ "config-upload-settings": "Immaggene e upload",
+ "config-upload-enable": "Premmette 'a carreca 'e file",
+ "config-upload-deleted": "Cartella p' 'e file scancellate:",
+ "config-upload-deleted-help": "Sciglite na cartella addò s'astipassero 'e file scancellate.\nIdealmente a sta cartella nun s'avess'a trasì r' 'a web",
"config-logo": "URL d\"o logo:",
- "config-cc-again": "Selezziona 'e novo...",
+ "config-instantcommons": "Appiccia Instant Commons",
+ "config-cc-error": "'O selettore 'e licienze Creative Commons nun mmustaje nisciuno risultato.\nNzertate manualmente 'o nomme d' 'a licienza.",
+ "config-cc-again": "Selezziona n'ata vota...",
+ "config-cc-not-chosen": "Sciglite quale licienza Creative Commons desiderate e cliccate ncopp' 'a \"prucede\".",
+ "config-advanced-settings": "Configurazione avanzata",
+ "config-cache-options": "Mpustaziune p' 'a cache d'oggette:",
+ "config-cache-none": "Nisciuna memorizzazione n cache (nisciuna funziunalità è luvata, ma 'a velocità se putesse ffà a meno dint' 'e wiki cchiù gruosse)",
+ "config-cache-accel": "Mettere 'n cache oggette PHP (APC, XCache o WinCache)",
+ "config-cache-memcached": "Aúsa 'o Memcached (richiede cchiù mpustaziune 'installazione e configuraziona)",
+ "config-memcached-servers": "Server memcached:",
+ "config-memcached-help": "Elenco 'e ll'indirizzi IP p' 'e putè ausà p' 'o Memcached.\nS'avess'a specificà uno pe' riga e scrivere 'a porta 'e trasuta. P'esempio:\n 127.0.0.1:11211\n 192.168.1.25:1234",
+ "config-memcache-needservers": "È stato scigliuto 'o tipo 'e caching Memcached, ma nun è stato mpustato 'a nisciunu server.",
+ "config-memcache-badip": "È stat'azzeccato nu indirizzo IP nun valido p' 'o Memcached: $1.",
+ "config-memcache-noport": "Nun avite specificato na porta p'ausà 'o server Memcached: $1. Si nun sapite 'a porta, chill' 'e default è 11211.",
+ "config-memcache-badport": "'E nummere 'e porta 'e Memcached avesser'a stà nfra $1 e $2.",
+ "config-extensions": "Estenziune",
+ "config-extensions-help": "L'estensiune elencate ncoppa so' state rilevate dint' 'a cartella vosta <code>./extensions</code>.\n\nChiste putessero richiedere nu poco 'e cchiù 'e mpustaziona, ma se putessero appiccià mo'",
+ "config-skins": "Skin",
+ "config-skins-help": "'E skin elencate ncoppa so' state rilevate dint' 'a cartella vosta <code>./skins</code>. Avit'appiccià minimo una e ne scegliere chilla predefinita.",
+ "config-skins-use-as-default": "Aùsa sta skin comme predefinita",
+ "config-skins-missing": "Nisciuna skin s'è truvata, MediaWiki ausasse na soluzione 'e ripiego nfin'a quanno nun sarrà installata una buona.",
+ "config-skins-must-enable-some": "Avit'a scegliere minimo na skin p' 'a puté appiccià.",
+ "config-skins-must-enable-default": "'A skin scigliuta comme predefinita s'avess'appiccià.",
"config-install-step-done": "fatto",
+ "config-install-step-failed": "fallito",
+ "config-install-extensions": "Ncludenno 'estenziune",
+ "config-install-database": "Configurazione database",
+ "config-install-schema": "Crianno schema",
+ "config-install-pg-schema-not-exist": "'O schema PostgreSQL nun esiste.",
+ "config-install-pg-commit": "Mannann' 'e cagnamiente",
+ "config-install-pg-plpgsql": "Cuntrollo p' 'o lenguaggio PL/pgSQL",
+ "config-install-user": "Crianno utente 'e database",
+ "config-install-stats": "Inizializzaziona d' 'e statistiche",
+ "config-install-keys": "Generaziona d' 'e chiave segrete",
"config-install-updates": "Mpiccià ll'agghiurnamiente ca nun fossero necessarie",
- "config-help": "ajùto"
+ "config-install-sysop": "Crianno nu cunto utente ammenistratore",
+ "config-install-subscribe-fail": "Nun se pò sottoscrivere mediawiki-announce: $1",
+ "config-install-mainpage": "Crianno 'a paggena prencepale ch' 'e cuntenute predefinite",
+ "config-install-extension-tables": "Crianno tabelle pe' estenziune appicciate",
+ "config-install-mainpage-failed": "Nun se pò nzertà 'a paggena prencepale: $1",
+ "config-download-localsettings": "Scarreca <code>LocalSettings.php</code>",
+ "config-help": "ajùto",
+ "config-help-tooltip": "cliccà pe' 'o spannere",
+ "config-nofile": "'O file \"$1\" nun se trova. Forse è stato scancellato?",
+ "mainpagetext": "<strong>MediaWiki è stato nstallato.</strong>"
}
diff --git a/includes/installer/i18n/nb.json b/includes/installer/i18n/nb.json
index 26772e98..c658c5c3 100644
--- a/includes/installer/i18n/nb.json
+++ b/includes/installer/i18n/nb.json
@@ -51,7 +51,6 @@
"config-env-bad": "Miljøet har blitt sjekket.\nDu kan installere MediaWiki.",
"config-env-php": "PHP $1 er innstallert.",
"config-env-hhvm": "HHVM $1 er installert.",
- "config-unicode-using-utf8": "Bruker Brion Vibbers utf8_normalize.so for Unicode-normalisering.",
"config-unicode-using-intl": "Bruker [http://pecl.php.net/intl intl PECL-utvidelsen] for Unicode-normalisering.",
"config-unicode-pure-php-warning": "'''Advarsel''': [http://pecl.php.net/intl intl PECL-utvidelsen] er ikke tilgjengelig for å håndtere Unicode-normaliseringen, faller tilbake til en langsommere ren-PHP-implementasjon.\nOm du kjører et nettsted med høy trafikk bør du lese litt om [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-normalisering].",
"config-unicode-update-warning": "'''Advarsel''': Den installerte versjonen av Unicode-normalisereren bruker en eldre versjon av [http://site.icu-project.org/ ICU-prosjektets] bibliotek.\nDu bør [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations oppgradere] om du er bekymret for å bruke Unicode.",
diff --git a/includes/installer/i18n/ne.json b/includes/installer/i18n/ne.json
index b3d40d22..f602ffe7 100644
--- a/includes/installer/i18n/ne.json
+++ b/includes/installer/i18n/ne.json
@@ -5,9 +5,12 @@
"RajeshPandey",
"सरोज कुमार ढकाल",
"Ganesh Paudel",
- "बिप्लब आनन्द"
+ "बिप्लब आनन्द",
+ "Nirjal stha"
]
},
+ "config-desc": "मेडियाविकिको लागि स्थापक",
+ "config-title": "मेडिया विकि $1 स्थापना",
"config-information": "जानकारी",
"config-localsettings-badkey": "तपाइले दिनु भएको कुन्जी गलत छ ।",
"config-your-language": "तपाईंको भाषा:",
@@ -18,6 +21,7 @@
"config-page-language": "भाषा",
"config-page-welcome": "मिडीयाविकिमा तपाईंलाई स्वागत छ!",
"config-page-dbconnect": "डेटाबेससँग सम्बन्ध बनाउने",
+ "config-page-dbsettings": "डेटावेस सेटिङ",
"config-page-name": "नाम",
"config-page-options": "विकल्पहरु",
"config-page-install": "स्थापना गर्ने",
@@ -25,6 +29,55 @@
"config-page-restart": "स्थापना फेरि सुरु गर्ने",
"config-page-readme": "पढ्नुहोस्",
"config-page-releasenotes": "प्रकाशन टिप्पणी",
+ "config-page-copying": "कपि हुदै",
+ "config-page-upgradedoc": "अद्यावधिक गरिदै",
+ "config-page-existingwiki": "विकि बन्द हुदै",
+ "config-restart": "हुन्छ, पुनः सुचारू गर्ने",
+ "config-env-php": "PHP $1 स्थापना गरिएको छ ।",
+ "config-env-hhvm": "HHVM $1 स्थापना गरिएको छ ।",
+ "config-db-type": "डाटाबेस प्रकारः",
+ "config-db-host": "डेटाबेस होस्ट:",
+ "config-db-host-oracle": "डेटाबेस TNS:",
+ "config-db-name": "डाटाबेस नामः",
+ "config-db-name-oracle": "डेटाबेस स्केमा:",
+ "config-db-username": "डाटाबेस प्रयोगकर्ता नामः",
+ "config-db-password": "डाटाबेस पासबर्डः",
+ "config-db-port": "डेटाबेस पोर्ट:",
+ "config-header-mysql": "MySQL सेटिङ",
+ "config-header-postgres": "PostgreSQL सेटिङहरू",
+ "config-header-sqlite": "SQLite सेटिङ्हरू",
+ "config-header-oracle": "ओरेकल सेटिङहरू",
+ "config-mysql-binary": "बाइनरी",
+ "config-mysql-utf8": "UTF-8",
+ "config-site-name": "विकीको नाम:",
+ "config-site-name-blank": "साइटको नाम लेख्नुहोस।",
+ "config-project-namespace": "आयोजना नेमस्पेस:",
+ "config-ns-generic": "परियोजना",
+ "config-ns-other": "अन्य(खुलाउनुहोस)",
+ "config-ns-other-default": "MyWiki",
+ "config-admin-box": "प्रवन्धक खाता",
+ "config-admin-name": "तपाईँको प्रयोगकर्ता नाम:",
+ "config-admin-password": "पासवर्ड:",
+ "config-admin-email": "इमेल ठेगाना:",
+ "config-optional-continue": "मलाई थप प्रश्नहरू सोध्नुहोस् ।",
+ "config-profile": "प्रयोगकर्ता अधिकार प्रोफाइल:",
+ "config-profile-wiki": "खुल्ला विकि",
+ "config-profile-no-anon": "खाता बनाउन नै पर्ने",
+ "config-profile-fishbowl": "अधिकार प्राप्त प्रयोगकर्ताहरू मात्र",
+ "config-profile-private": "निजी विकि",
+ "config-license": "प्रतिलिपी अधिकार र इजाजतपत्र:",
+ "config-license-none": "इजाजतपत्र फूटर नभएको",
+ "config-license-cc-by-sa": "क्रियटिभ कमन्स एट्रिव्युसन- सेयर अलाइक",
+ "config-license-cc-by": "क्रियटिभ कमन्स एट्रिव्युसन",
+ "config-email-settings": "इमेल सेटिंग",
+ "config-extensions": "एक्सटेन्सनहरू",
+ "config-skins": "स्किनहरू",
+ "config-install-step-done": "सम्पन्न",
+ "config-install-step-failed": "असफल",
+ "config-install-tables": "टेबल बनाउदै",
+ "config-install-stats": "तथ्यांक सुचारू हुदै",
+ "config-install-keys": "गोप्य चाबी उत्पन्न गर्दै",
+ "config-install-sysop": "प्रबन्धकको प्रयोगकर्ता खाता बनाउदै",
"config-help": "सहायता",
"config-help-tooltip": "विस्तार गर्न क्लीक गर्नुहोस्",
"mainpagetext": "'''मीडिया सफलतापूर्वक कम्प्यूटरमा स्थापित भयो ।'''",
diff --git a/includes/installer/i18n/nl.json b/includes/installer/i18n/nl.json
index d7bd9a67..1fd98ff5 100644
--- a/includes/installer/i18n/nl.json
+++ b/includes/installer/i18n/nl.json
@@ -13,7 +13,8 @@
"Southparkfan",
"Seb35",
"Mar(c)",
- "Sjoerddebruin"
+ "Sjoerddebruin",
+ "Esketti"
]
},
"config-desc": "Het installatieprogramma voor MediaWiki",
@@ -59,7 +60,6 @@
"config-env-bad": "De omgeving is gecontroleerd.\nU kunt MediaWiki niet installeren.",
"config-env-php": "PHP $1 is op dit moment geïnstalleerd.",
"config-env-hhvm": "HHVM $1 is geïnstalleerd.",
- "config-unicode-using-utf8": "Voor Unicode-normalisatie wordt utf8_normalize.so van Brion Vibber gebruikt.",
"config-unicode-using-intl": "Voor Unicode-normalisatie wordt de [http://pecl.php.net/intl PECL-extensie intl] gebruikt.",
"config-unicode-pure-php-warning": "'''Waarschuwing''': de [http://pecl.php.net/intl PECL-extensie intl] is niet beschikbaar om de Unicodenormalisatie af te handelen en daarom wordt de langzame PHP-implementatie gebruikt.\nAls u MediaWiki voor een website met veel verkeer installeert, lees u dan in over [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicodenormalisatie].",
"config-unicode-update-warning": "'''Waarschuwing''': de geïnstalleerde versie van de Unicodenormalisatiewrapper maakt gebruik van een oudere versie van [http://site.icu-project.org/ de bibliotheek van het ICU-project].\nU moet [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations bijwerken] als Unicode voor u van belang is.",
@@ -72,7 +72,7 @@
"config-magic-quotes-sybase": "'''Onherstelbare fout: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_sybase] is actief!'''\nDeze instelling zorgt voor onvoorspelbare gegevenscorruptie.\nU kunt MediaWiki niet installeren tenzij deze instelling is uitgeschakeld.",
"config-mbstring": "'''Onherstelbare fout: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] is actief!'''\nDeze instelling zorgt voor onvoorspelbare gegevenscorruptie.\nU kunt MediaWiki niet installeren tenzij deze instelling is uitgeschakeld.",
"config-safe-mode": "'''Waarschuwing:'''\n'''PHP's [http://www.php.net/features.safe-mode veilige modus] is actief.'''\nDit kan problemen veroorzaken, vooral bij het uploaden van bestanden en ondersteuning van <code>math</code>.",
- "config-xml-bad": "De XML-module van PHP ontbreekt.\nMediaWiki heeft de functies van deze module nodig en werkt niet zonder deze module.\nAls u gebruik maakt van Mandrake, installeer dan het package php-xml.",
+ "config-xml-bad": "PHP-XML-module ontbreekt.\nMediaWiki is vereist functies in deze module en zal niet werken in deze configuratie.\nMoet u de php-xml-RPM pakket.",
"config-pcre-old": "'''Onherstelbare fout:''' PCRE $1 of een latere versie is vereist.\nUw uitvoerbare versie van PHP is gekoppeld met PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Meer informatie].",
"config-pcre-no-utf8": "'''Fataal:''' de module PRCE van PHP lijkt te zijn gecompileerd zonder ondersteuning voor PCRE_UTF8.\nMediaWiki heeft ondersteuning voor UTF-8 nodig om correct te kunnen werken.",
"config-memory-raised": "PHP's <code>memory_limit</code> is $1 en is verhoogd tot $2.",
diff --git a/includes/installer/i18n/nn.json b/includes/installer/i18n/nn.json
index 5d75be70..06c14690 100644
--- a/includes/installer/i18n/nn.json
+++ b/includes/installer/i18n/nn.json
@@ -2,7 +2,8 @@
"@metadata": {
"authors": [
"Harald Khan",
- "Nghtwlkr"
+ "Nghtwlkr",
+ "Njardarlogar"
]
},
"config-your-language": "Språket ditt:",
@@ -36,6 +37,7 @@
"config-postgres-old": "PostgreSQL $1 eller seinare krevst, du har $2.",
"config-email-settings": "E-postinnstillingar",
"config-logo": "Logo-URL:",
+ "config-help": "hjelp",
"mainpagetext": "'''MediaWiki er no installert.'''",
"mainpagedocfooter": "Sjå [//meta.wikimedia.org/wiki/Help:Contents brukarmanualen] for informasjon om bruk og oppsettshjelp for wikiprogramvara.\n\n==Kome i gang==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Liste over oppsettsinnstillingar]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Spørsmål og svar om MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce E-postliste med informasjon om nye MediaWiki-versjonar]"
}
diff --git a/includes/installer/i18n/olo.json b/includes/installer/i18n/olo.json
new file mode 100644
index 00000000..9f8743cc
--- /dev/null
+++ b/includes/installer/i18n/olo.json
@@ -0,0 +1,59 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mashoi7"
+ ]
+ },
+ "config-your-language": "Sinun kieli:",
+ "config-wiki-language": "Wikin kieli:",
+ "config-back": "← Järilleh",
+ "config-continue": "Jatka →",
+ "config-page-language": "Kieli",
+ "config-page-welcome": "Tule terveh MediaWikih!",
+ "config-page-dbconnect": "Yhtistä tiedokandah",
+ "config-page-dbsettings": "Tiedokanduazetukset",
+ "config-page-name": "Nimi",
+ "config-page-options": "Azetukset",
+ "config-page-install": "Azenda",
+ "config-page-complete": "Valmis!",
+ "config-page-readme": "Luve minut",
+ "config-page-copying": "Kopiruitah",
+ "config-page-upgradedoc": "Päivitetäh",
+ "config-page-existingwiki": "Olemasolii wiki",
+ "config-restart": "Muga, käynnistä uvvelleh",
+ "config-env-php": "PHP $1 on azendettu.",
+ "config-env-hhvm": "HHVM $1 on azendettu.",
+ "config-db-name": "Tiedokannan nimi:",
+ "config-db-username": "Tiedokannan käyttäinimi:",
+ "config-db-password": "Tiedokannan peittosana:",
+ "config-type-mssql": "Microsoft SQL Server",
+ "config-header-mysql": "MySQL-azetukset",
+ "config-header-postgres": "PostgreSQL-azetukset",
+ "config-header-sqlite": "SQLite-azetukset",
+ "config-header-oracle": "Oracle-azetukset",
+ "config-header-mssql": "Microsoft SQL Server azetukset",
+ "config-mysql-innodb": "InnoDB",
+ "config-mysql-myisam": "MyISAM",
+ "config-mysql-utf8": "UTF-8",
+ "config-site-name": "Wikin nimi:",
+ "config-site-name-blank": "Kirjuta sivun nimi.",
+ "config-project-namespace": "Projektan nimitila:",
+ "config-ns-generic": "Projektu",
+ "config-ns-other-default": "MinunWiki",
+ "config-admin-name": "Sinun käyttäitunnus:",
+ "config-admin-password": "Peittosana:",
+ "config-admin-password-confirm": "Peittosana myös:",
+ "config-admin-name-blank": "Kirjuta administruattoran käyttäinimi.",
+ "config-admin-password-blank": "Kirjuta administruattorutilin peittosana.",
+ "config-admin-password-mismatch": "Sinun kirjutetut kaksi peittosanua ei oldu yhtenjyttymät.",
+ "config-admin-email": "Sähköpoštuadressu:",
+ "config-optional-continue": "Kyzy minuspäi ližiä kyzymyksii.",
+ "config-optional-skip": "Olen jo terstavunnuh, vaiku azenda wiki.",
+ "config-email-settings": "Sähköpoštuazetukset",
+ "config-logo": "Logon URL:",
+ "config-skins": "Ketut",
+ "config-install-step-done": "ruattu",
+ "config-install-user-alreadyexists": "Käyttäi \"$1\" on jo olemas",
+ "config-help": "abu",
+ "config-nofile": "Failua \"$1\" ei löydynyh. Ongo se otettu iäre?"
+}
diff --git a/includes/installer/i18n/or.json b/includes/installer/i18n/or.json
index 83fb3d83..fecf4749 100644
--- a/includes/installer/i18n/or.json
+++ b/includes/installer/i18n/or.json
@@ -5,6 +5,7 @@
"Psubhashish"
]
},
+ "config-information": "ସୂଚନା",
"config-session-error": "ଅଧିବେଶନ ଆରମ୍ଭରେ ଅସୁବିଧା: $1",
"config-your-language": "ଆପଣଙ୍କ ଭାଷା:",
"config-your-language-help": "ଇନଷ୍ଟଲ କରିବା ବେଳେ ବ୍ୟବହାର ପାଇଁ ଏକ ଭାଷା ବାଛନ୍ତୁ ।",
@@ -28,6 +29,20 @@
"config-page-existingwiki": "ଏବେକାର ଉଇକି",
"config-restart": "ହଁ, ଏହାକୁ ପୁନରାରମ୍ଭ କରନ୍ତୁ",
"config-env-php": "PHP $1 ଇନଷ୍ଟଲ ହେଲା ।",
+ "config-db-type": "ଡାଟାବେସ ପ୍ରକାର:",
+ "config-db-host": "ଡାଟାବେସ ହୋଷ୍ଟ:",
+ "config-db-name": "ଡାଟାବେସ ନାମ:",
+ "config-site-name": "ଉଇକିର ନାମ:",
+ "config-site-name-blank": "ସାଇଟ ନାମ ଦିଅନ୍ତୁ ।",
+ "config-project-namespace": "ପ୍ରକଳ୍ପ ନେମସ୍ପେସ:",
+ "config-ns-generic": "ପ୍ରକଳ୍ପ",
+ "config-ns-other": "ଅନ୍ୟ (ଦର୍ଶାଇବେ)",
+ "config-ns-other-default": "ମୋଉଇକି",
+ "config-admin-box": "ପରିଚାଳକ ଆକାଉଣ୍ଟ",
+ "config-admin-name": "ଆପଣଙ୍କର ବ୍ୟବହାରକାରୀ ନାମ:",
+ "config-admin-password": "ପାସୱାର୍ଡ",
+ "config-admin-password-confirm": "ଆଉଥରେ ପାସୱାର୍ଡ",
"config-license-cc-by-sa": "କ୍ରିଏଟିଭ କମନ୍ସ ଆଟ୍ରିବ୍ୟୁସନ-ସେଆର ଏଲାଇକ",
- "config-license-cc-by-nc-sa": "କ୍ରିଏଟିଭ କମନ୍ସ ଆଟ୍ରିବ୍ୟୁସନ-ନନକମର୍ସିଆଲ ସେଆର ଏଲାଇକ"
+ "config-license-cc-by-nc-sa": "କ୍ରିଏଟିଭ କମନ୍ସ ଆଟ୍ରିବ୍ୟୁସନ-ନନକମର୍ସିଆଲ ସେଆର ଏଲାଇକ",
+ "config-install-step-done": "ହୋଇଗଲା"
}
diff --git a/includes/installer/i18n/pl.json b/includes/installer/i18n/pl.json
index 5cf71c40..6a1d4a4f 100644
--- a/includes/installer/i18n/pl.json
+++ b/includes/installer/i18n/pl.json
@@ -18,7 +18,8 @@
"Alan ffm",
"Matik7",
"Pio387",
- "Darellur"
+ "Darellur",
+ "The Polish"
]
},
"config-desc": "Instalator MediaWiki",
@@ -64,7 +65,6 @@
"config-env-bad": "Środowisko oprogramowania zostało sprawdzone.\nNie możesz zainstalować MediaWiki.",
"config-env-php": "Zainstalowane jest PHP w wersji $1.",
"config-env-hhvm": "Zainstalowany jest HHVM $1.",
- "config-unicode-using-utf8": "Korzystanie z normalizacji Unicode utf8_normalize.so napisanej przez Brion Vibbera.",
"config-unicode-using-intl": "Korzystanie z [http://pecl.php.net/intl rozszerzenia intl PECL] do normalizacji Unicode.",
"config-unicode-pure-php-warning": "'''Uwaga!''' [http://pecl.php.net/intl Rozszerzenie intl PECL] do obsługi normalizacji Unicode nie jest dostępne. Użyta zostanie mało wydajna zwykła implementacja w PHP.\nJeśli prowadzisz stronę o dużym natężeniu ruchu, powinieneś zapoznać się z informacjami o [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalizacji Unicode].",
"config-unicode-update-warning": "'''Uwaga''' – zainstalowana wersja normalizacji Unicode korzysta z nieaktualnej biblioteki [http://site.icu-project.org/ projektu ICU].\nPowinieneś [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations zrobić aktualizację] jeśli chcesz korzystać w pełni z Unicode.",
@@ -77,7 +77,7 @@
"config-magic-quotes-sybase": "'''Błąd krytyczny – włączono [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase]!'''\nTa opcja powoduje nieprzewidywalne uszkodzenia wprowadzanych danych.\nZainstalować lub korzystać z MediaWiki można pod warunkiem, że ta opcja jest wyłączona.",
"config-mbstring": "'''Błąd krytyczny – włączono [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]!'''\nTa opcja powoduje błędy i może wywołać nieprzewidywalne uszkodzenia wprowadzanych danych.\nZainstalować lub korzystać z MediaWiki można pod warunkiem, że ta opcja jest wyłączona.",
"config-safe-mode": "'''Ostrzeżenie''' – uaktywniono [http://www.php.net/features.safe-mode tryb awaryjny] PHP.\nOpcja ta może powodować problemy, szczególnie w przypadku korzystania z przesyłania plików i używania znacznika <code>math</code>.",
- "config-xml-bad": "Brak modułu XML dla PHP.\nMediaWiki wymaga funkcji z tego modułu i nie może działać w tej konfiguracji.\nJeśli korzystasz z Mandrake, zainstaluj pakiet php-xml.",
+ "config-xml-bad": "Brak modułu XML dla PHP.\nMediaWiki wymaga funkcji z tego modułu i nie może działać w tej konfiguracji.\nZainstaluj pakiet RPM php-xml.",
"config-pcre-old": "<strong>Błąd krytyczny:</strong> Wymagany jest PCRE w wersji $1 lub nowszej.\nTwój plik wykonywalny PHP jest powiązany z wersją PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Więcej informacji].",
"config-pcre-no-utf8": "'''Błąd krytyczny''' – wydaje się, że moduł PCRE w PHP został skompilowany bez wsparcia dla UTF‐8.\nMediaWiki wymaga wsparcia dla UTF‐8 do prawidłowego działania.",
"config-memory-raised": "PHP <code>memory_limit</code> było ustawione na $1, zostanie zwiększone do $2.",
@@ -98,7 +98,7 @@
"config-no-scaling": "Nie odnaleziono biblioteki GD lub ImageMagick. Możliwość zmniejszania załadowywanych grafik zostanie wyłączona.",
"config-no-uri": "'''Błąd:''' Nie można określić aktualnego URI.\nInstalacja została przerwana.",
"config-no-cli-uri": "<strong>Ostrzeżenie:</strong> Nie wskazano <code>--scriptpath</code>, użycie wartości domyślnej: <code>$1</code>.",
- "config-using-server": "„<nowiki>$1</nowiki>“ jest adresem serwera, na którym instalowana jest wiki.",
+ "config-using-server": "„<nowiki>$1</nowiki>” jest adresem serwera, na którym instalowana jest wiki.",
"config-using-uri": "Wiki będzie zainstalowana pod adresem \"<nowiki>$1$2</nowiki>\".",
"config-uploads-not-safe": "'''Uwaga''' – domyślny katalog do którego zapisywane są przesyłane pliki <code>$1</code> jest podatny na wykonanie dowolnego skryptu.\nChociaż MediaWiki sprawdza wszystkie przesłane pliki pod kątem bezpieczeństwa, zaleca się jednak, aby [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security zamknąć tę lukę w zabezpieczeniach] przed włączeniem przesyłania plików.",
"config-no-cli-uploads-check": "'''Ostrzeżenie:''' Katalog domyślny przesyłanych plików ( <code>$1</code> ) nie jest sprawdzona względem luki\n wykonania dowolnego skryptu podczas instalacji CLI w zabezpieczeniach.",
@@ -117,8 +117,6 @@
"config-db-install-account": "Konto użytkownika dla instalatora",
"config-db-username": "Nazwa użytkownika bazy danych:",
"config-db-password": "Hasło bazy danych:",
- "config-db-password-empty": "Wprowadź hasło dla nowego użytkownika bazy danych: $1.\nChoć istnieje możliwość tworzenia użytkowników bez hasła, nie jest to bezpieczne.",
- "config-db-username-empty": "Należy podać wartość parametru \"{{int:config-db-username}}\".",
"config-db-install-username": "Wprowadź nazwę użytkownika, który będzie używany do łączenia się z bazą danych podczas procesu instalacji.\nNie jest to nazwa konta MediaWiki, a użytkownika bazy danych.",
"config-db-install-password": "Wprowadź hasło, które będzie wykorzystywane do łączenia się z bazą danych w procesie instalacji.\nTo nie jest hasło konta MediaWiki, lecz hasło do bazy danych.",
"config-db-install-help": "Podaj nazwę użytkownika i jego hasło, które zostaną użyte do połączenia z bazą danych w czasie procesu instalacji.",
@@ -164,7 +162,7 @@
"config-connection-error": "$1.\n\nSprawdź adres serwera, nazwę użytkownika i hasło, a następnie spróbuj ponownie.",
"config-invalid-schema": "Nieprawidłowa nazwa schematu dla MediaWiki „$1”.\nNazwa może zawierać wyłącznie liter ASCII (a-z, A-Z), cyfr (0-9) i podkreślenia (_).",
"config-db-sys-create-oracle": "Instalator może wykorzystać wyłącznie konto SYSDBA do tworzenia nowych kont użytkowników.",
- "config-db-sys-user-exists-oracle": "Konto użytkownika „$1“ już istnieje. SYSDBA można użyć tylko do utworzenia nowego konta!",
+ "config-db-sys-user-exists-oracle": "Konto użytkownika „$1” już istnieje. SYSDBA można użyć tylko do utworzenia nowego konta!",
"config-postgres-old": "Korzystasz z wersji $2 oprogramowania PostgreSQL, a potrzebna jest wersja co najmniej $1.",
"config-mssql-old": "Wymagany jest Microsoft SQL Server w wersji $1 lub nowszej. Masz zainstalowaną wersję $2.",
"config-sqlite-name-help": "Wybierz nazwę, która będzie identyfikować Twoją wiki.\nNie wolno używać spacji ani myślników.\nZostanie ona użyta jako nazwa pliku danych SQLite.",
@@ -309,10 +307,10 @@
"config-pg-no-create-privs": "Konto, które zostało określone dla instalacji nie ma wystarczających uprawnień, aby utworzyć konto.",
"config-pg-not-in-role": "Konto określone dla użytkownika sieci już istnieje.\nKonto określone dla instalacji nie ma uprawnień administratora ani nie jest przynależy do roli użytkownika sieci web, więc nie można utworzyć obiektów stanowiących własność użytkownika sieci.\n\nMediaWiki wymaga obecnie, by tabele były własnością konta zwykłego użytkownika. Podaj inną nazwę konta użytkownika, lub kliknij przycisk \"Wstecz\" i podaj nazwę konta użytkownika instalatora, które posiada odpowiednie uprawnienia.",
"config-install-user": "Tworzenie użytkownika bazy danych",
- "config-install-user-alreadyexists": "Konto użytkownika „$1“ już istnieje",
+ "config-install-user-alreadyexists": "Konto użytkownika „$1” już istnieje",
"config-install-user-create-failed": "Tworzenie użytkownika \"$1\" nie powiodło się: $2",
"config-install-user-grant-failed": "Przyznanie uprawnień użytkownikowi „$1” nie powiodło się – $2",
- "config-install-user-missing": "Nie istnieje konto użytkownika „$1“.",
+ "config-install-user-missing": "Nie istnieje konto użytkownika „$1”.",
"config-install-user-missing-create": "Określony użytkownik \"$1\" nie istnieje.\nKliknij poniższe pole wyboru „utwórz konto\" jeśli chcesz go utworzyć.",
"config-install-tables": "Tworzenie tabel",
"config-install-tables-exist": "'''Uwaga''' – wygląda na to, że tabele MediaWiki już istnieją.\nPomijam tworzenie tabel.",
@@ -324,8 +322,9 @@
"config-install-keys": "Generowanie tajnych kluczy",
"config-insecure-keys": "'''Ostrzeżenie:''' {{PLURAL:$2|Klucz bezpieczeństwa|Klucze bezpieczeństwa|Klucze bezpieczeństwa}} ($1) utworzone podczas instalacji {{PLURAL:$2|utworzony podczas instalacji nie jest|utworzone podczas instalacji nie są|utworzone podczas instalacji nie są}} w pełni bezpieczne. Być może warto wygenerować {{PLURAL:$2|własny klucz|własne klucze|własne klucze}}.",
"config-install-updates": "Zapobieganie uruchamianiu niepotrzebnych aktualizacji",
+ "config-install-updates-failed": "<strong>Błąd:</strong> Wstawianie kluczy aktualizacji d0 tabeli nie powiodło się z powodu następującego błędu: $1",
"config-install-sysop": "Tworzenie konta administratora",
- "config-install-subscribe-fail": "Nie można zapisać na listę „mediawiki-announce“ – $1",
+ "config-install-subscribe-fail": "Nie można zapisać na listę „mediawiki-announce” – $1",
"config-install-subscribe-notpossible": "cURL nie jest zainstalowany, więc <code>allow_url_fopen</code> nie jest dostępne.",
"config-install-mainpage": "Tworzenie strony głównej z domyślną zawartością",
"config-install-extension-tables": "Tworzenie tabel dla aktywnych rozszerzeń",
diff --git a/includes/installer/i18n/pms.json b/includes/installer/i18n/pms.json
index 36b48c8e..440b398b 100644
--- a/includes/installer/i18n/pms.json
+++ b/includes/installer/i18n/pms.json
@@ -57,11 +57,13 @@
"config-no-db": "Impossìbil trové un pilòta ëd base ëd dàit bon! A dev instalé un pilòta ëd base ëd dàit për PHP.\n{{PLURAL:$2|La sòrt ëd base ëd dàit mantnùa a l'é costa|Le sòrt ëd base ëd dàit mantùe a son coste}} sì-dapress: $1.\n\nS'a l'é compilasse PHP chiel-midem, ch'a lo configura torna con un client ëd base ëd dàit abilità, për esempi an dovrand <code>./configure --with-mysql</code>.\nS'a l'ha instalà PHP dai pachèt Debian o Ubuntu, antlora a dev ëdcò anstalé, për esempi, ël mòdul <code>php5-mysql</code>.",
"config-outdated-sqlite": "'''Avis''': chiel a l'ha SQLite $1, che a l'é pi vej che la version mìnima dont a-i é damanca $2. SQLite a sarà pa disponìbil.",
"config-no-fts3": "'''Avis''': SQLite a l'é compilà sensa ël mòdul [//sqlite.org/fts3.html FTS3], le funsion d'arserca a saran pa disponìbij su cost motor.",
+ "config-register-globals-error": "<strong>Eror: l'opsion <code>[http://php.net/register_globals register_globals]</code> dël PHP a l'é abilità.\nA dev esse disabilità për continué con l'instalassion.</strong>\nCh'a vëdda [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] për avèj d'agiut an sla manera ëd felo.",
+ "config-magic-quotes-gpc": "<strong>Eror crìtich: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] a l'é ativ!</strong>\nCosta opsion a danegia ij dat d'intrada ëd fasson nen prevedìbil.\nA peul pa instalé o dovré MediaWiki fin-a a che st'opsion a sia nen disabilità.",
"config-magic-quotes-runtime": "'''Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] a l'é ativ!'''\nCosta opsion a danegia ij dat d'intrada an manera pa prevedìbil.\nA peul pa instalé o dovré MediaWiki se st'opsion a l'é pa disabilità.",
"config-magic-quotes-sybase": "'''Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] a l'é ativ!'''\nCosta opsion a danegia ij dat d'intrada an manera pa prevedìbil.\nA peul pa instalé o dovré MediaWiki se st'opsion a l'é pa disabilità.",
"config-mbstring": "'''Fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] a l'é ativ!'''\nCosta opsion a càusa d'eror e a peul danegié ij dat d'intrada an manera pa prevedìbil.\nA peul pa instalé o dovré MediaWiki se st'opsion a l'é pa disabilità.",
"config-safe-mode": "'''Avis:''' [http://www.php.net/features.safe-mode Safe mode] ëd PHP a l'é ativ.\nA peul causé ëd problema, dzortut s'as deuvro ël cariament d'archivi e ël manteniment ëd <code>math</code>.",
- "config-xml-bad": "Mòdul XML ed PHP mancant.\nMediaWiki a l'ha da manca dle funsion an sto mòdul e a travajërà pa an costa configurassion.\nS'a fa giré mandrake, ch'a instala ël pachet php-xml.",
+ "config-xml-bad": "Ël mòdol XML ed PHP a l'é mancant.\nMediaWiki a l'ha da manca dle funsion ant ës mòdul e a marcërà pa an costa configurassion.\nA dev instalé ël pachet php-xml RPM.",
"config-pcre-no-utf8": "'''Fatal''': ël mòdul PCRE ëd PHP a smija esse compilà sensa l'apògg PCRE_UTF8.\nMediaWiki a ciama l'apògg d'UTF8 për marcé për da bin.",
"config-memory-raised": "<code>memory_limit</code> ëd PHP a l'é $1, aussà a $2.",
"config-memory-bad": "'''Avis:''' <code>memory_limit</code> ëd PHP a l'é $1.\nSossì a l'é probabilment tròp bass.\nL'instalassion a peul falì!",
diff --git a/includes/installer/i18n/ps.json b/includes/installer/i18n/ps.json
index 23d30277..8f2a0fd7 100644
--- a/includes/installer/i18n/ps.json
+++ b/includes/installer/i18n/ps.json
@@ -4,6 +4,8 @@
"Ahmed-Najib-Biabani-Ibrahimkhel"
]
},
+ "config-desc": "د مېډياويکي نصبونکی",
+ "config-title": "مېډياويکي $1 نصبېدنه",
"config-information": "مالومات",
"config-localsettings-key": "کونجۍ نومهالول:",
"config-localsettings-badkey": "کومه کونجۍ مو چې ورکړه ناسمه ده.",
@@ -19,12 +21,18 @@
"config-page-options": "خوښنې",
"config-page-install": "لگول",
"config-page-complete": "بشپړ!",
+ "config-page-restart": "نصبېدنه بياپيلول",
"config-page-readme": "ما ولوله",
+ "config-page-releasenotes": "خپاره شوي يادښتونه",
"config-page-copying": "لمېسنه",
"config-page-upgradedoc": "نومهالېدنه",
"config-page-existingwiki": "شته ويکي",
"config-restart": "هو، سر له نوي يې پيل کړه",
"config-env-php": "د $1 PHP نصب شو.",
+ "config-env-hhvm": "HHVM $1 نصب شو.",
+ "config-xcache": "[http://xcache.lighttpd.net/ XCache] نصب شو",
+ "config-apc": "[http://www.php.net/apc APC] نصب شو",
+ "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] نصب شو",
"config-db-type": "د توکبنسټ ډول:",
"config-db-host": "د توکبنسټ کوربه:",
"config-db-host-oracle": "د توکبنسټ TNS:",
@@ -32,16 +40,26 @@
"config-db-name": "د توکبنسټ نوم:",
"config-db-username": "د توکبنسټ کارن-نوم:",
"config-db-password": "د توکبنسټ پټنوم:",
+ "config-charset-mysql5-binary": "مای اس کيو ال 4.1/5.0 دوييز",
+ "config-charset-mysql5": "مای اس کيو ال 4.1/5.0 يو ټي اف-8",
+ "config-db-port": "د توکبنسټ ور:",
+ "config-db-schema": "د مېډياويکي طرحه:",
+ "config-type-mssql": "مايکروسافټ SQL پالنگر",
"config-header-mysql": "د MySQL امستنې",
"config-header-postgres": "د PostgreSQL امستنې",
"config-header-sqlite": "د SQLite امستنې",
"config-header-oracle": "د اورېکل امستنې",
+ "config-header-mssql": "د مايکروسافټ SQL پالنگر امستنې",
"config-sqlite-readonly": "د <code>$1</code> دوتنه د ليکلو وړ نه ده.",
"config-sqlite-cant-create-db": "د توکبنسټ دوتنه <code>$1</code> جوړه نه شوه.",
+ "config-mysql-binary": "دوه ايز",
+ "config-mysql-utf8": "UTF-8",
"config-site-name": "د ويکي نوم:",
"config-site-name-blank": "د وېبځي نوم وليکۍ.",
"config-project-namespace": "د پروژې نوم-تشيال:",
"config-ns-generic": "پروژه",
+ "config-ns-site-name": "ويکي نوم ته ورته: $1",
+ "config-ns-other": "بل (ځانگړی کړئ)",
"config-ns-other-default": "زما ويکي",
"config-admin-box": "د پازوال گڼون",
"config-admin-name": "ستاسې کارن نوم:",
@@ -55,7 +73,11 @@
"config-license-pd": "ټولگړی شپول",
"config-email-settings": "د برېښليک امستنې",
"config-email-user": "کارن تر کارن برېښليک چارنول",
+ "config-extensions": "شاتاړي",
+ "config-skins": "پوښۍ",
+ "config-skins-use-as-default": "همدا پوښۍ په تلواليزه توگه کارول",
"config-install-step-done": "ترسره شو",
+ "config-install-step-failed": "نابريال شو",
"config-install-user-alreadyexists": "د \"$1\" کارن له پخوا څخه شته",
"config-install-tables": "لښتيالونه جوړول",
"config-download-localsettings": "ښکته کول <code>LocalSettings.php</code>",
diff --git a/includes/installer/i18n/pt-br.json b/includes/installer/i18n/pt-br.json
index 132644da..27dddd39 100644
--- a/includes/installer/i18n/pt-br.json
+++ b/includes/installer/i18n/pt-br.json
@@ -14,7 +14,10 @@
"Rodrigo codignoli",
"Tuliouel",
"Marcos dias de oliveira",
- "Fasouzafreitas"
+ "Fasouzafreitas",
+ "TheEduGobi",
+ "Dianakc",
+ "Walesson"
]
},
"config-desc": "O instalador do MediaWiki",
@@ -60,23 +63,25 @@
"config-env-bad": "O ambiente foi verificado.\nVocê não pode instalar o MediaWiki.",
"config-env-php": "O PHP $1 está instalado.",
"config-env-hhvm": "HHVM $1 está instalado.",
- "config-unicode-using-utf8": "Usando o utf8_normalize.so, de Brion Vibber, para a normalização Unicode.",
"config-unicode-using-intl": "Usando a [http://pecl.php.net/intl extensão intl PECL] para a normalização Unicode.",
"config-unicode-pure-php-warning": "<strong>Aviso</strong>: A [http://pecl.php.net/intl extensão intl PECL] não está disponível para efetuar a normalização Unicode, abortando e passando para a lenta implementação de PHP puro.\nSe o seu site tem um alto volume de tráfego, informe-se sobre a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalização Unicode].",
"config-unicode-update-warning": "<strong>Aviso:</strong> A versão instalada do wrapper de normalização Unicode usa uma versão mais antiga da biblioteca do [//www.site.icu-project.org/projeto ICU].\nVocê deve [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations atualizar] se você tem quaisquer preocupações com o uso do Unicode.",
- "config-no-db": "Não foi possível encontrar um driver de banco de dados adequado! É necessário instalar um driver de banco de dados para o PHP.\nSão suportados os seguintes tipos de bancos de dados: $1.\n\nSe você mesmo tiver compilado o PHP, reconfigure-o com um cliente de banco de dados ativado usando, por exemplo <code>./configure --with-mysqli</code>.\nSe você instalou o PHP a partir de um pacote do Debian ou do Ubuntu, então será também necessário instalar, por exemplo, o pacote <code>php5-mysql</code>.",
+ "config-no-db": "Não foi possível localizar um driver de banco de dados apropriado! Você precisa instalar um driver de banco de dados para PHP. O banco de dados seguinte {{PLURAL: $ 2 | | tipo é tipos são}} suportado: $ 1. Se você compilou o PHP mesmo, reconfigurá-lo com um cliente de banco de dados ativada, por exemplo, usando <code> ./ configure --with-mysqli </ code>. Se você instalou o PHP a partir de um pacote Debian ou Ubuntu, então você também precisa instalar, por exemplo, o <code> php5-mysql </ code> pacote.",
"config-outdated-sqlite": "<strong>Aviso:</strong> você tem o SQLite versão $1, que é menor do que a versão mínima necessária $2. O SQLite não estará disponível.",
"config-no-fts3": "<strong>Aviso</strong> O SQLite foi compilado sem o [//sqlite.org/fts3.html módulo FTS3], as funcionalidades de pesquisa não estarão disponíveis nesta instalação.",
+ "config-register-globals-error": "<strong>Erro: a opção <code>[http://php.net/register_globals register_globals]</code> do PHP está ativada.\nA mesma deve ser desativada para continuar a instalação.</strong>\nVeja [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] para obter ajuda com isto.",
+ "config-magic-quotes-gpc": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] está ativa!</strong>\nEsta opção corrompe a entrada de dados imprevisivelmente.\nVocê não pode instalar ou usar a MediaWiki a menos que esta opção seja desativada.",
"config-magic-quotes-runtime": "<strong>Erro fatal: A opção [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] está ativada!</strong>\nEsta opção causa corrupção dos dados de entrada de forma imprevisível.\nVocê não pode instalar ou utilizar o MediaWiki a menos que esta opção seja desativada.",
"config-magic-quotes-sybase": "<strong>Erro fatal: A opção [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] está ativada!</strong>\nEsta opção corrompe os dados de entrada de forma imprevisível.\nVocê não pode instalar ou utilizar o MediaWiki a menos que esta opção seja desativada.",
"config-mbstring": "<strong>Erro fatal: A opção [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] está ativada!</strong>\nEsta opção causa erros e pode corromper os dados de forma imprevisível.\nVocê não pode instalar ou utilizar o MediaWiki a menos que esta opção seja desativada.",
"config-safe-mode": "<strong>Aviso:</strong> O [http://www.php.net/features.safe-mode safe mode] do PHP está ativado.\nEste modo pode causar problemas, especialmente no upload de arquivos e no suporte a <code>math</code>.",
- "config-xml-bad": "O módulo XML do PHP está ausente.\nO MediaWiki necessita de funções deste módulo e não funcionará com esta configuração.\nSe está utilizando o Mandrake, instale o pacote php-xml.",
+ "config-xml-bad": "Módulo XML do PHP está faltando. MediaWiki requer funções deste módulo e não vai funcionar nesta configuração. Pode ser necessário instalar o pacote RPM php-xml.",
"config-pcre-old": "<strong>Erro fatal:</strong> É necessário o PCRE $1 ou versão posterior.\nO binário do seu PHP foi vinculado com o PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Mais informações].",
"config-pcre-no-utf8": "<strong>Erro fatal:</strong> O módulo PCRE do PHP parece ser compilado sem suporte a PCRE_UTF8.\nO MediaWiki requer suporte a UTF-8 para funcionar corretamente.",
"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.\nIsso provavelmente é muito baixo.\nA instalação pode falhar!",
"config-ctype": "<strong>Erro fatal:</strong> O PHP deve ser compilado com suporte para a [http://www.php.net/manual/en/ctype.installation.php extensão Ctype].",
+ "config-iconv": "<strong>Fatal:</strong> O PHP deve ser compilado com suporte para a [http://www.php.net/manual/en/iconv.installation.php extensão iconv].",
"config-json": "<strong>Erro fatal:</strong> O PHP foi compilado sem suporte a JSON.\nVocê deve instalar a extensão PHP JSON ou a extensão [http://pecl.php.net/package/jsonc PECL jsonc] antes de instalar o MediaWiki.\n* A extensão JSON do PHP já está incluída no Red Hat Enterprise Linux (CentOS) 5 e 6, mas deve ser habilitado no <code>/etc/php.ini</code> ou no <code>/etc/php.d/json.ini</code>.\n* Algumas distribuições Linux lançadas após maio de 2013 omitem a extensão PHP, oferecendo em seu lugar a extensão PECL como parte do pacote <code>php5-json</code> ou do <code>php-pecl-jsonc</code>.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] está instalado",
"config-apc": "[http://www.php.net/apc APC] está instalado",
@@ -93,6 +98,8 @@
"config-no-cli-uri": "<strong>Aviso:</strong> Nenhum <code>--scriptpath</code> foi especificado, usando o padrão: <code>$1</code>.",
"config-using-server": "Utilizando o nome do servidor \"<nowiki>$1</nowiki>\".",
"config-using-uri": "Usando URL do servidor \"<nowiki>$1$2</nowiki>\".",
+ "config-no-cli-uploads-check": "<strong>Atenção:</strong> O seu diretório padrão para envios (<code>$1</code>) não está marcado para vulnerabilidade\npara execução de script arbitrário durante a instalação do CLI.",
+ "config-brokenlibxml": "O sistema tem uma combinação de PHP e libxml2 que é conflitante e pode causar corrupção de dados ocultos no MediaWiki e outros aplicativos da web.\nAtualize para o libxml2 2.7.3 ou mais recente ([https://bugs.php.net/bug.php?id=45996 bugs com o PHP]).\nInstalação abortada.",
"config-db-type": "Tipo de base de dados:",
"config-db-host": "Servidor da base de dados:",
"config-db-host-help": "Se a base de dados do seu servidor está em um servidor diferente, digite o nome do hospedeiro ou o endereço IP aqui.\n\nSe você está utilizando um hospedeiro web compartilhado, o seu provedor de hospedagem deverá fornecer o nome do hospedeiro correto na sua documentação.\n\nSe você está instalando em um servidor Windows e usando o MySQL, usar \"localhost\" pode não funcionar para o nome de servidor. Se não funcionar, tente \"127.0.01\" para o endereço de IP local.\n\nSe você está usando PostgreSQl, deixe este campo em branco para se conectar através de um socket Unix.",
@@ -104,10 +111,10 @@
"config-db-install-account": "Conta de usuário para instalação",
"config-db-username": "Nome de usuário do banco de dados:",
"config-db-password": "Senha do banco de dados:",
- "config-db-password-empty": "Por favor digite uma senha para o novo usuário do banco de dados: $1. Embora seja possível criar usuários sem senha, isto não é seguro.",
"config-db-install-username": "Digite o nome de usuário que será utilizado para conectar com o banco de dados durante o processo de instalação.\nEste não é a conta de usuário do MediaWiki; este é o nome de usuário para sua base de dados.",
"config-db-install-password": "Digite a senha que será utilizada para conectar com o banco de dados durante o processo de instalação.\nEsta não é a senha de usuário da conta do MediaWiki; esta será a senha para seu banco de dados.",
"config-db-install-help": "Digite o nome de usuário e a senha que serão utilizados para conectar com o banco de dados durante o processo de instalação.",
+ "config-db-account-lock": "Use o mesmo nome de usuário e senha durante a operação normal",
"config-db-wiki-account": "Conta de usuário para operação normal",
"config-db-wiki-help": "Digite o nome de usuário e senha que será usada para se conectar ao banco de dados durante a operação normal wiki.\nSe a conta não existir, e a conta de instalação tiver privilégios suficientes, a conta do usuário será criada com os privilégios mínimos necessários para o funcionamento do wiki.",
"config-db-prefix": "Prefixo da tabela de banco de dados:",
@@ -127,6 +134,7 @@
"config-oracle-temp-ts": "Tablespace temporário:",
"config-type-mysql": "MySQL (ou compatível)",
"config-type-mssql": "Microsoft SQL Server",
+ "config-support-info": "O MediaWiki suporta os sistemas de banco de dados a seguir:\n\n$1\n\nSe você não vê o sistema de banco de dados que você está tentando usar listados abaixo, siga as instruções relacionadas acima, para ativar o suporte.",
"config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] é um sistema de banco de dados leve que é muito bem suportado. ([http://www.php.net/manual/en/pdo.installation.php como compilar o PHP com suporte a SQLite], usa DOP)",
"config-header-mysql": "Configurações MySQL",
"config-header-postgres": "Configurações PostgreSQL",
@@ -198,6 +206,7 @@
"config-profile-private": "Wiki privada",
"config-license": "Direitos autorais e licenças:",
"config-license-none": "Sem rodapé com a licença",
+ "config-license-cc-by": "Atribuição Creative Commons",
"config-license-gfdl": "GNU Free Documentation License 1.3 ou posterior",
"config-license-pd": "Domínio público",
"config-license-cc-choose": "Selecionar uma licença personalizada da organização Creative Commons",
diff --git a/includes/installer/i18n/pt.json b/includes/installer/i18n/pt.json
index b63905b8..bbf27982 100644
--- a/includes/installer/i18n/pt.json
+++ b/includes/installer/i18n/pt.json
@@ -60,7 +60,6 @@
"config-env-bad": "O ambiente foi verificado.\nNão pode instalar o MediaWiki.",
"config-env-php": "O PHP $1 está instalado.",
"config-env-hhvm": "HHVM $1 está instalado.",
- "config-unicode-using-utf8": "A usar o utf8_normalize.so, por Brion Vibber, para a normalização Unicode.",
"config-unicode-using-intl": "A usar a [http://pecl.php.net/intl extensão intl PECL] para a normalização Unicode.",
"config-unicode-pure-php-warning": "'''Aviso''': A [http://pecl.php.net/intl extensão intl PECL] não está disponível para efetuar a normalização Unicode. Irá recorrer-se à implementação em PHP puro, que é mais lenta.\nSe o seu site tem alto volume de tráfego, devia informar-se um pouco sobre a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations/pt normalização Unicode].",
"config-unicode-update-warning": "'''Aviso''': A versão instalada do wrapper de normalização Unicode usa uma versão mais antiga da biblioteca do [http://site.icu-project.org/ projeto ICU].\nDevia [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations atualizá-la] se tem quaisquer preocupações sobre o uso do Unicode.",
@@ -71,12 +70,13 @@
"config-magic-quotes-sybase": "'''Erro fatal: A opção [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] está ativa!'''\nEsta opção causa corrupção dos dados de entrada, de uma forma imprevisível.\nNão pode instalar ou usar o MediaWiki a menos que esta opção seja desativada.",
"config-mbstring": "'''Erro fatal: A opção [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] está ativa!'''\nEsta opção causa erros e pode corromper os dados de uma forma imprevisível.\nNão pode instalar ou usar o MediaWiki a menos que esta opção seja desativada.",
"config-safe-mode": "'''Aviso:''' O [http://www.php.net/features.safe-mode safe mode] do PHP está ativo.\nEste modo pode causar problemas, especialmente no upload de ficheiros e no suporte a <code>math</code>.",
- "config-xml-bad": "Falta o módulo XML do PHP.\nO MediaWiki necessita de funções deste módulo e não funcionará com esta configuração.\nSe está a executar o Mandrake, instale o pacote php-xml.",
+ "config-xml-bad": "Falta o módulo XML do PHP.\nO MediaWiki necessita de funções deste módulo e não funcionará com esta configuração.\nPode precisar de instalar o pacote RPM chamado php-xml.",
"config-pcre-old": "<strong>Erro fatal:</strong> É necessário o PCRE $1 ou versão posterior.\nO <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-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": "'''Aviso:''' A configuração <code>memory_limit</code> do PHP é $1.\nIsto é provavelmente demasiado baixo.\nA instalação poderá falhar!",
"config-ctype": "'''Erro fatal''': O PHP tem de ser compilado com suporte para a [http://www.php.net/manual/en/ctype.installation.php extensão Ctype].",
+ "config-iconv": "<strong>Erro fatal:</strong> O PHP deve ser compilado com suporte à [http://www.php.net/manual/en/iconv.installation.php extensão iconv].",
"config-json": "<strong>Erro fatal:</strong> O PHP foi compilado sem suporte de JSON.\nTem de instalar a extensão JSON do PHP (incluída no PHP 5.2 ou posterior) ou a extensão [http://pecl.php.net/package/jsonc PECL jsonc] antes de instalar o MediaWiki.\n* A extensão JSON do PHP está incluída nas distribuções 5 e 6 do Red Hat Enterprise Linux (CentOS), mas tem de estar ativa nos ficheiros <code>/etc/php.ini</code> ou <code>/etc/php.d/json.ini</code>.\n* Algumas distribuições do Linux posteriores a maio de 2013 omitem a extensão JSON do PHP e substituem-na pela extensão PECL chamando-lhe <code>php5-json</code> ou <code>php-pecl-jsonc</code>.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] instalada",
"config-apc": "[http://www.php.net/apc APC] instalada",
@@ -110,8 +110,6 @@
"config-db-install-account": "Conta do utilizador para a instalação",
"config-db-username": "Nome do utilizador da base de dados:",
"config-db-password": "Palavra-chave do utilizador da base de dados:",
- "config-db-password-empty": "Introduza a palavra-chave do novo utilizador da base de dados: $1.\nEmbora seja possível criar utilizadores sem palavra-chave, fazê-lo não é seguro.",
- "config-db-username-empty": "Tem de introduzir um valor para \"{{int:config-db-username}}\"",
"config-db-install-username": "Introduza o nome de utilizador que será usado para aceder à base de dados durante o processo de instalação. Este utilizador não é o do MediaWiki; é o utilizador da base de dados.",
"config-db-install-password": "Introduza a palavra-chave do utilizador que será usado para aceder à base de dados durante o processo de instalação. Esta palavra-chave não é a do utilizador do MediaWiki; é a palavra-chave do utilizador da base de dados.",
"config-db-install-help": "Introduza o nome de utilizador e a palavra-chave que serão usados para aceder à base de dados durante o processo de instalação.",
diff --git a/includes/installer/i18n/qqq.json b/includes/installer/i18n/qqq.json
index fba5165c..bb42d88f 100644
--- a/includes/installer/i18n/qqq.json
+++ b/includes/installer/i18n/qqq.json
@@ -82,7 +82,7 @@
"config-memory-bad": "Parameters:\n* $1 is the configured <code>memory_limit</code>.",
"config-ctype": "Message if support for [http://www.php.net/manual/en/ctype.installation.php Ctype] is missing from PHP.\n{{Related|Config-fatal}}",
"config-iconv": "Message if support for [http://www.php.net/manual/en/iconv.installation.php iconv] is missing from PHP.\n{{Related|Config-fatal}}",
- "config-json": "Message if support for [[wikipedia:JSON|JSON]] is missing from PHP.\n* \"[[wikipedia:Red Hat Enterprise Linux|Red Hat Enterprise Linux]]\" (RHEL) and \"[[wikipedia:CentOS|CentOS]]\" refer to two almost-identical Linux distributions. \"5 and 6\" refers to version 5 or 6 of either distribution. Because RHEL 7 likely will not include the PHP extension, do not translate as \"5 or newer\".\n* \"The [http://www.php.net/json PHP extension]\" is the JSON extension included with PHP 5.2 and newer.\n* \"The [http://pecl.php.net/package/jsonc PECL extension]\" is based on the PHP extension, though excludes code some distributions have found unacceptable (see [[bugzilla:47431]]).\n{{Related|Config-fatal}}",
+ "config-json": "Message if support for [[wikipedia:JSON|JSON]] is missing from PHP.\n* \"[[wikipedia:Red Hat Enterprise Linux|Red Hat Enterprise Linux]]\" (RHEL) and \"[[wikipedia:CentOS|CentOS]]\" refer to two almost-identical Linux distributions. \"5 and 6\" refers to version 5 or 6 of either distribution. Because RHEL 7 likely will not include the PHP extension, do not translate as \"5 or newer\".\n* \"The [http://www.php.net/json PHP extension]\" is the JSON extension included with PHP 5.2 and newer.\n* \"The [http://pecl.php.net/package/jsonc PECL extension]\" is based on the PHP extension, though excludes code some distributions have found unacceptable (see [[phab:T49431]]).\n{{Related|Config-fatal}}",
"config-xcache": "Message indicates if this program is available",
"config-apc": "Message indicates if this program is available",
"config-wincache": "Message indicates if this program is available",
@@ -113,10 +113,8 @@
"config-db-name-oracle": "Field label in the MediaWiki installer where an Oracle database schema can be specified.",
"config-db-account-oracle-warn": "A \"[[:wikipedia:Front and back ends|backend]]\" is a system or component that ordinary users don't interact with directly and don't need to know about, and that is responsible for a distinct task or service - for example, a storage back-end is a generic system for storing data which other applications can use. Possible alternatives for back-end are \"system\" or \"service\", or (depending on context and language) even leave it untranslated.",
"config-db-install-account": "Legend in the MediaWiki installer for the section where database username and password have to be provided.",
- "config-db-username": "Used as label.\n\nAlso used in {{msg-mw|Config-db-username-empty}}.",
+ "config-db-username": "Used as label.",
"config-db-password": "Field label in the MediaWiki installer where database password has to be provided.",
- "config-db-password-empty": "Used as error message. Parameters:\n* $1 - database username",
- "config-db-username-empty": "Used as error message. Shown when the database username is not entered by the user.\n\nRefers to {{msg-mw|Config-db-username}}.",
"config-db-install-username": "Help box text in the MediaWiki installer clarifying the requirement for database username.",
"config-db-install-password": "Help box text in the MediaWiki installer clarifying the requirement for database password.",
"config-db-install-help": "Help text in MediaWiki installer.",
diff --git a/includes/installer/i18n/ro.json b/includes/installer/i18n/ro.json
index fcade71f..e0c78b7c 100644
--- a/includes/installer/i18n/ro.json
+++ b/includes/installer/i18n/ro.json
@@ -5,7 +5,8 @@
"Minisarm",
"Stelistcristi",
"XXN",
- "Tuxilina"
+ "Tuxilina",
+ "Strainu"
]
},
"config-desc": "Programul de instalare pentru MediaWiki",
@@ -43,19 +44,28 @@
"config-help-restart": "Doriți să ștergeți toate datele salvate introduse și să reporniți procesul de instalare?",
"config-restart": "Da, repornește.",
"config-env-good": "Verificarea mediului a fost efectuată cu succes.\nPuteți instala MediaWiki.",
+ "config-env-bad": "Verificarea mediului a fost efectuată.\nNu puteți instala MediaWiki.",
"config-env-php": "PHP $1 este instalat.",
"config-env-hhvm": "HHVM $1 este instalat.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] este instalat",
"config-apc": "[http://www.php.net/apc APC] este instalat",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] este instalat",
+ "config-diff3-bad": "GNU diff3 nu a fost găsit.",
+ "config-no-uri": "<strong>Eroare:</strong> Nu pot determina URI-ul curent.\nInstalare întreruptă.",
"config-db-type": "Tipul bazei de date:",
"config-db-host": "Gazdă bază de date:",
"config-db-host-oracle": "Baza de date TNS:",
"config-db-wiki-settings": "Identificați acest wiki",
"config-db-name": "Numele bazei de date:",
"config-db-name-oracle": "Schema bazei de date:",
+ "config-db-install-account": "Contul de utilizator pentru instalare",
"config-db-username": "Nume de utilizator pentru baza de date:",
"config-db-password": "Parola bazei de date:",
+ "config-db-install-username": "Introduceți numele de utilizator care va fi utilizat pentru conexiunea la baza de date în timpul procesului de instalare.\nNu este numele de utilizator al contului MediaWiki; este numele de utilizator al bazei dumneavoastră de date.",
+ "config-db-install-password": "Introduceți parola care va fi utilizată pentru conexiunea la baza de date în timpul procesului de instalare.\nNu este parola contului MediaWiki; este parola bazei dumneavoastră de date.",
+ "config-db-install-help": "Introduceți numele de utilizator și parola care vor fi utilizate pentru conexiunea la baza de date în timpul procesului de instalare.",
+ "config-db-account-lock": "Folosește același nume de utilizator și parolă în timpul funcționării normale",
+ "config-db-wiki-account": "Contul de utilizator pentru funcționarea normală",
"config-db-prefix": "Prefixul tabelelor din baza de date:",
"config-db-charset": "Setul de caractere al bazei de date",
"config-charset-mysql5-binary": "MySQL 4.1/5.0 binar",
@@ -65,6 +75,8 @@
"config-sqlite-dir": "Director de date SQLite:",
"config-oracle-def-ts": "Spațiu de stocare („tablespace”) implicit:",
"config-oracle-temp-ts": "Spațiu de stocare („tablespace”) temporar:",
+ "config-type-mysql": "MySQL (sau compatibil)",
+ "config-type-mssql": "Microsoft SQL Server",
"config-header-mysql": "Setările MySQL",
"config-header-postgres": "Setări PostgreSQL",
"config-header-sqlite": "Setări SQLite",
diff --git a/includes/installer/i18n/ru.json b/includes/installer/i18n/ru.json
index 386215ab..fa3512e5 100644
--- a/includes/installer/i18n/ru.json
+++ b/includes/installer/i18n/ru.json
@@ -64,7 +64,6 @@
"config-env-bad": "Была проведена проверка внешней среды.\nВы не можете установить MediaWiki.",
"config-env-php": "Установленная версия PHP: $1.",
"config-env-hhvm": "HHVM $1 установлена.",
- "config-unicode-using-utf8": "Использовать Brion Vibber utf8_normalize.so для нормализации Юникода.",
"config-unicode-using-intl": "Будет использовано [http://pecl.php.net/intl расширение «intl» для PECL] для нормализации Юникода.",
"config-unicode-pure-php-warning": "'''Внимание!''': [http://pecl.php.net/intl расширение intl из PECL] недоступно для нормализации Юникода, будет использоваться медленная реализация на чистом PHP.\nЕсли ваш сайт работает под высокой нагрузкой, вам следует больше узнать о [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations нормализации Юникода].",
"config-unicode-update-warning": "'''Предупреждение''': установленная версия обёртки нормализации Юникода использует старую версию библиотеки [http://site.icu-project.org/ проекта ICU].\nВы должны [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations обновить версию], если хотите полноценно использовать Юникод.",
@@ -77,7 +76,7 @@
"config-magic-quotes-sybase": "'''Проблема: включена опция PHP [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase]!'''\nЭто приводит к непредсказуемой порче вводимых данных.\nУстановка и использование MediaWiki без выключения этой опции невозможно.",
"config-mbstring": "'''Проблема: включена опция PHP [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]!'''\nЭто приводит к ошибкам и непредсказуемой порче вводимых данных.\nУстановка и использование MediaWiki без выключения этой опции невозможно.",
"config-safe-mode": "'''Предупреждение:''' PHP работает в [http://www.php.net/features.safe-mode «безопасном режиме»].\nЭто может привести к проблемам, особенно с загрузкой файлов и вставкой математических формул.",
- "config-xml-bad": "XML-модуль РНР отсутствует.\nMediaWiki не будет работать в этой конфигурации, так как требуется функционал этого модуля.\nЕсли вы работаете в Mandrake, установите PHP XML-пакет.",
+ "config-xml-bad": "Для РНР отсутствует XML-модуль.\nMediaWiki не будет работать в этой конфигурации, так как требуется функционал этого модуля.\nВозможно, вам понадобится установить RPM-пакет php-xml.",
"config-pcre-old": "'''Фатальная ошибка:''' требуется PCRE версии $1 или более поздняя.\nВаш исполняемый файл PHP связан с PCRE версии $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Подробнее].",
"config-pcre-no-utf8": "'''Фатальная ошибка'''. Модуль PCRE для PHP, похоже, собран без поддержки PCRE_UTF8.\nMediaWiki требует поддержки UTF-8 для корректной работы.",
"config-memory-raised": "Ограничение на доступную PHP память (<code>memory_limit</code>) поднято с $1 до $2.",
diff --git a/includes/installer/i18n/sah.json b/includes/installer/i18n/sah.json
index 14233aa8..ab257ddb 100644
--- a/includes/installer/i18n/sah.json
+++ b/includes/installer/i18n/sah.json
@@ -1,5 +1,12 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": [
+ "HalanTul"
+ ]
+ },
+ "config-desc": "MediaWiki инсталлятора",
+ "config-title": "MediaWiki $1 туруоруу",
+ "config-information": "Бу туһунан",
"mainpagetext": "'''«MediaWiki» сөпкө туруорулунна.'''",
"mainpagedocfooter": "Биики программатын туһунан [//meta.wikimedia.org/wiki/Help:Contents справочникка] көрүөххүн сөп.\n\n== Саҕаланыыта ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Конфигурация уларытыытын параметрдара]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki релизтарын почтовай испииһэгэ]"
}
diff --git a/includes/installer/i18n/sco.json b/includes/installer/i18n/sco.json
index 41818934..da33b300 100644
--- a/includes/installer/i18n/sco.json
+++ b/includes/installer/i18n/sco.json
@@ -49,7 +49,6 @@
"config-env-bad": "The environment haes been checked.\nYe canna install MediaWiki.",
"config-env-php": "PHP $1 is instâlled.",
"config-env-hhvm": "HHVM $1 is instawed.",
- "config-unicode-using-utf8": "Uising Brion Vibber's utf8_normalize.so fer Unicode normalization.",
"config-unicode-using-intl": "Uising the [http://pecl.php.net/intl intl PECL extension] fer Unicode normalization.",
"config-unicode-pure-php-warning": "<strong>Warnishment:</strong> The [http://pecl.php.net/intl intl PECL extension] is no available tae haunle Unicode normalisation, fawin back tae slaw pure-PHP implementation.\nGif ye rin ae hei-traffic steid, ye shid read ae wee bit oan [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization].",
"config-unicode-update-warning": "<strong>Warnishment:</strong> The instawed version o the Unicode normalization wrapper uises aen aulder version o [http://site.icu-project.org/ the ICU project's] librie.\nYe shid [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations upgrade] gif ye'r concerned aneat uisin Unicode.",
@@ -57,7 +56,7 @@
"config-outdated-sqlite": "<strong>Warnishment:</strong> ye have SQLite $1, this is lower than minimum required version $2. SQLite will be onavailable.",
"config-no-fts3": "<strong>Warnishment:</strong> SQLite is compiled wioot the [//sqlite.org/fts3.html FTS3 module], rake features will be onavailable oan this backend.",
"config-register-globals-error": "<strong>Mistak: PHP's <code>[http://php.net/register_globals register_globals]</code> optie is enablit.\nIt maun be disablit tae keep gaun wi the instawation.</strong>\nSee [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] fer help oan hou tae dae sae.",
- "config-magic-quotes-gpc": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] is active!</strong>\nThis option corrupts data input unpredictably.\nYe cannae install or uise MediaWiki unless this option is disabled.",
+ "config-magic-quotes-gpc": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] is active!</strong>\nThis optie corrupts data input onpredeectablie.\nYe cannae install or uise MediaWiki onless this optie is disabled.",
"config-magic-quotes-runtime": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] is active!'</strong>\nThis optie rots data input onpredictably.\nYe canna install or uise MediaWiki onless this optie is disabled.",
"config-magic-quotes-sybase": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] is active!</strong>\nThis optie rots data input onpredictably.\nYe canna install or uise MediaWiki onless this optie is disabled.",
"config-mbstring": "<strong>Fatal: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] is active!</strong>\nThis optie causes mistaks an can rot data onpredictably.\nYe canna install or uise MediaWiki onless this optie is disabled.",
diff --git a/includes/installer/i18n/sd.json b/includes/installer/i18n/sd.json
new file mode 100644
index 00000000..02e97978
--- /dev/null
+++ b/includes/installer/i18n/sd.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sindhu"
+ ]
+ },
+ "config-xml-bad": "PHP جو XML ماڊيول کٽل آهي. ميڊيا وڪيءَ کي هن فنڪشن ۾ ماڊيول گھربل آهن ۽ ترتيب يا ڪنفيگيوريشن ۾ ڪم نه ڪندي. \nتوهان کي گھرجي ته php-xml RPM پيڪيج انسٽال ڪريو."
+}
diff --git a/includes/installer/i18n/sk.json b/includes/installer/i18n/sk.json
index a22f94d6..aac1615d 100644
--- a/includes/installer/i18n/sk.json
+++ b/includes/installer/i18n/sk.json
@@ -3,7 +3,8 @@
"authors": [
"Kusavica",
"KuboF",
- "Sudo77(new)"
+ "Sudo77(new)",
+ "Hromoslav"
]
},
"config-desc": "Inštalátor pre MediaWiki",
@@ -50,6 +51,7 @@
"config-missing-db-name": "Musíte zadať hodnotu pre \"{{int:config-db-name}}\".",
"config-missing-db-host": "Musíte zadať hodnotu pre \"{{int:config-db-host}}\".",
"config-missing-db-server-oracle": "Musíte zadať hodnotu pre \"{{int:config-db-host-oracle}}\".",
+ "config-ns-generic": "Projekt",
"config-admin-box": "Účet správcu",
"config-admin-name": "Vaše používateľské meno:",
"config-admin-password": "Heslo:",
@@ -64,6 +66,7 @@
"config-optional-skip": "Už ma to nudí, proste nainštaluj wiki.",
"config-profile-wiki": "Otvorená wiki",
"config-profile-private": "Súkromná wiki",
+ "config-license-pd": "Voľné dielo",
"config-email-settings": "Nastavenia e-mailu",
"config-install-step-done": "hotovo",
"config-install-step-failed": "zlyhalo",
diff --git a/includes/installer/i18n/sq.json b/includes/installer/i18n/sq.json
index f3bb6dd9..7f0ad67f 100644
--- a/includes/installer/i18n/sq.json
+++ b/includes/installer/i18n/sq.json
@@ -1,5 +1,43 @@
{
- "@metadata": [],
+ "@metadata": {
+ "authors": [
+ "Ammartivari"
+ ]
+ },
+ "config-desc": "Instaluesi për MediaWiki",
+ "config-title": "Instalimi MediaWiki $1",
+ "config-information": "Të dhëna",
+ "config-your-language": "Gjuha juaj:",
+ "config-your-language-help": "Zgjidhni një gjuhë për ta përdorur gjatë procesit të instalimit.",
+ "config-wiki-language": "Gjuha wiki:",
+ "config-wiki-language-help": "Zgjidhni gjuhën në të cilën wiki do të jetë kryesisht e shkruar.",
+ "config-back": "← Prapa",
+ "config-continue": "Para →",
+ "config-page-language": "Gjuha",
+ "config-page-welcome": "Mirë se vini në MediaWiki!",
+ "config-page-dbconnect": "Lidhuni me bazën e të dhënave",
+ "config-page-dbsettings": "Cilësimet e bazës së të dhënave",
+ "config-page-name": "Emri",
+ "config-page-options": "Opcionet",
+ "config-page-install": "Instalo",
+ "config-page-complete": "Përfundoi!",
+ "config-page-restart": "Rinisni instalimin",
+ "config-page-copying": "Duke kopjuar",
+ "config-restart": "Po, rinisni",
+ "config-xcache": "[http://xcache.lighttpd.net/ XCache] u instalua",
+ "config-apc": "[http://www.php.net/apc APC] u instalua",
+ "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] u instalua",
+ "config-diff3-bad": "GNU diff3 nuk u gjet.",
+ "config-db-wiki-settings": "Identifikoni këtë wiki",
+ "config-db-name": "Emri i bazës së të dhënave:",
+ "config-admin-box": "Llogari administruesi",
+ "config-admin-name-blank": "Shkruani nofkën e një administruesi.",
+ "config-admin-password-blank": "Shkruani një fjalëkalim për llogarinë e administruesit.",
+ "config-admin-email": "Email adresa:",
+ "config-license-pd": "Domeni publik",
+ "config-logo": "URL-ja i logos:",
+ "config-install-tables": "Duke krijuar tabela",
+ "config-help": "ndihmë",
"mainpagetext": "'''MediaWiki software u instalua me sukses.'''",
"mainpagedocfooter": "Për më shumë informata rreth përdorimit të softwerit wiki , ju lutem shikoni [//meta.wikimedia.org/wiki/Help:Contents dokumentacionin përkatës].\n\n== Sa për fillim==\n* [//www.mediawiki.org/wiki/Help:Configuration_settings Parazgjedhjet e MediaWiki-t]\n* [//www.mediawiki.org/wiki/Help:FAQ Pyetjet e shpeshta rreth MediaWiki-t]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Njoftime rreth MediaWiki-t]"
}
diff --git a/includes/installer/i18n/sr-ec.json b/includes/installer/i18n/sr-ec.json
index c63ac008..95dad252 100644
--- a/includes/installer/i18n/sr-ec.json
+++ b/includes/installer/i18n/sr-ec.json
@@ -4,7 +4,8 @@
"Rancher",
"Михајло Анђелковић",
"Milicevic01",
- "Aktron"
+ "Aktron",
+ "Сербијана"
]
},
"config-desc": "Инсталација за Медијавики",
@@ -37,6 +38,7 @@
"config-help-restart": "Желите ли да обришете све сачуване податке које сте унели и поново покренете инсталацију?",
"config-restart": "Да, покрени поново",
"config-env-php": "PHP $1 је инсталиран.",
+ "config-env-hhvm": "HHVM $1 је инсталиран.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] је инсталиран",
"config-apc": "[http://www.php.net/apc APC] је инсталиран",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] је инсталиран",
@@ -44,7 +46,6 @@
"config-db-host": "Хост базе података",
"config-db-name": "Назив базе података:",
"config-db-password": "Лозинка за базу података:",
- "config-db-password-empty": "Унесите лозинку за новог корисника базе података: ($1).\n\nМада је могуће отворити налоге без лозинки, то се не препоручује.",
"config-type-mysql": "MySQL (или компактибилан)",
"config-type-postgres": "PostgreSQL",
"config-type-sqlite": "SQLite",
diff --git a/includes/installer/i18n/su.json b/includes/installer/i18n/su.json
index b8f131ee..ca4a5ef6 100644
--- a/includes/installer/i18n/su.json
+++ b/includes/installer/i18n/su.json
@@ -4,6 +4,13 @@
"Kandar"
]
},
+ "config-desc": "Panginstal MediaWiki",
+ "config-title": "Instalasi MediaWiki $1",
+ "config-information": "Émbaran",
+ "config-localsettings-upgrade": "Hiji berkas <code>LocalSettings.php</code> kapanggih.\nPikeun apgréd ngamutahirkeun ieu instalasi, mangga asupkeun sandi <code>$wgUpgradeKey</code> kana kotak di handap.\nAnjeun bisa manggihan sandina di <code>LocalSettings.php</code>.",
+ "config-localsettings-cli-upgrade": "Hiji berkas <code>LocalSettings.php</code> geus kabaca.\nPikeun apgréd ieu instalasi, mangga jalankeun <code>update.php</code>",
+ "config-localsettings-key": "Sandi apgréd:",
+ "config-localsettings-badkey": "Sandi anu diasupkeun salah.",
"mainpagetext": "<strong>MediaWiki geus réngsé diinstal.</strong>",
"mainpagedocfooter": "Mangga tingal ''[//meta.wikimedia.org/wiki/MediaWiki_localisation documentation on customizing the interface]'' jeung [//meta.wikimedia.org/wiki/MediaWiki_User%27s_Guide Tungtunan Pamaké] pikeun pitulung maké jeung konfigurasi."
}
diff --git a/includes/installer/i18n/sv.json b/includes/installer/i18n/sv.json
index 87ac7a53..68b26959 100644
--- a/includes/installer/i18n/sv.json
+++ b/includes/installer/i18n/sv.json
@@ -54,7 +54,6 @@
"config-env-bad": "Miljön har kontrollerats.\nDu kan inte installera MediaWiki.",
"config-env-php": "PHP $1 är installerat.",
"config-env-hhvm": "HHVM $1 är installerat.",
- "config-unicode-using-utf8": "Använder Brion Vibbers utf8_normalize.so för Unicode-normalisering.",
"config-unicode-using-intl": "Använder [http://pecl.php.net/intl intl PECL-tillägget] för Unicode-normalisering.",
"config-unicode-pure-php-warning": "'''Varning:''' [http://pecl.php.net/intl intl PECL-tillägget] är inte tillgängligt för att hantera Unicode-normalisering, faller tillbaka till en långsamt implementering i ren PHP.\nOm du driver en högtrafikerad webbplats bör du läsa lite om [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-normalisering].",
"config-unicode-update-warning": "'''Varning:''' Den installerade versionen av Unicode-normaliserings \"wrappern\" använder en äldre version av [http://site.icu-project.org/ ICU projektets] bibliotek.\nDu bör [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations uppgradera] om är intresserad av att använda Unicode.",
@@ -67,7 +66,7 @@
"config-magic-quotes-sybase": "'''Kritiskt: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] är aktiv!'''\nDetta alternativ korrumperar inmatad data oförutsägbart.\nDu kan inte installera eller använda MediaWiki om detta alternativ är aktiverat.",
"config-mbstring": "'''Kritiskt: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] är aktiv!'''\nDetta alternativ orsakar fel och kan korrumpera data oförutsägbart.\nDu kan inte installera eller använda MediaWiki om detta alternativ är aktiverat.",
"config-safe-mode": "''' Varning:''' PHP:s [http://www.php.net/features.safe-mode felsäkra läge] är aktivt.\nDet kan orsaka problem, särskilt om du använder filuppladdningar och <code>math</code>-stöd.",
- "config-xml-bad": "PHP:s XML-modul saknas.\nMediaWiki kräver funktioner i denna modul och kommer inte att fungera i den här konfigurationen.\nOm du kör Mandrake, installera php-xml-paketet.",
+ "config-xml-bad": "PHP:s XML-modul saknas.\nMediaWiki kräver funktioner i denna modul och kommer inte att fungera i den här konfigurationen.\nDu kan behöva installera RPM-paketet för php-xml.",
"config-pcre-old": "'''Kritiskt:''' PCRE $1 eller senare krävs.\nDin PHP-binär är länkad till PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Mer information].",
"config-pcre-no-utf8": "'''Kritiskt:''' PHP:s PCRE-modul verkar vara kompilerat utan PCRE_UTF8-stöd.\nMediaWiki kräver stöd för UTF-8 för att fungera korrekt.",
"config-memory-raised": "PHPs <code>memory_limit</code> är $1, ökad till $2.",
@@ -107,8 +106,6 @@
"config-db-install-account": "Användarkonto för installation",
"config-db-username": "Databas-användarnamn:",
"config-db-password": "Databas-lösenord:",
- "config-db-password-empty": "Ange ett lösenord för den nya databasanvändaren: $1.\nÄven om det kan vara möjligt att skapa användare utan lösenord är det inte säkert.",
- "config-db-username-empty": "Du måste ange ett värde för \"{{int:config-db-username}}\"",
"config-db-install-username": "Ange det användarnamn som ska används för att ansluta till databasen under installationsprocessen.\nDetta är inte användarnamnet för ditt MediaWiki-konto; detta är användarnamnet för din databas.",
"config-db-install-password": "Ange det lösenord som ska användas för att ansluta till databasen under installationsprocessen.\nDetta är inte lösenordet för ditt MediaWiki-konto; detta är lösenordet för din databas.",
"config-db-install-help": "Ange användarnamnet och lösenordet som kommer att användas för att ansluta till databasen under installationsprocessen.",
diff --git a/includes/installer/i18n/tokipona.json b/includes/installer/i18n/tokipona.json
new file mode 100644
index 00000000..348380f7
--- /dev/null
+++ b/includes/installer/i18n/tokipona.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robin0van0der0vliet"
+ ]
+ },
+ "config-page-language": "toki"
+}
diff --git a/includes/installer/i18n/tr.json b/includes/installer/i18n/tr.json
index e9b05cf2..c3fb23b4 100644
--- a/includes/installer/i18n/tr.json
+++ b/includes/installer/i18n/tr.json
@@ -8,7 +8,12 @@
"Trncmvsr",
"Sayginer",
"Trockya",
- "Aşilleus"
+ "Aşilleus",
+ "Nighteagle2000",
+ "Sadrettin",
+ "Captantrips",
+ "Stultiwikia",
+ "Meelo"
]
},
"config-desc": "MediaWiki yükleyicisi",
@@ -53,10 +58,18 @@
"config-env-good": "Ortam kontrol edildi.\nMediaWiki'yi kurabilirsiniz.",
"config-env-bad": "Ortam kontrol edildi.\nMediaWiki'yi kuramazsınız.",
"config-env-php": "PHP $1 kurulu.",
- "config-unicode-using-utf8": "Unikod normalleştirmesi için Brion Vibber'in utf8_normalize.so kullanılıyor.",
+ "config-env-hhvm": "HHVM $1 kuruldu",
"config-unicode-using-intl": "Unikod normalleştirmesi için [http://pecl.php.net/intl intl PECL uzantısı] kullanılıyor.",
- "config-xml-bad": "PHP 'nin XML modülü eksik.\nMediaWiki bu modüldeki fonksiyonlara ihtiyaç duyar ve şimdiki kurulumda çalışmayacaktır.\nMandrake kullanıyorsanız php-xml paketini yükleyin.",
+ "config-unicode-pure-php-warning": "<strong>Uyarı:</strong> [http://pecl.php.net/intl intl PECL uzantısı] Unicode normalizasyonunu kaldırabilecek şekilde müsait değil; bu yüzden sayfa saf PHP uygulamasına dönüyor. Yüksek trafik alan bir sayfa çalıştırıyorsanız, [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalizasyonu] ile ilgili biraz bilgi almalısınız.",
+ "config-outdated-sqlite": "<strong>Uyarı:</strong> Elinizde SQLite $1 var. Gerekli minimum sürüm: $2. SQLite kullanılamayacaktır.",
+ "config-no-fts3": "<strong>Uyarı:</strong> SQLite [//sqlite.org/fts3.html FTS3 modülü] olmadan derlendi, bu arkayüzde arama özellikleri kullanılamayacaktır.",
+ "config-safe-mode": "<strong>Uyarı:</strong> PHP'nin [http://www.php.net/features.safe-mode güvenli modu] aktif.\nDosya yüklemesi kullanılıyorsa veya <code>matematik kodu</code> desteğinde sıkıntı çıkarabilir.",
+ "config-xml-bad": "PHP 'nin XML modülü eksik.\nMediaWiki bu modüldeki fonksiyonlara ihtiyaç duyar ve şimdiki kurulumda çalışmayacaktır.\nPhp-xml RPM paketini yüklemeniz gerekebilir.",
"config-pcre-old": "<strong>Ağır hata:</strong> PCRE $1 veya daha üst versiyon gerekli.\nSizin PHP kurulumunuz PCRE $2 ile bağlı.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Daha fazla bilgi].",
+ "config-memory-raised": "PHP'nin <code>memory_limit</code> (hafıza sınırı) değeri $1, $2'ye yükseltildi.",
+ "config-memory-bad": "<strong>Uyarı:</strong> PHP'nin <code>memory_limit</code> (hafıza sınırı) değeri $1.\nBu büyük ihtimalle çok düşük.\nKurulum başarısız olabilir!",
+ "config-ctype": "<strong>Ölümcül:</strong> PHP [http://www.php.net/manual/en/ctype.installation.php Ctype uzantısı] desteği ile beraber derlenmelidir.",
+ "config-iconv": "<strong>Ölümcül:</strong> PHP [http://www.php.net/manual/en/iconv.installation.php iconv uzantısı] desteği ile beraber derlenmelidir.",
"config-xcache": "[http://xcache.lighttpd.net/ XCache] kurulu",
"config-apc": "[http://www.php.net/apc APC] kurulu",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] kurulu",
@@ -66,18 +79,29 @@
"config-git": "Sürüm kontrol yazılımı Git bulundu: <code>$1</code>.",
"config-git-bad": "Sürüm kontrol yazılımı Git bulunamadı.",
"config-imagemagick": "ImageMagick bulundu: <code>$1</code>.\nEğer yüklemeleri etkinleştirirseniz, küçük resimler etkinleştirilecektir.",
+ "config-gd": "Kurulu GD grafik kütüphanesi bulundu.\nDosya yüklemeyi açarsanız miniboy resim görüntüleme açılacaktır.",
+ "config-no-scaling": "GD kütüphanesi veya ImageMagick bulunamadı.\nMiniboy resim görüntüleme devre dışı kalacak.",
+ "config-no-uri": "<strong>Hata:</strong> Mevcut URI tespit edilemedi.\nKurulum iptal edildi.",
+ "config-no-cli-uri": "<strong>Uyarı:</strong> Herhangi bir <code>--scriptpath</code> belirlenmemiş, varsayılan kullanılıyor: <code>$1</code>.",
+ "config-using-server": "Sunucu adı olarak \"<nowiki>$1</nowiki>\" kullanılıyor.",
+ "config-using-uri": "Sunucu URLsi olarak \"<nowiki>$1$2</nowiki>\" kullanılıyor.",
"config-db-type": "Veritabanı tipi:",
"config-db-host": "Veritabanı sunucusu:",
"config-db-host-help": "Veritabanı sunucunuz farklı bir sunucu üzerinde ise, ana bilgisayar adını veya IP adresini buraya girin.\n\nPaylaşılan ağ barındırma hizmeti kullanıyorsanız, barındırma sağlayıcınız size doğru bir ana bilgisayar adını kendi belgelerinde vermiştir.\n\nEğer MySQL kullanan bir Windows sunucusuna yükleme yapıyorsanız, sunucu adı olarak \"localhost\" kullanırsanız çalışmayabilir. Çalışmazsa, yerel IP adresi için \"127.0.0.1\" deneyin.\n\nPostgreSQL kullanıyorsanız, bu alanı bir Unix soketi ile bağlanmak için boş bırakın.",
"config-db-host-oracle": "Veritabanı TNS:",
"config-db-wiki-settings": "Bu wikiyi tanımla",
"config-db-name": "Veritabanı adı:",
+ "config-db-name-help": "Vikinizi tanımlayan bir isim seçin.\nBoşluk karakteri içermemelidir.\n\nPaylaşılan bir web hosting servisi kullanıyorsanız, tedarikçiniz size ya kullanmanız için bir veritabanı ismi verecek ya da bir kontrol paneli vasıtasıyla sizin oluşturmanıza izin verecektir.",
"config-db-name-oracle": "Veritabanı şeması:",
"config-db-install-account": "Yükleme için kullanıcı hesabı",
"config-db-username": "Veritabanı kullanıcı adı:",
"config-db-password": "Veritabanı parolası:",
+ "config-db-password-empty": "Şu yeni veritabanı kullanıcısı için bir parola belirleyin: $1\nParolası olmayan hesaplar yaratmak mümkün olabilirse de, güvenli değildir.",
"config-db-username-empty": "\"{{int:config-db-username}}\" için bir değer girmelisiniz.",
"config-db-install-username": "Yükleme sırasında veritabanına bağlanmak için kullanılan kullanıcı adını girin.\nBu MediaWiki hesabının kullanıcı adı değildir; Bu veritabanın kullanıcı adıdır.",
+ "config-db-install-password": "Kurulum işlemi boyunca veritabanına bağlanmak için kullanılacak şifreyi girin.\nBu şifre MediaWiki hesap şifresi değil, veritabanınızın şifresidir.",
+ "config-db-install-help": "Kurulum işlemi boyunca veritabanına bağlanmak için kullanıcı adı ve şifre giriniz.",
+ "config-db-account-lock": "Normal çalışma sırasında aynı kullanıcı adı ve şifreyi kullanınız.",
"config-db-wiki-account": "Kullanıcı hesabı için normal işlem",
"config-db-prefix": "Veritabanı Tablo öneki:",
"config-db-charset": "Veritabanı karakter seti",
@@ -87,9 +111,13 @@
"config-mysql-old": "MySQL $1 veya daha yenisi gerekir. Sende bulunan $2 .",
"config-db-port": "Veritabanı bağlantı noktası:",
"config-db-schema": "MediaWiki için şema:",
+ "config-db-schema-help": "Bu şema yeterli olacaktır.\nEğer gerçekten ihtiyaç duyarsanız değiştirin.",
"config-pg-test-error": "Veritabanıyla bağlantı kurulamıyor ''' $1 ''':$2",
"config-sqlite-dir": "SQLite veri dizini",
"config-oracle-def-ts": "Varsayılan tablo alanı:",
+ "config-oracle-temp-ts": "Geçici tablo alanı:",
+ "config-type-mysql": "MySQL (veya uyumlu)",
+ "config-type-mssql": "Microsoft SQL Server",
"config-header-mysql": "MySQL ayarları",
"config-header-postgres": "PostgreSQL ayarları",
"config-header-sqlite": "SQLite ayarları",
@@ -97,21 +125,31 @@
"config-header-mssql": "Microsoft SQL Server ayarları",
"config-invalid-db-type": "Geçersiz veritabanı türü",
"config-missing-db-name": "\"Veritabanı adı\" için bir değer girmelisiniz",
- "config-missing-db-host": "\"Veritabanı host\" için bir değer girmelisiniz",
- "config-missing-db-server-oracle": "\"Veritabanının TNS\" için bir değer girmelisiniz",
+ "config-missing-db-host": "\"{{int:config-db-host}}\" için bir değer girmelisiniz.",
+ "config-missing-db-server-oracle": "\"{{int:config-db-host-oracle}}\" için bir değer girmelisiniz",
"config-invalid-db-name": "Geçersiz veritabanı adı \" $1 \".\nSadece ASCII harf (a-z, A-Z), rakamların (0-9), alt çizgi (_) ve tire (-) kullanın.",
"config-connection-error": "$1.\n\nSunucuyu kontrol edin, kullanıcı adı ve parolayı denetleyin ve yeniden deneyin.",
"config-invalid-schema": "Geçersiz şema MediaWiki için \" $1 \".\nYalnızca ASCII harf (a-z, A-Z), rakamların (0-9) ve alt çizgi (_) kullanın.",
+ "config-db-sys-create-oracle": "Kurulum yeni hesap oluştururken sadece SYSDBA hesabı kullanımını destekliyor.",
"config-db-sys-user-exists-oracle": "Kullanıcı hesabı \" $1 \" zaten var. SYSDBA sadece yeni bir hesap oluşturmak için kullanılabilir.",
"config-postgres-old": "PostgreSQL $1 veya daha yenisi gerekir. Sende $2 sürümü var.",
+ "config-mssql-old": "Microsoft SQL Server $1 veya daha yükseği gerekli. Sizdeki sürüm: $2.",
+ "config-sqlite-name-help": "Wiki'nizi tanımlayan bir ad seçin.\nBoşluk ya da tire kullanmayın.\nBu isim SQLite veri dosyası için kullanılacaktır.",
"config-sqlite-mkdir-error": "Veri dizini oluşturulurken bir hata oluştu \" $1 \".\nKonumu denetleyin ve yeniden deneyin.",
+ "config-sqlite-dir-unwritable": "Bu dizine yazılamadı: \"$1\"\nİzinleri değiştirerek tekrar deneyiniz.",
"config-sqlite-connection-error": "$1.\n\nVeri dizini ve veritabanı adını denetleyin ve yeniden deneyin.",
"config-sqlite-readonly": "Dosya <code>$1</code> yazılabilir değil.",
"config-sqlite-cant-create-db": "Veritabanı dosyası oluşturamadı <code>$1</code> .",
+ "config-sqlite-fts3-downgrade": "PHP, FTS3 desteğinden yoksun, tabloların sürümü düşürülüyor.",
+ "config-upgrade-done-no-regenerate": "Güncelleme tamam.\n\nVikinizi kullanmaya [$1 başlayabilrsiniz].",
"config-regenerate": "LocalSettings.php yi yeniden oluştur →",
"config-show-table-status": "<code>SHOW TABLE STATUS</code>sorgu başarısız!",
+ "config-unknown-collation": "<strong>Uyarı:</strong> Veritabanı tanınmayan bir harmanlama kullanıyor.",
+ "config-db-web-account": "Ağ erişimi için veritabanı hesabı",
+ "config-db-web-help": "Ağ sunucusunun olağan wiki işlemleri için veritabanına bağlanırken kullanacağı kullanıcı adı ve parolayı seçin.",
"config-db-web-account-same": "Yükleme için aynı hesabı kullan",
"config-db-web-create": "Eğer oluşturulmuş hesap yoksa yeni hesap oluştur",
+ "config-db-web-no-create-privs": "Kurulum için belirlediğiniz hesap, hesap yaratımı için gerekli izinlere sahip değil.\nBurada belirttiğiniz hesap halihazırda var olmalı.",
"config-mysql-engine": "Depolama motoru:",
"config-mysql-innodb": "InnoDB",
"config-mysql-myisam": "MyISAM",
@@ -119,9 +157,11 @@
"config-mysql-binary": "İkili",
"config-mysql-utf8": "UTF-8",
"config-mssql-auth": "Kimlik doğrulama türü:",
+ "config-mssql-install-auth": "Kurulum işlemi sırasında veritabanına bağlanmak için kullanılacak doğrulama türünü seçin.\n\"{{int:config-mssql-windowsauth}}\"'ı seçerseniz,ağ sunucusu olarak çalışan kullanıcının kimlik bilgileri kullanılacaktır.",
"config-mssql-sqlauth": "SQL Server kimlik doğrulaması",
"config-mssql-windowsauth": "Windows Kimlik Doğrulama",
"config-site-name": "Wiki adı:",
+ "config-site-name-help": "Bu tarayıcının başlık çubuğunda ve diğer yerlerde görünecek.",
"config-site-name-blank": "Bir site adı girin.",
"config-project-namespace": "Proje isim alanı:",
"config-ns-generic": "Proje",
@@ -143,6 +183,8 @@
"config-admin-email-help": "Wiki'de diğer kullanıcılardan e-posta almak, parolanızı sıfırlamak ve sizin izlediğiniz sayfalarda yapılan değişikliklerin bildirilmesini sağlamak için e-posta adresinizi girin. Bu alanı boş bırakabilirsiniz.",
"config-admin-error-user": "Bir yönetici adı ile oluşturma sırasında iç hata \"<nowiki> $1 </nowiki>\".",
"config-admin-error-bademail": "Geçersiz e-posta adresi girdiniz.",
+ "config-subscribe": "[https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Sürüm duyuruları e-posta listesi]ne abone olun.",
+ "config-subscribe-noemail": "Sürüm duyuruları e-posta listesine herhangi bir eposta adresi belirtmeden abone olmaya çalıştınız.\nLütfen abone olmak istiyorsanız bir posta adresi belirtiniz.",
"config-almost-done": "Neredeyse bitti\nŞimdi kalan yapılandırmaları atlayın ve wikiyi şimdi yükleyin.",
"config-optional-continue": "Bana daha fazla soru sor.",
"config-optional-skip": "Şimdiden sıkıldım, sadece wikiyi yükle.",
@@ -173,6 +215,7 @@
"config-advanced-settings": "Gelişmiş yapılandırma",
"config-memcached-servers": "Memcached sunucuları:",
"config-extensions": "Uzantılar",
+ "config-skins": "Görünümler",
"config-install-step-done": "Yapıldı",
"config-install-step-failed": "Başarısız",
"config-install-database": "Veritabanı ayarlama",
diff --git a/includes/installer/i18n/tt-cyrl.json b/includes/installer/i18n/tt-cyrl.json
index 16f2e54a..c4a230c0 100644
--- a/includes/installer/i18n/tt-cyrl.json
+++ b/includes/installer/i18n/tt-cyrl.json
@@ -2,9 +2,14 @@
"@metadata": {
"authors": [
"KhayR",
- "Seb35"
+ "Seb35",
+ "Ильнар"
]
},
+ "config-back": "← Артка",
+ "config-continue": "Киләсе →",
+ "config-page-language": "Тел",
+ "config-page-welcome": "MediaWiki проектына рәхим итегез!",
"mainpagetext": "«MediaWiki» уңышлы куелды.",
"mainpagedocfooter": "Бу вики турында мәгълүматны [//meta.wikimedia.org/wiki/Help:Contents биредә] табып була.\n\n== Кайбер файдалы ресурслар ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Көйләнмәләр исемлеге (инг.)];\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki турында еш бирелгән сораулар һәм җаваплар (инг.)];\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki'ның яңа версияләре турында хәбәрләр яздырып алу];\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]."
}
diff --git a/includes/installer/i18n/udm.json b/includes/installer/i18n/udm.json
index 8a46212a..1d4867d8 100644
--- a/includes/installer/i18n/udm.json
+++ b/includes/installer/i18n/udm.json
@@ -1,8 +1,18 @@
{
"@metadata": {
"authors": [
- "Andrewboltachev"
+ "Andrewboltachev",
+ "AlnashPiyash2"
]
},
+ "config-title": "MediaWiki $1 пуктон",
+ "config-your-language": "Тӥляд кылды:",
+ "config-back": "← Берлань",
+ "config-continue": "Азьлань →",
+ "config-page-language": "Кыл",
+ "config-page-options": "Настройкаос",
+ "config-page-complete": "Быдэстэмын!",
+ "config-page-readme": "Лыдӟы монэ",
+ "config-page-copying": "Лицензия",
"mainpagetext": "'''MediaWiki движок азинлыко пуктэмын.'''"
}
diff --git a/includes/installer/i18n/uk.json b/includes/installer/i18n/uk.json
index e0304433..b4a03cbb 100644
--- a/includes/installer/i18n/uk.json
+++ b/includes/installer/i18n/uk.json
@@ -56,11 +56,10 @@
"config-env-bad": "Було проведено перевірку середовища. Ви не можете встановити MediaWiki.",
"config-env-php": "Встановлено версію PHP: $1.",
"config-env-hhvm": "HHVM $1 встановлено.",
- "config-unicode-using-utf8": "Використовувати utf8_normalize.so Брайона Віббера для нормалізації Юнікоду.",
"config-unicode-using-intl": "Використовувати [http://pecl.php.net/intl міжнародне розширення PECL] для нормалізації Юнікоду.",
"config-unicode-pure-php-warning": "'''Увага''': [http://pecl.php.net/intl міжнародне розширення PECL] не може провести нормалізацію Юнікоду.\nЯкщо ваш сайт має високий трафік, вам варто почитати про [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations нормалізацію Юнікоду].",
"config-unicode-update-warning": "'''Увага''': Встановлена версія обгортки нормалізації Юнікоду використовує стару версію бібліотеки [http://site.icu-project.org/ проекту ICU].\nВи маєте [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations оновити версію], якщо плануєте повноцінно використовувати Юнікод.",
- "config-no-db": "Не вдалося знайти відповідний драйвер бази даних! Вам необхідно встановити драйвер бази даних для PHP. Підтримуються такі типи баз даних: $1.\n\nЯкщо ви скомпілювали PHP самостійно, переналаштуйте його з включенням клієнта бази даних, наприклад за допомогою <code>./configure --with-mysqli</code>.\n\nЯкщо установлено PHP з пакетів Debian або Ubuntu, тоді ви також повинні встановити, наприклад, пакунок <code>php5-mysql</code>.",
+ "config-no-db": "Не вдалося знайти потрібний драйвер бази даних! Вам необхідно встановити драйвер бази даних для PHP. Підтримуються {{PLURAL:$2|такий тип|такі типи}} баз даних: $1.\n\nЯкщо ви скомпілювали PHP самостійно, переналаштуйте його з увімкненим клієнтом бази даних, наприклад за допомогою <code>./configure --with-mysqli</code>.\n\nЯкщо установлено PHP з пакетів Debian або Ubuntu, тоді ви також повинні встановити, наприклад, пакунок <code>php5-mysql</code>.",
"config-outdated-sqlite": "'''Увага''': у Вас встановлена версія SQLite $1, а це нижче, ніж мінімально необхідна версія $2. SQLite буде недоступним.",
"config-no-fts3": "'''Увага''': SQLite зібраний без [//sqlite.org/fts3.html модуля FTS3], функції пошуку не будуть працювати у цій системі.",
"config-register-globals-error": "<strong>Помилка: Опція PHP <code>[http://php.net/register_globals register_globals]</code> увімкнена.\nЩоб продовжити це встановлення, її треба вимкнути.</strong>\nДив. довідку, як це зробити, на [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals].",
@@ -69,7 +68,7 @@
"config-magic-quotes-sybase": "'''Проблема: Опція PHP [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] увімкнена!'''\nЦя опція призводить до непередбачуваного пошкодження даних.\nВи не можете встановити і використовувати MediaWiki, поки не буде вимкнено цю опцію.",
"config-mbstring": "'''Проблема: Опція PHP [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] увімкнена!'''\nЦя опція призводить до непередбачуваного пошкодження даних.\nВи не можете встановити і використовувати MediaWiki, поки не буде вимкнено цю опцію.",
"config-safe-mode": "'''Увага:''' Опція PHP [http://www.php.net/features.safe-mode «безпечний режим»] увімкнена.\nЦе може спричинити проблеми, зокрема із завантаженням файлів та вставкою математичних формул.",
- "config-xml-bad": "XML-модуть PHP відсутній.\nMediaWiki необхідні його функції, без цього модуля вона працювати не буде.\nЯкщо Ви використовуєте Mandrake, встановіть php-xml пакет.",
+ "config-xml-bad": "XML-модуть PHP відсутній.\nMediaWiki необхідні його функції, без цього модуля вона працювати не буде.\nВам може знадобитися встановити php-xml RPM пакет.",
"config-pcre-old": "'''Фатальна помилка:''' потрібно PCRE версії $1 або пізнішої.\nВаш виконуваний файл PHP пов'язаний з PCRE версії $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Подробиці].",
"config-pcre-no-utf8": "'''Помилка''': PCRE-модуть PHP, вочевидь, було зібрано без підтримки PCRE_UTF8.\nMediaWiki вимагає підтримку UTF-8 для коректної роботи.",
"config-memory-raised": "Обмеження пам'яті PHP (<code>memory_limit</code>) $1, піднято до $2.",
@@ -109,8 +108,6 @@
"config-db-install-account": "Обліковий запис користувача для встановлення",
"config-db-username": "Ім'я користувача бази даних:",
"config-db-password": "Пароль бази даних:",
- "config-db-password-empty": "Будь ласка, введіть пароль для нового користувача бази даних: $1.\nХоча можна створювати користувачів без паролів, це не є безпечним.",
- "config-db-username-empty": "Ви повинні ввести значення для \"{{int:config-db username}}\"",
"config-db-install-username": "Введіть ім'я користувача, яке буде використано для підключення до бази даних під час процесу встановлення.\nЦе не ім'я користувача облікового запису MediaWiki; це ім'я користувача для Вашої бази даних.",
"config-db-install-password": "Введіть пароль, який буде використано для підключення до бази даних під час процесу встановлення.\nЦе не пароль облікового запису MediaWiki; це пароль для Вашої бази даних.",
"config-db-install-help": "Введіть ім'я користувача і пароль, які буде використано для підключення до бази даних у процесі встановлення.",
@@ -202,9 +199,9 @@
"config-ns-site-name": "Те ж саме, що й назва вікі: $1",
"config-ns-other": "Інше (вкажіть)",
"config-ns-other-default": "MyWiki",
- "config-project-namespace-help": "За прикладом Вікіпедії, чимало вікі тримають свої сторінки правил окремо від сторінок основного вмісту, у \"'''просторі імен проекту'''\".\nУсі назви сторінок у цьому просторі імен починаються з певного префікса, який Ви можете вказати тут.\nТрадиційно цей префікс виводиться з назви вікі, але не може містити знаки пунктуація, як-то \"#\" чи \":\".",
- "config-ns-invalid": "Вказаний простір імен \"<nowiki>$1</nowiki>\" не припустимий.\nВкажіть інший простір імен проекту.",
- "config-ns-conflict": "Вказаний простір імен \"<nowiki>$1</nowiki>\" конфліктує зі стандартним простором імен MediaWiki.\nВкажіть інший простір імен проекту.",
+ "config-project-namespace-help": "За прикладом Вікіпедії, чимало вікі тримають свої сторінки правил окремо від сторінок основного вмісту, у «'''просторі назв проекту'''».\nУсі назви сторінок у цьому просторі назв починаються з певного префікса, який Ви можете вказати тут.\nЗазвичай цей префікс виводиться з назви вікі, але не може містити знаки пунктуації, як-то «#» чи «:».",
+ "config-ns-invalid": "Вказаний простір назв «<nowiki>$1</nowiki>» не припустимий.\nВкажіть інший простір назв проекту.",
+ "config-ns-conflict": "Вказаний простір назв «<nowiki>$1</nowiki>» конфліктує зі стандартним простором назв MediaWiki.\nВкажіть інший простір назв проекту.",
"config-admin-box": "Обліковий запис адміністратора",
"config-admin-name": "Ваше ім'я користувача:",
"config-admin-password": "Пароль:",
diff --git a/includes/installer/i18n/vi.json b/includes/installer/i18n/vi.json
index 30342aa3..3923f7e1 100644
--- a/includes/installer/i18n/vi.json
+++ b/includes/installer/i18n/vi.json
@@ -50,7 +50,6 @@
"config-env-bad": "Đã kiểm tra môi trường.\nBạn không thể cài đặt MediaWiki.",
"config-env-php": "PHP $1 đã được cài đặt.",
"config-env-hhvm": "HHVM $1 được cài đặt.",
- "config-unicode-using-utf8": "Đang sử dụng utf8_normalize.so của Brion Vibber để chuẩn hóa văn bản Unicode.",
"config-unicode-using-intl": "Sẽ sử dụng [http://pecl.php.net/intl phần mở rộng PECL intl] để chuẩn hóa Unicode.",
"config-unicode-pure-php-warning": "<strong>Cảnh báo:</strong> [http://pecl.php.net/intl intl PECL extension] không được phép xử lý Unicode chuẩn hóa, trả lại thực thi PHP-gốc chậm.\nNếu bạn chạy một site lưu lượng lớn, bạn phải để ý qua một chút trên [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization].",
"config-unicode-update-warning": "<strong>Cảnh báo:</strong> Phiên bản cài đặt của gói Unicode chuẩn hóa sử dụng một phiên bản cũ của thư viện [http://site.icu-project.org/ the ICU project].\nBạn phải [//www.mediawiki.org/wiki/Special:MyLanguage/nâng cấp Unicode_normalization_considerations] nếu bạn quan tâm đến việc sử dụng Unicode.",
@@ -63,7 +62,7 @@
"config-magic-quotes-sybase": "<strong>Lỗi chí tử: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] đang hoạt động!</strong>\nTùy chọn này sẽ làm hỏng dữ liệu nhập một cách không thể đoán trước.\nBạn không thể cài đặt hoặc sử dụng MediaWiki trừ phi tùy chọn này bị vô hiệu.",
"config-mbstring": "<strong>Lỗi chí tử: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] được kích hoạt!</strong>\nTùy chọn này gây lỗi và có thể làm hỏng dữ liệu một cách không thể đoán trước.\nBạn không thể cài đặt hoặc sử dụng MediaWiki trừ phi tùy chọn này bị vô hiệu.",
"config-safe-mode": "<strong>Cảnh báo:</strong> [http://www.php.net/features.safe-mode Chế độ an toàn] của PHP đang được kích hoạt.\nNó có thể gây vấn đề, nhất là nếu dùng các chức năng tải lên tập tin và <code>math</code>.",
- "config-xml-bad": "Mô đun XML của PHP đang bị thiếu.\nMediaWiki yêu cầu các hàm trong mô đun này và sẽ không hoạt động trong cấu hình này.\nNếu bạn đang chạy Mandrake, hãy cài đặt gói php-xml.",
+ "config-xml-bad": "Mô đun XML của PHP đang bị thiếu.\nMediaWiki yêu cầu các hàm trong mô đun này và sẽ không hoạt động trong cấu hình này.\nBạn có thể cần cài đặt gói RPM php-xml.",
"config-pcre-old": "<strong>Lỗi chí tử:</strong> PCRE $1 trở lên được yêu cầu phải có.\nBản nhị phân PHP của bạn dang được liên kết với PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Thông tin bổ sung].",
"config-pcre-no-utf8": "<strong>Lỗi chí tử:</strong> Mô đun PCRE của PHP dường như được biên dịch mà không có hỗ trợ PCRE_UTF8.\nMediaWiki yêu cầu phải có hỗ trợ UTF-8 để hoạt động chính xác.",
"config-memory-raised": "<code>memory_limit</code> của PHP là $1, tăng lên $2.",
@@ -103,8 +102,6 @@
"config-db-install-account": "Tài khoản người dùng để cài đặt",
"config-db-username": "Tên người dùng cơ sở dữ liệu:",
"config-db-password": "Mật khẩu cơ sở dữ liệu:",
- "config-db-password-empty": "Xin nhập vào một mật khẩu cho người dùng cơ sở dữ liệu mới: $1. Tuy bạn có thể tạo một tài khoản người dùng mà không cần mật khẩu, nhưng khi đó sẽ không đảm bảo tính bảo mật cho bạn.",
- "config-db-username-empty": "Bạn phải nhập một giá trị cho “{{int:config-db-username}}”",
"config-db-install-username": "Nhập tên người dùng để kết nối với cơ sở dữ liệu trong quá trình cài đặt.\nĐây không phải là tên người dùng của tài khoản MediaWiki; đây là tên người dùng cho cơ sở dữ liệu của bạn.",
"config-db-install-password": "Nhập mật khẩu để kết nối với cơ sở dữ liệu trong quá trình cài đặt.\nĐây không phải là mật khẩu của tài khoản MediaWiki; đây là mật khẩu cho cơ sở dữ liệu của bạn.",
"config-db-install-help": "Nhập tên người dùng và mật khẩu sẽ được sử dụng để kết nối với cơ sở dữ liệu trong quá trình cài đặt.",
diff --git a/includes/installer/i18n/wuu.json b/includes/installer/i18n/wuu.json
index 01052d3b..283ad3c1 100644
--- a/includes/installer/i18n/wuu.json
+++ b/includes/installer/i18n/wuu.json
@@ -1,9 +1,11 @@
{
"@metadata": {
"authors": [
- "Wu-chinese.com"
+ "Wu-chinese.com",
+ "Poiuyt"
]
},
+ "config-information": "信息",
"mainpagetext": "'''MediaWiki安装成功哉!'''",
"mainpagedocfooter": "请访问[//meta.wikimedia.org/wiki/Help:Contents 用户手册]以获得使用此维基软件个信息!\n\n== 入门 ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings MediaWiki 配置设置列表]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki 常见问题解答]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki 发布邮件列表]"
}
diff --git a/includes/installer/i18n/xmf.json b/includes/installer/i18n/xmf.json
new file mode 100644
index 00000000..dea81d9c
--- /dev/null
+++ b/includes/installer/i18n/xmf.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Silovan"
+ ]
+ },
+ "config-desc": "MediaWiki-შ ინსტალატორი",
+ "config-title": "MediaWiki $1 ინსტალაცია",
+ "config-information": "ინფორმაცია",
+ "config-localsettings-key": "გოახალაფაშ კილა:",
+ "config-localsettings-badkey": "კილა, ნამუთ თქვა წჷმარინეთინ ცაგანა რე.",
+ "config-session-error": "ჩილათაშ დოჭყაფაშ სესია: $1",
+ "config-your-language": "თქვან ნინა:",
+ "config-your-language-help": "გეგშაგორით ნინა, ნამუსჷთ ინსტალაციაშ პროცესის გიმირინუანთინ.",
+ "config-wiki-language": "ვიკიშ ნინა:",
+ "config-back": "← უკახალე",
+ "config-continue": "უკული →",
+ "config-page-language": "ნინა",
+ "config-page-welcome": "ბედინერ ორდას თქვანი მოზოჯუა მედიავიკიშა!",
+ "config-page-dbconnect": "მუნაჩემეფიშ ბაზაწჷმა მერსხუალა",
+ "config-page-dbsettings": "მუნაჩემეფიშ ბაზაშ კონფიგურაცია",
+ "config-page-name": "ჯოხო",
+ "config-page-options": "პარამეტრეფი",
+ "config-page-install": "ინსტალაცია",
+ "config-page-complete": "თებული რე!",
+ "config-page-restart": "ინსტალაციაშ დუდშე დოჭყაფა",
+ "config-page-readme": "წემკითხი",
+ "config-page-releasenotes": "გიშაშქუმალაშ მეღანკუეფი",
+ "config-page-upgradedoc": "გოახალაფა",
+ "config-help-restart": "გოკონანო თქვან მიშნაჸონეფი არძო ჩუალირ მუნაჩემიშ ლასუა დო ინსტალაციაშ დუდშე დოჭყაფა?",
+ "config-restart": "ქო, დუდშე დიჭყით",
+ "config-env-php": "PHP $1 დოინსტალირაფირი რე."
+}
diff --git a/includes/installer/i18n/yi.json b/includes/installer/i18n/yi.json
index e1d2226c..e8772803 100644
--- a/includes/installer/i18n/yi.json
+++ b/includes/installer/i18n/yi.json
@@ -9,6 +9,7 @@
"config-desc": "דער אינסטאלירער פאר מעדיעוויקי",
"config-title": "מעדיעוויקי $1 אינסטאלירונג",
"config-information": "אינפֿארמאציע",
+ "config-localsettings-key": "אקטואליזירונג־שליסל:",
"config-localsettings-badkey": "דעם שליסל וואס איר האט אײַנגעגעבן איז פאלש.",
"config-session-error": "פֿעלער ביים אָנהייבן סעסיע: $1",
"config-your-language": "אײַער שפראך:",
@@ -34,14 +35,28 @@
"config-page-existingwiki": "עקזיסטירנדע וויקי",
"config-help-restart": "צי ווילט איר אפראמען די גארע געשפייכלערטע דאטן וואס איר האט אײַנגעגעבן און ווידער אנהייבן דעם אינסטאלאציע־פראצעס?",
"config-restart": "יא, ווידעראמאל אנהייבן",
+ "config-env-good": "מ'האט קאנטראלירט די סביבה.\nאיר קענט אינסטאלירן מעדיעוויקי.",
+ "config-env-bad": "מ'האט קאנטראלירט די סביבה.\nאיר קענט נישט אינסטאלירן מעדיעוויקי.",
"config-env-php": "PHP $1 איז אינצטאלירט.",
+ "config-env-hhvm": "HHVM $1 איז אינסטאלירט.",
+ "config-xcache": "[http://xcache.lighttpd.net/ XCache] איז אינסטאלירט",
"config-apc": "[http://www.php.net/apc APC] איז אינסטאלירט",
"config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] איז אינסטאלירט",
"config-diff3-bad": "GNU diff3 נישט געטראפן.",
+ "config-using-server": "באניצן סארווער־נאמען \"<nowiki>$1</nowiki>\".",
+ "config-using-uri": "באניצן סארווער־אדרעס \"<nowiki>$1$2</nowiki>\".",
"config-db-type": "דאטנבאזע טיפ:",
+ "config-db-host": "דאטנבאזע־סארווער:",
"config-db-host-oracle": "דאטנבאזע־TNS:",
+ "config-db-wiki-settings": "אידענטיפיצירן די דאזיקע וויקי",
"config-db-name": "דאטנבאזע נאָמען:",
+ "config-db-install-account": "באניצער־קאנטע פאר אינסטאלאציע",
"config-db-username": "דאטנבאזע באניצער־נאָמען:",
+ "config-db-password": "דאטנבאזע־פאסווארט:",
+ "config-invalid-db-type": "אומגילטיגער דאטנבאזע־טיפ",
+ "config-missing-db-name": "איר דארפט איינגעבן א ווערט פאר \"{{int:config-db-name}}\".",
+ "config-missing-db-host": "איר דארפט איינגעבן א ווערט פאר \"{{int:config-db-host}}\".",
+ "config-missing-db-server-oracle": "איר דארפט איינגעבן א ווערט פאר \"{{int:config-db-host-oracle}}\".",
"config-project-namespace": "פראיעקט נאָמענטייל:",
"config-ns-generic": "פראיעקט",
"config-admin-name": "אײַער באַניצער־נאָמען:",
diff --git a/includes/installer/i18n/zh-hans.json b/includes/installer/i18n/zh-hans.json
index cbd48f15..414b6e90 100644
--- a/includes/installer/i18n/zh-hans.json
+++ b/includes/installer/i18n/zh-hans.json
@@ -68,7 +68,6 @@
"config-env-bad": "环境检查已经完成。您不能安装MediaWiki。",
"config-env-php": "PHP $1已安装。",
"config-env-hhvm": "HHVM $1已安装。",
- "config-unicode-using-utf8": "使用Brion Vibber的utf8_normalize.so实现Unicode正常化。",
"config-unicode-using-intl": "使用[http://pecl.php.net/intl intl PECL扩展程序]标准化Unicode。",
"config-unicode-pure-php-warning": "<strong>警告:</strong>因为尚未安装 [http://pecl.php.net/intl intl PECL 扩展]以处理 Unicode 正常化,故只能退而采用运行较慢的纯 PHP 实现的方法。\n如果您运行着一个高流量的网站,请参阅 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode标准化]一文。",
"config-unicode-update-warning": "'''警告''':Unicode正常化封装器的已安装版本使用了旧版本的[http://site.icu-project.org/ ICU项目]库。如果您需要使用Unicode,请将其[//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations 升级]。",
@@ -81,7 +80,7 @@
"config-magic-quotes-sybase": "'''毁灭性错误:[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_sybase]已启用!'''\n此选项会无法预测地破坏输入的数据,请将其禁用,否则您将不能安装或使用MediaWiki。",
"config-mbstring": "'''毁灭性错误:[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload]已启用!'''\n此选项会导致错误并不可预测地破坏数据,请将其禁用,否则您将不能安装或使用MediaWiki。",
"config-safe-mode": "'''警告:'''PHP的[http://www.php.net/features.safe-mode 安全模式]已启用。它可能会导致一些问题,尤其在对文件上传和数学公式<code>math</code>的支持方面。",
- "config-xml-bad": "缺少PHP的XML模块。MediaWiki需要使用该模块提供的函数,在当前配置下将无法工作。如果您正在使用Mandrake Linux,请安装php-xml包。",
+ "config-xml-bad": "缺少PHP的XML模块。MediaWiki需要使用该模块提供的函数,在当前配置下将无法工作。您可能需要安装php-xml RPM包。",
"config-pcre-old": "'' 致命错误: ''需要PCRE $1 或更高版本。\n您的 PHP 二进制文件与 PCRE $2 链接。\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE 详细信息]。",
"config-pcre-no-utf8": "'''毁灭性错误''':PHP的PCRE模块在编译时可能没有包含PCRE_UTF8支持。MediaWiki需要UTF-8支持才能正常工作。",
"config-memory-raised": "PHP的内存使用上限<code>memory_limit</code>为$1,自动提升到$2。",
@@ -121,8 +120,6 @@
"config-db-install-account": "用于安装的用户帐号",
"config-db-username": "数据库用户名:",
"config-db-password": "数据库密码:",
- "config-db-password-empty": "请为新数据库用户$1输入密码。尽管您可以创建不使用密码的用户,但这样做并不安全。",
- "config-db-username-empty": "您必须输入用于“{{int:config-db-username}}”的值。",
"config-db-install-username": "请输入在安装过程中用于连接数据库的用户名。请勿输入MediaWiki帐号的用户名,请输入您数据库的用户名。",
"config-db-install-password": "请输入在安装过程中用于连接数据库的密码。请勿输入MediaWiki帐号的密码,请输入您数据库的密码。",
"config-db-install-help": "请输入在安装过程中用于连接数据库的用户名和密码。",
diff --git a/includes/installer/i18n/zh-hant.json b/includes/installer/i18n/zh-hant.json
index 4c7b0c50..d6f88a73 100644
--- a/includes/installer/i18n/zh-hant.json
+++ b/includes/installer/i18n/zh-hant.json
@@ -71,7 +71,7 @@
"config-magic-quotes-sybase": "<strong>嚴重:[http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] 選項被開啟!</strong>\n此選項會導致資料在無法預測的情況下損壞。\n您必須將開選項關閉方可繼續安裝 MediaWiki。",
"config-mbstring": "<strong>嚴重:[http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] 選項被開啟!</strong>\n此選項會導致資料在無法預測的情況下損壞。\n您必須將開選項關閉方可繼續安裝 MediaWiki。",
"config-safe-mode": "<strong>警告:</strong>PHP 的 [http://www.php.net/features.safe-mode 安全模式] 選項被開啟。它可能會導致檔案上傳與數學函數 <code>math</code> 的問題。",
- "config-xml-bad": "PHP 缺少的 XML 模組。\nMediaWiki 需要使用此模組中所提供的函數,且在目前的設定下將無法繼續作業。\n如果您使用的是 Mandrake Linux,請安裝 php-xml 套件。",
+ "config-xml-bad": "PHP 缺少的 XML 模組。\nMediaWiki 需要使用此模組中所提供的函數,且在目前的設定下將無法繼續作業。\n您可能需要安裝 php-xml RPM 套件。",
"config-pcre-old": "<strong>嚴重:</strong> 需要使用 PCRE $1 或更新的版本。\n您的 PHP 執行檔使用的是 PCRE $2。\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE 詳細資訊]。",
"config-pcre-no-utf8": "<strong>嚴重:</strong> PHP 的 PCRE 模組在編譯時未包含 PCRE_UTF8 支援。\nMediaWiki 需要支援 UTF-8 才可正常運作。",
"config-memory-raised": "PHP 的記憶體使用上限 <code>memory_limit</code> 目前為 $1,自動提高到 $2。",
@@ -93,7 +93,7 @@
"config-no-uri": "<strong>錯誤:</strong>無法辨識目前的 URI 位置。\n安裝已中止。",
"config-no-cli-uri": "<strong>警告:</strong>:未指定 <code>--scriptpath</code> 指令參數,使用預設值:<code>$1</code>。",
"config-using-server": "使用伺服器名稱 \"<nowiki>$1</nowiki>\"。",
- "config-using-uri": "使用伺服器 URL 位置 \"<nowiki>$1$2</nowiki>\"。",
+ "config-using-uri": "使用伺服器 URL \"<nowiki>$1$2</nowiki>\"。",
"config-uploads-not-safe": "<strong>警告:</strong>您預設的上傳目錄 <code>$1</code> 有可被任意執行 Script 的漏洞。\n雖然 MediaWiki 會對所有上傳的檔案進行安全檢查,但我們仍強烈建議您在開啟上傳功能前了解如何 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security 關閉此安全漏洞]。",
"config-no-cli-uploads-check": "<strong>警告:</strong>透過指令介面安不會檢查您預設的上傳目錄 (<code>$1</code>) 是否有可任意執行 Script 的安全性漏洞。",
"config-brokenlibxml": "您的系統使用了可能造成 MediaWiki 或其他網頁應用程式資料損毀問題的 PHP 與 limbxml2 版本。\n請升級 libxml2 2.7.3 或更新的版本 ([https://bugs.php.net/bug.php?id=45996 PHP 問題報告])。\n安裝已中止。",
@@ -111,8 +111,6 @@
"config-db-install-account": "安裝程式使用的使用者帳號",
"config-db-username": "資料庫使用者名稱:",
"config-db-password": "資料庫密碼:",
- "config-db-password-empty": "請輸入新增資料庫使用者 $1 的密碼。\n雖然您可以不設定任何密碼,但這樣做並不安全。",
- "config-db-username-empty": "您必須輸入 \"{{int:config-db-username}}\" 欄位的內容。",
"config-db-install-username": "請輸入在安裝過程中用來連線資料庫的使用者名稱。\n請注意,這不是 MediaWiki 帳號的使用者名稱,這是您資料庫的使用者名稱。",
"config-db-install-password": "請輸入在安裝過程中用來連線資料庫的密碼。\n請注意,這不是 MediaWiki 帳號的密碼,這是您資料庫的密碼。",
"config-db-install-help": "請輸入在安裝過程中用來連線資料庫的使用者名稱及密碼。",
@@ -190,7 +188,7 @@
"config-mysql-charset": "資料庫字元集:",
"config-mysql-binary": "二進制",
"config-mysql-utf8": "UTF-8",
- "config-mysql-charset-help": "在 <strong>二進制模式</strong> 下,MediaWiki 將 UTF-8 的文字儲存在二進位型態的欄位。\n這個模式比 MySQL 的 UTF-8 模式還要更有效,並且可以讓您使用完整的 Unicode 字元集。\n\n在 <storng>UTF-8 模式</strong> 下,MySQL 可以知道您的資料使用何種編碼儲存,您可以正常的取得與轉換內容,但此個模式只支援到 Unicode 中的 [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes 基本多文種平面] 字元。",
+ "config-mysql-charset-help": "在 <strong>二進制模式</strong> 下,MediaWiki 將 UTF-8 的文字儲存在二進位型態的欄位。\n這個模式比 MySQL 的 UTF-8 模式還要更有效,並且可以讓您使用完整的 Unicode 字元集。\n\n在 <strong>UTF-8 模式</strong> 下,MySQL 可以知道您的資料使用何種編碼儲存,您可以正常的取得與轉換內容,但此個模式只支援到 Unicode 中的 [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes 基本多文種平面] 字元。",
"config-mssql-auth": "身份驗證類型:",
"config-mssql-install-auth": "請選擇安裝程序中要用來連線資料庫使用的身份驗證類型。\n若您選擇 \"{{int:config-mssql-windowsauth}}\",不論網頁伺服器是使用何種身份執行都會使用這組驗證資料。",
"config-mssql-web-auth": "請選擇一般操作中要用來連線資料庫使用的身份驗證類型。\n若您選擇 \"{{int:config-mssql-windowsauth}}\",不論網頁伺服器是使用何種身份執行都會使用這組驗證資料。",
@@ -261,7 +259,7 @@
"config-upload-help": "檔案上傳功能會讓您的伺服器暴露在潛藏的安全性風險之下。\n要取得更多相關的資訊,請參考 [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security 安全性章節]。\n\n要開啟檔案上傳需要將 MediaWiki 根目錄底下的 <code>images</code> 目錄開啟網頁伺服器的寫入權,\n然後再啟動選項。",
"config-upload-deleted": "已刪除檔案的目錄:",
"config-upload-deleted-help": "請選擇用來存放已刪除檔案的目錄。\n理想情況下,此目錄不可被網頁直接存取。",
- "config-logo": "標誌 URL 位置:",
+ "config-logo": "Logo 網址:",
"config-logo-help": "在 MediaWiki 的預設介面,側欄選單上方有一塊 135x160 像素用來放置標誌的區域。\n請上傳合適大小的圖片並在此輸入 URL 網址。\n\n您可以透過 <code>$wgStylePath</code> 或者 <code>$wgScriptPath</code> 來表示您的圖片與這些路徑的相對位置。\n\n如果您不想使用標誌,可略過此欄位。",
"config-instantcommons": "開啟即時共享資源",
"config-instantcommons-help": "[//www.mediawiki.org/wiki/InstantCommons 即時共享資源] 是允許 Wiki 使用來自 [//commons.wikimedia.org/ Wikimedia Commons] 網站上的圖片、聲音以及其他媒體的一項功能。\n若要開啟此功能,您的 MediaWiki 必須能夠連線網際網路。\n更多有關此功能的訊息,包含如何存除了 Wikimedia Commons 之外其他網站的說明,請參考 \n[//www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos 操作手冊]。",
@@ -277,7 +275,7 @@
"config-memcached-servers": "Memcached 伺服器:",
"config-memcached-help": "請列出 Memcached 伺服器的 IP 位址。\n每一行只指定一個位置並且要註明使用的埠號,例如:\n 127.0.0.1:11211\n 192.168.1.25:1234",
"config-memcache-needservers": "您的快取類型選擇使用 Memcached,但並未設定任何的伺服器。",
- "config-memcache-badip": "您輸入了一筆無效的 Memcached IP 位置:$1。",
+ "config-memcache-badip": "您輸入了一筆無效的 Memcached IP 位址:$1。",
"config-memcache-noport": "您沒有輸入 Memcached 伺服器的埠號:$1。\n如果您不曉得埠號為多少,預設為 11211。",
"config-memcache-badport": "Memcached 埠號應介於 $1 到 $2 之間。",
"config-extensions": "擴充套件",
diff --git a/includes/interwiki/Interwiki.php b/includes/interwiki/Interwiki.php
index 02fbb080..33e50668 100644
--- a/includes/interwiki/Interwiki.php
+++ b/includes/interwiki/Interwiki.php
@@ -115,6 +115,17 @@ class Interwiki {
}
/**
+ * Purge the cache for an interwiki prefix
+ * @param string $prefix
+ * @since 1.26
+ */
+ public static function invalidateCache( $prefix ) {
+ $cache = ObjectCache::getMainWANInstance();
+ $key = wfMemcKey( 'interwiki', $prefix );
+ $cache->delete( $key );
+ }
+
+ /**
* Fetch interwiki prefix data from local cache in constant database.
*
* @note More logic is explained in DefaultSettings.
@@ -191,16 +202,18 @@ class Interwiki {
* @return Interwiki|bool Interwiki if $prefix is valid, otherwise false
*/
protected static function load( $prefix ) {
- global $wgMemc, $wgInterwikiExpiry;
+ global $wgInterwikiExpiry;
$iwData = array();
if ( !Hooks::run( 'InterwikiLoadPrefix', array( $prefix, &$iwData ) ) ) {
return Interwiki::loadFromArray( $iwData );
}
+ $cache = ObjectCache::getMainWANInstance();
+
if ( !$iwData ) {
$key = wfMemcKey( 'interwiki', $prefix );
- $iwData = $wgMemc->get( $key );
+ $iwData = $cache->get( $key );
if ( $iwData === '!NONEXISTENT' ) {
// negative cache hit
return false;
@@ -232,13 +245,13 @@ class Interwiki {
'iw_local' => $iw->mLocal,
'iw_trans' => $iw->mTrans
);
- $wgMemc->add( $key, $mc, $wgInterwikiExpiry );
+ $cache->set( $key, $mc, $wgInterwikiExpiry );
return $iw;
}
// negative cache hit
- $wgMemc->add( $key, '!NONEXISTENT', $wgInterwikiExpiry );
+ $cache->set( $key, '!NONEXISTENT', $wgInterwikiExpiry );
return false;
}
diff --git a/includes/jobqueue/Job.php b/includes/jobqueue/Job.php
index f8de0b5d..3e23391c 100644
--- a/includes/jobqueue/Job.php
+++ b/includes/jobqueue/Job.php
@@ -32,7 +32,7 @@ abstract class Job implements IJobSpecification {
/** @var string */
public $command;
- /** @var array|bool Array of job parameters or false if none */
+ /** @var array Array of job parameters */
public $params;
/** @var array Additional queue metadata */
@@ -58,11 +58,11 @@ abstract class Job implements IJobSpecification {
*
* @param string $command Job command
* @param Title $title Associated title
- * @param array|bool $params Job parameters
+ * @param array $params Job parameters
* @throws MWException
* @return Job
*/
- public static function factory( $command, Title $title, $params = false ) {
+ public static function factory( $command, Title $title, $params = array() ) {
global $wgJobClasses;
if ( isset( $wgJobClasses[$command] ) ) {
$class = $wgJobClasses[$command];
@@ -80,7 +80,7 @@ abstract class Job implements IJobSpecification {
public function __construct( $command, $title, $params = false ) {
$this->command = $command;
$this->title = $title;
- $this->params = $params;
+ $this->params = is_array( $params ) ? $params : array(); // sanity
// expensive jobs may set this to true
$this->removeDuplicates = false;
@@ -135,6 +135,24 @@ abstract class Job implements IJobSpecification {
}
/**
+ * @return int|null UNIX timestamp of when the job was queued, or null
+ * @since 1.26
+ */
+ public function getQueuedTimestamp() {
+ return isset( $this->metadata['timestamp'] )
+ ? wfTimestampOrNull( TS_UNIX, $this->metadata['timestamp'] )
+ : null;
+ }
+
+ /**
+ * @return int|null UNIX timestamp of when the job was runnable, or null
+ * @since 1.26
+ */
+ public function getReadyTimestamp() {
+ return $this->getReleaseTimestamp() ?: $this->getQueuedTimestamp();
+ }
+
+ /**
* Whether the queue should reject insertion of this job if a duplicate exists
*
* This can be used to avoid duplicated effort or combined with delayed jobs to
@@ -196,15 +214,27 @@ abstract class Job implements IJobSpecification {
}
/**
+ * Get "root job" parameters for a task
+ *
+ * This is used to no-op redundant jobs, including child jobs of jobs,
+ * as long as the children inherit the root job parameters. When a job
+ * with root job parameters and "rootJobIsSelf" set is pushed, the
+ * deduplicateRootJob() method is automatically called on it. If the
+ * root job is only virtual and not actually pushed (e.g. the sub-jobs
+ * are inserted directly), then call deduplicateRootJob() directly.
+ *
* @see JobQueue::deduplicateRootJob()
+ *
* @param string $key A key that identifies the task
* @return array Map of:
+ * - rootJobIsSelf : true
* - rootJobSignature : hash (e.g. SHA1) that identifies the task
* - rootJobTimestamp : TS_MW timestamp of this instance of the task
* @since 1.21
*/
public static function newRootJobParams( $key ) {
return array(
+ 'rootJobIsSelf' => true,
'rootJobSignature' => sha1( $key ),
'rootJobTimestamp' => wfTimestampNow()
);
@@ -237,6 +267,14 @@ abstract class Job implements IJobSpecification {
}
/**
+ * @see JobQueue::deduplicateRootJob()
+ * @return bool Whether this is job is a root job
+ */
+ public function isRootJob() {
+ return $this->hasRootJobParams() && !empty( $this->params['rootJobIsSelf'] );
+ }
+
+ /**
* Insert a single job into the queue.
* @return bool True on success
* @deprecated since 1.21
diff --git a/includes/jobqueue/JobQueue.php b/includes/jobqueue/JobQueue.php
index 91fe86cf..69a3defb 100644
--- a/includes/jobqueue/JobQueue.php
+++ b/includes/jobqueue/JobQueue.php
@@ -94,7 +94,7 @@ abstract class JobQueue {
* This might be useful for improving concurrency for job acquisition.
* - claimTTL : If supported, the queue will recycle jobs that have been popped
* but not acknowledged as completed after this many seconds. Recycling
- * of jobs simple means re-inserting them into the queue. Jobs can be
+ * of jobs simply means re-inserting them into the queue. Jobs can be
* attempted up to three times before being discarded.
*
* Queue classes should throw an exception if they do not support the options given.
@@ -286,7 +286,7 @@ abstract class JobQueue {
* This does not require $wgJobClasses to be set for the given job type.
* Outside callers should use JobQueueGroup::push() instead of this function.
*
- * @param Job|array $jobs A single job or an array of Jobs
+ * @param JobSpecification|JobSpecification[] $jobs
* @param int $flags Bitfield (supports JobQueue::QOS_ATOMIC)
* @return void
* @throws JobQueueError
@@ -301,7 +301,7 @@ abstract class JobQueue {
* This does not require $wgJobClasses to be set for the given job type.
* Outside callers should use JobQueueGroup::push() instead of this function.
*
- * @param array $jobs List of Jobs
+ * @param JobSpecification[] $jobs
* @param int $flags Bitfield (supports JobQueue::QOS_ATOMIC)
* @return void
* @throws MWException
@@ -323,11 +323,17 @@ abstract class JobQueue {
$this->doBatchPush( $jobs, $flags );
$this->aggr->notifyQueueNonEmpty( $this->wiki, $this->type );
+
+ foreach ( $jobs as $job ) {
+ if ( $job->isRootJob() ) {
+ $this->deduplicateRootJob( $job );
+ }
+ }
}
/**
* @see JobQueue::batchPush()
- * @param array $jobs
+ * @param JobSpecification[] $jobs
* @param int $flags
*/
abstract protected function doBatchPush( array $jobs, $flags );
@@ -359,7 +365,7 @@ abstract class JobQueue {
// Flag this job as an old duplicate based on its "root" job...
try {
if ( $job && $this->isRootJobOldDuplicate( $job ) ) {
- JobQueue::incrStats( 'job-pop-duplicate', $this->type, 1, $this->wiki );
+ JobQueue::incrStats( 'dupe_pops', $this->type );
$job = DuplicateJob::newFromJob( $job ); // convert to a no-op
}
} catch ( Exception $e ) {
@@ -425,11 +431,11 @@ abstract class JobQueue {
*
* This does nothing for certain queue classes.
*
- * @param Job $job
+ * @param IJobSpecification $job
* @throws MWException
* @return bool
*/
- final public function deduplicateRootJob( Job $job ) {
+ final public function deduplicateRootJob( IJobSpecification $job ) {
if ( $job->getType() !== $this->type ) {
throw new MWException( "Got '{$job->getType()}' job; expected '{$this->type}'." );
}
@@ -440,11 +446,11 @@ abstract class JobQueue {
/**
* @see JobQueue::deduplicateRootJob()
- * @param Job $job
+ * @param IJobSpecification $job
* @throws MWException
* @return bool
*/
- protected function doDeduplicateRootJob( Job $job ) {
+ protected function doDeduplicateRootJob( IJobSpecification $job ) {
if ( !$job->hasRootJobParams() ) {
throw new MWException( "Cannot register root job; missing parameters." );
}
@@ -549,35 +555,6 @@ abstract class JobQueue {
}
/**
- * Return a map of task names to task definition maps.
- * A "task" is a fast periodic queue maintenance action.
- * Mutually exclusive tasks must implement their own locking in the callback.
- *
- * Each task value is an associative array with:
- * - name : the name of the task
- * - callback : a PHP callable that performs the task
- * - period : the period in seconds corresponding to the task frequency
- *
- * @return array
- */
- final public function getPeriodicTasks() {
- $tasks = $this->doGetPeriodicTasks();
- foreach ( $tasks as $name => &$def ) {
- $def['name'] = $name;
- }
-
- return $tasks;
- }
-
- /**
- * @see JobQueue::getPeriodicTasks()
- * @return array
- */
- protected function doGetPeriodicTasks() {
- return array();
- }
-
- /**
* Clear any process and persistent caches
*
* @return void
@@ -616,6 +593,20 @@ abstract class JobQueue {
}
/**
+ * Get an iterator to traverse over all claimed jobs in this queue
+ *
+ * Callers should be quick to iterator over it or few results
+ * will be returned due to jobs being acknowledged and deleted
+ *
+ * @return Iterator
+ * @throws JobQueueError
+ * @since 1.26
+ */
+ public function getAllAcquiredJobs() {
+ return new ArrayIterator( array() ); // not implemented
+ }
+
+ /**
* Get an iterator to traverse over all abandoned jobs in this queue
*
* @return Iterator
@@ -646,7 +637,6 @@ abstract class JobQueue {
* @since 1.22
*/
final public function getSiblingQueuesWithJobs( array $types ) {
-
return $this->doGetSiblingQueuesWithJobs( $types );
}
@@ -670,7 +660,6 @@ abstract class JobQueue {
* @since 1.22
*/
final public function getSiblingQueueSizes( array $types ) {
-
return $this->doGetSiblingQueueSizes( $types );
}
@@ -689,15 +678,15 @@ abstract class JobQueue {
* @param string $key Event type
* @param string $type Job type
* @param int $delta
- * @param string $wiki Wiki ID (added in 1.23)
* @since 1.22
*/
- public static function incrStats( $key, $type, $delta = 1, $wiki = null ) {
- wfIncrStats( $key, $delta );
- wfIncrStats( "{$key}-{$type}", $delta );
- if ( $wiki !== null ) {
- wfIncrStats( "{$key}-{$type}-{$wiki}", $delta );
+ public static function incrStats( $key, $type, $delta = 1 ) {
+ static $stats;
+ if ( !$stats ) {
+ $stats = RequestContext::getMain()->getStats();
}
+ $stats->updateCount( "jobqueue.{$key}.all", $delta );
+ $stats->updateCount( "jobqueue.{$key}.{$type}", $delta );
}
/**
diff --git a/includes/jobqueue/JobQueueDB.php b/includes/jobqueue/JobQueueDB.php
index d5f47ffd..d1e4a135 100644
--- a/includes/jobqueue/JobQueueDB.php
+++ b/includes/jobqueue/JobQueueDB.php
@@ -29,7 +29,6 @@
*/
class JobQueueDB extends JobQueue {
const CACHE_TTL_SHORT = 30; // integer; seconds to cache info without re-validating
- const CACHE_TTL_LONG = 300; // integer; seconds to cache info that is kept up to date
const MAX_AGE_PRUNE = 604800; // integer; seconds a job can live once claimed
const MAX_JOB_RANDOM = 2147483647; // integer; 2^31 - 1, used for job_random
const MAX_OFFSET = 255; // integer; maximum number of rows to skip
@@ -71,15 +70,6 @@ class JobQueueDB extends JobQueue {
* @return bool
*/
protected function doIsEmpty() {
- $key = $this->getCacheKey( 'empty' );
-
- $isEmpty = $this->cache->get( $key );
- if ( $isEmpty === 'true' ) {
- return true;
- } elseif ( $isEmpty === 'false' ) {
- return false;
- }
-
$dbr = $this->getSlaveDB();
try {
$found = $dbr->selectField( // unclaimed job
@@ -88,7 +78,6 @@ class JobQueueDB extends JobQueue {
} catch ( DBError $e ) {
$this->throwDBException( $e );
}
- $this->cache->add( $key, $found ? 'false' : 'true', self::CACHE_TTL_LONG );
return !$found;
}
@@ -256,12 +245,9 @@ class JobQueueDB extends JobQueue {
foreach ( array_chunk( $rows, 50 ) as $rowBatch ) {
$dbw->insert( 'job', $rowBatch, $method );
}
- JobQueue::incrStats( 'job-insert', $this->type, count( $rows ), $this->wiki );
- JobQueue::incrStats(
- 'job-insert-duplicate',
- $this->type,
- count( $rowSet ) + count( $rowList ) - count( $rows ),
- $this->wiki
+ JobQueue::incrStats( 'inserts', $this->type, count( $rows ) );
+ JobQueue::incrStats( 'dupe_inserts', $this->type,
+ count( $rowSet ) + count( $rowList ) - count( $rows )
);
} catch ( DBError $e ) {
if ( $flags & self::QOS_ATOMIC ) {
@@ -273,8 +259,6 @@ class JobQueueDB extends JobQueue {
$dbw->commit( $method );
}
- $this->cache->set( $this->getCacheKey( 'empty' ), 'false', JobQueueDB::CACHE_TTL_LONG );
-
return;
}
@@ -283,10 +267,6 @@ class JobQueueDB extends JobQueue {
* @return Job|bool
*/
protected function doPop() {
- if ( $this->cache->get( $this->getCacheKey( 'empty' ) ) === 'true' ) {
- return false; // queue is empty
- }
-
$dbw = $this->getMasterDB();
try {
$dbw->commit( __METHOD__, 'flush' ); // flush existing transaction
@@ -309,22 +289,23 @@ class JobQueueDB extends JobQueue {
}
// Check if we found a row to reserve...
if ( !$row ) {
- $this->cache->set( $this->getCacheKey( 'empty' ), 'true', self::CACHE_TTL_LONG );
break; // nothing to do
}
- JobQueue::incrStats( 'job-pop', $this->type, 1, $this->wiki );
+ JobQueue::incrStats( 'pops', $this->type );
// Get the job object from the row...
- $title = Title::makeTitleSafe( $row->job_namespace, $row->job_title );
- if ( !$title ) {
- $dbw->delete( 'job', array( 'job_id' => $row->job_id ), __METHOD__ );
- wfDebug( "Row has invalid title '{$row->job_title}'.\n" );
- continue; // try again
- }
+ $title = Title::makeTitle( $row->job_namespace, $row->job_title );
$job = Job::factory( $row->job_cmd, $title,
self::extractBlob( $row->job_params ), $row->job_id );
$job->metadata['id'] = $row->job_id;
+ $job->metadata['timestamp'] = $row->job_timestamp;
break; // done
} while ( true );
+
+ if ( !$job || mt_rand( 0, 9 ) == 0 ) {
+ // Handled jobs that need to be recycled/deleted;
+ // any recycled jobs will be picked up next attempt
+ $this->recycleAndDeleteStaleJobs();
+ }
} catch ( DBError $e ) {
$this->throwDBException( $e );
}
@@ -495,6 +476,8 @@ class JobQueueDB extends JobQueue {
// Delete a row with a single DELETE without holding row locks over RTTs...
$dbw->delete( 'job',
array( 'job_cmd' => $this->type, 'job_id' => $job->metadata['id'] ), __METHOD__ );
+
+ JobQueue::incrStats( 'acks', $this->type );
} catch ( DBError $e ) {
$this->throwDBException( $e );
}
@@ -504,11 +487,11 @@ class JobQueueDB extends JobQueue {
/**
* @see JobQueue::doDeduplicateRootJob()
- * @param Job $job
+ * @param IJobSpecification $job
* @throws MWException
* @return bool
*/
- protected function doDeduplicateRootJob( Job $job ) {
+ protected function doDeduplicateRootJob( IJobSpecification $job ) {
$params = $job->getParams();
if ( !isset( $params['rootJobSignature'] ) ) {
throw new MWException( "Cannot register root job; missing 'rootJobSignature'." );
@@ -560,22 +543,10 @@ class JobQueueDB extends JobQueue {
}
/**
- * @return array
- */
- protected function doGetPeriodicTasks() {
- return array(
- 'recycleAndDeleteStaleJobs' => array(
- 'callback' => array( $this, 'recycleAndDeleteStaleJobs' ),
- 'period' => ceil( $this->claimTTL / 2 )
- )
- );
- }
-
- /**
* @return void
*/
protected function doFlushCaches() {
- foreach ( array( 'empty', 'size', 'acquiredcount' ) as $type ) {
+ foreach ( array( 'size', 'acquiredcount' ) as $type ) {
$this->cache->delete( $this->getCacheKey( $type ) );
}
}
@@ -585,18 +556,35 @@ class JobQueueDB extends JobQueue {
* @return Iterator
*/
public function getAllQueuedJobs() {
+ return $this->getJobIterator( array( 'job_cmd' => $this->getType(), 'job_token' => '' ) );
+ }
+
+ /**
+ * @see JobQueue::getAllAcquiredJobs()
+ * @return Iterator
+ */
+ public function getAllAcquiredJobs() {
+ return $this->getJobIterator( array( 'job_cmd' => $this->getType(), "job_token > ''" ) );
+ }
+
+ /**
+ * @param array $conds Query conditions
+ * @return Iterator
+ */
+ protected function getJobIterator( array $conds ) {
$dbr = $this->getSlaveDB();
try {
return new MappedIterator(
- $dbr->select( 'job', self::selectFields(),
- array( 'job_cmd' => $this->getType(), 'job_token' => '' ) ),
- function ( $row ) use ( $dbr ) {
+ $dbr->select( 'job', self::selectFields(), $conds ),
+ function ( $row ) {
$job = Job::factory(
$row->job_cmd,
Title::makeTitle( $row->job_namespace, $row->job_title ),
- strlen( $row->job_params ) ? unserialize( $row->job_params ) : false
+ strlen( $row->job_params ) ? unserialize( $row->job_params ) : array()
);
$job->metadata['id'] = $row->job_id;
+ $job->metadata['timestamp'] = $row->job_timestamp;
+
return $job;
}
);
@@ -613,6 +601,10 @@ class JobQueueDB extends JobQueue {
protected function doGetSiblingQueuesWithJobs( array $types ) {
$dbr = $this->getSlaveDB();
+ // @note: this does not check whether the jobs are claimed or not.
+ // This is useful so JobQueueGroup::pop() also sees queues that only
+ // have stale jobs. This lets recycleAndDeleteStaleJobs() re-enqueue
+ // failed jobs so that they can be popped again for that edge case.
$res = $dbr->select( 'job', 'DISTINCT job_cmd',
array( 'job_cmd' => $types ), __METHOD__ );
@@ -685,9 +677,7 @@ class JobQueueDB extends JobQueue {
);
$affected = $dbw->affectedRows();
$count += $affected;
- JobQueue::incrStats( 'job-recycle', $this->type, $affected, $this->wiki );
- // The tasks recycled jobs or release delayed jobs into the queue
- $this->cache->set( $this->getCacheKey( 'empty' ), 'false', self::CACHE_TTL_LONG );
+ JobQueue::incrStats( 'recycles', $this->type, $affected );
$this->aggr->notifyQueueNonEmpty( $this->wiki, $this->type );
}
}
@@ -714,7 +704,7 @@ class JobQueueDB extends JobQueue {
$dbw->delete( 'job', array( 'job_id' => $ids ), __METHOD__ );
$affected = $dbw->affectedRows();
$count += $affected;
- JobQueue::incrStats( 'job-abandon', $this->type, $affected, $this->wiki );
+ JobQueue::incrStats( 'abandons', $this->type, $affected );
}
$dbw->unlock( "jobqueue-recycle-{$this->type}", __METHOD__ );
diff --git a/includes/jobqueue/JobQueueFederated.php b/includes/jobqueue/JobQueueFederated.php
index d985d449..109ca019 100644
--- a/includes/jobqueue/JobQueueFederated.php
+++ b/includes/jobqueue/JobQueueFederated.php
@@ -93,6 +93,8 @@ class JobQueueFederated extends JobQueue {
) {
unset( $baseConfig[$o] ); // partition queue doesn't care about this
}
+ // The class handles all aggregator calls already
+ unset( $baseConfig['aggregator'] );
// Get the partition queue objects
foreach ( $partitionMap as $partition => $w ) {
if ( !isset( $params['configByPartition'][$partition] ) ) {
@@ -328,7 +330,7 @@ class JobQueueFederated extends JobQueue {
return false;
}
- protected function doDeduplicateRootJob( Job $job ) {
+ protected function doDeduplicateRootJob( IJobSpecification $job ) {
$params = $job->getRootJobParams();
$sigature = $params['rootJobSignature'];
$partition = $this->partitionRing->getLiveLocation( $sigature );
@@ -373,27 +375,7 @@ class JobQueueFederated extends JobQueue {
$this->throwErrorIfAllPartitionsDown( $failed );
}
- protected function doGetPeriodicTasks() {
- $tasks = array();
- /** @var JobQueue $queue */
- foreach ( $this->partitionQueues as $partition => $queue ) {
- foreach ( $queue->getPeriodicTasks() as $task => $def ) {
- $tasks["{$partition}:{$task}"] = $def;
- }
- }
-
- return $tasks;
- }
-
protected function doFlushCaches() {
- static $types = array(
- 'empty',
- 'size',
- 'acquiredcount',
- 'delayedcount',
- 'abandonedcount'
- );
-
/** @var JobQueue $queue */
foreach ( $this->partitionQueues as $queue ) {
$queue->doFlushCaches();
@@ -422,6 +404,17 @@ class JobQueueFederated extends JobQueue {
return $iterator;
}
+ public function getAllAcquiredJobs() {
+ $iterator = new AppendIterator();
+
+ /** @var JobQueue $queue */
+ foreach ( $this->partitionQueues as $queue ) {
+ $iterator->append( $queue->getAllAcquiredJobs() );
+ }
+
+ return $iterator;
+ }
+
public function getAllAbandonedJobs() {
$iterator = new AppendIterator();
diff --git a/includes/jobqueue/JobQueueGroup.php b/includes/jobqueue/JobQueueGroup.php
index ebd547a0..5bd1cc94 100644
--- a/includes/jobqueue/JobQueueGroup.php
+++ b/includes/jobqueue/JobQueueGroup.php
@@ -28,7 +28,7 @@
* @since 1.21
*/
class JobQueueGroup {
- /** @var array */
+ /** @var JobQueueGroup[] */
protected static $instances = array();
/** @var ProcessCacheLRU */
@@ -40,6 +40,9 @@ class JobQueueGroup {
/** @var array Map of (bucket => (queue => JobQueue, types => list of types) */
protected $coalescedQueues;
+ /** @var Job[] */
+ protected $bufferedJobs = array();
+
const TYPE_DEFAULT = 1; // integer; jobs popped by default
const TYPE_ANY = 2; // integer; any job
@@ -100,13 +103,13 @@ class JobQueueGroup {
}
/**
- * Insert jobs into the respective queues of with the belong.
+ * Insert jobs into the respective queues of which they belong
*
* This inserts the jobs into the queue specified by $wgJobTypeConf
* and updates the aggregate job queue information cache as needed.
*
- * @param Job|Job[] $jobs A single Job or a list of Jobs
- * @throws MWException
+ * @param IJobSpecification|IJobSpecification[] $jobs A single Job or a list of Jobs
+ * @throws InvalidArgumentException
* @return void
*/
public function push( $jobs ) {
@@ -115,13 +118,11 @@ class JobQueueGroup {
return;
}
+ $this->assertValidJobs( $jobs );
+
$jobsByType = array(); // (job type => list of jobs)
foreach ( $jobs as $job ) {
- if ( $job instanceof IJobSpecification ) {
- $jobsByType[$job->getType()][] = $job;
- } else {
- throw new MWException( "Attempted to push a non-Job object into a queue." );
- }
+ $jobsByType[$job->getType()][] = $job;
}
foreach ( $jobsByType as $type => $jobs ) {
@@ -137,6 +138,42 @@ class JobQueueGroup {
}
/**
+ * Buffer jobs for insertion via push() or call it now if in CLI mode
+ *
+ * Note that MediaWiki::restInPeace() calls pushLazyJobs()
+ *
+ * @param IJobSpecification|IJobSpecification[] $jobs A single Job or a list of Jobs
+ * @return void
+ * @since 1.26
+ */
+ public function lazyPush( $jobs ) {
+ if ( PHP_SAPI === 'cli' ) {
+ $this->push( $jobs );
+ return;
+ }
+
+ $jobs = is_array( $jobs ) ? $jobs : array( $jobs );
+
+ // Throw errors now instead of on push(), when other jobs may be buffered
+ $this->assertValidJobs( $jobs );
+
+ $this->bufferedJobs = array_merge( $this->bufferedJobs, $jobs );
+ }
+
+ /**
+ * Push all jobs buffered via lazyPush() into their respective queues
+ *
+ * @return void
+ * @since 1.26
+ */
+ public static function pushLazyJobs() {
+ foreach ( self::$instances as $group ) {
+ $group->push( $group->bufferedJobs );
+ $group->bufferedJobs = array();
+ }
+ }
+
+ /**
* Pop a job off one of the job queues
*
* This pops a job off a queue as specified by $wgJobTypeConf and
@@ -188,10 +225,10 @@ class JobQueueGroup {
* Acknowledge that a job was completed
*
* @param Job $job
- * @return bool
+ * @return void
*/
public function ack( Job $job ) {
- return $this->get( $job->getType() )->ack( $job );
+ $this->get( $job->getType() )->ack( $job );
}
/**
@@ -211,7 +248,6 @@ class JobQueueGroup {
* This does nothing for certain queue classes.
*
* @return void
- * @throws MWException
*/
public function waitForBackups() {
global $wgJobTypeConf;
@@ -342,69 +378,6 @@ class JobQueueGroup {
}
/**
- * Execute any due periodic queue maintenance tasks for all queues.
- *
- * A task is "due" if the time ellapsed since the last run is greater than
- * the defined run period. Concurrent calls to this function will cause tasks
- * to be attempted twice, so they may need their own methods of mutual exclusion.
- *
- * @return int Number of tasks run
- */
- public function executeReadyPeriodicTasks() {
- global $wgMemc;
-
- list( $db, $prefix ) = wfSplitWikiID( $this->wiki );
- $key = wfForeignMemcKey( $db, $prefix, 'jobqueuegroup', 'taskruns', 'v1' );
- $lastRuns = $wgMemc->get( $key ); // (queue => task => UNIX timestamp)
-
- $count = 0;
- $tasksRun = array(); // (queue => task => UNIX timestamp)
- foreach ( $this->getQueueTypes() as $type ) {
- $queue = $this->get( $type );
- foreach ( $queue->getPeriodicTasks() as $task => $definition ) {
- if ( $definition['period'] <= 0 ) {
- continue; // disabled
- } elseif ( !isset( $lastRuns[$type][$task] )
- || $lastRuns[$type][$task] < ( time() - $definition['period'] )
- ) {
- try {
- if ( call_user_func( $definition['callback'] ) !== null ) {
- $tasksRun[$type][$task] = time();
- ++$count;
- }
- } catch ( JobQueueError $e ) {
- MWExceptionHandler::logException( $e );
- }
- }
- }
- }
-
- if ( $count === 0 ) {
- return $count; // nothing to update
- }
-
- $wgMemc->merge( $key, function ( $cache, $key, $lastRuns ) use ( $tasksRun ) {
- if ( is_array( $lastRuns ) ) {
- foreach ( $tasksRun as $type => $tasks ) {
- foreach ( $tasks as $task => $timestamp ) {
- if ( !isset( $lastRuns[$type][$task] )
- || $timestamp > $lastRuns[$type][$task]
- ) {
- $lastRuns[$type][$task] = $timestamp;
- }
- }
- }
- } else {
- $lastRuns = $tasksRun;
- }
-
- return $lastRuns;
- } );
-
- return $count;
- }
-
- /**
* @param string $name
* @return mixed
*/
@@ -427,4 +400,24 @@ class JobQueueGroup {
}
}
}
+
+ /**
+ * @param array $jobs
+ * @throws InvalidArgumentException
+ */
+ private function assertValidJobs( array $jobs ) {
+ foreach ( $jobs as $job ) { // sanity checks
+ if ( !( $job instanceof IJobSpecification ) ) {
+ throw new InvalidArgumentException( "Expected IJobSpecification objects" );
+ }
+ }
+ }
+
+ function __destruct() {
+ $n = count( $this->bufferedJobs );
+ if ( $n > 0 ) {
+ $type = implode( ', ', array_unique( array_map( 'get_class', $this->bufferedJobs ) ) );
+ trigger_error( __METHOD__ . ": $n buffered job(s) of type(s) $type never inserted." );
+ }
+ }
}
diff --git a/includes/jobqueue/JobQueueRedis.php b/includes/jobqueue/JobQueueRedis.php
index 6c823fb9..29c8068a 100644
--- a/includes/jobqueue/JobQueueRedis.php
+++ b/includes/jobqueue/JobQueueRedis.php
@@ -81,6 +81,7 @@ class JobQueueRedis extends JobQueue {
* - daemonized : Set to true if the redisJobRunnerService runs in the background.
* This will disable job recycling/undelaying from the MediaWiki side
* to avoid redundance and out-of-sync configuration.
+ * @throws InvalidArgumentException
*/
public function __construct( array $params ) {
parent::__construct( $params );
@@ -89,7 +90,7 @@ class JobQueueRedis extends JobQueue {
$this->compression = isset( $params['compression'] ) ? $params['compression'] : 'none';
$this->redisPool = RedisConnectionPool::singleton( $params['redisConfig'] );
if ( empty( $params['daemonized'] ) ) {
- throw new Exception(
+ throw new InvalidArgumentException(
"Non-daemonized mode is no longer supported. Please install the " .
"mediawiki/services/jobrunner service and update \$wgJobTypeConf as needed." );
}
@@ -110,7 +111,7 @@ class JobQueueRedis extends JobQueue {
/**
* @see JobQueue::doIsEmpty()
* @return bool
- * @throws MWException
+ * @throws JobQueueError
*/
protected function doIsEmpty() {
return $this->doGetSize() == 0;
@@ -119,7 +120,7 @@ class JobQueueRedis extends JobQueue {
/**
* @see JobQueue::doGetSize()
* @return int
- * @throws MWException
+ * @throws JobQueueError
*/
protected function doGetSize() {
$conn = $this->getConnection();
@@ -205,7 +206,7 @@ class JobQueueRedis extends JobQueue {
if ( $flags & self::QOS_ATOMIC ) {
$batches = array( $items ); // all or nothing
} else {
- $batches = array_chunk( $items, 500 ); // avoid tying up the server
+ $batches = array_chunk( $items, 100 ); // avoid tying up the server
}
$failed = 0;
$pushed = 0;
@@ -222,9 +223,9 @@ class JobQueueRedis extends JobQueue {
throw new RedisException( "Could not insert {$failed} {$this->type} job(s)." );
}
- JobQueue::incrStats( 'job-insert', $this->type, count( $items ), $this->wiki );
- JobQueue::incrStats( 'job-insert-duplicate', $this->type,
- count( $items ) - $failed - $pushed, $this->wiki );
+ JobQueue::incrStats( 'inserts', $this->type, count( $items ) );
+ JobQueue::incrStats( 'dupe_inserts', $this->type,
+ count( $items ) - $failed - $pushed );
} catch ( RedisException $e ) {
$this->throwRedisException( $conn, $e );
}
@@ -300,7 +301,7 @@ LUA;
break; // no jobs; nothing to do
}
- JobQueue::incrStats( 'job-pop', $this->type, 1, $this->wiki );
+ JobQueue::incrStats( 'job-pop', $this->type );
$item = $this->unserialize( $blob );
if ( $item === false ) {
wfDebugLog( 'JobQueueRedis', "Could not unserialize {$this->type} job." );
@@ -356,13 +357,15 @@ LUA;
* @see JobQueue::doAck()
* @param Job $job
* @return Job|bool
- * @throws MWException|JobQueueError
+ * @throws UnexpectedValueException
+ * @throws JobQueueError
*/
protected function doAck( Job $job ) {
if ( !isset( $job->metadata['uuid'] ) ) {
- throw new MWException( "Job of type '{$job->getType()}' has no UUID." );
+ throw new UnexpectedValueException( "Job of type '{$job->getType()}' has no UUID." );
}
+ $uuid = $job->metadata['uuid'];
$conn = $this->getConnection();
try {
static $script =
@@ -379,16 +382,18 @@ LUA;
$this->getQueueKey( 'z-claimed' ), # KEYS[1]
$this->getQueueKey( 'h-attempts' ), # KEYS[2]
$this->getQueueKey( 'h-data' ), # KEYS[3]
- $job->metadata['uuid'] # ARGV[1]
+ $uuid # ARGV[1]
),
3 # number of first argument(s) that are keys
);
if ( !$res ) {
- wfDebugLog( 'JobQueueRedis', "Could not acknowledge {$this->type} job." );
+ wfDebugLog( 'JobQueueRedis', "Could not acknowledge {$this->type} job $uuid." );
return false;
}
+
+ JobQueue::incrStats( 'job-ack', $this->type );
} catch ( RedisException $e ) {
$this->throwRedisException( $conn, $e );
}
@@ -398,13 +403,14 @@ LUA;
/**
* @see JobQueue::doDeduplicateRootJob()
- * @param Job $job
+ * @param IJobSpecification $job
* @return bool
- * @throws MWException|JobQueueError
+ * @throws JobQueueError
+ * @throws LogicException
*/
- protected function doDeduplicateRootJob( Job $job ) {
+ protected function doDeduplicateRootJob( IJobSpecification $job ) {
if ( !$job->hasRootJobParams() ) {
- throw new MWException( "Cannot register root job; missing parameters." );
+ throw new LogicException( "Cannot register root job; missing parameters." );
}
$params = $job->getRootJobParams();
@@ -441,6 +447,7 @@ LUA;
// Get the last time this root job was enqueued
$timestamp = $conn->get( $this->getRootJobCacheKey( $params['rootJobSignature'] ) );
} catch ( RedisException $e ) {
+ $timestamp = false;
$this->throwRedisException( $conn, $e );
}
@@ -473,70 +480,84 @@ LUA;
/**
* @see JobQueue::getAllQueuedJobs()
* @return Iterator
+ * @throws JobQueueError
*/
public function getAllQueuedJobs() {
$conn = $this->getConnection();
try {
- $that = $this;
-
- return new MappedIterator(
- $conn->lRange( $this->getQueueKey( 'l-unclaimed' ), 0, -1 ),
- function ( $uid ) use ( $that, $conn ) {
- return $that->getJobFromUidInternal( $uid, $conn );
- },
- array( 'accept' => function ( $job ) {
- return is_object( $job );
- } )
- );
+ $uids = $conn->lRange( $this->getQueueKey( 'l-unclaimed' ), 0, -1 );
} catch ( RedisException $e ) {
$this->throwRedisException( $conn, $e );
}
+
+ return $this->getJobIterator( $conn, $uids );
}
/**
- * @see JobQueue::getAllQueuedJobs()
+ * @see JobQueue::getAllDelayedJobs()
* @return Iterator
+ * @throws JobQueueError
*/
public function getAllDelayedJobs() {
$conn = $this->getConnection();
try {
- $that = $this;
-
- return new MappedIterator( // delayed jobs
- $conn->zRange( $this->getQueueKey( 'z-delayed' ), 0, -1 ),
- function ( $uid ) use ( $that, $conn ) {
- return $that->getJobFromUidInternal( $uid, $conn );
- },
- array( 'accept' => function ( $job ) {
- return is_object( $job );
- } )
- );
+ $uids = $conn->zRange( $this->getQueueKey( 'z-delayed' ), 0, -1 );
} catch ( RedisException $e ) {
$this->throwRedisException( $conn, $e );
}
+
+ return $this->getJobIterator( $conn, $uids );
+ }
+
+ /**
+ * @see JobQueue::getAllAcquiredJobs()
+ * @return Iterator
+ * @throws JobQueueError
+ */
+ public function getAllAcquiredJobs() {
+ $conn = $this->getConnection();
+ try {
+ $uids = $conn->zRange( $this->getQueueKey( 'z-claimed' ), 0, -1 );
+ } catch ( RedisException $e ) {
+ $this->throwRedisException( $conn, $e );
+ }
+
+ return $this->getJobIterator( $conn, $uids );
}
/**
* @see JobQueue::getAllAbandonedJobs()
* @return Iterator
+ * @throws JobQueueError
*/
public function getAllAbandonedJobs() {
$conn = $this->getConnection();
try {
- $that = $this;
-
- return new MappedIterator( // delayed jobs
- $conn->zRange( $this->getQueueKey( 'z-abandoned' ), 0, -1 ),
- function ( $uid ) use ( $that, $conn ) {
- return $that->getJobFromUidInternal( $uid, $conn );
- },
- array( 'accept' => function ( $job ) {
- return is_object( $job );
- } )
- );
+ $uids = $conn->zRange( $this->getQueueKey( 'z-abandoned' ), 0, -1 );
} catch ( RedisException $e ) {
$this->throwRedisException( $conn, $e );
}
+
+ return $this->getJobIterator( $conn, $uids );
+ }
+
+ /**
+ * @param RedisConnRef $conn
+ * @param array $uids List of job UUIDs
+ * @return MappedIterator
+ */
+ protected function getJobIterator( RedisConnRef $conn, array $uids ) {
+ $that = $this;
+
+ return new MappedIterator(
+ $uids,
+ function ( $uid ) use ( $that, $conn ) {
+ return $that->getJobFromUidInternal( $uid, $conn );
+ },
+ array( 'accept' => function ( $job ) {
+ return is_object( $job );
+ } )
+ );
}
public function getCoalesceLocationInternal() {
@@ -575,7 +596,8 @@ LUA;
* @param string $uid
* @param RedisConnRef $conn
* @return Job|bool Returns false if the job does not exist
- * @throws MWException|JobQueueError
+ * @throws JobQueueError
+ * @throws UnexpectedValueException
*/
public function getJobFromUidInternal( $uid, RedisConnRef $conn ) {
try {
@@ -583,13 +605,16 @@ LUA;
if ( $data === false ) {
return false; // not found
}
- $item = $this->unserialize( $conn->hGet( $this->getQueueKey( 'h-data' ), $uid ) );
+ $item = $this->unserialize( $data );
if ( !is_array( $item ) ) { // this shouldn't happen
- throw new MWException( "Could not find job with ID '$uid'." );
+ throw new UnexpectedValueException( "Could not find job with ID '$uid'." );
}
$title = Title::makeTitle( $item['namespace'], $item['title'] );
$job = Job::factory( $item['type'], $title, $item['params'] );
$job->metadata['uuid'] = $item['uuid'];
+ $job->metadata['timestamp'] = $item['timestamp'];
+ // Add in attempt count for debugging at showJobs.php
+ $job->metadata['attempts'] = $conn->hGet( $this->getQueueKey( 'h-attempts' ), $uid );
return $job;
} catch ( RedisException $e ) {
@@ -598,13 +623,6 @@ LUA;
}
/**
- * @return array
- */
- protected function doGetPeriodicTasks() {
- return array(); // managed in the runner loop
- }
-
- /**
* @param IJobSpecification $job
* @return array
*/
@@ -631,15 +649,12 @@ LUA;
* @return Job|bool
*/
protected function getJobFromFields( array $fields ) {
- $title = Title::makeTitleSafe( $fields['namespace'], $fields['title'] );
- if ( $title ) {
- $job = Job::factory( $fields['type'], $title, $fields['params'] );
- $job->metadata['uuid'] = $fields['uuid'];
+ $title = Title::makeTitle( $fields['namespace'], $fields['title'] );
+ $job = Job::factory( $fields['type'], $title, $fields['params'] );
+ $job->metadata['uuid'] = $fields['uuid'];
+ $job->metadata['timestamp'] = $fields['timestamp'];
- return $job;
- }
-
- return false;
+ return $job;
}
/**
diff --git a/includes/jobqueue/JobRunner.php b/includes/jobqueue/JobRunner.php
index b8c5d6cf..13043629 100644
--- a/includes/jobqueue/JobRunner.php
+++ b/includes/jobqueue/JobRunner.php
@@ -36,6 +36,11 @@ class JobRunner implements LoggerAwareInterface {
protected $debug;
/**
+ * @var LoggerInterface $logger
+ */
+ protected $logger;
+
+ /**
* @param callable $debug Optional debug output handler
*/
public function setDebugHandler( $debug ) {
@@ -43,12 +48,8 @@ class JobRunner implements LoggerAwareInterface {
}
/**
- * @var LoggerInterface $logger
- */
- protected $logger;
-
- /**
* @param LoggerInterface $logger
+ * @return void
*/
public function setLogger( LoggerInterface $logger ) {
$this->logger = $logger;
@@ -88,7 +89,7 @@ class JobRunner implements LoggerAwareInterface {
* @return array Summary response that can easily be JSON serialized
*/
public function run( array $options ) {
- global $wgJobClasses;
+ global $wgJobClasses, $wgTrxProfilerLimits;
$response = array( 'jobs' => array(), 'reached' => 'none-ready' );
@@ -102,43 +103,43 @@ class JobRunner implements LoggerAwareInterface {
return $response;
}
- $group = JobQueueGroup::singleton();
- // Handle any required periodic queue maintenance
- $count = $group->executeReadyPeriodicTasks();
- if ( $count > 0 ) {
- $msg = "Executed $count periodic queue task(s).";
- $this->logger->debug( $msg );
- $this->debugCallback( $msg );
- }
-
// Bail out if in read-only mode
if ( wfReadOnly() ) {
$response['reached'] = 'read-only';
return $response;
}
- // Bail out if there is too much DB lag
- list( , $maxLag ) = wfGetLBFactory()->getMainLB( wfWikiID() )->getMaxLag();
- if ( $maxLag >= 5 ) {
+ // Catch huge single updates that lead to slave lag
+ $trxProfiler = Profiler::instance()->getTransactionProfiler();
+ $trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
+ $trxProfiler->setExpectations( $wgTrxProfilerLimits['JobRunner'], __METHOD__ );
+
+ // Bail out if there is too much DB lag.
+ // This check should not block as we want to try other wiki queues.
+ $maxAllowedLag = 3;
+ list( , $maxLag ) = wfGetLB( wfWikiID() )->getMaxLag();
+ if ( $maxLag >= $maxAllowedLag ) {
$response['reached'] = 'slave-lag-limit';
return $response;
}
+ $group = JobQueueGroup::singleton();
+
// Flush any pending DB writes for sanity
- wfGetLBFactory()->commitMasterChanges();
+ wfGetLBFactory()->commitAll();
// Some jobs types should not run until a certain timestamp
$backoffs = array(); // map of (type => UNIX expiry)
$backoffDeltas = array(); // map of (type => seconds)
$wait = 'wait'; // block to read backoffs the first time
- $jobsRun = 0;
+ $stats = RequestContext::getMain()->getStats();
+ $jobsPopped = 0;
$timeMsTotal = 0;
$flags = JobQueueGroup::USE_CACHE;
- $checkPeriod = 5.0; // seconds
- $checkPhase = mt_rand( 0, 1000 * $checkPeriod ) / 1000; // avoid stampedes
$startTime = microtime( true ); // time since jobs started running
- $lastTime = microtime( true ) - $checkPhase; // time since last slave check
+ $checkLagPeriod = 1.0; // check slave lag this many seconds
+ $lastCheckTime = 1; // timestamp of last slave check
do {
// Sync the persistent backoffs with concurrent runners
$backoffs = $this->syncBackoffDeltas( $backoffs, $backoffDeltas, $wait );
@@ -154,6 +155,7 @@ class JobRunner implements LoggerAwareInterface {
}
if ( $job ) { // found a job
+ $popTime = time();
$jType = $job->getType();
// Back off of certain jobs for a while (for throttling and for errors)
@@ -168,25 +170,47 @@ class JobRunner implements LoggerAwareInterface {
}
$msg = $job->toString() . " STARTING";
- $this->logger->info( $msg );
+ $this->logger->debug( $msg );
$this->debugCallback( $msg );
// Run the job...
$jobStartTime = microtime( true );
try {
- ++$jobsRun;
+ ++$jobsPopped;
$status = $job->run();
$error = $job->getLastError();
- wfGetLBFactory()->commitMasterChanges();
+ $this->commitMasterChanges( $job );
+
+ DeferredUpdates::doUpdates();
+ $this->commitMasterChanges( $job );
} catch ( Exception $e ) {
MWExceptionHandler::rollbackMasterChangesAndLog( $e );
$status = false;
$error = get_class( $e ) . ': ' . $e->getMessage();
MWExceptionHandler::logException( $e );
}
+ // Commit all outstanding connections that are in a transaction
+ // to get a fresh repeatable read snapshot on every connection.
+ wfGetLBFactory()->commitAll();
$timeMs = intval( ( microtime( true ) - $jobStartTime ) * 1000 );
$timeMsTotal += $timeMs;
+ // Record how long jobs wait before getting popped
+ $readyTs = $job->getReadyTimestamp();
+ if ( $readyTs ) {
+ $pickupDelay = $popTime - $readyTs;
+ $stats->timing( 'jobqueue.pickup_delay.all', 1000 * $pickupDelay );
+ $stats->timing( "jobqueue.pickup_delay.$jType", 1000 * $pickupDelay );
+ }
+ // Record root job age for jobs being run
+ $root = $job->getRootJobParams();
+ if ( $root['rootJobTimestamp'] ) {
+ $age = $popTime - wfTimestamp( TS_UNIX, $root['rootJobTimestamp'] );
+ $stats->timing( "jobqueue.pickup_root_age.$jType", 1000 * $age );
+ }
+ // Track the execution time for jobs
+ $stats->timing( "jobqueue.run.$jType", $timeMs );
+
// Mark the job as done on success or when the job cannot be retried
if ( $status !== false || !$job->allowRetries() ) {
$group->ack( $job ); // done
@@ -218,7 +242,7 @@ class JobRunner implements LoggerAwareInterface {
);
// Break out if we hit the job count or wall time limits...
- if ( $maxJobs && $jobsRun >= $maxJobs ) {
+ if ( $maxJobs && $jobsPopped >= $maxJobs ) {
$response['reached'] = 'job-limit';
break;
} elseif ( $maxTime && ( microtime( true ) - $startTime ) > $maxTime ) {
@@ -229,21 +253,24 @@ class JobRunner implements LoggerAwareInterface {
// Don't let any of the main DB slaves get backed up.
// This only waits for so long before exiting and letting
// other wikis in the farm (on different masters) get a chance.
- $timePassed = microtime( true ) - $lastTime;
- if ( $timePassed >= 5 || $timePassed < 0 ) {
- if ( !wfWaitForSlaves( $lastTime, false, '*', 5 ) ) {
+ $timePassed = microtime( true ) - $lastCheckTime;
+ if ( $timePassed >= $checkLagPeriod || $timePassed < 0 ) {
+ if ( !wfWaitForSlaves( $lastCheckTime, false, '*', $maxAllowedLag ) ) {
$response['reached'] = 'slave-lag-limit';
break;
}
- $lastTime = microtime( true );
+ $lastCheckTime = microtime( true );
}
// Don't let any queue slaves/backups fall behind
- if ( $jobsRun > 0 && ( $jobsRun % 100 ) == 0 ) {
+ if ( $jobsPopped > 0 && ( $jobsPopped % 100 ) == 0 ) {
$group->waitForBackups();
}
// Bail if near-OOM instead of in a job
- $this->assertMemoryOK();
+ if ( !$this->checkMemoryOK() ) {
+ $response['reached'] = 'memory-limit';
+ break;
+ }
}
} while ( $job ); // stop when there are no jobs
@@ -298,7 +325,6 @@ class JobRunner implements LoggerAwareInterface {
* @return array Map of (job type => backoff expiry timestamp)
*/
private function loadBackoffs( array $backoffs, $mode = 'wait' ) {
-
$file = wfTempDir() . '/mw-runJobs-backoffs.json';
if ( is_file( $file ) ) {
$noblock = ( $mode === 'nowait' ) ? LOCK_NB : 0;
@@ -336,7 +362,6 @@ class JobRunner implements LoggerAwareInterface {
* @return array The new backoffs account for $backoffs and the latest file data
*/
private function syncBackoffDeltas( array $backoffs, array &$deltas, $mode = 'wait' ) {
-
if ( !$deltas ) {
return $this->loadBackoffs( $backoffs, $mode );
}
@@ -374,9 +399,9 @@ class JobRunner implements LoggerAwareInterface {
/**
* Make sure that this script is not too close to the memory usage limit.
* It is better to die in between jobs than OOM right in the middle of one.
- * @throws MWException
+ * @return bool
*/
- private function assertMemoryOK() {
+ private function checkMemoryOK() {
static $maxBytes = null;
if ( $maxBytes === null ) {
$m = array();
@@ -390,8 +415,14 @@ class JobRunner implements LoggerAwareInterface {
}
$usedBytes = memory_get_usage();
if ( $maxBytes && $usedBytes >= 0.95 * $maxBytes ) {
- throw new MWException( "Detected excessive memory usage ($usedBytes/$maxBytes)." );
+ $msg = "Detected excessive memory usage ($usedBytes/$maxBytes).";
+ $this->debugCallback( $msg );
+ $this->logger->error( $msg );
+
+ return false;
}
+
+ return true;
}
/**
@@ -403,4 +434,68 @@ class JobRunner implements LoggerAwareInterface {
call_user_func_array( $this->debug, array( wfTimestamp( TS_DB ) . " $msg\n" ) );
}
}
+
+ /**
+ * Issue a commit on all masters who are currently in a transaction and have
+ * made changes to the database. It also supports sometimes waiting for the
+ * local wiki's slaves to catch up. See the documentation for
+ * $wgJobSerialCommitThreshold for more.
+ *
+ * @param Job $job
+ * @throws DBError
+ */
+ private function commitMasterChanges( Job $job ) {
+ global $wgJobSerialCommitThreshold;
+
+ $lb = wfGetLB( wfWikiID() );
+ if ( $wgJobSerialCommitThreshold !== false ) {
+ // Generally, there is one master connection to the local DB
+ $dbwSerial = $lb->getAnyOpenConnection( $lb->getWriterIndex() );
+ } else {
+ $dbwSerial = false;
+ }
+
+ if ( !$dbwSerial
+ || !$dbwSerial->namedLocksEnqueue()
+ || $dbwSerial->pendingWriteQueryDuration() < $wgJobSerialCommitThreshold
+ ) {
+ // Writes are all to foreign DBs, named locks don't form queues,
+ // or $wgJobSerialCommitThreshold is not reached; commit changes now
+ wfGetLBFactory()->commitMasterChanges();
+ return;
+ }
+
+ $ms = intval( 1000 * $dbwSerial->pendingWriteQueryDuration() );
+ $msg = $job->toString() . " COMMIT ENQUEUED [{$ms}ms of writes]";
+ $this->logger->info( $msg );
+ $this->debugCallback( $msg );
+
+ // Wait for an exclusive lock to commit
+ if ( !$dbwSerial->lock( 'jobrunner-serial-commit', __METHOD__, 30 ) ) {
+ // This will trigger a rollback in the main loop
+ throw new DBError( $dbwSerial, "Timed out waiting on commit queue." );
+ }
+ // Wait for the generic slave to catch up
+ $pos = $lb->getMasterPos();
+ if ( $pos ) {
+ $lb->waitForOne( $pos );
+ }
+
+ $fname = __METHOD__;
+ // Re-ping all masters with transactions. This throws DBError if some
+ // connection died while waiting on locks/slaves, triggering a rollback.
+ wfGetLBFactory()->forEachLB( function( LoadBalancer $lb ) use ( $fname ) {
+ $lb->forEachOpenConnection( function( DatabaseBase $conn ) use ( $fname ) {
+ if ( $conn->writesOrCallbacksPending() ) {
+ $conn->query( "SELECT 1", $fname );
+ }
+ } );
+ } );
+
+ // Actually commit the DB master changes
+ wfGetLBFactory()->commitMasterChanges();
+
+ // Release the lock
+ $dbwSerial->unlock( 'jobrunner-serial-commit', __METHOD__ );
+ }
}
diff --git a/includes/jobqueue/JobSpecification.php b/includes/jobqueue/JobSpecification.php
index 42d2a39b..d59c09b5 100644
--- a/includes/jobqueue/JobSpecification.php
+++ b/includes/jobqueue/JobSpecification.php
@@ -59,6 +59,26 @@ interface IJobSpecification {
public function getDeduplicationInfo();
/**
+ * @see JobQueue::deduplicateRootJob()
+ * @return array
+ * @since 1.26
+ */
+ public function getRootJobParams();
+
+ /**
+ * @see JobQueue::deduplicateRootJob()
+ * @return bool
+ * @since 1.22
+ */
+ public function hasRootJobParams();
+
+ /**
+ * @see JobQueue::deduplicateRootJob()
+ * @return bool Whether this is job is a root job
+ */
+ public function isRootJob();
+
+ /**
* @return Title Descriptive title (this can simply be informative)
*/
public function getTitle();
@@ -68,7 +88,7 @@ interface IJobSpecification {
* Job queue task description base code
*
* Example usage:
- * <code>
+ * @code
* $job = new JobSpecification(
* 'null',
* array( 'lives' => 1, 'usleep' => 100, 'pi' => 3.141569 ),
@@ -76,7 +96,7 @@ interface IJobSpecification {
* Title::makeTitle( NS_SPECIAL, 'nullity' )
* );
* JobQueueGroup::singleton()->push( $job )
- * </code>
+ * @endcode
*
* @ingroup JobQueue
* @since 1.23
@@ -97,7 +117,7 @@ class JobSpecification implements IJobSpecification {
/**
* @param string $type
* @param array $params Map of key/values
- * @param array $opts Map of key/values
+ * @param array $opts Map of key/values; includes 'removeDuplicates'
* @param Title $title Optional descriptive title
*/
public function __construct(
@@ -108,7 +128,7 @@ class JobSpecification implements IJobSpecification {
$this->type = $type;
$this->params = $params;
- $this->title = $title ?: Title::newMainPage();
+ $this->title = $title ?: Title::makeTitle( NS_SPECIAL, 'Badtitle/' . get_class( $this ) );
$this->opts = $opts;
}
@@ -125,51 +145,28 @@ class JobSpecification implements IJobSpecification {
}
}
- /**
- * @return string
- */
public function getType() {
return $this->type;
}
- /**
- * @return Title
- */
public function getTitle() {
return $this->title;
}
- /**
- * @return array
- */
public function getParams() {
return $this->params;
}
- /**
- * @return int|null UNIX timestamp to delay running this job until, otherwise null
- */
public function getReleaseTimestamp() {
return isset( $this->params['jobReleaseTimestamp'] )
? wfTimestampOrNull( TS_UNIX, $this->params['jobReleaseTimestamp'] )
: null;
}
- /**
- * @return bool Whether only one of each identical set of jobs should be run
- */
public function ignoreDuplicates() {
return !empty( $this->opts['removeDuplicates'] );
}
- /**
- * Subclasses may need to override this to make duplication detection work.
- * The resulting map conveys everything that makes the job unique. This is
- * only checked if ignoreDuplicates() returns true, meaning that duplicate
- * jobs are supposed to be ignored.
- *
- * @return array Map of key/values
- */
public function getDeduplicationInfo() {
$info = array(
'type' => $this->getType(),
@@ -188,6 +185,26 @@ class JobSpecification implements IJobSpecification {
return $info;
}
+ public function getRootJobParams() {
+ return array(
+ 'rootJobSignature' => isset( $this->params['rootJobSignature'] )
+ ? $this->params['rootJobSignature']
+ : null,
+ 'rootJobTimestamp' => isset( $this->params['rootJobTimestamp'] )
+ ? $this->params['rootJobTimestamp']
+ : null
+ );
+ }
+
+ public function hasRootJobParams() {
+ return isset( $this->params['rootJobSignature'] )
+ && isset( $this->params['rootJobTimestamp'] );
+ }
+
+ public function isRootJob() {
+ return $this->hasRootJobParams() && !empty( $this->params['rootJobIsSelf'] );
+ }
+
/**
* @return array Field/value map that can immediately be serialized
* @since 1.25
diff --git a/includes/jobqueue/aggregator/JobQueueAggregator.php b/includes/jobqueue/aggregator/JobQueueAggregator.php
index febc277a..aa02d1fa 100644
--- a/includes/jobqueue/aggregator/JobQueueAggregator.php
+++ b/includes/jobqueue/aggregator/JobQueueAggregator.php
@@ -169,4 +169,4 @@ class JobQueueAggregatorNull extends JobQueueAggregator {
protected function doPurge() {
return true;
}
-} \ No newline at end of file
+}
diff --git a/includes/jobqueue/aggregator/JobQueueAggregatorRedis.php b/includes/jobqueue/aggregator/JobQueueAggregatorRedis.php
index 847dd6f4..6c49646b 100644
--- a/includes/jobqueue/aggregator/JobQueueAggregatorRedis.php
+++ b/includes/jobqueue/aggregator/JobQueueAggregatorRedis.php
@@ -77,6 +77,7 @@ class JobQueueAggregatorRedis extends JobQueueAggregator {
try {
$conn->multi( Redis::PIPELINE );
$conn->hSetNx( $this->getQueueTypesKey(), $type, 'enabled' );
+ $conn->sAdd( $this->getWikiSetKey(), $wiki );
$conn->hSet( $this->getReadyQueueKey(), $this->encQueueName( $type, $wiki ), time() );
$conn->exec();
@@ -198,6 +199,13 @@ class JobQueueAggregatorRedis extends JobQueueAggregator {
}
/**
+ * @return string
+ */
+ private function getWikiSetKey() {
+ return "jobqueue:aggregator:s-wikis:v2"; // global
+ }
+
+ /**
* @param string $type
* @param string $wiki
* @return string
diff --git a/includes/jobqueue/jobs/ActivityUpdateJob.php b/includes/jobqueue/jobs/ActivityUpdateJob.php
new file mode 100644
index 00000000..f146e6e8
--- /dev/null
+++ b/includes/jobqueue/jobs/ActivityUpdateJob.php
@@ -0,0 +1,75 @@
+<?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
+ * @author Aaron Schulz
+ * @ingroup JobQueue
+ */
+
+/**
+ * Job for updating user activity like "last viewed" timestamps
+ *
+ * @ingroup JobQueue
+ * @since 1.26
+ */
+class ActivityUpdateJob extends Job {
+ function __construct( Title $title, array $params ) {
+ parent::__construct( 'activityUpdateJob', $title, $params );
+
+ if ( !isset( $params['type'] ) ) {
+ throw new InvalidArgumentException( "Missing 'type' parameter." );
+ }
+
+ $this->removeDuplicates = true;
+ }
+
+ public function run() {
+ if ( $this->params['type'] === 'updateWatchlistNotification' ) {
+ $this->updateWatchlistNotification();
+ } else {
+ throw new Exception( "Invalid 'type' parameter '{$this->params['type']}'." );
+ }
+
+ return true;
+ }
+
+ protected function updateWatchlistNotification() {
+ $casTimestamp = ( $this->params['notifTime'] !== null )
+ ? $this->params['notifTime']
+ : $this->params['curTime'];
+
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update( 'watchlist',
+ array(
+ 'wl_notificationtimestamp' => $dbw->timestampOrNull( $this->params['notifTime'] )
+ ),
+ array(
+ 'wl_user' => $this->params['userid'],
+ 'wl_namespace' => $this->title->getNamespace(),
+ 'wl_title' => $this->title->getDBkey(),
+ // Add a "check and set" style comparison to handle conflicts.
+ // The inequality always avoids updates when the current value
+ // is already NULL per ANSI SQL. This is desired since NULL means
+ // that the user is "caught up" on edits already. When the field
+ // is non-NULL, make sure not to set it back in time or set it to
+ // NULL when newer revisions were in fact added to the page.
+ 'wl_notificationtimestamp < ' . $dbw->addQuotes( $dbw->timestamp( $casTimestamp ) )
+ ),
+ __METHOD__
+ );
+ }
+}
diff --git a/includes/jobqueue/jobs/AssembleUploadChunksJob.php b/includes/jobqueue/jobs/AssembleUploadChunksJob.php
index b7f09e77..a1de77e6 100644
--- a/includes/jobqueue/jobs/AssembleUploadChunksJob.php
+++ b/includes/jobqueue/jobs/AssembleUploadChunksJob.php
@@ -27,7 +27,7 @@
* @ingroup Upload
*/
class AssembleUploadChunksJob extends Job {
- public function __construct( $title, $params ) {
+ public function __construct( Title $title, array $params ) {
parent::__construct( 'AssembleUploadChunks', $title, $params );
$this->removeDuplicates = true;
}
diff --git a/includes/jobqueue/jobs/DoubleRedirectJob.php b/includes/jobqueue/jobs/DoubleRedirectJob.php
index 2561f2f1..ab638967 100644
--- a/includes/jobqueue/jobs/DoubleRedirectJob.php
+++ b/includes/jobqueue/jobs/DoubleRedirectJob.php
@@ -41,6 +41,16 @@ class DoubleRedirectJob extends Job {
private static $user;
/**
+ * @param Title $title
+ * @param array $params
+ */
+ function __construct( Title $title, array $params ) {
+ parent::__construct( 'fixDoubleRedirect', $title, $params );
+ $this->reason = $params['reason'];
+ $this->redirTitle = Title::newFromText( $params['redirTitle'] );
+ }
+
+ /**
* Insert jobs into the job queue to fix redirects to the given title
* @param string $reason The reason for the fix, see message
* "double-redirect-fixed-<reason>"
@@ -82,16 +92,6 @@ class DoubleRedirectJob extends Job {
}
/**
- * @param Title $title
- * @param array|bool $params
- */
- function __construct( $title, $params = false ) {
- parent::__construct( 'fixDoubleRedirect', $title, $params );
- $this->reason = $params['reason'];
- $this->redirTitle = Title::newFromText( $params['redirTitle'] );
- }
-
- /**
* @return bool
*/
function run() {
diff --git a/includes/jobqueue/jobs/DuplicateJob.php b/includes/jobqueue/jobs/DuplicateJob.php
index c5e3a234..068d5319 100644
--- a/includes/jobqueue/jobs/DuplicateJob.php
+++ b/includes/jobqueue/jobs/DuplicateJob.php
@@ -33,7 +33,7 @@ final class DuplicateJob extends Job {
* @param Title $title
* @param array $params Job parameters
*/
- function __construct( $title, $params ) {
+ function __construct( Title $title, array $params ) {
parent::__construct( 'duplicate', $title, $params );
}
diff --git a/includes/jobqueue/jobs/EmaillingJob.php b/includes/jobqueue/jobs/EmaillingJob.php
index df8ae63e..beeb0673 100644
--- a/includes/jobqueue/jobs/EmaillingJob.php
+++ b/includes/jobqueue/jobs/EmaillingJob.php
@@ -28,7 +28,7 @@
* @ingroup JobQueue
*/
class EmaillingJob extends Job {
- function __construct( $title, $params ) {
+ function __construct( Title $title = null, array $params ) {
parent::__construct( 'sendMail', Title::newMainPage(), $params );
}
@@ -38,7 +38,7 @@ class EmaillingJob extends Job {
$this->params['from'],
$this->params['subj'],
$this->params['body'],
- $this->params['replyto']
+ array( 'replyTo' => $this->params['replyto'] )
);
return $status->isOK();
diff --git a/includes/jobqueue/jobs/EnotifNotifyJob.php b/includes/jobqueue/jobs/EnotifNotifyJob.php
index 1ed99a58..9a5c3c72 100644
--- a/includes/jobqueue/jobs/EnotifNotifyJob.php
+++ b/includes/jobqueue/jobs/EnotifNotifyJob.php
@@ -27,7 +27,7 @@
* @ingroup JobQueue
*/
class EnotifNotifyJob extends Job {
- function __construct( $title, $params ) {
+ function __construct( Title $title, array $params ) {
parent::__construct( 'enotifNotify', $title, $params );
}
diff --git a/includes/jobqueue/jobs/EnqueueJob.php b/includes/jobqueue/jobs/EnqueueJob.php
index 46fb2aa7..c7ee9b65 100644
--- a/includes/jobqueue/jobs/EnqueueJob.php
+++ b/includes/jobqueue/jobs/EnqueueJob.php
@@ -40,13 +40,13 @@ final class EnqueueJob extends Job {
* @param Title $title
* @param array $params Job parameters
*/
- function __construct( $title, $params ) {
+ function __construct( Title $title, array $params ) {
parent::__construct( 'enqueue', $title, $params );
}
/**
- * @param Job|JobSpecification|array $jobs
- * @return JobRouteJob
+ * @param JobSpecification|JobSpecification[] $jobs
+ * @return EnqueueJob
*/
public static function newFromLocalJobs( $jobs ) {
$jobs = is_array( $jobs ) ? $jobs : array( $jobs );
@@ -56,9 +56,11 @@ final class EnqueueJob extends Job {
/**
* @param array $jobsByWiki Map of (wiki => JobSpecification list)
- * @return JobRouteJob
+ * @return EnqueueJob
*/
public static function newFromJobsByWiki( array $jobsByWiki ) {
+ $deduplicate = true;
+
$jobMapsByWiki = array();
foreach ( $jobsByWiki as $wiki => $jobs ) {
$jobMapsByWiki[$wiki] = array();
@@ -68,10 +70,19 @@ final class EnqueueJob extends Job {
} else {
throw new InvalidArgumentException( "Jobs must be of type JobSpecification." );
}
+ $deduplicate = $deduplicate && $job->ignoreDuplicates();
}
}
- return new self( Title::newMainPage(), array( 'jobsByWiki' => $jobMapsByWiki ) );
+ $eJob = new self(
+ Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __CLASS__ ),
+ array( 'jobsByWiki' => $jobMapsByWiki )
+ );
+ // If *all* jobs to be pushed are to be de-duplicated (a common case), then
+ // de-duplicate this whole job itself to avoid build up in high traffic cases
+ $eJob->removeDuplicates = $deduplicate;
+
+ return $eJob;
}
public function run() {
diff --git a/includes/jobqueue/jobs/HTMLCacheUpdateJob.php b/includes/jobqueue/jobs/HTMLCacheUpdateJob.php
index e5e521c3..a9010c25 100644
--- a/includes/jobqueue/jobs/HTMLCacheUpdateJob.php
+++ b/includes/jobqueue/jobs/HTMLCacheUpdateJob.php
@@ -34,7 +34,7 @@
* @ingroup JobQueue
*/
class HTMLCacheUpdateJob extends Job {
- function __construct( $title, $params = '' ) {
+ function __construct( Title $title, array $params ) {
parent::__construct( 'htmlCacheUpdate', $title, $params );
// Base backlink purge jobs can be de-duplicated
$this->removeDuplicates = ( !isset( $params['range'] ) && !isset( $params['pages'] ) );
diff --git a/includes/jobqueue/jobs/NullJob.php b/includes/jobqueue/jobs/NullJob.php
index f94d6ebc..26d3c5c8 100644
--- a/includes/jobqueue/jobs/NullJob.php
+++ b/includes/jobqueue/jobs/NullJob.php
@@ -49,7 +49,7 @@ class NullJob extends Job {
* @param Title $title
* @param array $params Job parameters (lives, usleep)
*/
- function __construct( $title, $params ) {
+ function __construct( Title $title, array $params ) {
parent::__construct( 'null', $title, $params );
if ( !isset( $this->params['lives'] ) ) {
$this->params['lives'] = 1;
diff --git a/includes/jobqueue/jobs/PublishStashedFileJob.php b/includes/jobqueue/jobs/PublishStashedFileJob.php
index a922dd3d..8a180ec3 100644
--- a/includes/jobqueue/jobs/PublishStashedFileJob.php
+++ b/includes/jobqueue/jobs/PublishStashedFileJob.php
@@ -29,7 +29,7 @@
* @ingroup JobQueue
*/
class PublishStashedFileJob extends Job {
- public function __construct( $title, $params ) {
+ public function __construct( Title $title, array $params ) {
parent::__construct( 'PublishStashedFile', $title, $params );
$this->removeDuplicates = true;
}
diff --git a/includes/jobqueue/jobs/RecentChangesUpdateJob.php b/includes/jobqueue/jobs/RecentChangesUpdateJob.php
index cc04595d..d6fa26b8 100644
--- a/includes/jobqueue/jobs/RecentChangesUpdateJob.php
+++ b/includes/jobqueue/jobs/RecentChangesUpdateJob.php
@@ -27,7 +27,7 @@
* @since 1.25
*/
class RecentChangesUpdateJob extends Job {
- function __construct( $title, $params ) {
+ function __construct( Title $title, array $params ) {
parent::__construct( 'recentChangesUpdate', $title, $params );
if ( !isset( $params['type'] ) ) {
@@ -75,11 +75,13 @@ class RecentChangesUpdateJob extends Job {
$lockKey = wfWikiID() . ':recentchanges-prune';
$dbw = wfGetDB( DB_MASTER );
- if ( !$dbw->lock( $lockKey, __METHOD__, 1 ) ) {
+ if ( !$dbw->lockIsFree( $lockKey, __METHOD__ )
+ || !$dbw->lock( $lockKey, __METHOD__, 1 )
+ ) {
return; // already in progress
}
- $batchSize = 100; // Avoid slave lag
+ $batchSize = 100; // avoid slave lag
$cutoff = $dbw->timestamp( time() - $wgRCMaxAge );
do {
$rcIds = $dbw->selectFieldValues( 'recentchanges',
diff --git a/includes/jobqueue/jobs/RefreshLinksJob.php b/includes/jobqueue/jobs/RefreshLinksJob.php
index 1252b0b5..935d2fb1 100644
--- a/includes/jobqueue/jobs/RefreshLinksJob.php
+++ b/includes/jobqueue/jobs/RefreshLinksJob.php
@@ -37,7 +37,9 @@
class RefreshLinksJob extends Job {
const PARSE_THRESHOLD_SEC = 1.0;
- function __construct( $title, $params = '' ) {
+ const CLOCK_FUDGE = 10;
+
+ function __construct( Title $title, array $params ) {
parent::__construct( 'refreshLinks', $title, $params );
// A separate type is used just for cascade-protected backlinks
if ( !empty( $this->params['prioritize'] ) ) {
@@ -109,9 +111,6 @@ class RefreshLinksJob extends Job {
* @return bool
*/
protected function runForTitle( Title $title = null ) {
- $linkCache = LinkCache::singleton();
- $linkCache->clear();
-
if ( is_null( $title ) ) {
$this->setLastError( "refreshLinks: Invalid title" );
return false;
@@ -124,14 +123,18 @@ class RefreshLinksJob extends Job {
wfGetLB()->waitFor( $this->params['masterPos'] );
}
- $page = WikiPage::factory( $title );
+ // Clear out title cache data from prior job transaction snapshots
+ $linkCache = LinkCache::singleton();
+ $linkCache->clear();
- // Fetch the current revision...
+ // Fetch the current page and revision...
+ $page = WikiPage::factory( $title );
$revision = Revision::newFromTitle( $title, false, Revision::READ_NORMAL );
if ( !$revision ) {
$this->setLastError( "refreshLinks: Article not found {$title->getPrefixedDBkey()}" );
return false; // XXX: what if it was just deleted?
}
+
$content = $revision->getContent( Revision::RAW );
if ( !$content ) {
// If there is no content, pretend the content is empty
@@ -140,34 +143,50 @@ class RefreshLinksJob extends Job {
$parserOutput = false;
$parserOptions = $page->makeParserOptions( 'canonical' );
- // If page_touched changed after this root job (with a good slave lag skew factor),
- // then it is likely that any views of the pages already resulted in re-parses which
- // are now in cache. This can be reused to avoid expensive parsing in some cases.
+ // If page_touched changed after this root job, then it is likely that
+ // any views of the pages already resulted in re-parses which are now in
+ // cache. The cache can be reused to avoid expensive parsing in some cases.
if ( isset( $this->params['rootJobTimestamp'] ) ) {
- $skewedTimestamp = wfTimestamp( TS_UNIX, $this->params['rootJobTimestamp'] ) + 5;
- if ( $page->getLinksTimestamp() > wfTimestamp( TS_MW, $skewedTimestamp ) ) {
+ $opportunistic = !empty( $this->params['isOpportunistic'] );
+
+ $skewedTimestamp = $this->params['rootJobTimestamp'];
+ if ( $opportunistic ) {
+ // Neither clock skew nor DB snapshot/slave lag matter much for such
+ // updates; focus on reusing the (often recently updated) cache
+ } else {
+ // For transclusion updates, the template changes must be reflected
+ $skewedTimestamp = wfTimestamp( TS_MW,
+ wfTimestamp( TS_UNIX, $skewedTimestamp ) + self::CLOCK_FUDGE
+ );
+ }
+
+ if ( $page->getLinksTimestamp() > $skewedTimestamp ) {
// Something already updated the backlinks since this job was made
return true;
}
- if ( $page->getTouched() > wfTimestamp( TS_MW, $skewedTimestamp ) ) {
+
+ if ( $page->getTouched() >= $skewedTimestamp || $opportunistic ) {
+ // Something bumped page_touched since this job was made
+ // or the cache is otherwise suspected to be up-to-date
$parserOutput = ParserCache::singleton()->getDirty( $page, $parserOptions );
- if ( $parserOutput && $parserOutput->getCacheTime() <= $skewedTimestamp ) {
+ if ( $parserOutput && $parserOutput->getCacheTime() < $skewedTimestamp ) {
$parserOutput = false; // too stale
}
}
}
+
// Fetch the current revision and parse it if necessary...
if ( $parserOutput == false ) {
$start = microtime( true );
// Revision ID must be passed to the parser output to get revision variables correct
$parserOutput = $content->getParserOutput(
$title, $revision->getId(), $parserOptions, false );
- $ellapsed = microtime( true ) - $start;
+ $elapsed = microtime( true ) - $start;
// If it took a long time to render, then save this back to the cache to avoid
// wasted CPU by other apaches or job runners. We don't want to always save to
// cache as this can cause high cache I/O and LRU churn when a template changes.
- if ( $ellapsed >= self::PARSE_THRESHOLD_SEC
- && $page->isParserCacheUsed( $parserOptions, $revision->getId() )
+ if ( $elapsed >= self::PARSE_THRESHOLD_SEC
+ && $page->shouldCheckParserCache( $parserOptions, $revision->getId() )
&& $parserOutput->isCacheable()
) {
$ctime = wfTimestamp( TS_MW, (int)$start ); // cache time
diff --git a/includes/jobqueue/jobs/ThumbnailRenderJob.php b/includes/jobqueue/jobs/ThumbnailRenderJob.php
index ab381388..f558c488 100644
--- a/includes/jobqueue/jobs/ThumbnailRenderJob.php
+++ b/includes/jobqueue/jobs/ThumbnailRenderJob.php
@@ -27,7 +27,7 @@
* @ingroup JobQueue
*/
class ThumbnailRenderJob extends Job {
- public function __construct( $title, $params ) {
+ public function __construct( Title $title, array $params ) {
parent::__construct( 'ThumbnailRender', $title, $params );
}
@@ -50,16 +50,16 @@ class ThumbnailRenderJob extends Job {
return false;
}
} elseif ( $wgUploadThumbnailRenderMethod === 'http' ) {
- $status = $this->hitThumbUrl( $file, $transformParams );
+ $thumbUrl = '';
+ $status = $this->hitThumbUrl( $file, $transformParams, $thumbUrl );
wfDebug( __METHOD__ . ": received status {$status}\n" );
- if ( $status === 200 || $status === 301 || $status === 302 ) {
+ // 400 happens when requesting a size greater or equal than the original
+ if ( $status === 200 || $status === 301 || $status === 302 || $status === 400 ) {
return true;
} elseif ( $status ) {
- // Note that this currently happens (500) when requesting sizes larger then or
- // equal to the original, which is harmless.
- $this->setLastError( __METHOD__ . ': incorrect HTTP status ' . $status );
+ $this->setLastError( __METHOD__ . ': incorrect HTTP status ' . $status . ' when hitting ' . $thumbUrl );
return false;
} else {
$this->setLastError( __METHOD__ . ': HTTP request failure' );
@@ -75,7 +75,7 @@ class ThumbnailRenderJob extends Job {
}
}
- protected function hitThumbUrl( $file, $transformParams ) {
+ protected function hitThumbUrl( $file, $transformParams, &$thumbUrl ) {
global $wgUploadThumbnailRenderHttpCustomHost, $wgUploadThumbnailRenderHttpCustomDomain;
$thumbName = $file->thumbName( $transformParams );
diff --git a/includes/jobqueue/jobs/UploadFromUrlJob.php b/includes/jobqueue/jobs/UploadFromUrlJob.php
index d15fd025..ade48106 100644
--- a/includes/jobqueue/jobs/UploadFromUrlJob.php
+++ b/includes/jobqueue/jobs/UploadFromUrlJob.php
@@ -39,7 +39,7 @@ class UploadFromUrlJob extends Job {
/** @var User */
protected $user;
- public function __construct( $title, $params ) {
+ public function __construct( Title $title, array $params ) {
parent::__construct( 'uploadFromUrl', $title, $params );
}
@@ -166,11 +166,11 @@ class UploadFromUrlJob extends Job {
}
/**
- * Initialize the session data. Sets the intial result to queued.
+ * Initialize the session data. Sets the initial result to queued.
*/
public function initializeSessionData() {
$session =& self::getSessionData( $this->params['sessionKey'] );
- $$session['result'] = 'Queued';
+ $session['result'] = 'Queued';
}
/**
diff --git a/includes/json/FormatJson.php b/includes/json/FormatJson.php
index 095811ff..f85ee920 100644
--- a/includes/json/FormatJson.php
+++ b/includes/json/FormatJson.php
@@ -380,7 +380,7 @@ class FormatJson {
$inComment = false;
$multiline = false;
- for ($idx = 0; $idx < $maxLen; $idx++) {
+ for ( $idx = 0; $idx < $maxLen; $idx++ ) {
switch ( $str[$idx] ) {
case '"':
$lookBehind = ( $idx - 1 >= 0 ) ? $str[$idx - 1] : '';
diff --git a/includes/libs/BufferingStatsdDataFactory.php b/includes/libs/BufferingStatsdDataFactory.php
index ea5b09dc..100d2a4e 100644
--- a/includes/libs/BufferingStatsdDataFactory.php
+++ b/includes/libs/BufferingStatsdDataFactory.php
@@ -20,6 +20,8 @@
* @file
*/
+use Liuggio\StatsdClient\Entity\StatsdData;
+use Liuggio\StatsdClient\Entity\StatsdDataInterface;
use Liuggio\StatsdClient\Factory\StatsdDataFactory;
/**
@@ -38,11 +40,28 @@ class BufferingStatsdDataFactory extends StatsdDataFactory {
$this->prefix = $prefix;
}
- public function produceStatsdData( $key, $value = 1, $metric = self::STATSD_METRIC_COUNT ) {
- $this->buffer[] = $entity = $this->produceStatsdDataEntity();
+ /**
+ * Normalize a metric key for StatsD
+ *
+ * Replace occurences of '::' with dots and any other non-alphanumeric
+ * characters with underscores. Combine runs of dots or underscores.
+ * Then trim leading or trailing dots or underscores.
+ *
+ * @param string $key
+ * @since 1.26
+ */
+ private static function normalizeMetricKey( $key ) {
+ $key = preg_replace( '/[:.]+/', '.', $key );
+ $key = preg_replace( '/[^a-z0-9.]+/i', '_', $key );
+ $key = trim( $key, '_.' );
+ return str_replace( array( '._', '_.' ), '.', $key );
+ }
+
+ public function produceStatsdData( $key, $value = 1, $metric = StatsdDataInterface::STATSD_METRIC_COUNT ) {
+ $entity = $this->produceStatsdDataEntity();
if ( $key !== null ) {
- $prefixedKey = ltrim( $this->prefix . '.' . $key, '.' );
- $entity->setKey( $prefixedKey );
+ $key = self::normalizeMetricKey( "{$this->prefix}.{$key}" );
+ $entity->setKey( $key );
}
if ( $value !== null ) {
$entity->setValue( $value );
@@ -50,9 +69,16 @@ class BufferingStatsdDataFactory extends StatsdDataFactory {
if ( $metric !== null ) {
$entity->setMetric( $metric );
}
+ // Don't bother buffering a counter update with a delta of zero.
+ if ( !( $metric === StatsdDataInterface::STATSD_METRIC_COUNT && !$value ) ) {
+ $this->buffer[] = $entity;
+ }
return $entity;
}
+ /**
+ * @return StatsdData[]
+ */
public function getBuffer() {
return $this->buffer;
}
diff --git a/includes/libs/CSSMin.php b/includes/libs/CSSMin.php
index ffe26a96..5a8c4c7b 100644
--- a/includes/libs/CSSMin.php
+++ b/includes/libs/CSSMin.php
@@ -31,6 +31,9 @@ class CSSMin {
/* Constants */
+ /** @var string Strip marker for comments. **/
+ const PLACEHOLDER = "\x7fPLACEHOLDER\x7f";
+
/**
* Internet Explorer data URI length limit. See encodeImageAsDataURI().
*/
@@ -57,13 +60,15 @@ class CSSMin {
/* Static Methods */
/**
- * Gets a list of local file paths which are referenced in a CSS style sheet
+ * Gets a list of local file paths which are referenced in a CSS style sheet.
*
- * This function will always return an empty array if the second parameter is not given or null
- * for backwards-compatibility.
+ * If you wish non-existent files to be listed too, use getAllLocalFileReferences().
*
- * @param string $source CSS data to remap
- * @param string $path File path where the source was read from (optional)
+ * For backwards-compatibility, if the second parameter is not given or null,
+ * this function will return an empty array instead of erroring out.
+ *
+ * @param string $source CSS stylesheet source to process
+ * @param string $path File path where the source was read from
* @return array List of local file references
*/
public static function getLocalFileReferences( $source, $path = null ) {
@@ -71,11 +76,31 @@ class CSSMin {
return array();
}
+ $files = self::getAllLocalFileReferences( $source, $path );
+
+ // Skip non-existent files
+ $files = array_filter( $files, function ( $file ) {
+ return file_exists( $file );
+ } );
+
+ return $files;
+ }
+
+ /**
+ * Gets a list of local file paths which are referenced in a CSS style sheet, including
+ * non-existent files.
+ *
+ * @param string $source CSS stylesheet source to process
+ * @param string $path File path where the source was read from
+ * @return array List of local file references
+ */
+ public static function getAllLocalFileReferences( $source, $path ) {
+ $stripped = preg_replace( '/' . self::COMMENT_REGEX . '/s', '', $source );
$path = rtrim( $path, '/' ) . '/';
$files = array();
$rFlags = PREG_OFFSET_CAPTURE | PREG_SET_ORDER;
- if ( preg_match_all( '/' . self::URL_REGEX . '/', $source, $matches, $rFlags ) ) {
+ if ( preg_match_all( '/' . self::URL_REGEX . '/', $stripped, $matches, $rFlags ) ) {
foreach ( $matches as $match ) {
$url = $match['file'][0];
@@ -84,13 +109,7 @@ class CSSMin {
break;
}
- $file = $path . $url;
- // Skip non-existent files
- if ( file_exists( $file ) ) {
- break;
- }
-
- $files[] = $file;
+ $files[] = $path . $url;
}
}
return $files;
@@ -232,19 +251,22 @@ class CSSMin {
$remote = substr( $remote, 0, -1 );
}
+ // Disallow U+007F DELETE, which is illegal anyway, and which
+ // we use for comment placeholders.
+ $source = str_replace( "\x7f", "?", $source );
+
// Replace all comments by a placeholder so they will not interfere with the remapping.
// Warning: This will also catch on anything looking like the start of a comment between
// quotation marks (e.g. "foo /* bar").
$comments = array();
- $placeholder = uniqid( '', true );
$pattern = '/(?!' . CSSMin::EMBED_REGEX . ')(' . CSSMin::COMMENT_REGEX . ')/s';
$source = preg_replace_callback(
$pattern,
- function ( $match ) use ( &$comments, $placeholder ) {
+ function ( $match ) use ( &$comments ) {
$comments[] = $match[ 0 ];
- return $placeholder . ( count( $comments ) - 1 ) . 'x';
+ return CSSMin::PLACEHOLDER . ( count( $comments ) - 1 ) . 'x';
},
$source
);
@@ -257,13 +279,13 @@ class CSSMin {
$source = preg_replace_callback(
$pattern,
- function ( $matchOuter ) use ( $local, $remote, $embedData, $placeholder ) {
+ function ( $matchOuter ) use ( $local, $remote, $embedData ) {
$rule = $matchOuter[0];
// Check for global @embed comment and remove it. Allow other comments to be present
// before @embed (they have been replaced with placeholders at this point).
$embedAll = false;
- $rule = preg_replace( '/^((?:\s+|' . $placeholder . '(\d+)x)*)' . CSSMin::EMBED_REGEX . '\s*/', '$1', $rule, 1, $embedAll );
+ $rule = preg_replace( '/^((?:\s+|' . CSSMin::PLACEHOLDER . '(\d+)x)*)' . CSSMin::EMBED_REGEX . '\s*/', '$1', $rule, 1, $embedAll );
// Build two versions of current rule: with remapped URLs
// and with embedded data: URIs (where possible).
@@ -328,7 +350,7 @@ class CSSMin {
}, $source );
// Re-insert comments
- $pattern = '/' . $placeholder . '(\d+)x/';
+ $pattern = '/' . CSSMin::PLACEHOLDER . '(\d+)x/';
$source = preg_replace_callback( $pattern, function( $match ) use ( &$comments ) {
return $comments[ $match[1] ];
}, $source );
@@ -393,16 +415,16 @@ class CSSMin {
if ( $local === false ) {
// Assume that all paths are relative to $remote, and make them absolute
- return $remote . '/' . $url;
+ $url = $remote . '/' . $url;
} else {
// We drop the query part here and instead make the path relative to $remote
$url = "{$remote}/{$file}";
// Path to the actual file on the filesystem
$localFile = "{$local}/{$file}";
if ( file_exists( $localFile ) ) {
- // Add version parameter as a time-stamp in ISO 8601 format,
- // using Z for the timezone, meaning GMT
- $url .= '?' . gmdate( 'Y-m-d\TH:i:s\Z', round( filemtime( $localFile ), -2 ) );
+ // Add version parameter as the first five hex digits
+ // of the MD5 hash of the file's contents.
+ $url .= '?' . substr( md5_file( $localFile ), 0, 5 );
if ( $embed ) {
$data = self::encodeImageAsDataURI( $localFile );
if ( $data !== false ) {
@@ -412,8 +434,11 @@ class CSSMin {
}
// If any of these conditions failed (file missing, we don't want to embed it
// or it's not embeddable), return the URL (possibly with ?timestamp part)
- return $url;
}
+ if ( function_exists( 'wfRemoveDotSegments' ) ) {
+ $url = wfRemoveDotSegments( $url );
+ }
+ return $url;
}
/**
diff --git a/includes/libs/HashRing.php b/includes/libs/HashRing.php
index 2022b225..e7a10997 100644
--- a/includes/libs/HashRing.php
+++ b/includes/libs/HashRing.php
@@ -223,8 +223,8 @@ class HashRing {
* @return array List of locations
* @throws UnexpectedValueException
*/
- public function getLiveLocations( $item ) {
- return $this->getLiveRing()->getLocations( $item );
+ public function getLiveLocations( $item, $limit ) {
+ return $this->getLiveRing()->getLocations( $item, $limit );
}
/**
diff --git a/includes/libs/HttpStatus.php b/includes/libs/HttpStatus.php
index 809bfdf5..442298a6 100644
--- a/includes/libs/HttpStatus.php
+++ b/includes/libs/HttpStatus.php
@@ -26,11 +26,10 @@
class HttpStatus {
/**
- * Get the message associated with HTTP response code $code
+ * Get the message associated with an HTTP response status code
*
- * @param $code Integer: status code
- * @return String or null: message or null if $code is not in the list of
- * messages
+ * @param int $code Status code
+ * @return string|null Message, or null if $code is not known
*/
public static function getMessage( $code ) {
static $statusMessage = array(
@@ -88,4 +87,25 @@ class HttpStatus {
return isset( $statusMessage[$code] ) ? $statusMessage[$code] : null;
}
+ /**
+ * Output an HTTP status code header
+ *
+ * @since 1.26
+ * @param int $code Status code
+ */
+ public static function header( $code ) {
+ static $version = null;
+ $message = self::getMessage( $code );
+ if ( $message === null ) {
+ trigger_error( "Unknown HTTP status code $code", E_USER_WARNING );
+ return false;
+ }
+
+ if ( $version === null ) {
+ $version = isset( $_SERVER['SERVER_PROTOCOL'] ) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.0' ? '1.0' : '1.1';
+ }
+
+ header( "HTTP/$version $code $message" );
+ }
+
}
diff --git a/includes/libs/IPSet.php b/includes/libs/IPSet.php
deleted file mode 100644
index c1c841e6..00000000
--- a/includes/libs/IPSet.php
+++ /dev/null
@@ -1,276 +0,0 @@
-<?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
- * @author Brandon Black <blblack@gmail.com>
- */
-
-/**
- * Matches IP addresses against a set of CIDR specifications
- *
- * Usage:
- * // At startup, calculate the optimized data structure for the set:
- * $ipset = new IPSet( $wgSquidServersNoPurge );
- * // runtime check against cached set (returns bool):
- * $allowme = $ipset->match( $ip );
- *
- * In rough benchmarking, this takes about 80% more time than
- * in_array() checks on a short (a couple hundred at most) array
- * of addresses. It's fast either way at those levels, though,
- * and IPSet would scale better than in_array if the array were
- * much larger.
- *
- * For mixed-family CIDR sets, however, this code gives well over
- * 100x speedup vs iterating IP::isInRange() over an array
- * of CIDR specs.
- *
- * The basic implementation is two separate binary trees
- * (IPv4 and IPv6) as nested php arrays with keys named 0 and 1.
- * The values false and true are terminal match-fail and match-success,
- * otherwise the value is a deeper node in the tree.
- *
- * A simple depth-compression scheme is also implemented: whole-byte
- * tree compression at whole-byte boundaries only, where no branching
- * occurs during that whole byte of depth. A compressed node has
- * keys 'comp' (the byte to compare) and 'next' (the next node to
- * recurse into if 'comp' matched successfully).
- *
- * For example, given these inputs:
- * 25.0.0.0/9
- * 25.192.0.0/10
- *
- * The v4 tree would look like:
- * root4 => array(
- * 'comp' => 25,
- * 'next' => array(
- * 0 => true,
- * 1 => array(
- * 0 => false,
- * 1 => true,
- * ),
- * ),
- * );
- *
- * (multi-byte compression nodes were attempted as well, but were
- * a net loss in my test scenarios due to additional match complexity)
- *
- * @since 1.24
- */
-class IPSet {
- /** @var array $root4: the root of the IPv4 matching tree */
- private $root4 = array( false, false );
-
- /** @var array $root6: the root of the IPv6 matching tree */
- private $root6 = array( false, false );
-
- /**
- * __construct() instantiate the object from an array of CIDR specs
- *
- * @param array $cfg array of IPv[46] CIDR specs as strings
- * @return IPSet new IPSet object
- *
- * Invalid input network/mask values in $cfg will result in issuing
- * E_WARNING and/or E_USER_WARNING and the bad values being ignored.
- */
- public function __construct( array $cfg ) {
- foreach ( $cfg as $cidr ) {
- $this->addCidr( $cidr );
- }
-
- self::recOptimize( $this->root4 );
- self::recCompress( $this->root4, 0, 24 );
- self::recOptimize( $this->root6 );
- self::recCompress( $this->root6, 0, 120 );
- }
-
- /**
- * Add a single CIDR spec to the internal matching trees
- *
- * @param string $cidr string CIDR spec, IPv[46], optional /mask (def all-1's)
- */
- private function addCidr( $cidr ) {
- // v4 or v6 check
- if ( strpos( $cidr, ':' ) === false ) {
- $node =& $this->root4;
- $defMask = '32';
- } else {
- $node =& $this->root6;
- $defMask = '128';
- }
-
- // Default to all-1's mask if no netmask in the input
- if ( strpos( $cidr, '/' ) === false ) {
- $net = $cidr;
- $mask = $defMask;
- } else {
- list( $net, $mask ) = explode( '/', $cidr, 2 );
- if ( !ctype_digit( $mask ) || intval( $mask ) > $defMask ) {
- trigger_error( "IPSet: Bad mask '$mask' from '$cidr', ignored", E_USER_WARNING );
- return;
- }
- }
- $mask = intval( $mask ); // explicit integer convert, checked above
-
- // convert $net to an array of integer bytes, length 4 or 16:
- $raw = inet_pton( $net );
- if ( $raw === false ) {
- return; // inet_pton() sends an E_WARNING for us
- }
- $rawOrd = array_map( 'ord', str_split( $raw ) );
-
- // special-case: zero mask overwrites the whole tree with a pair of terminal successes
- if ( $mask == 0 ) {
- $node = array( true, true );
- return;
- }
-
- // iterate the bits of the address while walking the tree structure for inserts
- $curBit = 0;
- while ( 1 ) {
- $maskShift = 7 - ( $curBit & 7 );
- $node =& $node[( $rawOrd[$curBit >> 3] & ( 1 << $maskShift ) ) >> $maskShift];
- ++$curBit;
- if ( $node === true ) {
- // already added a larger supernet, no need to go deeper
- return;
- } elseif ( $curBit == $mask ) {
- // this may wipe out deeper subnets from earlier
- $node = true;
- return;
- } elseif ( $node === false ) {
- // create new subarray to go deeper
- $node = array( false, false );
- }
- }
- }
-
- /**
- * Match an IP address against the set
- *
- * @param string $ip string IPv[46] address
- * @return bool true is match success, false is match failure
- *
- * If $ip is unparseable, inet_pton may issue an E_WARNING to that effect
- */
- public function match( $ip ) {
- $raw = inet_pton( $ip );
- if ( $raw === false ) {
- return false; // inet_pton() sends an E_WARNING for us
- }
-
- $rawOrd = array_map( 'ord', str_split( $raw ) );
- if ( count( $rawOrd ) == 4 ) {
- $node =& $this->root4;
- } else {
- $node =& $this->root6;
- }
-
- $curBit = 0;
- while ( 1 ) {
- if ( isset( $node['comp'] ) ) {
- // compressed node, matches 1 whole byte on a byte boundary
- if ( $rawOrd[$curBit >> 3] != $node['comp'] ) {
- return false;
- }
- $curBit += 8;
- $node =& $node['next'];
- } else {
- // uncompressed node, walk in the correct direction for the current bit-value
- $maskShift = 7 - ( $curBit & 7 );
- $node =& $node[( $rawOrd[$curBit >> 3] & ( 1 << $maskShift ) ) >> $maskShift];
- ++$curBit;
- }
-
- if ( $node === true || $node === false ) {
- return $node;
- }
- }
- }
-
- /**
- * Recursively merges adjacent nets into larger supernets
- *
- * @param array &$node Tree node to optimize, by-reference
- *
- * e.g.: 8.0.0.0/8 + 9.0.0.0/8 -> 8.0.0.0/7
- */
- private static function recOptimize( &$node ) {
- if ( $node[0] !== false && $node[0] !== true && self::recOptimize( $node[0] ) ) {
- $node[0] = true;
- }
- if ( $node[1] !== false && $node[1] !== true && self::recOptimize( $node[1] ) ) {
- $node[1] = true;
- }
- if ( $node[0] === true && $node[1] === true ) {
- return true;
- }
- return false;
- }
-
- /**
- * Recursively compresses a tree
- *
- * @param array &$node Tree node to compress, by-reference
- * @param integer $curBit current depth in the tree
- * @param integer $maxCompStart maximum depth at which compression can start, family-specific
- *
- * This is a very simplistic compression scheme: if we go through a whole
- * byte of address starting at a byte boundary with no real branching
- * other than immediate false-vs-(node|true), compress that subtree down to a single
- * byte-matching node.
- * The $maxCompStart check elides recursing the final 7 levels of depth (family-dependent)
- */
- private static function recCompress( &$node, $curBit, $maxCompStart ) {
- if ( !( $curBit & 7 ) ) { // byte boundary, check for depth-8 single path(s)
- $byte = 0;
- $cnode =& $node;
- $i = 8;
- while ( $i-- ) {
- if ( $cnode[0] === false ) {
- $byte |= 1 << $i;
- $cnode =& $cnode[1];
- } elseif ( $cnode[1] === false ) {
- $cnode =& $cnode[0];
- } else {
- // partial-byte branching, give up
- break;
- }
- }
- if ( $i == -1 ) { // means we did not exit the while() via break
- $node = array(
- 'comp' => $byte,
- 'next' => &$cnode,
- );
- $curBit += 8;
- if ( $cnode !== true ) {
- self::recCompress( $cnode, $curBit, $maxCompStart );
- }
- return;
- }
- }
-
- ++$curBit;
- if ( $curBit <= $maxCompStart ) {
- if ( $node[0] !== false && $node[0] !== true ) {
- self::recCompress( $node[0], $curBit, $maxCompStart );
- }
- if ( $node[1] !== false && $node[1] !== true ) {
- self::recCompress( $node[1], $curBit, $maxCompStart );
- }
- }
- }
-}
diff --git a/includes/libs/JavaScriptMinifier.php b/includes/libs/JavaScriptMinifier.php
index 2990782c..141a5153 100644
--- a/includes/libs/JavaScriptMinifier.php
+++ b/includes/libs/JavaScriptMinifier.php
@@ -565,6 +565,14 @@ class JavaScriptMinifier {
$out .= ' ';
$lineLength++;
}
+ if (
+ $type === self::TYPE_LITERAL
+ && ( $token === 'true' || $token === 'false' )
+ && ( $state === self::EXPRESSION || $state === self::PROPERTY_EXPRESSION )
+ && $last !== '.'
+ ) {
+ $token = ( $token === 'true' ) ? '!0' : '!1';
+ }
$out .= $token;
$lineLength += $end - $pos; // += strlen( $token )
diff --git a/includes/libs/MapCacheLRU.php b/includes/libs/MapCacheLRU.php
index 0b6db32e..a0230bee 100644
--- a/includes/libs/MapCacheLRU.php
+++ b/includes/libs/MapCacheLRU.php
@@ -20,6 +20,7 @@
* @file
* @ingroup Cache
*/
+use Wikimedia\Assert\Assert;
/**
* Handles a simple LRU key/value map with a maximum number of entries
@@ -41,9 +42,9 @@ class MapCacheLRU {
* @throws Exception When $maxCacheKeys is not an int or =< 0.
*/
public function __construct( $maxKeys ) {
- if ( !is_int( $maxKeys ) || $maxKeys < 1 ) {
- throw new Exception( __METHOD__ . " must be given an integer and >= 1" );
- }
+ Assert::parameterType( 'integer', $maxKeys, '$maxKeys' );
+ Assert::parameter( $maxKeys >= 1, '$maxKeys', 'must be >= 1' );
+
$this->maxCacheKeys = $maxKeys;
}
diff --git a/includes/libs/MultiHttpClient.php b/includes/libs/MultiHttpClient.php
index fb2daa69..6af3ed51 100644
--- a/includes/libs/MultiHttpClient.php
+++ b/includes/libs/MultiHttpClient.php
@@ -58,8 +58,8 @@ class MultiHttpClient {
/**
* @param array $options
- * - connTimeout : default connection timeout
- * - reqTimeout : default request timeout
+ * - connTimeout : default connection timeout (seconds)
+ * - reqTimeout : default request timeout (seconds)
* - proxy : HTTP proxy to use
* - usePipelining : whether to use HTTP pipelining if possible (for all hosts)
* - maxConnsPerHost : maximum number of concurrent connections (per host)
@@ -72,7 +72,9 @@ class MultiHttpClient {
throw new Exception( "Cannot find CA bundle: " . $this->caBundlePath );
}
}
- static $opts = array( 'connTimeout', 'reqTimeout', 'usePipelining', 'maxConnsPerHost', 'proxy' );
+ static $opts = array(
+ 'connTimeout', 'reqTimeout', 'usePipelining', 'maxConnsPerHost', 'proxy'
+ );
foreach ( $opts as $key ) {
if ( isset( $options[$key] ) ) {
$this->$key = $options[$key];
@@ -84,19 +86,19 @@ class MultiHttpClient {
* Execute an HTTP(S) request
*
* This method returns a response map of:
- * - code : HTTP response code or 0 if there was a serious cURL error
- * - reason : HTTP response reason (empty if there was a serious cURL error)
- * - headers : <header name/value associative array>
- * - body : HTTP response body or resource (if "stream" was set)
+ * - code : HTTP response code or 0 if there was a serious cURL error
+ * - reason : HTTP response reason (empty if there was a serious cURL error)
+ * - headers : <header name/value associative array>
+ * - body : HTTP response body or resource (if "stream" was set)
* - error : Any cURL error string
- * The map also stores integer-indexed copies of these values. This lets callers do:
- * <code>
+ * The map also stores integer-indexed copies of these values. This lets callers do:
+ * @code
* list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $http->run( $req );
- * </code>
+ * @endcode
* @param array $req HTTP request array
* @param array $opts
- * - connTimeout : connection timeout per request
- * - reqTimeout : post-connection timeout per request
+ * - connTimeout : connection timeout per request (seconds)
+ * - reqTimeout : post-connection timeout per request (seconds)
* @return array Response array for request
*/
final public function run( array $req, array $opts = array() ) {
@@ -114,17 +116,17 @@ class MultiHttpClient {
* - body : HTTP response body or resource (if "stream" was set)
* - error : Any cURL error string
* The map also stores integer-indexed copies of these values. This lets callers do:
- * <code>
+ * @code
* list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $req['response'];
- * </code>
+ * @endcode
* All headers in the 'headers' field are normalized to use lower case names.
* This is true for the request headers and the response headers. Integer-indexed
* method/URL entries will also be changed to use the corresponding string keys.
*
* @param array $reqs Map of HTTP request arrays
* @param array $opts
- * - connTimeout : connection timeout per request
- * - reqTimeout : post-connection timeout per request
+ * - connTimeout : connection timeout per request (seconds)
+ * - reqTimeout : post-connection timeout per request (seconds)
* - usePipelining : whether to use HTTP pipelining if possible
* - maxConnsPerHost : maximum number of concurrent connections (per host)
* @return array $reqs With response array populated for each
@@ -189,6 +191,7 @@ class MultiHttpClient {
// @TODO: use a per-host rolling handle window (e.g. CURLMOPT_MAX_HOST_CONNECTIONS)
$batches = array_chunk( $indexes, $this->maxConnsPerHost );
+ $infos = array();
foreach ( $batches as $batch ) {
// Attach all cURL handles for this batch
@@ -201,6 +204,10 @@ class MultiHttpClient {
// Do any available work...
do {
$mrc = curl_multi_exec( $chm, $active );
+ $info = curl_multi_info_read( $chm );
+ if ( $info !== false ) {
+ $infos[(int)$info['handle']] = $info;
+ }
} while ( $mrc == CURLM_CALL_MULTI_PERFORM );
// Wait (if possible) for available work...
if ( $active > 0 && $mrc == CURLM_OK ) {
@@ -216,10 +223,20 @@ class MultiHttpClient {
foreach ( $reqs as $index => &$req ) {
$ch = $handles[$index];
curl_multi_remove_handle( $chm, $ch );
- if ( curl_errno( $ch ) !== 0 ) {
- $req['response']['error'] = "(curl error: " .
- curl_errno( $ch ) . ") " . curl_error( $ch );
+
+ if ( isset( $infos[(int)$ch] ) ) {
+ $info = $infos[(int)$ch];
+ $errno = $info['result'];
+ if ( $errno !== 0 ) {
+ $req['response']['error'] = "(curl error: $errno)";
+ if ( function_exists( 'curl_strerror' ) ) {
+ $req['response']['error'] .= " " . curl_strerror( $errno );
+ }
+ }
+ } else {
+ $req['response']['error'] = "(curl error: no status set)";
}
+
// For convenience with the list() operator
$req['response'][0] = $req['response']['code'];
$req['response'][1] = $req['response']['reason'];
diff --git a/includes/libs/ObjectFactory.php b/includes/libs/ObjectFactory.php
index ec8c36a1..1cb544b8 100644
--- a/includes/libs/ObjectFactory.php
+++ b/includes/libs/ObjectFactory.php
@@ -49,6 +49,13 @@ class ObjectFactory {
* constructor/callable. This behavior can be suppressed by adding
* closure_expansion => false to the specification.
*
+ * The specification may also contain a 'calls' key that describes method
+ * calls to make on the newly created object before returning it. This
+ * pattern is often known as "setter injection". The value of this key is
+ * expected to be an associative array with method names as keys and
+ * argument lists as values. The argument list will be expanded (or not)
+ * in the same way as the 'args' key for the main object.
+ *
* @param array $spec Object specification
* @return object
* @throws InvalidArgumentException when object specification does not
@@ -58,18 +65,11 @@ class ObjectFactory {
*/
public static function getObjectFromSpec( $spec ) {
$args = isset( $spec['args'] ) ? $spec['args'] : array();
+ $expandArgs = !isset( $spec['closure_expansion'] ) ||
+ $spec['closure_expansion'] === true;
- if ( !isset( $spec['closure_expansion'] ) ||
- $spec['closure_expansion'] === true
- ) {
- $args = array_map( function ( $value ) {
- if ( is_object( $value ) && $value instanceof Closure ) {
- // If an argument is a Closure, call it.
- return $value();
- } else {
- return $value;
- }
- }, $args );
+ if ( $expandArgs ) {
+ $args = static::expandClosures( $args );
}
if ( isset( $spec['class'] ) ) {
@@ -88,6 +88,33 @@ class ObjectFactory {
);
}
+ if ( isset( $spec['calls'] ) && is_array( $spec['calls'] ) ) {
+ // Call additional methods on the newly created object
+ foreach ( $spec['calls'] as $method => $margs ) {
+ if ( $expandArgs ) {
+ $margs = static::expandClosures( $margs );
+ }
+ call_user_func_array( array( $obj, $method ), $margs );
+ }
+ }
+
return $obj;
}
+
+ /**
+ * Iterate a list and call any closures it contains.
+ *
+ * @param array $list List of things
+ * @return array List with any Closures replaced with their output
+ */
+ protected static function expandClosures( $list ) {
+ return array_map( function ( $value ) {
+ if ( is_object( $value ) && $value instanceof Closure ) {
+ // If $value is a Closure, call it.
+ return $value();
+ } else {
+ return $value;
+ }
+ }, $list );
+ }
}
diff --git a/includes/libs/ProcessCacheLRU.php b/includes/libs/ProcessCacheLRU.php
index 8d80eb38..b55ff9da 100644
--- a/includes/libs/ProcessCacheLRU.php
+++ b/includes/libs/ProcessCacheLRU.php
@@ -20,6 +20,7 @@
* @file
* @ingroup Cache
*/
+use Wikimedia\Assert\Assert;
/**
* Handles per process caching of items
@@ -128,9 +129,9 @@ class ProcessCacheLRU {
* @throws UnexpectedValueException
*/
public function resize( $maxKeys ) {
- if ( !is_int( $maxKeys ) || $maxKeys < 1 ) {
- throw new UnexpectedValueException( __METHOD__ . " must be given an integer >= 1" );
- }
+ Assert::parameterType( 'integer', $maxKeys, '$maxKeys' );
+ Assert::parameter( $maxKeys >= 1, '$maxKeys', 'must be >= 1' );
+
$this->maxCacheKeys = $maxKeys;
while ( count( $this->cache ) > $this->maxCacheKeys ) {
reset( $this->cache );
diff --git a/includes/libs/ReplacementArray.php b/includes/libs/ReplacementArray.php
index 7fdb3093..b6faa378 100644
--- a/includes/libs/ReplacementArray.php
+++ b/includes/libs/ReplacementArray.php
@@ -76,7 +76,7 @@ class ReplacementArray {
* @param array $data
*/
public function mergeArray( $data ) {
- $this->data = array_merge( $this->data, $data );
+ $this->data = $data + $this->data;
$this->fss = false;
}
@@ -84,7 +84,7 @@ class ReplacementArray {
* @param ReplacementArray $other
*/
public function merge( ReplacementArray $other ) {
- $this->data = array_merge( $this->data, $other->data );
+ $this->data = $other->data + $this->data;
$this->fss = false;
}
@@ -111,7 +111,10 @@ class ReplacementArray {
* @return string
*/
public function replace( $subject ) {
- if ( function_exists( 'fss_prep_replace' ) ) {
+ if (
+ function_exists( 'fss_prep_replace' ) &&
+ version_compare( PHP_VERSION, '5.5.0' ) < 0
+ ) {
if ( $this->fss === false ) {
$this->fss = fss_prep_replace( $this->data );
}
diff --git a/includes/libs/RiffExtractor.php b/includes/libs/RiffExtractor.php
new file mode 100644
index 00000000..f987c59d
--- /dev/null
+++ b/includes/libs/RiffExtractor.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Extractor for the Resource Interchange File Format
+ *
+ * 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
+ * @author Bryan Tong Minh
+ * @ingroup Media
+ */
+
+class RiffExtractor {
+ public static function findChunksFromFile( $filename, $maxChunks = -1 ) {
+ $file = fopen( $filename, 'rb' );
+ $info = self::findChunks( $file, $maxChunks );
+ fclose( $file );
+ return $info;
+ }
+
+ public static function findChunks( $file, $maxChunks = -1 ) {
+ $riff = fread( $file, 4 );
+ if ( $riff !== 'RIFF' ) {
+ return false;
+ }
+
+ // Next four bytes are fileSize
+ $fileSize = fread( $file, 4 );
+ if ( !$fileSize || strlen( $fileSize ) != 4 ) {
+ return false;
+ }
+
+ // Next four bytes are the FourCC
+ $fourCC = fread( $file, 4 );
+ if ( !$fourCC || strlen( $fourCC ) != 4 ) {
+ return false;
+ }
+
+ // Create basic info structure
+ $info = array(
+ 'fileSize' => self::extractUInt32( $fileSize ),
+ 'fourCC' => $fourCC,
+ 'chunks' => array(),
+ );
+ $numberOfChunks = 0;
+
+ // Find out the chunks
+ while ( !feof( $file ) && !( $numberOfChunks >= $maxChunks && $maxChunks >= 0 ) ) {
+ $chunkStart = ftell( $file );
+
+ $chunkFourCC = fread( $file, 4 );
+ if ( !$chunkFourCC || strlen( $chunkFourCC ) != 4 ) {
+ return $info;
+ }
+
+ $chunkSize = fread( $file, 4 );
+ if ( !$chunkSize || strlen( $chunkSize ) != 4 ) {
+ return $info;
+ }
+ $intChunkSize = self::extractUInt32( $chunkSize );
+
+ // Add chunk info to the info structure
+ $info['chunks'][] = array(
+ 'fourCC' => $chunkFourCC,
+ 'start' => $chunkStart,
+ 'size' => $intChunkSize
+ );
+
+ // Uneven chunks have padding bytes
+ $padding = $intChunkSize % 2;
+ // Seek to the next chunk
+ fseek( $file, $intChunkSize + $padding, SEEK_CUR );
+
+ }
+
+ return $info;
+ }
+
+ /**
+ * Extract a little-endian uint32 from a 4 byte string
+ * @param string $string 4-byte string
+ * @return int
+ */
+ public static function extractUInt32( $string ) {
+ $unpacked = unpack( 'V', $string );
+ return $unpacked[1];
+ }
+};
diff --git a/includes/libs/SamplingStatsdClient.php b/includes/libs/SamplingStatsdClient.php
new file mode 100644
index 00000000..f7afdb5e
--- /dev/null
+++ b/includes/libs/SamplingStatsdClient.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Copyright 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use Liuggio\StatsdClient\StatsdClient;
+use Liuggio\StatsdClient\Entity\StatsdData;
+use Liuggio\StatsdClient\Entity\StatsdDataInterface;
+
+/**
+ * A statsd client that applies the sampling rate to the data items before sending them.
+ *
+ * @since 1.26
+ */
+class SamplingStatsdClient extends StatsdClient {
+ /**
+ * Sets sampling rate for all items in $data.
+ * The sample rate specified in a StatsdData entity overrides the sample rate specified here.
+ *
+ * {@inheritDoc}
+ */
+ public function appendSampleRate( $data, $sampleRate = 1 ) {
+ if ( $sampleRate < 1 ) {
+ array_walk( $data, function( $item ) use ( $sampleRate ) {
+ /** @var $item StatsdData */
+ if ( $item->getSampleRate() === 1 ) {
+ $item->setSampleRate( $sampleRate );
+ }
+ } );
+ }
+
+ return $data;
+ }
+
+ /**
+ * Sample the metrics according to their sample rate and send the remaining ones.
+ *
+ * {@inheritDoc}
+ */
+ public function send( $data, $sampleRate = 1 ) {
+ if ( !is_array( $data ) ) {
+ $data = array( $data );
+ }
+ if ( !$data ) {
+ return;
+ }
+ foreach ( $data as $item ) {
+ if ( !( $item instanceof StatsdDataInterface ) ) {
+ throw new InvalidArgumentException(
+ 'SamplingStatsdClient does not accept stringified messages' );
+ }
+ }
+
+ // add sampling
+ if ( $sampleRate < 1 ) {
+ $data = $this->appendSampleRate( $data, $sampleRate );
+ }
+ $data = $this->sampleData( $data );
+
+ $messages = array_map( 'strval', $data );
+
+ // reduce number of packets
+ if ( $this->getReducePacket() ) {
+ $data = $this->reduceCount( $data );
+ }
+ //failures in any of this should be silently ignored if ..
+ $written = 0;
+ try {
+ $fp = $this->getSender()->open();
+ if ( !$fp ) {
+ return;
+ }
+ foreach ( $messages as $message ) {
+ $written += $this->getSender()->write( $fp, $message );
+ }
+ $this->getSender()->close( $fp );
+ } catch ( Exception $e ) {
+ $this->throwException( $e );
+ }
+
+ return $written;
+ }
+
+ /**
+ * Throw away some of the data according to the sample rate.
+ * @param StatsdDataInterface[] $data
+ * @return array
+ * @throws LogicException
+ */
+ protected function sampleData( $data ) {
+ $newData = array();
+ $mt_rand_max = mt_getrandmax();
+ foreach ( $data as $item ) {
+ $samplingRate = $item->getSampleRate();
+ if ( $samplingRate <= 0.0 || $samplingRate > 1.0 ) {
+ throw new LogicException( 'Sampling rate shall be within ]0, 1]' );
+ }
+ if (
+ $samplingRate === 1 ||
+ ( mt_rand() / $mt_rand_max <= $samplingRate )
+ ) {
+ $newData[] = $item;
+ }
+ }
+ return $newData;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function throwException( Exception $exception ) {
+ if ( !$this->getFailSilently() ) {
+ throw $exception;
+ }
+ }
+}
diff --git a/includes/libs/ScopedPHPTimeout.php b/includes/libs/ScopedPHPTimeout.php
deleted file mode 100644
index d1493c30..00000000
--- a/includes/libs/ScopedPHPTimeout.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-/**
- * Expansion of the PHP execution time limit feature for a function call.
- *
- * 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
- */
-
-/**
- * Class to expand PHP execution time for a function call.
- * Use this when performing changes that should not be interrupted.
- *
- * On construction, set_time_limit() is called and set to $seconds.
- * If the client aborts the connection, PHP will continue to run.
- * When the object goes out of scope, the timer is restarted, with
- * the original time limit minus the time the object existed.
- */
-class ScopedPHPTimeout {
- protected $startTime; // float; seconds
- protected $oldTimeout; // integer; seconds
- protected $oldIgnoreAbort; // boolean
-
- protected static $stackDepth = 0; // integer
- protected static $totalCalls = 0; // integer
- protected static $totalElapsed = 0; // float; seconds
-
- /* Prevent callers in infinite loops from running forever */
- const MAX_TOTAL_CALLS = 1000000;
- const MAX_TOTAL_TIME = 300; // seconds
-
- /**
- * @param $seconds integer
- */
- public function __construct( $seconds ) {
- if ( ini_get( 'max_execution_time' ) > 0 ) { // CLI uses 0
- if ( self::$totalCalls >= self::MAX_TOTAL_CALLS ) {
- trigger_error( "Maximum invocations of " . __CLASS__ . " exceeded." );
- } elseif ( self::$totalElapsed >= self::MAX_TOTAL_TIME ) {
- trigger_error( "Time limit within invocations of " . __CLASS__ . " exceeded." );
- } elseif ( self::$stackDepth > 0 ) { // recursion guard
- trigger_error( "Resursive invocation of " . __CLASS__ . " attempted." );
- } else {
- $this->oldIgnoreAbort = ignore_user_abort( true );
- $this->oldTimeout = ini_set( 'max_execution_time', $seconds );
- $this->startTime = microtime( true );
- ++self::$stackDepth;
- ++self::$totalCalls; // proof against < 1us scopes
- }
- }
- }
-
- /**
- * Restore the original timeout.
- * This does not account for the timer value on __construct().
- */
- public function __destruct() {
- if ( $this->oldTimeout ) {
- $elapsed = microtime( true ) - $this->startTime;
- // Note: a limit of 0 is treated as "forever"
- set_time_limit( max( 1, $this->oldTimeout - (int)$elapsed ) );
- // If each scoped timeout is for less than one second, we end up
- // restoring the original timeout without any decrease in value.
- // Thus web scripts in an infinite loop can run forever unless we
- // take some measures to prevent this. Track total time and calls.
- self::$totalElapsed += $elapsed;
- --self::$stackDepth;
- ignore_user_abort( $this->oldIgnoreAbort );
- }
- }
-}
diff --git a/includes/libs/XmlTypeCheck.php b/includes/libs/XmlTypeCheck.php
index 6d01986d..34afb689 100644
--- a/includes/libs/XmlTypeCheck.php
+++ b/includes/libs/XmlTypeCheck.php
@@ -39,6 +39,13 @@ class XmlTypeCheck {
public $filterMatch = false;
/**
+ * Will contain the type of filter hit if the optional element filter returned
+ * a match at some point.
+ * @var mixed
+ */
+ public $filterMatchType = false;
+
+ /**
* Name of the document's root element, including any namespace
* as an expanded URL.
*/
@@ -173,7 +180,7 @@ class XmlTypeCheck {
// First, move through anything that isn't an element, and
// handle any processing instructions with the callback
do {
- if( !$this->readNext( $reader ) ) {
+ if ( !$this->readNext( $reader ) ) {
// Hit the end of the document before any elements
$this->wellFormed = false;
return;
@@ -294,17 +301,20 @@ class XmlTypeCheck {
list( $name, $attribs ) = array_pop( $this->elementDataContext );
$data = array_pop( $this->elementData );
$this->stackDepth--;
+ $callbackReturn = false;
- if ( is_callable( $this->filterCallback )
- && call_user_func(
+ if ( is_callable( $this->filterCallback ) ) {
+ $callbackReturn = call_user_func(
$this->filterCallback,
$name,
$attribs,
$data
- )
- ) {
- // Filter hit
+ );
+ }
+ if ( $callbackReturn ) {
+ // Filter hit!
$this->filterMatch = true;
+ $this->filterMatchType = $callbackReturn;
}
}
@@ -321,15 +331,18 @@ class XmlTypeCheck {
* @param $data
*/
private function processingInstructionHandler( $target, $data ) {
+ $callbackReturn = false;
if ( $this->parserOptions['processing_instruction_handler'] ) {
- if ( call_user_func(
+ $callbackReturn = call_user_func(
$this->parserOptions['processing_instruction_handler'],
$target,
$data
- ) ) {
- // Filter hit!
- $this->filterMatch = true;
- }
+ );
+ }
+ if ( $callbackReturn ) {
+ // Filter hit!
+ $this->filterMatch = true;
+ $this->filterMatchType = $callbackReturn;
}
}
}
diff --git a/includes/libs/composer/ComposerLock.php b/includes/libs/composer/ComposerLock.php
index 9c7bf2f9..22c33191 100644
--- a/includes/libs/composer/ComposerLock.php
+++ b/includes/libs/composer/ComposerLock.php
@@ -30,6 +30,9 @@ class ComposerLock {
$deps[$installed['name']] = array(
'version' => ComposerJson::normalizeVersion( $installed['version'] ),
'type' => $installed['type'],
+ 'licenses' => isset( $installed['license'] ) ? $installed['license'] : array(),
+ 'authors' => isset( $installed['authors'] ) ? $installed['authors'] : array(),
+ 'description' => isset( $installed['description'] ) ? $installed['description']: '',
);
}
diff --git a/includes/libs/eventrelayer/EventRelayer.php b/includes/libs/eventrelayer/EventRelayer.php
new file mode 100644
index 00000000..f95ba3f0
--- /dev/null
+++ b/includes/libs/eventrelayer/EventRelayer.php
@@ -0,0 +1,65 @@
+<?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
+ * @author Aaron Schulz
+ */
+
+/**
+ * Base class for reliable event relays
+ */
+abstract class EventRelayer {
+ /**
+ * @param array $params
+ */
+ public function __construct( array $params ) {
+ }
+
+ /**
+ * @param string $channel
+ * @param array $event Event data map
+ * @return bool Success
+ */
+ final public function notify( $channel, $event ) {
+ return $this->doNotify( $channel, array( $event ) );
+ }
+
+ /**
+ * @param string $channel
+ * @param array $events List of event data maps
+ * @return bool Success
+ */
+ final public function notifyMulti( $channel, $events ) {
+ return $this->doNotify( $channel, $events );
+ }
+
+ /**
+ * @param string $channel
+ * @param array $events List of event data maps
+ * @return bool Success
+ */
+ abstract protected function doNotify( $channel, array $events );
+}
+
+/**
+ * No-op class for publishing messages into a PubSub system
+ */
+class EventRelayerNull extends EventRelayer {
+ public function doNotify( $channel, array $events ) {
+ return true;
+ }
+}
diff --git a/includes/libs/eventrelayer/EventRelayerMCRD.php b/includes/libs/eventrelayer/EventRelayerMCRD.php
new file mode 100644
index 00000000..1e8b2a40
--- /dev/null
+++ b/includes/libs/eventrelayer/EventRelayerMCRD.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author Aaron Schulz
+ */
+
+/**
+ * Relayed that uses the mcrelaypushd server
+ */
+class EventRelayerMCRD extends EventRelayer {
+ /** @var MultiHttpClient */
+ protected $http;
+ /** @var string */
+ protected $baseUrl;
+
+ /**
+ * Additional params include 'mcrdConfig', which is a map of:
+ * - url : The base URL of the service (without paths)
+ * @param array $params
+ */
+ public function __construct( array $params ) {
+ parent::__construct( $params );
+
+ $this->baseUrl = $params['mcrdConfig']['url'];
+
+ $httpConfig = isset( $params['httpConfig'] ) ? $params['httpConfig'] : array();
+ if ( !isset( $httpConfig['connTimeout'] ) ) {
+ $httpConfig['connTimeout'] = 1;
+ }
+ if ( !isset( $httpConfig['reqTimeout'] ) ) {
+ $httpConfig['reqTimeout'] = .25;
+ }
+
+ $this->http = new MultiHttpClient( $httpConfig );
+ }
+
+ protected function doNotify( $channel, array $events ) {
+ if ( !count( $events ) ) {
+ return true;
+ }
+
+ $response = $this->http->run( array(
+ 'url' => "{$this->baseUrl}/relayer/api/v1.0/" . rawurlencode( $channel ),
+ 'method' => 'POST',
+ 'body' => json_encode( array( 'events' => $events ) ),
+ 'headers' => array( 'content-type' => 'application/json' )
+ ) );
+
+ return $response['code'] == 201;
+ }
+}
diff --git a/includes/libs/objectcache/APCBagOStuff.php b/includes/libs/objectcache/APCBagOStuff.php
index eaf11557..0dbbaba9 100644
--- a/includes/libs/objectcache/APCBagOStuff.php
+++ b/includes/libs/objectcache/APCBagOStuff.php
@@ -27,43 +27,38 @@
* @ingroup Cache
*/
class APCBagOStuff extends BagOStuff {
- public function get( $key, &$casToken = null ) {
- $val = apc_fetch( $key );
+ /**
+ * @var string String to append to each APC key. This may be changed
+ * whenever the handling of values is changed, to prevent existing code
+ * from encountering older values which it cannot handle.
+ **/
+ const KEY_SUFFIX = ':1';
- $casToken = $val;
+ public function get( $key, &$casToken = null, $flags = 0 ) {
+ $val = apc_fetch( $key . self::KEY_SUFFIX );
- if ( is_string( $val ) ) {
- if ( $this->isInteger( $val ) ) {
- $val = intval( $val );
- } else {
- $val = unserialize( $val );
- }
- }
+ $casToken = $val;
return $val;
}
public function set( $key, $value, $exptime = 0 ) {
- if ( !$this->isInteger( $value ) ) {
- $value = serialize( $value );
- }
-
- apc_store( $key, $value, $exptime );
+ apc_store( $key . self::KEY_SUFFIX, $value, $exptime );
return true;
}
public function delete( $key ) {
- apc_delete( $key );
+ apc_delete( $key . self::KEY_SUFFIX );
return true;
}
public function incr( $key, $value = 1 ) {
- return apc_inc( $key, $value );
+ return apc_inc( $key . self::KEY_SUFFIX, $value );
}
public function decr( $key, $value = 1 ) {
- return apc_dec( $key, $value );
+ return apc_dec( $key . self::KEY_SUFFIX, $value );
}
}
diff --git a/includes/libs/objectcache/BagOStuff.php b/includes/libs/objectcache/BagOStuff.php
index 0b791e5a..ddbe8eaa 100644
--- a/includes/libs/objectcache/BagOStuff.php
+++ b/includes/libs/objectcache/BagOStuff.php
@@ -1,7 +1,5 @@
<?php
/**
- * Classes to cache objects in PHP accelerators, SQL database or DBA files
- *
* Copyright © 2003-2004 Brion Vibber <brion@pobox.com>
* https://www.mediawiki.org/
*
@@ -37,29 +35,34 @@ use Psr\Log\NullLogger;
* the PHP memcached client.
*
* backends for local hash array and SQL table included:
- * <code>
+ * @code
* $bag = new HashBagOStuff();
* $bag = new SqlBagOStuff(); # connect to db first
- * </code>
+ * @endcode
*
* @ingroup Cache
*/
abstract class BagOStuff implements LoggerAwareInterface {
- private $debugMode = false;
-
+ /** @var array[] Lock tracking */
+ protected $locks = array();
+ /** @var integer */
protected $lastError = self::ERR_NONE;
- /**
- * @var LoggerInterface
- */
+ /** @var LoggerInterface */
protected $logger;
+ /** @var bool */
+ private $debugMode = false;
+
/** Possible values for getLastError() */
const ERR_NONE = 0; // no error
const ERR_NO_RESPONSE = 1; // no response
const ERR_UNREACHABLE = 2; // can't connect
const ERR_UNEXPECTED = 3; // response gave some error
+ /** Bitfield constants for get()/getMulti() */
+ const READ_LATEST = 1; // use latest data for replicated stores
+
public function __construct( array $params = array() ) {
if ( isset( $params['logger'] ) ) {
$this->setLogger( $params['logger'] );
@@ -87,9 +90,10 @@ abstract class BagOStuff implements LoggerAwareInterface {
* Get an item with the given key. Returns false if it does not exist.
* @param string $key
* @param mixed $casToken [optional]
+ * @param integer $flags Bitfield; supports READ_LATEST [optional]
* @return mixed Returns false on failure
*/
- abstract public function get( $key, &$casToken = null );
+ abstract public function get( $key, &$casToken = null, $flags = 0 );
/**
* Set an item.
@@ -109,18 +113,20 @@ abstract class BagOStuff implements LoggerAwareInterface {
/**
* Merge changes into the existing cache value (possibly creating a new one).
- * The callback function returns the new value given the current value (possibly false),
- * and takes the arguments: (this BagOStuff object, cache key, current value).
+ * The callback function returns the new value given the current value
+ * (which will be false if not present), and takes the arguments:
+ * (this BagOStuff, cache key, current value).
*
* @param string $key
* @param callable $callback Callback method to be executed
* @param int $exptime Either an interval in seconds or a unix timestamp for expiry
* @param int $attempts The amount of times to attempt a merge in case of failure
* @return bool Success
+ * @throws InvalidArgumentException
*/
public function merge( $key, $callback, $exptime = 0, $attempts = 10 ) {
if ( !is_callable( $callback ) ) {
- throw new Exception( "Got invalid callback." );
+ throw new InvalidArgumentException( "Got invalid callback." );
}
return $this->mergeViaLock( $key, $callback, $exptime, $attempts );
@@ -137,11 +143,17 @@ abstract class BagOStuff implements LoggerAwareInterface {
*/
protected function mergeViaCas( $key, $callback, $exptime = 0, $attempts = 10 ) {
do {
+ $this->clearLastError();
$casToken = null; // passed by reference
$currentValue = $this->get( $key, $casToken );
+ if ( $this->getLastError() ) {
+ return false; // don't spam retries (retry only on races)
+ }
+
// Derive the new value from the old value
$value = call_user_func( $callback, $this, $key, $currentValue );
+ $this->clearLastError();
if ( $value === false ) {
$success = true; // do nothing
} elseif ( $currentValue === false ) {
@@ -151,6 +163,9 @@ abstract class BagOStuff implements LoggerAwareInterface {
// Try to update the key, failing if it gets changed in the meantime
$success = $this->cas( $casToken, $key, $value, $exptime );
}
+ if ( $this->getLastError() ) {
+ return false; // IO error; don't spam retries
+ }
} while ( !$success && --$attempts );
return $success;
@@ -164,6 +179,7 @@ abstract class BagOStuff implements LoggerAwareInterface {
* @param mixed $value
* @param int $exptime Either an interval in seconds or a unix timestamp for expiry
* @return bool Success
+ * @throws Exception
*/
protected function cas( $casToken, $key, $value, $exptime = 0 ) {
throw new Exception( "CAS is not implemented in " . __CLASS__ );
@@ -183,14 +199,18 @@ abstract class BagOStuff implements LoggerAwareInterface {
return false;
}
+ $this->clearLastError();
$currentValue = $this->get( $key );
- // Derive the new value from the old value
- $value = call_user_func( $callback, $this, $key, $currentValue );
-
- if ( $value === false ) {
- $success = true; // do nothing
+ if ( $this->getLastError() ) {
+ $success = false;
} else {
- $success = $this->set( $key, $value, $exptime ); // set the new value
+ // Derive the new value from the old value
+ $value = call_user_func( $callback, $this, $key, $currentValue );
+ if ( $value === false ) {
+ $success = true; // do nothing
+ } else {
+ $success = $this->set( $key, $value, $exptime ); // set the new value
+ }
}
if ( !$this->unlock( $key ) ) {
@@ -202,48 +222,116 @@ abstract class BagOStuff implements LoggerAwareInterface {
}
/**
+ * Acquire an advisory lock on a key string
+ *
+ * Note that if reentry is enabled, duplicate calls ignore $expiry
+ *
* @param string $key
- * @param int $timeout Lock wait timeout [optional]
- * @param int $expiry Lock expiry [optional]
+ * @param int $timeout Lock wait timeout; 0 for non-blocking [optional]
+ * @param int $expiry Lock expiry [optional]; 1 day maximum
+ * @param string $rclass Allow reentry if set and the current lock used this value
* @return bool Success
*/
- public function lock( $key, $timeout = 6, $expiry = 6 ) {
+ public function lock( $key, $timeout = 6, $expiry = 6, $rclass = '' ) {
+ // Avoid deadlocks and allow lock reentry if specified
+ if ( isset( $this->locks[$key] ) ) {
+ if ( $rclass != '' && $this->locks[$key]['class'] === $rclass ) {
+ ++$this->locks[$key]['depth'];
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ $expiry = min( $expiry ?: INF, 86400 );
+
$this->clearLastError();
$timestamp = microtime( true ); // starting UNIX timestamp
if ( $this->add( "{$key}:lock", 1, $expiry ) ) {
- return true;
- } elseif ( $this->getLastError() ) {
- return false;
+ $locked = true;
+ } elseif ( $this->getLastError() || $timeout <= 0 ) {
+ $locked = false; // network partition or non-blocking
+ } else {
+ $uRTT = ceil( 1e6 * ( microtime( true ) - $timestamp ) ); // estimate RTT (us)
+ $sleep = 2 * $uRTT; // rough time to do get()+set()
+
+ $attempts = 0; // failed attempts
+ do {
+ if ( ++$attempts >= 3 && $sleep <= 5e5 ) {
+ // Exponentially back off after failed attempts to avoid network spam.
+ // About 2*$uRTT*(2^n-1) us of "sleep" happen for the next n attempts.
+ $sleep *= 2;
+ }
+ usleep( $sleep ); // back off
+ $this->clearLastError();
+ $locked = $this->add( "{$key}:lock", 1, $expiry );
+ if ( $this->getLastError() ) {
+ $locked = false; // network partition
+ break;
+ }
+ } while ( !$locked && ( microtime( true ) - $timestamp ) < $timeout );
}
- $uRTT = ceil( 1e6 * ( microtime( true ) - $timestamp ) ); // estimate RTT (us)
- $sleep = 2 * $uRTT; // rough time to do get()+set()
-
- $locked = false; // lock acquired
- $attempts = 0; // failed attempts
- do {
- if ( ++$attempts >= 3 && $sleep <= 5e5 ) {
- // Exponentially back off after failed attempts to avoid network spam.
- // About 2*$uRTT*(2^n-1) us of "sleep" happen for the next n attempts.
- $sleep *= 2;
- }
- usleep( $sleep ); // back off
- $this->clearLastError();
- $locked = $this->add( "{$key}:lock", 1, $expiry );
- if ( $this->getLastError() ) {
- return false;
- }
- } while ( !$locked && ( microtime( true ) - $timestamp ) < $timeout );
+ if ( $locked ) {
+ $this->locks[$key] = array( 'class' => $rclass, 'depth' => 1 );
+ }
return $locked;
}
/**
+ * Release an advisory lock on a key string
+ *
* @param string $key
* @return bool Success
*/
public function unlock( $key ) {
- return $this->delete( "{$key}:lock" );
+ if ( isset( $this->locks[$key] ) && --$this->locks[$key]['depth'] <= 0 ) {
+ unset( $this->locks[$key] );
+
+ return $this->delete( "{$key}:lock" );
+ }
+
+ return true;
+ }
+
+ /**
+ * Get a lightweight exclusive self-unlocking lock
+ *
+ * Note that the same lock cannot be acquired twice.
+ *
+ * This is useful for task de-duplication or to avoid obtrusive
+ * (though non-corrupting) DB errors like INSERT key conflicts
+ * or deadlocks when using LOCK IN SHARE MODE.
+ *
+ * @param string $key
+ * @param int $timeout Lock wait timeout; 0 for non-blocking [optional]
+ * @param int $expiry Lock expiry [optional]; 1 day maximum
+ * @param string $rclass Allow reentry if set and the current lock used this value
+ * @return ScopedCallback|null Returns null on failure
+ * @since 1.26
+ */
+ final public function getScopedLock( $key, $timeout = 6, $expiry = 30, $rclass = '' ) {
+ $expiry = min( $expiry ?: INF, 86400 );
+
+ if ( !$this->lock( $key, $timeout, $expiry, $rclass ) ) {
+ return null;
+ }
+
+ $lSince = microtime( true ); // lock timestamp
+ // PHP 5.3: Can't use $this in a closure
+ $that = $this;
+ $logger = $this->logger;
+
+ return new ScopedCallback( function() use ( $that, $logger, $key, $lSince, $expiry ) {
+ $latency = .050; // latency skew (err towards keeping lock present)
+ $age = ( microtime( true ) - $lSince + $latency );
+ if ( ( $age + $latency ) >= $expiry ) {
+ $logger->warning( "Lock for $key held too long ($age sec)." );
+ return; // expired; it's not "safe" to delete the key
+ }
+ $that->unlock( $key );
+ } );
}
/**
@@ -260,14 +348,13 @@ abstract class BagOStuff implements LoggerAwareInterface {
return false;
}
- /* *** Emulated functions *** */
-
/**
* Get an associative array containing the item for each of the keys that have items.
* @param array $keys List of strings
+ * @param integer $flags Bitfield; supports READ_LATEST [optional]
* @return array
*/
- public function getMulti( array $keys ) {
+ public function getMulti( array $keys, $flags = 0 ) {
$res = array();
foreach ( $keys as $key ) {
$val = $this->get( $key );
@@ -334,7 +421,7 @@ abstract class BagOStuff implements LoggerAwareInterface {
* Decrease stored value of $key by $value while preserving its TTL
* @param string $key
* @param int $value
- * @return int
+ * @return int|bool New value or false on failure
*/
public function decr( $key, $value = 1 ) {
return $this->incr( $key, - $value );
@@ -384,6 +471,24 @@ abstract class BagOStuff implements LoggerAwareInterface {
}
/**
+ * Modify a cache update operation array for EventRelayer::notify()
+ *
+ * This is used for relayed writes, e.g. for broadcasting a change
+ * to multiple data-centers. If the array contains a 'val' field
+ * then the command involves setting a key to that value. Note that
+ * for simplicity, 'val' is always a simple scalar value. This method
+ * is used to possibly serialize the value and add any cache-specific
+ * key/values needed for the relayer daemon (e.g. memcached flags).
+ *
+ * @param array $event
+ * @return array
+ * @since 1.26
+ */
+ public function modifySimpleRelayEvent( array $event ) {
+ return $event;
+ }
+
+ /**
* @param string $text
*/
protected function debug( $text ) {
diff --git a/includes/libs/objectcache/EmptyBagOStuff.php b/includes/libs/objectcache/EmptyBagOStuff.php
index 4ccf2707..55e84b05 100644
--- a/includes/libs/objectcache/EmptyBagOStuff.php
+++ b/includes/libs/objectcache/EmptyBagOStuff.php
@@ -27,7 +27,7 @@
* @ingroup Cache
*/
class EmptyBagOStuff extends BagOStuff {
- public function get( $key, &$casToken = null ) {
+ public function get( $key, &$casToken = null, $flags = 0 ) {
return false;
}
diff --git a/includes/libs/objectcache/HashBagOStuff.php b/includes/libs/objectcache/HashBagOStuff.php
index 2c8b05a5..b685e41f 100644
--- a/includes/libs/objectcache/HashBagOStuff.php
+++ b/includes/libs/objectcache/HashBagOStuff.php
@@ -48,7 +48,7 @@ class HashBagOStuff extends BagOStuff {
return true;
}
- public function get( $key, &$casToken = null ) {
+ public function get( $key, &$casToken = null, $flags = 0 ) {
if ( !isset( $this->bag[$key] ) ) {
return false;
}
@@ -68,20 +68,8 @@ class HashBagOStuff extends BagOStuff {
}
function delete( $key ) {
- if ( !isset( $this->bag[$key] ) ) {
- return false;
- }
-
unset( $this->bag[$key] );
return true;
}
-
- public function lock( $key, $timeout = 6, $expiry = 6 ) {
- return true;
- }
-
- function unlock( $key ) {
- return true;
- }
}
diff --git a/includes/libs/objectcache/ReplicatedBagOStuff.php b/includes/libs/objectcache/ReplicatedBagOStuff.php
new file mode 100644
index 00000000..9e80e9fd
--- /dev/null
+++ b/includes/libs/objectcache/ReplicatedBagOStuff.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Cache
+ * @author Aaron Schulz
+ */
+
+/**
+ * A cache class that directs writes to one set of servers and reads to
+ * another. This assumes that the servers used for reads are setup to slave
+ * those that writes go to. This can easily be used with redis for example.
+ *
+ * In the WAN scenario (e.g. multi-datacenter case), this is useful when
+ * writes are rare or they usually take place in the primary datacenter.
+ *
+ * @ingroup Cache
+ * @since 1.26
+ */
+class ReplicatedBagOStuff extends BagOStuff {
+ /** @var BagOStuff */
+ protected $writeStore;
+ /** @var BagOStuff */
+ protected $readStore;
+
+ /**
+ * Constructor. Parameters are:
+ * - writeFactory : ObjectFactory::getObjectFromSpec parameters yeilding BagOStuff.
+ * This object will be used for writes (e.g. the master DB).
+ * - readFactory : ObjectFactory::getObjectFromSpec parameters yeilding BagOStuff.
+ * This object will be used for reads (e.g. a slave DB).
+ *
+ * @param array $params
+ * @throws InvalidArgumentException
+ */
+ public function __construct( $params ) {
+ parent::__construct( $params );
+
+ if ( !isset( $params['writeFactory'] ) ) {
+ throw new InvalidArgumentException(
+ __METHOD__ . ': the "writeFactory" parameter is required' );
+ }
+ if ( !isset( $params['readFactory'] ) ) {
+ throw new InvalidArgumentException(
+ __METHOD__ . ': the "readFactory" parameter is required' );
+ }
+
+ $this->writeStore = ( $params['writeFactory'] instanceof BagOStuff )
+ ? $params['writeFactory']
+ : ObjectFactory::getObjectFromSpec( $params['writeFactory'] );
+ $this->readStore = ( $params['readFactory'] instanceof BagOStuff )
+ ? $params['readFactory']
+ : ObjectFactory::getObjectFromSpec( $params['readFactory'] );
+ }
+
+ public function setDebug( $debug ) {
+ $this->writeStore->setDebug( $debug );
+ $this->readStore->setDebug( $debug );
+ }
+
+ public function get( $key, &$casToken = null, $flags = 0 ) {
+ return ( $flags & self::READ_LATEST )
+ ? $this->writeStore->get( $key, $casToken, $flags )
+ : $this->readStore->get( $key, $casToken, $flags );
+ }
+
+ public function getMulti( array $keys, $flags = 0 ) {
+ return ( $flags & self::READ_LATEST )
+ ? $this->writeStore->getMulti( $keys, $flags )
+ : $this->readStore->getMulti( $keys, $flags );
+ }
+
+ public function set( $key, $value, $exptime = 0 ) {
+ return $this->writeStore->set( $key, $value, $exptime );
+ }
+
+ public function delete( $key ) {
+ return $this->writeStore->delete( $key );
+ }
+
+ public function add( $key, $value, $exptime = 0 ) {
+ return $this->writeStore->add( $key, $value, $exptime );
+ }
+
+ public function incr( $key, $value = 1 ) {
+ return $this->writeStore->incr( $key, $value );
+ }
+
+ public function decr( $key, $value = 1 ) {
+ return $this->writeStore->decr( $key, $value );
+ }
+
+ public function lock( $key, $timeout = 6, $expiry = 6, $rclass = '' ) {
+ return $this->writeStore->lock( $key, $timeout, $expiry, $rclass );
+ }
+
+ public function unlock( $key ) {
+ return $this->writeStore->unlock( $key );
+ }
+
+ public function merge( $key, $callback, $exptime = 0, $attempts = 10 ) {
+ return $this->writeStore->merge( $key, $callback, $exptime, $attempts );
+ }
+
+ public function getLastError() {
+ return ( $this->writeStore->getLastError() != self::ERR_NONE )
+ ? $this->writeStore->getLastError()
+ : $this->readStore->getLastError();
+ }
+
+ public function clearLastError() {
+ $this->writeStore->clearLastError();
+ $this->readStore->clearLastError();
+ }
+}
diff --git a/includes/libs/objectcache/WANObjectCache.php b/includes/libs/objectcache/WANObjectCache.php
new file mode 100644
index 00000000..2d921a70
--- /dev/null
+++ b/includes/libs/objectcache/WANObjectCache.php
@@ -0,0 +1,746 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Cache
+ * @author Aaron Schulz
+ */
+
+/**
+ * Multi-datacenter aware caching interface
+ *
+ * All operations go to the local cache, except the delete()
+ * and touchCheckKey(), which broadcast to all clusters.
+ * This class is intended for caching data from primary stores.
+ * If the get() method does not return a value, then the caller
+ * should query the new value and backfill the cache using set().
+ * When the source data changes, the delete() method should be called.
+ * Since delete() is expensive, it should be avoided. One can do so if:
+ * - a) The object cached is immutable; or
+ * - b) Validity is checked against the source after get(); or
+ * - c) Using a modest TTL is reasonably correct and performant
+ * Consider using getWithSetCallback() instead of the get()/set() cycle.
+ *
+ * Instances of this class must be configured to point to a valid
+ * PubSub endpoint, and there must be listeners on the cache servers
+ * that subscribe to the endpoint and update the caches.
+ *
+ * Broadcasted operations like delete() and touchCheckKey() are done
+ * synchronously in the local cluster, but are relayed asynchronously.
+ * This means that callers in other datacenters will see older values
+ * for a however many milliseconds the datacenters are apart. As with
+ * any cache, this should not be relied on for cases where reads are
+ * used to determine writes to source (e.g. non-cache) data stores.
+ *
+ * All values are wrapped in metadata arrays. Keys use a "WANCache:" prefix
+ * to avoid collisions with keys that are not wrapped as metadata arrays. The
+ * prefixes are as follows:
+ * - a) "WANCache:v" : used for regular value keys
+ * - b) "WANCache:s" : used for temporarily storing values of tombstoned keys
+ * - c) "WANCache:t" : used for storing timestamp "check" keys
+ *
+ * @ingroup Cache
+ * @since 1.26
+ */
+class WANObjectCache {
+ /** @var BagOStuff The local cluster cache */
+ protected $cache;
+ /** @var string Cache pool name */
+ protected $pool;
+ /** @var EventRelayer */
+ protected $relayer;
+
+ /** @var int */
+ protected $lastRelayError = self::ERR_NONE;
+
+ /** Seconds to tombstone keys on delete() */
+ const HOLDOFF_TTL = 10;
+ /** Seconds to keep dependency purge keys around */
+ const CHECK_KEY_TTL = 31536000; // 1 year
+ /** Seconds to keep lock keys around */
+ const LOCK_TTL = 5;
+ /** Default remaining TTL at which to consider pre-emptive regeneration */
+ const LOW_TTL = 10;
+ /** Default TTL for temporarily caching tombstoned keys */
+ const TEMP_TTL = 5;
+
+ /** Idiom for set()/getWithSetCallback() TTL */
+ const TTL_NONE = 0;
+ /** Idiom for getWithSetCallback() callbacks to avoid calling set() */
+ const TTL_UNCACHEABLE = -1;
+
+ /** Cache format version number */
+ const VERSION = 1;
+
+ /** Fields of value holder arrays */
+ const FLD_VERSION = 0;
+ const FLD_VALUE = 1;
+ const FLD_TTL = 2;
+ const FLD_TIME = 3;
+
+ /** Possible values for getLastError() */
+ const ERR_NONE = 0; // no error
+ const ERR_NO_RESPONSE = 1; // no response
+ const ERR_UNREACHABLE = 2; // can't connect
+ const ERR_UNEXPECTED = 3; // response gave some error
+ const ERR_RELAY = 4; // relay broadcast failed
+
+ const VALUE_KEY_PREFIX = 'WANCache:v:';
+ const STASH_KEY_PREFIX = 'WANCache:s:';
+ const TIME_KEY_PREFIX = 'WANCache:t:';
+
+ const PURGE_VAL_PREFIX = 'PURGED:';
+
+ /**
+ * @param array $params
+ * - cache : BagOStuff object
+ * - pool : pool name
+ * - relayer : EventRelayer object
+ */
+ public function __construct( array $params ) {
+ $this->cache = $params['cache'];
+ $this->pool = $params['pool'];
+ $this->relayer = $params['relayer'];
+ }
+
+ /**
+ * @return WANObjectCache Cache that wraps EmptyBagOStuff
+ */
+ public static function newEmpty() {
+ return new self( array(
+ 'cache' => new EmptyBagOStuff(),
+ 'pool' => 'empty',
+ 'relayer' => new EventRelayerNull( array() )
+ ) );
+ }
+
+ /**
+ * Fetch the value of a key from cache
+ *
+ * If passed in, $curTTL is set to the remaining TTL (current time left):
+ * - a) INF; if the key exists, has no TTL, and is not expired by $checkKeys
+ * - b) float (>=0); if the key exists, has a TTL, and is not expired by $checkKeys
+ * - c) float (<0); if the key is tombstoned or existing but expired by $checkKeys
+ * - d) null; if the key does not exist and is not tombstoned
+ *
+ * If a key is tombstoned, $curTTL will reflect the time since delete().
+ *
+ * The timestamp of $key will be checked against the last-purge timestamp
+ * of each of $checkKeys. Those $checkKeys not in cache will have the last-purge
+ * initialized to the current timestamp. If any of $checkKeys have a timestamp
+ * greater than that of $key, then $curTTL will reflect how long ago $key
+ * became invalid. Callers can use $curTTL to know when the value is stale.
+ * The $checkKeys parameter allow mass invalidations by updating a single key:
+ * - a) Each "check" key represents "last purged" of some source data
+ * - b) Callers pass in relevant "check" keys as $checkKeys in get()
+ * - c) When the source data that "check" keys represent changes,
+ * the touchCheckKey() method is called on them
+ *
+ * For keys that are hot/expensive, consider using getWithSetCallback() instead.
+ *
+ * @param string $key Cache key
+ * @param mixed $curTTL Approximate TTL left on the key if present [returned]
+ * @param array $checkKeys List of "check" keys
+ * @return mixed Value of cache key or false on failure
+ */
+ final public function get( $key, &$curTTL = null, array $checkKeys = array() ) {
+ $curTTLs = array();
+ $values = $this->getMulti( array( $key ), $curTTLs, $checkKeys );
+ $curTTL = isset( $curTTLs[$key] ) ? $curTTLs[$key] : null;
+
+ return isset( $values[$key] ) ? $values[$key] : false;
+ }
+
+ /**
+ * Fetch the value of several keys from cache
+ *
+ * @see WANObjectCache::get()
+ *
+ * @param array $keys List of cache keys
+ * @param array $curTTLs Map of (key => approximate TTL left) for existing keys [returned]
+ * @param array $checkKeys List of "check" keys
+ * @return array Map of (key => value) for keys that exist
+ */
+ final public function getMulti(
+ array $keys, &$curTTLs = array(), array $checkKeys = array()
+ ) {
+ $result = array();
+ $curTTLs = array();
+
+ $vPrefixLen = strlen( self::VALUE_KEY_PREFIX );
+ $valueKeys = self::prefixCacheKeys( $keys, self::VALUE_KEY_PREFIX );
+ $checkKeys = self::prefixCacheKeys( $checkKeys, self::TIME_KEY_PREFIX );
+
+ // Fetch all of the raw values
+ $wrappedValues = $this->cache->getMulti( array_merge( $valueKeys, $checkKeys ) );
+ $now = microtime( true );
+
+ // Get/initialize the timestamp of all the "check" keys
+ $checkKeyTimes = array();
+ foreach ( $checkKeys as $checkKey ) {
+ $timestamp = isset( $wrappedValues[$checkKey] )
+ ? self::parsePurgeValue( $wrappedValues[$checkKey] )
+ : false;
+ if ( !is_float( $timestamp ) ) {
+ // Key is not set or invalid; regenerate
+ $this->cache->add( $checkKey,
+ self::PURGE_VAL_PREFIX . $now, self::CHECK_KEY_TTL );
+ $timestamp = $now;
+ }
+
+ $checkKeyTimes[] = $timestamp;
+ }
+
+ // Get the main cache value for each key and validate them
+ foreach ( $valueKeys as $vKey ) {
+ if ( !isset( $wrappedValues[$vKey] ) ) {
+ continue; // not found
+ }
+
+ $key = substr( $vKey, $vPrefixLen ); // unprefix
+
+ list( $value, $curTTL ) = $this->unwrap( $wrappedValues[$vKey], $now );
+ if ( $value !== false ) {
+ $result[$key] = $value;
+ foreach ( $checkKeyTimes as $checkKeyTime ) {
+ // Force dependant keys to be invalid for a while after purging
+ // to reduce race conditions involving stale data getting cached
+ $safeTimestamp = $checkKeyTime + self::HOLDOFF_TTL;
+ if ( $safeTimestamp >= $wrappedValues[$vKey][self::FLD_TIME] ) {
+ $curTTL = min( $curTTL, $checkKeyTime - $now );
+ }
+ }
+ }
+
+ $curTTLs[$key] = $curTTL;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Set the value of a key from cache
+ *
+ * Simply calling this method when source data changes is not valid because
+ * the changes do not replicate to the other WAN sites. In that case, delete()
+ * should be used instead. This method is intended for use on cache misses.
+ *
+ * @param string $key Cache key
+ * @param mixed $value
+ * @param integer $ttl Seconds to live [0=forever]
+ * @return bool Success
+ */
+ final public function set( $key, $value, $ttl = 0 ) {
+ $key = self::VALUE_KEY_PREFIX . $key;
+ $wrapped = $this->wrap( $value, $ttl );
+
+ $func = function ( $cache, $key, $cWrapped ) use ( $wrapped ) {
+ return ( is_string( $cWrapped ) )
+ ? false // key is tombstoned; do nothing
+ : $wrapped;
+ };
+
+ return $this->cache->merge( $key, $func, $ttl, 1 );
+ }
+
+ /**
+ * Purge a key from all clusters
+ *
+ * This should only be called when the underlying data (being cached)
+ * changes in a significant way. This deletes the key and starts a hold-off
+ * period where the key cannot be written to for a few seconds (HOLDOFF_TTL).
+ * This is done to avoid the following race condition:
+ * a) Some DB data changes and delete() is called on a corresponding key
+ * b) A request refills the key with a stale value from a lagged DB
+ * c) The stale value is stuck there until the key is expired/evicted
+ *
+ * This is implemented by storing a special "tombstone" value at the cache
+ * key that this class recognizes; get() calls will return false for the key
+ * and any set() calls will refuse to replace tombstone values at the key.
+ * For this to always avoid writing stale values, the following must hold:
+ * a) Replication lag is bounded to being less than HOLDOFF_TTL; or
+ * b) If lag is higher, the DB will have gone into read-only mode already
+ *
+ * If called twice on the same key, then the last hold-off TTL takes
+ * precedence. For idempotence, the $ttl should not vary for different
+ * delete() calls on the same key. Also note that lowering $ttl reduces
+ * the effective range of the 'lockTSE' parameter to getWithSetCallback().
+ *
+ * @param string $key Cache key
+ * @param integer $ttl How long to block writes to the key [seconds]
+ * @return bool True if the item was purged or not found, false on failure
+ */
+ final public function delete( $key, $ttl = self::HOLDOFF_TTL ) {
+ $key = self::VALUE_KEY_PREFIX . $key;
+ // Avoid indefinite key salting for sanity
+ $ttl = max( $ttl, 1 );
+ // Update the local cluster immediately
+ $ok = $this->cache->set( $key, self::PURGE_VAL_PREFIX . microtime( true ), $ttl );
+ // Publish the purge to all clusters
+ return $this->relayPurge( $key, $ttl ) && $ok;
+ }
+
+ /**
+ * Fetch the value of a timestamp "check" key
+ *
+ * The key will be *initialized* to the current time if not set,
+ * so only call this method if this behavior is actually desired
+ *
+ * The timestamp can be used to check whether a cached value is valid.
+ * Callers should not assume that this returns the same timestamp in
+ * all datacenters due to relay delays.
+ *
+ * The level of staleness can roughly be estimated from this key, but
+ * if the key was evicted from cache, such calculations may show the
+ * time since expiry as ~0 seconds.
+ *
+ * Note that "check" keys won't collide with other regular keys
+ *
+ * @param string $key
+ * @return float UNIX timestamp of the key
+ */
+ final public function getCheckKeyTime( $key ) {
+ $key = self::TIME_KEY_PREFIX . $key;
+
+ $time = self::parsePurgeValue( $this->cache->get( $key ) );
+ if ( $time === false ) {
+ // Casting assures identical floats for the next getCheckKeyTime() calls
+ $time = (string)microtime( true );
+ $this->cache->add( $key, self::PURGE_VAL_PREFIX . $time, self::CHECK_KEY_TTL );
+ $time = (float)$time;
+ }
+
+ return $time;
+ }
+
+ /**
+ * Purge a "check" key from all clusters, invalidating keys that use it
+ *
+ * This should only be called when the underlying data (being cached)
+ * changes in a significant way, and it is impractical to call delete()
+ * on all keys that should be changed. When get() is called on those
+ * keys, the relevant "check" keys must be supplied for this to work.
+ *
+ * The "check" key essentially represents a last-modified field.
+ * It is set in the future a few seconds when this is called, to
+ * avoid race conditions where dependent keys get updated with a
+ * stale value (e.g. from a DB slave).
+ *
+ * This is typically useful for keys with static names or some cases
+ * dynamically generated names where a low number of combinations exist.
+ * When a few important keys get a large number of hits, a high cache
+ * time is usually desired as well as lockTSE logic. The resetCheckKey()
+ * method is less appropriate in such cases since the "time since expiry"
+ * cannot be inferred.
+ *
+ * Note that "check" keys won't collide with other regular keys
+ *
+ * @see WANObjectCache::get()
+ *
+ * @param string $key Cache key
+ * @return bool True if the item was purged or not found, false on failure
+ */
+ final public function touchCheckKey( $key ) {
+ $key = self::TIME_KEY_PREFIX . $key;
+ // Update the local cluster immediately
+ $ok = $this->cache->set( $key,
+ self::PURGE_VAL_PREFIX . microtime( true ), self::CHECK_KEY_TTL );
+ // Publish the purge to all clusters
+ return $this->relayPurge( $key, self::CHECK_KEY_TTL ) && $ok;
+ }
+
+ /**
+ * Delete a "check" key from all clusters, invalidating keys that use it
+ *
+ * This is similar to touchCheckKey() in that keys using it via
+ * getWithSetCallback() will be invalidated. The differences are:
+ * a) The timestamp will be deleted from all caches and lazily
+ * re-initialized when accessed (rather than set everywhere)
+ * b) Thus, dependent keys will be known to be invalid, but not
+ * for how long (they are treated as "just" purged), which
+ * effects any lockTSE logic in getWithSetCallback()
+ * The advantage is that this does not place high TTL keys on every cache
+ * server, making it better for code that will cache many different keys
+ * and either does not use lockTSE or uses a low enough TTL anyway.
+ *
+ * This is typically useful for keys with dynamically generated names
+ * where a high number of combinations exist.
+ *
+ * Note that "check" keys won't collide with other regular keys
+ *
+ * @see WANObjectCache::touchCheckKey()
+ * @see WANObjectCache::get()
+ *
+ * @param string $key Cache key
+ * @return bool True if the item was purged or not found, false on failure
+ */
+ final public function resetCheckKey( $key ) {
+ $key = self::TIME_KEY_PREFIX . $key;
+ // Update the local cluster immediately
+ $ok = $this->cache->delete( $key );
+ // Publish the purge to all clusters
+ return $this->relayDelete( $key ) && $ok;
+ }
+
+ /**
+ * Method to fetch/regenerate cache keys
+ *
+ * On cache miss, the key will be set to the callback result,
+ * unless the callback returns false. The arguments supplied are:
+ * (current value or false, &$ttl)
+ * The callback function returns the new value given the current
+ * value (false if not present). Preemptive re-caching and $checkKeys
+ * can result in a non-false current value. The TTL of the new value
+ * can be set dynamically by altering $ttl in the callback (by reference).
+ *
+ * Usually, callbacks ignore the current value, but it can be used
+ * to maintain "most recent X" values that come from time or sequence
+ * based source data, provided that the "as of" id/time is tracked.
+ *
+ * Usage of $checkKeys is similar to get()/getMulti(). However,
+ * rather than the caller having to inspect a "current time left"
+ * variable (e.g. $curTTL, $curTTLs), a cache regeneration will be
+ * triggered using the callback.
+ *
+ * The simplest way to avoid stampedes for hot keys is to use
+ * the 'lockTSE' option in $opts. If cache purges are needed, also:
+ * a) Pass $key into $checkKeys
+ * b) Use touchCheckKey( $key ) instead of delete( $key )
+ * Following this pattern lets the old cache be used until a
+ * single thread updates it as needed. Also consider tweaking
+ * the 'lowTTL' parameter.
+ *
+ * Example usage:
+ * @code
+ * $key = wfMemcKey( 'cat-recent-actions', $catId );
+ * // Function that derives the new key value given the old value
+ * $callback = function( $cValue, &$ttl ) { ... };
+ * // Get the key value from cache or from source on cache miss;
+ * // try to only let one cluster thread manage doing cache updates
+ * $opts = array( 'lockTSE' => 5, 'lowTTL' => 10 );
+ * $value = $cache->getWithSetCallback( $key, $callback, 60, array(), $opts );
+ * @endcode
+ *
+ * Example usage:
+ * @code
+ * $key = wfMemcKey( 'cat-state', $catId );
+ * // The "check" keys that represent things the value depends on;
+ * // Calling touchCheckKey() on them invalidates "cat-state"
+ * $checkKeys = array(
+ * wfMemcKey( 'water-bowls', $houseId ),
+ * wfMemcKey( 'food-bowls', $houseId ),
+ * wfMemcKey( 'people-present', $houseId )
+ * );
+ * // Function that derives the new key value
+ * $callback = function() { ... };
+ * // Get the key value from cache or from source on cache miss;
+ * // try to only let one cluster thread manage doing cache updates
+ * $opts = array( 'lockTSE' => 5, 'lowTTL' => 10 );
+ * $value = $cache->getWithSetCallback( $key, $callback, 60, $checkKeys, $opts );
+ * @endcode
+ *
+ * @see WANObjectCache::get()
+ *
+ * @param string $key Cache key
+ * @param integer $ttl Seconds to live for key updates. Special values are:
+ * - WANObjectCache::TTL_NONE : Cache forever
+ * - WANObjectCache::TTL_UNCACHEABLE: Do not cache at all
+ * @param callable $callback Value generation function
+ * @param array $opts Options map:
+ * - checkKeys: List of "check" keys.
+ * - lowTTL: Consider pre-emptive updates when the current TTL (sec) of the key is less than
+ * this. It becomes more likely over time, becoming a certainty once the key is expired.
+ * Default: WANObjectCache::LOW_TTL seconds.
+ * - lockTSE: If the key is tombstoned or expired (by checkKeys) less than this many seconds
+ * ago, then try to have a single thread handle cache regeneration at any given time.
+ * Other threads will try to use stale values if possible. If, on miss, the time since
+ * expiration is low, the assumption is that the key is hot and that a stampede is worth
+ * avoiding. Setting this above WANObjectCache::HOLDOFF_TTL makes no difference. The
+ * higher this is set, the higher the worst-case staleness can be.
+ * Use WANObjectCache::TSE_NONE to disable this logic. Default: WANObjectCache::TSE_NONE.
+ * - tempTTL : TTL of the temp key used to cache values while a key is tombstoned.
+ * This avoids excessive regeneration of hot keys on delete() but may
+ * result in stale values.
+ * @return mixed Value to use for the key
+ */
+ final public function getWithSetCallback(
+ $key, $ttl, $callback, array $opts = array(), $oldOpts = array()
+ ) {
+ // Back-compat with 1.26: Swap $ttl and $callback
+ if ( is_int( $callback ) ) {
+ $temp = $ttl;
+ $ttl = $callback;
+ $callback = $temp;
+ }
+ // Back-compat with 1.26: $checkKeys as separate parameter
+ if ( $oldOpts || ( is_array( $opts ) && isset( $opts[0] ) ) ) {
+ $checkKeys = $opts;
+ $opts = $oldOpts;
+ } else {
+ $checkKeys = isset( $opts['checkKeys'] ) ? $opts['checkKeys'] : array();
+ }
+
+ $lowTTL = isset( $opts['lowTTL'] ) ? $opts['lowTTL'] : min( self::LOW_TTL, $ttl );
+ $lockTSE = isset( $opts['lockTSE'] ) ? $opts['lockTSE'] : -1;
+ $tempTTL = isset( $opts['tempTTL'] ) ? $opts['tempTTL'] : self::TEMP_TTL;
+
+ // Get the current key value
+ $curTTL = null;
+ $cValue = $this->get( $key, $curTTL, $checkKeys ); // current value
+ $value = $cValue; // return value
+
+ // Determine if a regeneration is desired
+ if ( $value !== false && $curTTL > 0 && !$this->worthRefresh( $curTTL, $lowTTL ) ) {
+ return $value;
+ }
+
+ // A deleted key with a negative TTL left must be tombstoned
+ $isTombstone = ( $curTTL !== null && $value === false );
+ // Assume a key is hot if requested soon after invalidation
+ $isHot = ( $curTTL !== null && $curTTL <= 0 && abs( $curTTL ) <= $lockTSE );
+
+ $lockAcquired = false;
+ if ( $isHot ) {
+ // Acquire a cluster-local non-blocking lock
+ if ( $this->cache->lock( $key, 0, self::LOCK_TTL ) ) {
+ // Lock acquired; this thread should update the key
+ $lockAcquired = true;
+ } elseif ( $value !== false ) {
+ // If it cannot be acquired; then the stale value can be used
+ return $value;
+ }
+ }
+
+ if ( !$lockAcquired && ( $isTombstone || $isHot ) ) {
+ // Use the stash value for tombstoned keys to reduce regeneration load.
+ // For hot keys, either another thread has the lock or the lock failed;
+ // use the stash value from the last thread that regenerated it.
+ $value = $this->cache->get( self::STASH_KEY_PREFIX . $key );
+ if ( $value !== false ) {
+ return $value;
+ }
+ }
+
+ if ( !is_callable( $callback ) ) {
+ throw new InvalidArgumentException( "Invalid cache miss callback provided." );
+ }
+
+ // Generate the new value from the callback...
+ $value = call_user_func_array( $callback, array( $cValue, &$ttl ) );
+ // When delete() is called, writes are write-holed by the tombstone,
+ // so use a special stash key to pass the new value around threads.
+ if ( $value !== false && ( $isHot || $isTombstone ) && $ttl >= 0 ) {
+ $this->cache->set( self::STASH_KEY_PREFIX . $key, $value, $tempTTL );
+ }
+
+ if ( $lockAcquired ) {
+ $this->cache->unlock( $key );
+ }
+
+ if ( $value !== false && $ttl >= 0 ) {
+ // Update the cache; this will fail if the key is tombstoned
+ $this->set( $key, $value, $ttl );
+ }
+
+ return $value;
+ }
+
+ /**
+ * Get the "last error" registered; clearLastError() should be called manually
+ * @return int ERR_* constant for the "last error" registry
+ */
+ final public function getLastError() {
+ if ( $this->lastRelayError ) {
+ // If the cache and the relayer failed, focus on the later.
+ // An update not making it to the relayer means it won't show up
+ // in other DCs (nor will consistent re-hashing see up-to-date values).
+ // On the other hand, if just the cache update failed, then it should
+ // eventually be applied by the relayer.
+ return $this->lastRelayError;
+ }
+
+ $code = $this->cache->getLastError();
+ switch ( $code ) {
+ case BagOStuff::ERR_NONE:
+ return self::ERR_NONE;
+ case BagOStuff::ERR_NO_RESPONSE:
+ return self::ERR_NO_RESPONSE;
+ case BagOStuff::ERR_UNREACHABLE:
+ return self::ERR_UNREACHABLE;
+ default:
+ return self::ERR_UNEXPECTED;
+ }
+ }
+
+ /**
+ * Clear the "last error" registry
+ */
+ final public function clearLastError() {
+ $this->cache->clearLastError();
+ $this->lastRelayError = self::ERR_NONE;
+ }
+
+ /**
+ * Do the actual async bus purge of a key
+ *
+ * This must set the key to "PURGED:<UNIX timestamp>"
+ *
+ * @param string $key Cache key
+ * @param integer $ttl How long to keep the tombstone [seconds]
+ * @return bool Success
+ */
+ protected function relayPurge( $key, $ttl ) {
+ $event = $this->cache->modifySimpleRelayEvent( array(
+ 'cmd' => 'set',
+ 'key' => $key,
+ 'val' => 'PURGED:$UNIXTIME$',
+ 'ttl' => max( $ttl, 1 ),
+ 'sbt' => true, // substitute $UNIXTIME$ with actual microtime
+ ) );
+
+ $ok = $this->relayer->notify( "{$this->pool}:purge", $event );
+ if ( !$ok ) {
+ $this->lastRelayError = self::ERR_RELAY;
+ }
+
+ return $ok;
+ }
+
+ /**
+ * Do the actual async bus delete of a key
+ *
+ * @param string $key Cache key
+ * @return bool Success
+ */
+ protected function relayDelete( $key ) {
+ $event = $this->cache->modifySimpleRelayEvent( array(
+ 'cmd' => 'delete',
+ 'key' => $key,
+ ) );
+
+ $ok = $this->relayer->notify( "{$this->pool}:purge", $event );
+ if ( !$ok ) {
+ $this->lastRelayError = self::ERR_RELAY;
+ }
+
+ return $ok;
+ }
+
+ /**
+ * Check if a key should be regenerated (using random probability)
+ *
+ * This returns false if $curTTL >= $lowTTL. Otherwise, the chance
+ * of returning true increases steadily from 0% to 100% as the $curTTL
+ * moves from $lowTTL to 0 seconds. This handles widely varying
+ * levels of cache access traffic.
+ *
+ * @param float $curTTL Approximate TTL left on the key if present
+ * @param float $lowTTL Consider a refresh when $curTTL is less than this
+ * @return bool
+ */
+ protected function worthRefresh( $curTTL, $lowTTL ) {
+ if ( $curTTL >= $lowTTL ) {
+ return false;
+ } elseif ( $curTTL <= 0 ) {
+ return true;
+ }
+
+ $chance = ( 1 - $curTTL / $lowTTL );
+
+ return mt_rand( 1, 1e9 ) <= 1e9 * $chance;
+ }
+
+ /**
+ * Do not use this method outside WANObjectCache
+ *
+ * @param mixed $value
+ * @param integer $ttl [0=forever]
+ * @return string
+ */
+ protected function wrap( $value, $ttl ) {
+ return array(
+ self::FLD_VERSION => self::VERSION,
+ self::FLD_VALUE => $value,
+ self::FLD_TTL => $ttl,
+ self::FLD_TIME => microtime( true )
+ );
+ }
+
+ /**
+ * Do not use this method outside WANObjectCache
+ *
+ * @param array|string|bool $wrapped
+ * @param float $now Unix Current timestamp (preferrable pre-query)
+ * @return array (mixed; false if absent/invalid, current time left)
+ */
+ protected function unwrap( $wrapped, $now ) {
+ // Check if the value is a tombstone
+ $purgeTimestamp = self::parsePurgeValue( $wrapped );
+ if ( is_float( $purgeTimestamp ) ) {
+ // Purged values should always have a negative current $ttl
+ $curTTL = min( -0.000001, $purgeTimestamp - $now );
+ return array( false, $curTTL );
+ }
+
+ if ( !is_array( $wrapped ) // not found
+ || !isset( $wrapped[self::FLD_VERSION] ) // wrong format
+ || $wrapped[self::FLD_VERSION] !== self::VERSION // wrong version
+ ) {
+ return array( false, null );
+ }
+
+ if ( $wrapped[self::FLD_TTL] > 0 ) {
+ // Get the approximate time left on the key
+ $age = $now - $wrapped[self::FLD_TIME];
+ $curTTL = max( $wrapped[self::FLD_TTL] - $age, 0.0 );
+ } else {
+ // Key had no TTL, so the time left is unbounded
+ $curTTL = INF;
+ }
+
+ return array( $wrapped[self::FLD_VALUE], $curTTL );
+ }
+
+ /**
+ * @param array $keys
+ * @param string $prefix
+ * @return string[]
+ */
+ protected static function prefixCacheKeys( array $keys, $prefix ) {
+ $res = array();
+ foreach ( $keys as $key ) {
+ $res[] = $prefix . $key;
+ }
+
+ return $res;
+ }
+
+ /**
+ * @param string $value String like "PURGED:<timestamp>"
+ * @return float|bool UNIX timestamp or false on failure
+ */
+ protected static function parsePurgeValue( $value ) {
+ $m = array();
+ if ( is_string( $value ) &&
+ preg_match( '/^' . self::PURGE_VAL_PREFIX . '([^:]+)$/', $value, $m )
+ ) {
+ return (float)$m[1];
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/includes/libs/objectcache/WinCacheBagOStuff.php b/includes/libs/objectcache/WinCacheBagOStuff.php
index 53625746..c480aa08 100644
--- a/includes/libs/objectcache/WinCacheBagOStuff.php
+++ b/includes/libs/objectcache/WinCacheBagOStuff.php
@@ -28,15 +28,7 @@
* @ingroup Cache
*/
class WinCacheBagOStuff extends BagOStuff {
-
- /**
- * Get a value from the WinCache object cache
- *
- * @param string $key Cache key
- * @param int $casToken [optional] Cas token
- * @return mixed
- */
- public function get( $key, &$casToken = null ) {
+ public function get( $key, &$casToken = null, $flags = 0 ) {
$val = wincache_ucache_get( $key );
$casToken = $val;
@@ -48,14 +40,6 @@ class WinCacheBagOStuff extends BagOStuff {
return $val;
}
- /**
- * Store a value in the WinCache object cache
- *
- * @param string $key Cache key
- * @param mixed $value Value to store
- * @param int $expire Expiration time
- * @return bool
- */
public function set( $key, $value, $expire = 0 ) {
$result = wincache_ucache_set( $key, serialize( $value ), $expire );
@@ -64,25 +48,10 @@ class WinCacheBagOStuff extends BagOStuff {
return ( is_array( $result ) && $result === array() ) || $result;
}
- /**
- * Store a value in the WinCache object cache, race condition-safe
- *
- * @param int $casToken Cas token
- * @param string $key Cache key
- * @param int $value Object to store
- * @param int $exptime Expiration time
- * @return bool
- */
protected function cas( $casToken, $key, $value, $exptime = 0 ) {
return wincache_ucache_cas( $key, $casToken, serialize( $value ) );
}
- /**
- * Remove a value from the WinCache object cache
- *
- * @param string $key Cache key
- * @return bool
- */
public function delete( $key ) {
wincache_ucache_delete( $key );
diff --git a/includes/libs/objectcache/XCacheBagOStuff.php b/includes/libs/objectcache/XCacheBagOStuff.php
index cfee9236..9dbff6f1 100644
--- a/includes/libs/objectcache/XCacheBagOStuff.php
+++ b/includes/libs/objectcache/XCacheBagOStuff.php
@@ -28,14 +28,7 @@
* @ingroup Cache
*/
class XCacheBagOStuff extends BagOStuff {
- /**
- * Get a value from the XCache object cache
- *
- * @param string $key Cache key
- * @param mixed $casToken Cas token
- * @return mixed
- */
- public function get( $key, &$casToken = null ) {
+ public function get( $key, &$casToken = null, $flags = 0 ) {
$val = xcache_get( $key );
if ( is_string( $val ) ) {
@@ -51,14 +44,6 @@ class XCacheBagOStuff extends BagOStuff {
return $val;
}
- /**
- * Store a value in the XCache object cache
- *
- * @param string $key Cache key
- * @param mixed $value Object to store
- * @param int $expire Expiration time
- * @return bool
- */
public function set( $key, $value, $expire = 0 ) {
if ( !$this->isInteger( $value ) ) {
$value = serialize( $value );
@@ -68,12 +53,6 @@ class XCacheBagOStuff extends BagOStuff {
return true;
}
- /**
- * Remove a value from the XCache object cache
- *
- * @param string $key Cache key
- * @return bool
- */
public function delete( $key ) {
xcache_unset( $key );
return true;
diff --git a/includes/libs/virtualrest/ParsoidVirtualRESTService.php b/includes/libs/virtualrest/ParsoidVirtualRESTService.php
index 32a27f79..43dfab3c 100644
--- a/includes/libs/virtualrest/ParsoidVirtualRESTService.php
+++ b/includes/libs/virtualrest/ParsoidVirtualRESTService.php
@@ -24,21 +24,27 @@
*/
class ParsoidVirtualRESTService extends VirtualRESTService {
/**
- * Example requests:
- * GET /local/v1/page/$title/html/$oldid
- * * $oldid is optional
- * POST /local/v1/transform/html/to/wikitext/$title/$oldid
+ * Example Parsoid v3 requests:
+ * GET /local/v3/page/html/$title/{$revision}
+ * * $revision is optional
+ * POST /local/v3/transform/html/to/wikitext/{$title}{/$revision}
* * body: array( 'html' => ... )
- * * $title and $oldid are optional
- * POST /local/v1/transform/wikitext/to/html/$title
- * * body: array( 'wikitext' => ... ) or array( 'wikitext' => ..., 'body' => true/false )
+ * * $title and $revision are optional
+ * POST /local/v3/transform/wikitext/to/html/{$title}{/$revision}
+ * * body: array( 'wikitext' => ... ) or array( 'wikitext' => ..., 'bodyOnly' => true/false )
* * $title is optional
+ * * $revision is optional
+ *
+ * There are also deprecated "v1" requests; see onParsoid1Request
+ * for details.
* @param array $params Key/value map
* - url : Parsoid server URL
- * - prefix : Parsoid prefix for this wiki
+ * - domain : Wiki domain to use
* - timeout : Parsoid timeout (optional)
* - forwardCookies : Cookies to forward to Parsoid, or false. (optional)
* - HTTPProxy : Parsoid HTTP proxy (optional)
+ * - restbaseCompat : whether to parse URL as if they were meant for RESTBase
+ * boolean (optional)
*/
public function __construct( array $params ) {
// for backwards compatibility:
@@ -46,7 +52,30 @@ class ParsoidVirtualRESTService extends VirtualRESTService {
$params['url'] = $params['URL'];
unset( $params['URL'] );
}
- parent::__construct( $params );
+ // set up defaults and merge them with the given params
+ $mparams = array_merge( array(
+ 'name' => 'parsoid',
+ 'url' => 'http://localhost:8000/',
+ 'prefix' => 'localhost',
+ 'domain' => 'localhost',
+ 'forwardCookies' => false,
+ 'HTTPProxy' => null,
+ ), $params );
+ // Ensure that the url parameter has a trailing slash.
+ $mparams['url'] = preg_replace(
+ '#/?$#',
+ '/',
+ $mparams['url']
+ );
+ // Ensure the correct domain format: strip protocol, port,
+ // and trailing slash if present. This lets us use
+ // $wgCanonicalServer as a default value, which is very convenient.
+ $mparams['domain'] = preg_replace(
+ '/^(https?:\/\/)?([^\/:]+?)(:\d+)?\/?$/',
+ '$2',
+ $mparams['domain']
+ );
+ parent::__construct( $mparams );
}
public function onRequests( array $reqs, Closure $idGeneratorFunc ) {
@@ -56,71 +85,143 @@ class ParsoidVirtualRESTService extends VirtualRESTService {
list(
$targetWiki, // 'local'
- $version, // 'v1'
- $reqType // 'page' or 'transform'
+ $version, // 'v3' ('v1' for restbase compatibility)
+ $reqType, // 'page' or 'transform'
+ $format, // 'html' or 'wikitext'
+ // $title (optional)
+ // $revision (optional)
) = $parts;
+ if ( isset( $this->params['restbaseCompat'] ) && $this->params['restbaseCompat'] ) {
+ if ( $version !== 'v1' ) {
+ throw new Exception( "Only RESTBase v1 API is supported." );
+ }
+ # Map RESTBase v1 API to Parsoid v3 API (pretty easy)
+ $req['url'] = preg_replace( '#^local/v1/#', 'local/v3/', $req['url'] );
+ } elseif ( $version !== 'v3' ) {
+ $result[$key] = $this->onParsoid1Request( $req, $idGeneratorFunc );
+ continue;
+ }
if ( $targetWiki !== 'local' ) {
+
throw new Exception( "Only 'local' target wiki is currently supported" );
- } elseif ( $version !== 'v1' ) {
- throw new Exception( "Only version 1 exists" );
- } elseif ( $reqType !== 'page' && $reqType !== 'transform' ) {
- throw new Exception( "Request type must be either 'page' or 'transform'" );
}
-
- $req['url'] = $this->params['url'] . '/' . urlencode( $this->params['prefix'] ) . '/';
-
- if ( $reqType === 'page' ) {
- $title = $parts[3];
- if ( $parts[4] !== 'html' ) {
- throw new Exception( "Only 'html' output format is currently supported" );
- }
- if ( isset( $parts[5] ) ) {
- $req['url'] .= $title . '?oldid=' . $parts[5];
- } else {
- $req['url'] .= $title;
- }
- } elseif ( $reqType === 'transform' ) {
- if ( $parts[4] !== 'to' ) {
- throw new Exception( "Part index 4 is not 'to'" );
- }
-
- if ( isset( $parts[6] ) ) {
- $req['url'] .= $parts[6];
- }
-
- if ( $parts[3] === 'html' & $parts[5] === 'wikitext' ) {
- if ( !isset( $req['body']['html'] ) ) {
- throw new Exception( "You must set an 'html' body key for this request" );
- }
- if ( isset( $parts[7] ) ) {
- $req['body']['oldid'] = $parts[7];
- }
- } elseif ( $parts[3] == 'wikitext' && $parts[5] == 'html' ) {
- if ( !isset( $req['body']['wikitext'] ) ) {
- throw new Exception( "You must set a 'wikitext' body key for this request" );
- }
- $req['body']['wt'] = $req['body']['wikitext'];
- unset( $req['body']['wikitext'] );
- } else {
- throw new Exception( "Transformation unsupported" );
- }
+ if ( $reqType !== 'page' && $reqType !== 'transform' ) {
+ throw new Exception( "Request action must be either 'page' or 'transform'" );
}
-
- if ( isset( $this->params['HTTPProxy'] ) && $this->params['HTTPProxy'] ) {
+ if ( $format !== 'html' && $format !== 'wikitext' ) {
+ throw new Exception( "Request format must be either 'html' or 'wt'" );
+ }
+ // replace /local/ with the current domain
+ $req['url'] = preg_replace( '#^local/#', $this->params['domain'] . '/', $req['url'] );
+ // and prefix it with the service URL
+ $req['url'] = $this->params['url'] . $req['url'];
+ // set the appropriate proxy, timeout and headers
+ if ( $this->params['HTTPProxy'] ) {
$req['proxy'] = $this->params['HTTPProxy'];
}
- if ( isset( $this->params['timeout'] ) ) {
+ if ( $this->params['timeout'] != null ) {
$req['reqTimeout'] = $this->params['timeout'];
}
-
- // Forward cookies
- if ( isset( $this->params['forwardCookies'] ) ) {
+ if ( $this->params['forwardCookies'] ) {
$req['headers']['Cookie'] = $this->params['forwardCookies'];
}
-
$result[$key] = $req;
}
return $result;
}
+
+ /**
+ * Remap a Parsoid v1 request to a Parsoid v3 request.
+ *
+ * Example Parsoid v1 requests:
+ * GET /local/v1/page/$title/html/$oldid
+ * * $oldid is optional
+ * POST /local/v1/transform/html/to/wikitext/$title/$oldid
+ * * body: array( 'html' => ... )
+ * * $title and $oldid are optional
+ * POST /local/v1/transform/wikitext/to/html/$title
+ * * body: array( 'wikitext' => ... ) or array( 'wikitext' => ..., 'body' => true/false )
+ * * $title is optional
+ *
+ * NOTE: the POST APIs aren't "real" Parsoid v1 APIs, they are just what
+ * Visual Editor "pretends" the V1 API is like. A previous version of
+ * ParsoidVirtualRESTService translated these to the "real" Parsoid v1
+ * API. We now translate these to the "real" Parsoid v3 API.
+ */
+ public function onParsoid1Request( array $req, Closure $idGeneratorFunc ) {
+
+ $parts = explode( '/', $req['url'] );
+ list(
+ $targetWiki, // 'local'
+ $version, // 'v1'
+ $reqType // 'page' or 'transform'
+ ) = $parts;
+ if ( $targetWiki !== 'local' ) {
+ throw new Exception( "Only 'local' target wiki is currently supported" );
+ } elseif ( $version !== 'v1' ) {
+ throw new Exception( "Only v1 and v3 are supported." );
+ } elseif ( $reqType !== 'page' && $reqType !== 'transform' ) {
+ throw new Exception( "Request type must be either 'page' or 'transform'" );
+ }
+ $req['url'] = $this->params['url'] . $this->params['domain'] . '/v3/';
+ if ( $reqType === 'page' ) {
+ $title = $parts[3];
+ if ( $parts[4] !== 'html' ) {
+ throw new Exception( "Only 'html' output format is currently supported" );
+ }
+ $req['url'] .= 'page/html/' . $title;
+ if ( isset( $parts[5] ) ) {
+ $req['url'] .= '/' . $parts[5];
+ } elseif ( isset( $req['query']['oldid'] ) && $req['query']['oldid'] ) {
+ $req['url'] .= '/' . $req['query']['oldid'];
+ unset( $req['query']['oldid'] );
+ }
+ } elseif ( $reqType === 'transform' ) {
+ $req['url'] .= 'transform/'. $parts[3] . '/to/' . $parts[5];
+ // the title
+ if ( isset( $parts[6] ) ) {
+ $req['url'] .= '/' . $parts[6];
+ }
+ // revision id
+ if ( isset( $parts[7] ) ) {
+ $req['url'] .= '/' . $parts[7];
+ } elseif ( isset( $req['body']['oldid'] ) && $req['body']['oldid'] ) {
+ $req['url'] .= '/' . $req['body']['oldid'];
+ unset( $req['body']['oldid'] );
+ }
+ if ( $parts[4] !== 'to' ) {
+ throw new Exception( "Part index 4 is not 'to'" );
+ }
+ if ( $parts[3] === 'html' && $parts[5] === 'wikitext' ) {
+ if ( !isset( $req['body']['html'] ) ) {
+ throw new Exception( "You must set an 'html' body key for this request" );
+ }
+ } elseif ( $parts[3] == 'wikitext' && $parts[5] == 'html' ) {
+ if ( !isset( $req['body']['wikitext'] ) ) {
+ throw new Exception( "You must set a 'wikitext' body key for this request" );
+ }
+ if ( isset( $req['body']['body'] ) ) {
+ $req['body']['bodyOnly'] = $req['body']['body'];
+ unset( $req['body']['body'] );
+ }
+ } else {
+ throw new Exception( "Transformation unsupported" );
+ }
+ }
+ // set the appropriate proxy, timeout and headers
+ if ( $this->params['HTTPProxy'] ) {
+ $req['proxy'] = $this->params['HTTPProxy'];
+ }
+ if ( $this->params['timeout'] != null ) {
+ $req['reqTimeout'] = $this->params['timeout'];
+ }
+ if ( $this->params['forwardCookies'] ) {
+ $req['headers']['Cookie'] = $this->params['forwardCookies'];
+ }
+
+ return $req;
+
+ }
+
}
diff --git a/includes/libs/virtualrest/RestbaseVirtualRESTService.php b/includes/libs/virtualrest/RestbaseVirtualRESTService.php
index 8fe5b921..3a7bc587 100644
--- a/includes/libs/virtualrest/RestbaseVirtualRESTService.php
+++ b/includes/libs/virtualrest/RestbaseVirtualRESTService.php
@@ -1,6 +1,6 @@
<?php
/**
- * Virtual HTTP service client for Restbase
+ * Virtual HTTP service client for RESTBase
*
* 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
@@ -19,23 +19,23 @@
*/
/**
- * Virtual REST service for Restbase
+ * Virtual REST service for RESTBase
* @since 1.25
*/
class RestbaseVirtualRESTService extends VirtualRESTService {
/**
- * Example requests:
- * GET /local/v1/page/{title}/html{/revision}
+ * Example RESTBase v1 requests:
+ * GET /local/v1/page/html/{title}{/revision}
* POST /local/v1/transform/html/to/wikitext{/title}{/revision}
* * body: array( 'html' => ... )
* POST /local/v1/transform/wikitext/to/html{/title}{/revision}
* * body: array( 'wikitext' => ... ) or array( 'wikitext' => ..., 'bodyOnly' => true/false )
*
* @param array $params Key/value map
- * - url : Restbase server URL
+ * - url : RESTBase server URL
* - domain : Wiki domain to use
* - timeout : request timeout in seconds (optional)
- * - forwardCookies : cookies to forward to Restbase/Parsoid (as a Cookie
+ * - forwardCookies : cookies to forward to RESTBase/Parsoid (as a Cookie
* header string) or false (optional)
* Note: forwardCookies will in the future be a boolean
* only, signifing request cookies should be forwarded
@@ -48,18 +48,27 @@ class RestbaseVirtualRESTService extends VirtualRESTService {
public function __construct( array $params ) {
// set up defaults and merge them with the given params
$mparams = array_merge( array(
- 'url' => 'http://localhost:7231',
+ 'name' => 'restbase',
+ 'url' => 'http://localhost:7231/',
'domain' => 'localhost',
'timeout' => 100,
'forwardCookies' => false,
'HTTPProxy' => null,
'parsoidCompat' => false
), $params );
- // ensure the correct domain format
+ // Ensure that the url parameter has a trailing slash.
+ $mparams['url'] = preg_replace(
+ '#/?$#',
+ '/',
+ $mparams['url']
+ );
+ // Ensure the correct domain format: strip protocol, port,
+ // and trailing slash if present. This lets us use
+ // $wgCanonicalServer as a default value, which is very convenient.
$mparams['domain'] = preg_replace(
- '/^(https?:\/\/)?([^\/:]+?)(\/|:\d+\/?)?$/',
- '$2',
- $mparams['domain']
+ '/^(https?:\/\/)?([^\/:]+?)(:\d+)?\/?$/',
+ '$2',
+ $mparams['domain']
);
parent::__construct( $mparams );
}
@@ -73,7 +82,7 @@ class RestbaseVirtualRESTService extends VirtualRESTService {
$result = array();
foreach ( $reqs as $key => $req ) {
// replace /local/ with the current domain
- $req['url'] = preg_replace( '/^\/local\//', '/' . $this->params['domain'] . '/', $req['url'] );
+ $req['url'] = preg_replace( '#^local/#', $this->params['domain'] . '/', $req['url'] );
// and prefix it with the service URL
$req['url'] = $this->params['url'] . $req['url'];
// set the appropriate proxy, timeout and headers
@@ -94,83 +103,164 @@ class RestbaseVirtualRESTService extends VirtualRESTService {
}
/**
- * Remaps Parsoid requests to Restbase paths
+ * Remaps Parsoid v1/v3 requests to RESTBase v1 requests.
*/
public function onParsoidRequests( array $reqs, Closure $idGeneratorFunc ) {
$result = array();
foreach ( $reqs as $key => $req ) {
$parts = explode( '/', $req['url'] );
- list(
- $targetWiki, // 'local'
- $version, // 'v1'
- $reqType // 'page' or 'transform'
- ) = $parts;
- if ( $targetWiki !== 'local' ) {
- throw new Exception( "Only 'local' target wiki is currently supported" );
- } elseif ( $reqType !== 'page' && $reqType !== 'transform' ) {
- throw new Exception( "Request type must be either 'page' or 'transform'" );
+ if ( $parts[1] === 'v3' ) {
+ $result[$key] = $this->onParsoid3Request( $req, $idGeneratorFunc );
+ } elseif ( $parts[1] === 'v1' ) {
+ $result[$key] = $this->onParsoid1Request( $req, $idGeneratorFunc );
+ } else {
+ throw new Exception( "Only v1 and v3 are supported." );
}
- $req['url'] = $this->params['url'] . '/' . $this->params['domain'] . '/v1/' . $reqType . '/';
- if ( $reqType === 'page' ) {
- $title = $parts[3];
- if ( $parts[4] !== 'html' ) {
- throw new Exception( "Only 'html' output format is currently supported" );
- }
- $req['url'] .= 'html/' . $title;
- if ( isset( $parts[5] ) ) {
- $req['url'] .= '/' . $parts[5];
- } elseif ( isset( $req['query']['oldid'] ) && $req['query']['oldid'] ) {
- $req['url'] .= '/' . $req['query']['oldid'];
- unset( $req['query']['oldid'] );
- }
- } elseif ( $reqType === 'transform' ) {
- // from / to transform
- $req['url'] .= $parts[3] . '/to/' . $parts[5];
- // the title
- if ( isset( $parts[6] ) ) {
- $req['url'] .= '/' . $parts[6];
- }
- // revision id
- if ( isset( $parts[7] ) ) {
- $req['url'] .= '/' . $parts[7];
- } elseif ( isset( $req['body']['oldid'] ) && $req['body']['oldid'] ) {
- $req['url'] .= '/' . $req['body']['oldid'];
- unset( $req['body']['oldid'] );
- }
- if ( $parts[4] !== 'to' ) {
- throw new Exception( "Part index 4 is not 'to'" );
- }
- if ( $parts[3] === 'html' & $parts[5] === 'wikitext' ) {
- if ( !isset( $req['body']['html'] ) ) {
- throw new Exception( "You must set an 'html' body key for this request" );
- }
- } elseif ( $parts[3] == 'wikitext' && $parts[5] == 'html' ) {
- if ( !isset( $req['body']['wikitext'] ) ) {
- throw new Exception( "You must set a 'wikitext' body key for this request" );
- }
- if ( isset( $req['body']['body'] ) ) {
- $req['body']['bodyOnly'] = $req['body']['body'];
- unset( $req['body']['body'] );
- }
- } else {
- throw new Exception( "Transformation unsupported" );
- }
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * Remap a Parsoid v1 request to a RESTBase v1 request.
+ *
+ * Example Parsoid v1 requests:
+ * GET /local/v1/page/$title/html/$oldid
+ * * $oldid is optional
+ * POST /local/v1/transform/html/to/wikitext/$title/$oldid
+ * * body: array( 'html' => ... )
+ * * $title and $oldid are optional
+ * POST /local/v1/transform/wikitext/to/html/$title
+ * * body: array( 'wikitext' => ... ) or array( 'wikitext' => ..., 'body' => true/false )
+ * * $title is optional
+ *
+ * NOTE: the POST APIs aren't "real" Parsoid v1 APIs, they are just what
+ * Visual Editor "pretends" the V1 API is like. (See
+ * ParsoidVirtualRESTService.)
+ */
+ public function onParsoid1Request( array $req, Closure $idGeneratorFunc ) {
+ $parts = explode( '/', $req['url'] );
+ list(
+ $targetWiki, // 'local'
+ $version, // 'v1'
+ $reqType // 'page' or 'transform'
+ ) = $parts;
+ if ( $targetWiki !== 'local' ) {
+ throw new Exception( "Only 'local' target wiki is currently supported" );
+ } elseif ( $version !== 'v1' ) {
+ throw new Exception( "Version mismatch: should not happen." );
+ } elseif ( $reqType !== 'page' && $reqType !== 'transform' ) {
+ throw new Exception( "Request type must be either 'page' or 'transform'" );
+ }
+ $req['url'] = $this->params['url'] . $this->params['domain'] . '/v1/' . $reqType . '/';
+ if ( $reqType === 'page' ) {
+ $title = $parts[3];
+ if ( $parts[4] !== 'html' ) {
+ throw new Exception( "Only 'html' output format is currently supported" );
}
- // set the appropriate proxy, timeout and headers
- if ( $this->params['HTTPProxy'] ) {
- $req['proxy'] = $this->params['HTTPProxy'];
+ $req['url'] .= 'html/' . $title;
+ if ( isset( $parts[5] ) ) {
+ $req['url'] .= '/' . $parts[5];
+ } elseif ( isset( $req['query']['oldid'] ) && $req['query']['oldid'] ) {
+ $req['url'] .= '/' . $req['query']['oldid'];
+ unset( $req['query']['oldid'] );
}
- if ( $this->params['timeout'] != null ) {
- $req['reqTimeout'] = $this->params['timeout'];
+ } elseif ( $reqType === 'transform' ) {
+ // from / to transform
+ $req['url'] .= $parts[3] . '/to/' . $parts[5];
+ // the title
+ if ( isset( $parts[6] ) ) {
+ $req['url'] .= '/' . $parts[6];
}
- if ( $this->params['forwardCookies'] ) {
- $req['headers']['Cookie'] = $this->params['forwardCookies'];
+ // revision id
+ if ( isset( $parts[7] ) ) {
+ $req['url'] .= '/' . $parts[7];
+ } elseif ( isset( $req['body']['oldid'] ) && $req['body']['oldid'] ) {
+ $req['url'] .= '/' . $req['body']['oldid'];
+ unset( $req['body']['oldid'] );
+ }
+ if ( $parts[4] !== 'to' ) {
+ throw new Exception( "Part index 4 is not 'to'" );
+ }
+ if ( $parts[3] === 'html' && $parts[5] === 'wikitext' ) {
+ if ( !isset( $req['body']['html'] ) ) {
+ throw new Exception( "You must set an 'html' body key for this request" );
+ }
+ } elseif ( $parts[3] == 'wikitext' && $parts[5] == 'html' ) {
+ if ( !isset( $req['body']['wikitext'] ) ) {
+ throw new Exception( "You must set a 'wikitext' body key for this request" );
+ }
+ if ( isset( $req['body']['body'] ) ) {
+ $req['body']['bodyOnly'] = $req['body']['body'];
+ unset( $req['body']['body'] );
+ }
+ } else {
+ throw new Exception( "Transformation unsupported" );
}
- $result[$key] = $req;
+ }
+ // set the appropriate proxy, timeout and headers
+ if ( $this->params['HTTPProxy'] ) {
+ $req['proxy'] = $this->params['HTTPProxy'];
+ }
+ if ( $this->params['timeout'] != null ) {
+ $req['reqTimeout'] = $this->params['timeout'];
+ }
+ if ( $this->params['forwardCookies'] ) {
+ $req['headers']['Cookie'] = $this->params['forwardCookies'];
}
- return $result;
+ return $req;
+
+ }
+
+ /**
+ * Remap a Parsoid v3 request to a RESTBase v1 request.
+ *
+ * Example Parsoid v3 requests:
+ * GET /local/v3/page/html/$title/{$revision}
+ * * $revision is optional
+ * POST /local/v3/transform/html/to/wikitext/{$title}{/$revision}
+ * * body: array( 'html' => ... )
+ * * $title and $revision are optional
+ * POST /local/v3/transform/wikitext/to/html/{$title}{/$revision}
+ * * body: array( 'wikitext' => ... ) or array( 'wikitext' => ..., 'bodyOnly' => true/false )
+ * * $title is optional
+ * * $revision is optional
+ */
+ public function onParsoid3Request( array $req, Closure $idGeneratorFunc ) {
+
+ $parts = explode( '/', $req['url'] );
+ list(
+ $targetWiki, // 'local'
+ $version, // 'v3'
+ $action, // 'transform' or 'page'
+ $format, // 'html' or 'wikitext'
+ // $title, // optional
+ // $revision, // optional
+ ) = $parts;
+ if ( $targetWiki !== 'local' ) {
+ throw new Exception( "Only 'local' target wiki is currently supported" );
+ } elseif ( $version !== 'v3' ) {
+ throw new Exception( "Version mismatch: should not happen." );
+ }
+ // replace /local/ with the current domain, change v3 to v1,
+ $req['url'] = preg_replace( '#^local/v3/#', $this->params['domain'] . '/v1/', $req['url'] );
+ // and prefix it with the service URL
+ $req['url'] = $this->params['url'] . $req['url'];
+ // set the appropriate proxy, timeout and headers
+ if ( $this->params['HTTPProxy'] ) {
+ $req['proxy'] = $this->params['HTTPProxy'];
+ }
+ if ( $this->params['timeout'] != null ) {
+ $req['reqTimeout'] = $this->params['timeout'];
+ }
+ if ( $this->params['forwardCookies'] ) {
+ $req['headers']['Cookie'] = $this->params['forwardCookies'];
+ }
+
+ return $req;
}
diff --git a/includes/libs/virtualrest/SwiftVirtualRESTService.php b/includes/libs/virtualrest/SwiftVirtualRESTService.php
index 011dabe0..88b0e1f1 100644
--- a/includes/libs/virtualrest/SwiftVirtualRESTService.php
+++ b/includes/libs/virtualrest/SwiftVirtualRESTService.php
@@ -45,7 +45,11 @@ class SwiftVirtualRESTService extends VirtualRESTService {
* - swiftAuthTTL : Swift authentication TTL (seconds)
*/
public function __construct( array $params ) {
- parent::__construct( $params );
+ // set up defaults and merge them with the given params
+ $mparams = array_merge( array(
+ 'name' => 'swift'
+ ), $params );
+ parent::__construct( $mparams );
}
/**
diff --git a/includes/libs/virtualrest/VirtualRESTService.php b/includes/libs/virtualrest/VirtualRESTService.php
index 05c2afc1..01a4ea6e 100644
--- a/includes/libs/virtualrest/VirtualRESTService.php
+++ b/includes/libs/virtualrest/VirtualRESTService.php
@@ -45,6 +45,17 @@ abstract class VirtualRESTService {
}
/**
+ * Return the name of this service, in a form suitable for error
+ * reporting or debugging.
+ *
+ * @return string The name of the service behind this VRS object.
+ */
+ public function getName() {
+ return isset( $this->params['name'] ) ? $this->params['name'] :
+ get_class( $this );
+ }
+
+ /**
* Prepare virtual HTTP(S) requests (for this service) for execution
*
* This method should mangle any of the $reqs entry fields as needed:
@@ -84,8 +95,8 @@ abstract class VirtualRESTService {
*
* This method may mangle any of the $reqs entry 'response' fields as needed:
* - code : perform any code normalization [as needed]
- * - reason : perform any reason normalization [as needed]
- * - headers : perform any header normalization [as needed]
+ * - reason : perform any reason normalization [as needed]
+ * - headers : perform any header normalization [as needed]
*
* This method can also remove some of the requests as well as add new ones
* (using $idGenerator to set each of the entries' array keys). For any existing
diff --git a/includes/libs/virtualrest/VirtualRESTServiceClient.php b/includes/libs/virtualrest/VirtualRESTServiceClient.php
index e8bb38d8..519da431 100644
--- a/includes/libs/virtualrest/VirtualRESTServiceClient.php
+++ b/includes/libs/virtualrest/VirtualRESTServiceClient.php
@@ -127,9 +127,9 @@ class VirtualRESTServiceClient {
* - body : HTTP response body or resource (if "stream" was set)
* - error : Any cURL error string
* The map also stores integer-indexed copies of these values. This lets callers do:
- * <code>
- * list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $client->run( $req );
- * </code>
+ * @code
+ * list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $client->run( $req );
+ * @endcode
* @param array $req Virtual HTTP request maps
* @return array Response array for request
*/
@@ -148,9 +148,9 @@ class VirtualRESTServiceClient {
* - body : HTTP response body or resource (if "stream" was set)
* - error : Any cURL error string
* The map also stores integer-indexed copies of these values. This lets callers do:
- * <code>
- * list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $responses[0];
- * </code>
+ * @code
+ * list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $responses[0];
+ * @endcode
*
* @param array $reqs Map of Virtual HTTP request maps
* @return array $reqs Map of corresponding response values with the same keys/order
diff --git a/includes/logging/ContentModelLogFormatter.php b/includes/logging/ContentModelLogFormatter.php
new file mode 100644
index 00000000..982fcc30
--- /dev/null
+++ b/includes/logging/ContentModelLogFormatter.php
@@ -0,0 +1,34 @@
+<?php
+
+class ContentModelLogFormatter extends LogFormatter {
+ protected function getMessageParameters() {
+ $lang = $this->context->getLanguage();
+ $params = parent::getMessageParameters();
+ $params[3] = ContentHandler::getLocalizedName( $params[3], $lang );
+ $params[4] = ContentHandler::getLocalizedName( $params[4], $lang );
+ return $params;
+ }
+
+ public function getActionLinks() {
+ if ( $this->entry->isDeleted( LogPage::DELETED_ACTION ) // Action is hidden
+ || $this->entry->getSubtype() !== 'change'
+ || !$this->context->getUser()->isAllowed( 'editcontentmodel' )
+ ) {
+ return '';
+ }
+
+ $params = $this->extractParameters();
+ $revert = Linker::linkKnown(
+ SpecialPage::getTitleFor( 'ChangeContentModel' ),
+ $this->msg( 'logentry-contentmodel-change-revertlink' )->escaped(),
+ array(),
+ array(
+ 'pagetitle' => $this->entry->getTarget()->getPrefixedText(),
+ 'model' => $params[3],
+ 'reason' => $this->msg( 'logentry-contentmodel-change-revert' )->inContentLanguage()->text(),
+ )
+ );
+
+ return $this->msg( 'parentheses' )->rawParams( $revert )->escaped();
+ }
+}
diff --git a/includes/logging/LogEntry.php b/includes/logging/LogEntry.php
index 66c2bde1..8427adbb 100644
--- a/includes/logging/LogEntry.php
+++ b/includes/logging/LogEntry.php
@@ -115,6 +115,28 @@ abstract class LogEntryBase implements LogEntry {
public function isLegacy() {
return false;
}
+
+ /**
+ * Create a blob from a parameter array
+ *
+ * @param array $params
+ * @return string
+ * @since 1.26
+ */
+ public static function makeParamBlob( $params ) {
+ return serialize( (array)$params );
+ }
+
+ /**
+ * Extract a parameter array from a blob
+ *
+ * @param string $blob
+ * @return array
+ * @since 1.26
+ */
+ public static function extractParams( $blob ) {
+ return unserialize( $blob );
+ }
}
/**
@@ -224,14 +246,14 @@ class DatabaseLogEntry extends LogEntryBase {
public function getParameters() {
if ( !isset( $this->params ) ) {
$blob = $this->getRawParameters();
- wfSuppressWarnings();
- $params = unserialize( $blob );
- wfRestoreWarnings();
+ MediaWiki\suppressWarnings();
+ $params = LogEntryBase::extractParams( $blob );
+ MediaWiki\restoreWarnings();
if ( $params !== false ) {
$this->params = $params;
$this->legacy = false;
} else {
- $this->params = $blob === '' ? array() : explode( "\n", $blob );
+ $this->params = LogPage::extractParams( $blob );
$this->legacy = true;
}
}
@@ -516,7 +538,7 @@ class ManualLogEntry extends LogEntryBase {
'log_title' => $this->getTarget()->getDBkey(),
'log_page' => $this->getTarget()->getArticleID(),
'log_comment' => $comment,
- 'log_params' => serialize( (array)$this->getParameters() ),
+ 'log_params' => LogEntryBase::makeParamBlob( $this->getParameters() ),
);
if ( isset( $this->deleted ) ) {
$data['log_deleted'] = $this->deleted;
@@ -584,7 +606,7 @@ class ManualLogEntry extends LogEntryBase {
$this->getSubtype(),
$this->getTarget(),
$this->getComment(),
- serialize( (array)$this->getParameters() ),
+ LogEntryBase::makeParamBlob( $this->getParameters() ),
$newId,
$formatter->getIRCActionComment() // Used for IRC feeds
);
diff --git a/includes/logging/LogEventsList.php b/includes/logging/LogEventsList.php
index dfe31365..1b56584f 100644
--- a/includes/logging/LogEventsList.php
+++ b/includes/logging/LogEventsList.php
@@ -36,6 +36,11 @@ class LogEventsList extends ContextSource {
protected $mDefaultQuery;
/**
+ * @var bool
+ */
+ protected $showTagEditUI;
+
+ /**
* Constructor.
* The first two parameters used to be $skin and $out, but now only a context
* is needed, that's why there's a second unused parameter.
@@ -55,6 +60,7 @@ class LogEventsList extends ContextSource {
}
$this->flags = $flags;
+ $this->showTagEditUI = ChangeTags::showTagEditingUI( $this->getUser() );
}
/**
@@ -348,7 +354,7 @@ class LogEventsList extends ContextSource {
$user = $this->getUser();
// If change tag editing is available to this user, return the checkbox
- if ( $this->flags & self::USE_CHECKBOXES && ChangeTags::showTagEditingUI( $user ) ) {
+ if ( $this->flags & self::USE_CHECKBOXES && $this->showTagEditUI ) {
return Xml::check(
'showhiderevisions',
false,
diff --git a/includes/logging/LogFormatter.php b/includes/logging/LogFormatter.php
index 9c2fdd35..f31a42aa 100644
--- a/includes/logging/LogFormatter.php
+++ b/includes/logging/LogFormatter.php
@@ -193,6 +193,8 @@ class LogFormatter {
* @return string Text
*/
public function getIRCActionText() {
+ global $wgContLang;
+
$this->plaintext = true;
$this->irctext = true;
@@ -271,6 +273,10 @@ class LogFormatter {
$text = wfMessage( 'modifiedarticleprotection' )
->rawParams( $target . ' ' . $parameters[0] )->inContentLanguage()->escaped();
break;
+ case 'move_prot':
+ $text = wfMessage( 'movedarticleprotection' )
+ ->rawParams( $target, $parameters['4::oldtitle'] )->inContentLanguage()->escaped();
+ break;
}
break;
@@ -338,7 +344,6 @@ class LogFormatter {
case 'block':
switch ( $entry->getSubtype() ) {
case 'block':
- global $wgContLang;
// Keep compatibility with extensions by checking for
// new key (5::duration/6::flags) or old key (0/optional 1)
if ( $entry->isLegacy() ) {
@@ -358,7 +363,6 @@ class LogFormatter {
->rawParams( $target )->inContentLanguage()->escaped();
break;
case 'reblock':
- global $wgContLang;
$duration = $wgContLang->translateBlockExpiry( $parameters['5::duration'] );
$flags = BlockLogFormatter::formatBlockFlags( $parameters['6::flags'], $wgContLang );
$text = wfMessage( 'reblock-logentry' )
@@ -790,7 +794,7 @@ class LogFormatter {
break;
case 'number':
- if ( ctype_digit( $value ) ) {
+ if ( ctype_digit( $value ) || is_int( $value ) ) {
$value = (int)$value;
} else {
$value = (float)$value;
diff --git a/includes/logging/LogPager.php b/includes/logging/LogPager.php
index bf489ab9..598a45f0 100644
--- a/includes/logging/LogPager.php
+++ b/includes/logging/LogPager.php
@@ -192,7 +192,7 @@ class LogPager extends ReverseChronologicalPager {
* @return void
*/
private function limitTitle( $page, $pattern ) {
- global $wgMiserMode;
+ global $wgMiserMode, $wgUserrightsInterwikiDelimiter;
if ( $page instanceof Title ) {
$title = $page;
@@ -209,7 +209,6 @@ class LogPager extends ReverseChronologicalPager {
$doUserRightsLogLike = false;
if ( $this->types == array( 'rights' ) ) {
- global $wgUserrightsInterwikiDelimiter;
$parts = explode( $wgUserrightsInterwikiDelimiter, $title->getDBKey() );
if ( count( $parts ) == 2 ) {
list( $name, $database ) = array_map( 'trim', $parts );
@@ -249,7 +248,7 @@ class LogPager extends ReverseChronologicalPager {
$user = $this->getUser();
if ( !$user->isAllowed( 'deletedhistory' ) ) {
$this->mConds[] = $db->bitAnd( 'log_deleted', LogPage::DELETED_ACTION ) . ' = 0';
- } elseif ( !$user->isAllowed( 'suppressrevision' ) ) {
+ } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
$this->mConds[] = $db->bitAnd( 'log_deleted', LogPage::SUPPRESSED_ACTION ) .
' != ' . LogPage::SUPPRESSED_ACTION;
}
diff --git a/includes/logging/PatrolLogFormatter.php b/includes/logging/PatrolLogFormatter.php
index 00337432..7fe0143f 100644
--- a/includes/logging/PatrolLogFormatter.php
+++ b/includes/logging/PatrolLogFormatter.php
@@ -68,9 +68,11 @@ class PatrolLogFormatter extends LogFormatter {
$params = $entry->getParameters();
static $map = array(
- '4::curid',
- '5::previd',
+ '4:number:curid',
+ '5:number:previd',
'6:bool:auto',
+ '4::curid' => '4:number:curid',
+ '5::previd' => '5:number:previd',
'6::auto' => '6:bool:auto',
);
foreach ( $map as $index => $key ) {
diff --git a/includes/logging/ProtectLogFormatter.php b/includes/logging/ProtectLogFormatter.php
new file mode 100644
index 00000000..5327e072
--- /dev/null
+++ b/includes/logging/ProtectLogFormatter.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Formatter for protect log entries.
+ *
+ * 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
+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
+ * @since 1.26
+ */
+
+/**
+ * This class formats protect log entries.
+ *
+ * @since 1.26
+ */
+class ProtectLogFormatter extends LogFormatter {
+ public function getPreloadTitles() {
+ $subtype = $this->entry->getSubtype();
+ if ( $subtype === 'move_prot' ) {
+ $params = $this->extractParameters();
+ return array( Title::newFromText( $params[3] ) );
+ }
+ return array();
+ }
+
+ protected function getMessageParameters() {
+ $params = parent::getMessageParameters();
+
+ $subtype = $this->entry->getSubtype();
+ if ( $subtype === 'move_prot' ) {
+ $oldname = $this->makePageLink( Title::newFromText( $params[3] ), array( 'redirect' => 'no' ) );
+ $params[3] = Message::rawParam( $oldname );
+ }
+
+ return $params;
+ }
+
+ protected function getParametersForApi() {
+ $entry = $this->entry;
+ $params = $entry->getParameters();
+
+ static $map = array(
+ // param keys for move_prot sub type
+ '4:title:oldtitle',
+ '4::oldtitle' => '4:title:oldtitle',
+ );
+ foreach ( $map as $index => $key ) {
+ if ( isset( $params[$index] ) ) {
+ $params[$key] = $params[$index];
+ unset( $params[$index] );
+ }
+ }
+
+ return $params;
+ }
+}
diff --git a/includes/mail/EmailNotification.php b/includes/mail/EmailNotification.php
index 81c4e38d..01b6afab 100644
--- a/includes/mail/EmailNotification.php
+++ b/includes/mail/EmailNotification.php
@@ -43,6 +43,20 @@
* Visit the documentation pages under http://meta.wikipedia.com/Enotif
*/
class EmailNotification {
+
+ /**
+ * Notification is due to user's user talk being edited
+ */
+ const USER_TALK = 'user_talk';
+ /**
+ * Notification is due to a watchlisted page being edited
+ */
+ const WATCHLIST = 'watchlist';
+ /**
+ * Notification because user is notified for all changes
+ */
+ const ALL_CHANGES = 'all_changes';
+
protected $subject, $body, $replyto, $from;
protected $timestamp, $summary, $minorEdit, $oldid, $composed_common, $pageStatus;
protected $mailTargets = array();
@@ -61,7 +75,7 @@ class EmailNotification {
* @param User $editor The editor that triggered the update. Their notification
* timestamp will not be updated(they have already seen it)
* @param Title $title The title to update timestamps for
- * @param string $timestamp Set the upate timestamp to this value
+ * @param string $timestamp Set the update timestamp to this value
* @return int[]
*/
public static function updateWatchlistTimestamp( User $editor, Title $title, $timestamp ) {
@@ -110,7 +124,6 @@ class EmailNotification {
/**
* Send emails corresponding to the user $editor editing the page $title.
- * Also updates wl_notificationtimestamp.
*
* May be deferred via the job queue.
*
@@ -136,7 +149,9 @@ class EmailNotification {
$sendEmail = true;
// If nobody is watching the page, and there are no users notified on all changes
- // don't bother creating a job/trying to send emails
+ // don't bother creating a job/trying to send emails, unless it's a
+ // talk page with an applicable notification.
+ //
// $watchers deals with $wgEnotifWatchlist
if ( !count( $watchers ) && !count( $wgUsersNotifiedOnAllChanges ) ) {
$sendEmail = false;
@@ -168,7 +183,7 @@ class EmailNotification {
'pageStatus' => $pageStatus
);
$job = new EnotifNotifyJob( $title, $params );
- JobQueueGroup::singleton()->push( $job );
+ JobQueueGroup::singleton()->lazyPush( $job );
} else {
$this->actuallyNotifyOnPageChange(
$editor,
@@ -187,8 +202,8 @@ class EmailNotification {
* Immediate version of notifyOnPageChange().
*
* Send emails corresponding to the user $editor editing the page $title.
- * Also updates wl_notificationtimestamp.
*
+ * @note Do not call directly. Use notifyOnPageChange so that wl_notificationtimestamp is updated.
* @param User $editor
* @param Title $title
* @param string $timestamp Edit timestamp
@@ -202,7 +217,7 @@ class EmailNotification {
public function actuallyNotifyOnPageChange( $editor, $title, $timestamp, $summary, $minorEdit,
$oldid, $watchers, $pageStatus = 'changed' ) {
# we use $wgPasswordSender as sender's address
- global $wgEnotifWatchlist;
+ global $wgEnotifWatchlist, $wgBlockDisablesLogin;
global $wgEnotifMinorEdits, $wgEnotifUserTalk;
# The following code is only run, if several conditions are met:
@@ -235,21 +250,23 @@ class EmailNotification {
&& $this->canSendUserTalkEmail( $editor, $title, $minorEdit )
) {
$targetUser = User::newFromName( $title->getText() );
- $this->compose( $targetUser );
+ $this->compose( $targetUser, self::USER_TALK );
$userTalkId = $targetUser->getId();
}
if ( $wgEnotifWatchlist ) {
// Send updates to watchers other than the current editor
+ // and don't send to watchers who are blocked and cannot login
$userArray = UserArray::newFromIDs( $watchers );
foreach ( $userArray as $watchingUser ) {
if ( $watchingUser->getOption( 'enotifwatchlistpages' )
&& ( !$minorEdit || $watchingUser->getOption( 'enotifminoredits' ) )
&& $watchingUser->isEmailConfirmed()
&& $watchingUser->getID() != $userTalkId
+ && !( $wgBlockDisablesLogin && $watchingUser->isBlocked() )
) {
if ( Hooks::run( 'SendWatchlistEmailNotification', array( $watchingUser, $title, $this ) ) ) {
- $this->compose( $watchingUser );
+ $this->compose( $watchingUser, self::WATCHLIST );
}
}
}
@@ -263,7 +280,7 @@ class EmailNotification {
continue;
}
$user = User::newFromName( $name );
- $this->compose( $user );
+ $this->compose( $user, self::ALL_CHANGES );
}
$this->sendMails();
@@ -276,7 +293,7 @@ class EmailNotification {
* @return bool
*/
private function canSendUserTalkEmail( $editor, $title, $minorEdit ) {
- global $wgEnotifUserTalk;
+ global $wgEnotifUserTalk, $wgBlockDisablesLogin;
$isUserTalkPage = ( $title->getNamespace() == NS_USER_TALK );
if ( $wgEnotifUserTalk && $isUserTalkPage ) {
@@ -286,6 +303,8 @@ class EmailNotification {
wfDebug( __METHOD__ . ": user talk page edited, but user does not exist\n" );
} elseif ( $targetUser->getId() == $editor->getId() ) {
wfDebug( __METHOD__ . ": user edited their own talk page, no notification sent\n" );
+ } elseif ( $wgBlockDisablesLogin && $targetUser->isBlocked() ) {
+ wfDebug( __METHOD__ . ": talk page owner is blocked and cannot login, no notification sent\n" );
} elseif ( $targetUser->getOption( 'enotifusertalkpages' )
&& ( !$minorEdit || $targetUser->getOption( 'enotifminoredits' ) )
) {
@@ -422,8 +441,9 @@ class EmailNotification {
*
* Call sendMails() to send any mails that were queued.
* @param User $user
+ * @param string $source
*/
- function compose( $user ) {
+ function compose( $user, $source ) {
global $wgEnotifImpersonal;
if ( !$this->composed_common ) {
@@ -433,7 +453,7 @@ class EmailNotification {
if ( $wgEnotifImpersonal ) {
$this->mailTargets[] = MailAddress::newFromUser( $user );
} else {
- $this->sendPersonalised( $user );
+ $this->sendPersonalised( $user, $source );
}
}
@@ -453,10 +473,11 @@ class EmailNotification {
* Returns true if the mail was sent successfully.
*
* @param User $watchingUser
+ * @param string $source
* @return bool
* @private
*/
- function sendPersonalised( $watchingUser ) {
+ function sendPersonalised( $watchingUser, $source ) {
global $wgContLang, $wgEnotifUseRealName;
// From the PHP manual:
// Note: The to parameter cannot be an address in the form of
@@ -477,7 +498,15 @@ class EmailNotification {
$wgContLang->userTime( $this->timestamp, $watchingUser ) ),
$this->body );
- return UserMailer::send( $to, $this->from, $this->subject, $body, $this->replyto );
+ $headers = array();
+ if ( $source === self::WATCHLIST ) {
+ $headers['List-Help'] = 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Watchlist';
+ }
+
+ return UserMailer::send( $to, $this->from, $this->subject, $body, array(
+ 'replyTo' => $this->replyto,
+ 'headers' => $headers,
+ ) );
}
/**
@@ -502,7 +531,9 @@ class EmailNotification {
$wgContLang->time( $this->timestamp, false, false ) ),
$this->body );
- return UserMailer::send( $addresses, $this->from, $this->subject, $body, $this->replyto );
+ return UserMailer::send( $addresses, $this->from, $this->subject, $body, array(
+ 'replyTo' => $this->replyto,
+ ) );
}
}
diff --git a/includes/mail/UserMailer.php b/includes/mail/UserMailer.php
index 3cabdaeb..7c5f18dd 100644
--- a/includes/mail/UserMailer.php
+++ b/includes/mail/UserMailer.php
@@ -43,7 +43,7 @@ class UserMailer {
protected static function sendWithPear( $mailer, $dest, $headers, $body ) {
$mailResult = $mailer->send( $dest, $headers, $body );
- # Based on the result return an error string,
+ // Based on the result return an error string,
if ( PEAR::isError( $mailResult ) ) {
wfDebug( "PEAR::Mail failed: " . $mailResult->getMessage() . "\n" );
return Status::newFatal( 'pear-mail-error', $mailResult->getMessage() );
@@ -102,16 +102,35 @@ class UserMailer {
* @param MailAddress $from Sender's email
* @param string $subject Email's subject.
* @param string $body Email's text or Array of two strings to be the text and html bodies
- * @param MailAddress $replyto Optional reply-to email (default: null).
- * @param string $contentType Optional custom Content-Type (default: text/plain; charset=UTF-8)
+ * @param array $options:
+ * 'replyTo' MailAddress
+ * 'contentType' string default 'text/plain; charset=UTF-8'
+ * 'headers' array Extra headers to set
+ *
+ * Previous versions of this function had $replyto as the 5th argument and $contentType
+ * as the 6th. These are still supported for backwards compatability, but deprecated.
+ *
* @throws MWException
* @throws Exception
* @return Status
*/
- public static function send( $to, $from, $subject, $body, $replyto = null,
- $contentType = 'text/plain; charset=UTF-8'
- ) {
+ public static function send( $to, $from, $subject, $body, $options = array() ) {
global $wgSMTP, $wgEnotifMaxRecips, $wgAdditionalMailParams, $wgAllowHTMLEmail;
+ $contentType = 'text/plain; charset=UTF-8';
+ $headers = array();
+ if ( is_array( $options ) ) {
+ $replyto = isset( $options['replyTo'] ) ? $options['replyTo'] : null;
+ $contentType = isset( $options['contentType'] ) ? $options['contentType'] : $contentType;
+ $headers = isset( $options['headers'] ) ? $options['headers'] : $headers;
+ } else {
+ // Old calling style
+ wfDeprecated( __METHOD__ . ' with $replyto as 5th parameter', '1.26' );
+ $replyto = $options;
+ if ( func_num_args() === 6 ) {
+ $contentType = func_get_arg( 5 );
+ }
+ }
+
$mime = null;
if ( !is_array( $to ) ) {
$to = array( $to );
@@ -147,7 +166,7 @@ class UserMailer {
wfDebug( __METHOD__ . ': sending mail to ' . implode( ', ', $to ) . "\n" );
- # Make sure we have at least one address
+ // Make sure we have at least one address
$has_address = false;
foreach ( $to as $u ) {
if ( $u->address ) {
@@ -159,32 +178,32 @@ class UserMailer {
return Status::newFatal( 'user-mail-no-addy' );
}
- # Forge email headers
- # -------------------
- #
- # WARNING
- #
- # DO NOT add To: or Subject: headers at this step. They need to be
- # handled differently depending upon the mailer we are going to use.
- #
- # To:
- # PHP mail() first argument is the mail receiver. The argument is
- # used as a recipient destination and as a To header.
- #
- # PEAR mailer has a recipient argument which is only used to
- # send the mail. If no To header is given, PEAR will set it to
- # to 'undisclosed-recipients:'.
- #
- # NOTE: To: is for presentation, the actual recipient is specified
- # by the mailer using the Rcpt-To: header.
- #
- # Subject:
- # PHP mail() second argument to pass the subject, passing a Subject
- # as an additional header will result in a duplicate header.
- #
- # PEAR mailer should be passed a Subject header.
- #
- # -- hashar 20120218
+ // Forge email headers
+ // -------------------
+ //
+ // WARNING
+ //
+ // DO NOT add To: or Subject: headers at this step. They need to be
+ // handled differently depending upon the mailer we are going to use.
+ //
+ // To:
+ // PHP mail() first argument is the mail receiver. The argument is
+ // used as a recipient destination and as a To header.
+ //
+ // PEAR mailer has a recipient argument which is only used to
+ // send the mail. If no To header is given, PEAR will set it to
+ // to 'undisclosed-recipients:'.
+ //
+ // NOTE: To: is for presentation, the actual recipient is specified
+ // by the mailer using the Rcpt-To: header.
+ //
+ // Subject:
+ // PHP mail() second argument to pass the subject, passing a Subject
+ // as an additional header will result in a duplicate header.
+ //
+ // PEAR mailer should be passed a Subject header.
+ //
+ // -- hashar 20120218
$headers['From'] = $from->toString();
$returnPath = $from->address;
@@ -192,9 +211,9 @@ class UserMailer {
// Hook to generate custom VERP address for 'Return-Path'
Hooks::run( 'UserMailerChangeReturnPath', array( $to, &$returnPath ) );
- # Add the envelope sender address using the -f command line option when PHP mail() is used.
- # Will default to the $from->address when the UserMailerChangeReturnPath hook fails and the
- # generated VERP address when the hook runs effectively.
+ // Add the envelope sender address using the -f command line option when PHP mail() is used.
+ // Will default to the $from->address when the UserMailerChangeReturnPath hook fails and the
+ // generated VERP address when the hook runs effectively.
$extraParams .= ' -f ' . $returnPath;
$headers['Return-Path'] = $returnPath;
@@ -206,9 +225,11 @@ class UserMailer {
$headers['Date'] = MWTimestamp::getLocalInstance()->format( 'r' );
$headers['Message-ID'] = self::makeMsgId();
$headers['X-Mailer'] = 'MediaWiki mailer';
+ $headers['List-Unsubscribe'] = '<' . SpecialPage::getTitleFor( 'Preferences' )
+ ->getFullURL( '', false, PROTO_CANONICAL ) . '>';
- # Line endings need to be different on Unix and Windows due to
- # the bug described at http://trac.wordpress.org/ticket/2603
+ // Line endings need to be different on Unix and Windows due to
+ // the bug described at http://trac.wordpress.org/ticket/2603
if ( wfIsWindows() ) {
$endl = "\r\n";
} else {
@@ -223,7 +244,10 @@ class UserMailer {
// remove the html body for text email fall back
$body = $body['text'];
} else {
- require_once 'Mail/mime.php';
+ // Check if pear/mail_mime is already loaded (via composer)
+ if ( !class_exists( 'Mail_mime' ) ) {
+ require_once 'Mail/mime.php';
+ }
if ( wfIsWindows() ) {
$body['text'] = str_replace( "\n", "\r\n", $body['text'] );
$body['html'] = str_replace( "\n", "\r\n", $body['html'] );
@@ -260,22 +284,22 @@ class UserMailer {
}
if ( is_array( $wgSMTP ) ) {
- #
- # PEAR MAILER
- #
-
- if ( !stream_resolve_include_path( 'Mail.php' ) ) {
- throw new MWException( 'PEAR mail package is not installed' );
+ // Check if pear/mail is already loaded (via composer)
+ if ( !class_exists( 'Mail' ) ) {
+ // PEAR MAILER
+ if ( !stream_resolve_include_path( 'Mail.php' ) ) {
+ throw new MWException( 'PEAR mail package is not installed' );
+ }
+ require_once 'Mail.php';
}
- require_once 'Mail.php';
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
// Create the mail object using the Mail::factory method
$mail_object =& Mail::factory( 'smtp', $wgSMTP );
if ( PEAR::isError( $mail_object ) ) {
wfDebug( "PEAR::Mail factory failed: " . $mail_object->getMessage() . "\n" );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return Status::newFatal( 'pear-mail-error', $mail_object->getMessage() );
}
@@ -283,28 +307,28 @@ class UserMailer {
$headers['Subject'] = self::quotedPrintable( $subject );
- # When sending only to one recipient, shows it its email using To:
+ // When sending only to one recipient, shows it its email using To:
if ( count( $to ) == 1 ) {
$headers['To'] = $to[0]->toString();
}
- # Split jobs since SMTP servers tends to limit the maximum
- # number of possible recipients.
+ // Split jobs since SMTP servers tends to limit the maximum
+ // number of possible recipients.
$chunks = array_chunk( $to, $wgEnotifMaxRecips );
foreach ( $chunks as $chunk ) {
$status = self::sendWithPear( $mail_object, $chunk, $headers, $body );
- # FIXME : some chunks might be sent while others are not!
+ // FIXME : some chunks might be sent while others are not!
if ( !$status->isOK() ) {
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $status;
}
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return Status::newGood();
} else {
- #
- # PHP mail()
- #
+ //
+ // PHP mail()
+ //
if ( count( $to ) > 1 ) {
$headers['To'] = 'undisclosed-recipients:;';
}
@@ -400,7 +424,7 @@ class UserMailer {
* @return string
*/
public static function quotedPrintable( $string, $charset = '' ) {
- # Probably incomplete; see RFC 2045
+ // Probably incomplete; see RFC 2045
if ( empty( $charset ) ) {
$charset = 'UTF-8';
}
diff --git a/includes/media/Bitmap.php b/includes/media/Bitmap.php
index 3b1d978e..0cc093bf 100644
--- a/includes/media/Bitmap.php
+++ b/includes/media/Bitmap.php
@@ -92,9 +92,8 @@ class BitmapHandler extends TransformationalImageHandler {
// JPEG decoder hint to reduce memory, available since IM 6.5.6-2
$decoderHint = array( '-define', "jpeg:size={$params['physicalDimensions']}" );
}
- } elseif ( $params['mimeType'] == 'image/png' ) {
+ } elseif ( $params['mimeType'] == 'image/png' || $params['mimeType'] == 'image/webp' ) {
$quality = array( '-quality', '95' ); // zlib 9, adaptive filtering
-
} elseif ( $params['mimeType'] == 'image/gif' ) {
if ( $this->getImageArea( $image ) > $wgMaxAnimatedGifArea ) {
// Extract initial frame only; we're so big it'll
@@ -121,9 +120,9 @@ class BitmapHandler extends TransformationalImageHandler {
'-layers', 'merge',
'-background', 'white',
);
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$xcfMeta = unserialize( $image->getMetadata() );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $xcfMeta
&& isset( $xcfMeta['colorType'] )
&& $xcfMeta['colorType'] === 'greyscale-alpha'
diff --git a/includes/media/BitmapMetadataHandler.php b/includes/media/BitmapMetadataHandler.php
index c8d37bbb..a5cddac9 100644
--- a/includes/media/BitmapMetadataHandler.php
+++ b/includes/media/BitmapMetadataHandler.php
@@ -21,6 +21,8 @@
* @ingroup Media
*/
+use MediaWiki\Logger\LoggerFactory;
+
/**
* Class to deal with reconciling and extracting metadata from bitmap images.
* This is meant to comply with http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
@@ -167,7 +169,7 @@ class BitmapMetadataHandler {
}
}
if ( isset( $seg['XMP'] ) && $showXMP ) {
- $xmp = new XMPReader();
+ $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ) );
$xmp->parse( $seg['XMP'] );
foreach ( $seg['XMP_ext'] as $xmpExt ) {
/* Support for extended xmp in jpeg files
@@ -203,7 +205,7 @@ class BitmapMetadataHandler {
if ( isset( $array['text']['xmp']['x-default'] )
&& $array['text']['xmp']['x-default'] !== '' && $showXMP
) {
- $xmp = new XMPReader();
+ $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ) );
$xmp->parse( $array['text']['xmp']['x-default'] );
$xmpRes = $xmp->getResults();
foreach ( $xmpRes as $type => $xmpSection ) {
@@ -237,7 +239,7 @@ class BitmapMetadataHandler {
}
if ( $baseArray['xmp'] !== '' && XMPReader::isSupported() ) {
- $xmp = new XMPReader();
+ $xmp = new XMPReader( LoggerFactory::getInstance( 'XMP' ) );
$xmp->parse( $baseArray['xmp'] );
$xmpRes = $xmp->getResults();
foreach ( $xmpRes as $type => $xmpSection ) {
diff --git a/includes/media/DjVu.php b/includes/media/DjVu.php
index 1b0eb492..b422bfa2 100644
--- a/includes/media/DjVu.php
+++ b/includes/media/DjVu.php
@@ -27,6 +27,8 @@
* @ingroup Media
*/
class DjVuHandler extends ImageHandler {
+ const EXPENSIVE_SIZE_LIMIT = 10485760; // 10MiB
+
/**
* @return bool
*/
@@ -50,6 +52,15 @@ class DjVuHandler extends ImageHandler {
}
/**
+ * True if creating thumbnails from the file is large or otherwise resource-intensive.
+ * @param File $file
+ * @return bool
+ */
+ public function isExpensiveToThumbnail( $file ) {
+ return $file->getSize() > static::EXPENSIVE_SIZE_LIMIT;
+ }
+
+ /**
* @param File $file
* @return bool
*/
@@ -137,31 +148,12 @@ class DjVuHandler extends ImageHandler {
function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
global $wgDjvuRenderer, $wgDjvuPostProcessor;
- // Fetch XML and check it, to give a more informative error message than the one which
- // normaliseParams will inevitably give.
- $xml = $image->getMetadata();
- if ( !$xml ) {
- $width = isset( $params['width'] ) ? $params['width'] : 0;
- $height = isset( $params['height'] ) ? $params['height'] : 0;
-
- return new MediaTransformError( 'thumbnail_error', $width, $height,
- wfMessage( 'djvu_no_xml' )->text() );
- }
-
if ( !$this->normaliseParams( $image, $params ) ) {
return new TransformParameterError( $params );
}
$width = $params['width'];
$height = $params['height'];
$page = $params['page'];
- if ( $page > $this->pageCount( $image ) ) {
- return new MediaTransformError(
- 'thumbnail_error',
- $width,
- $height,
- wfMessage( 'djvu_page_error' )->text()
- );
- }
if ( $flags & self::TRANSFORM_LATER ) {
$params = array(
@@ -273,9 +265,9 @@ class DjVuHandler extends ImageHandler {
return $metadata;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$unser = unserialize( $metadata );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( is_array( $unser ) ) {
if ( isset( $unser['error'] ) ) {
return false;
@@ -312,7 +304,7 @@ class DjVuHandler extends ImageHandler {
return false;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
try {
// Set to false rather than null to avoid further attempts
$image->dejaMetaTree = false;
@@ -335,7 +327,7 @@ class DjVuHandler extends ImageHandler {
} catch ( Exception $e ) {
wfDebug( "Bogus multipage XML metadata on '{$image->getName()}'\n" );
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $gettext ) {
return $image->djvuTextTree;
} else {
@@ -384,29 +376,55 @@ class DjVuHandler extends ImageHandler {
}
function pageCount( $image ) {
- $tree = $this->getMetaTree( $image );
- if ( !$tree ) {
- return false;
+ global $wgMemc;
+
+ $key = wfMemcKey( 'file-djvu', 'pageCount', $image->getSha1() );
+
+ $count = $wgMemc->get( $key );
+ if ( $count === false ) {
+ $tree = $this->getMetaTree( $image );
+ if ( !$tree ) {
+ return false;
+ }
+ $count = count( $tree->xpath( '//OBJECT' ) );
+ $wgMemc->set( $key, $count );
}
- return count( $tree->xpath( '//OBJECT' ) );
+ return $count;
}
function getPageDimensions( $image, $page ) {
- $tree = $this->getMetaTree( $image );
- if ( !$tree ) {
- return false;
- }
+ global $wgMemc;
- $o = $tree->BODY[0]->OBJECT[$page - 1];
- if ( $o ) {
- return array(
- 'width' => intval( $o['width'] ),
- 'height' => intval( $o['height'] )
- );
- } else {
- return false;
+ $key = wfMemcKey( 'file-djvu', 'dimensions', $image->getSha1() );
+
+ $dimsByPage = $wgMemc->get( $key );
+ if ( !is_array( $dimsByPage ) ) {
+ $tree = $this->getMetaTree( $image );
+ if ( !$tree ) {
+ return false;
+ }
+
+ $dimsByPage = array();
+ $count = count( $tree->xpath( '//OBJECT' ) );
+ for ( $i = 0; $i < $count; ++$i ) {
+ $o = $tree->BODY[0]->OBJECT[$i];
+ if ( $o ) {
+ $dimsByPage[$i] = array(
+ 'width' => (int)$o['width'],
+ 'height' => (int)$o['height']
+ );
+ } else {
+ $dimsByPage[$i] = false;
+ }
+ }
+
+ $wgMemc->set( $key, $dimsByPage );
}
+
+ $index = $page - 1; // MW starts pages at 1
+
+ return isset( $dimsByPage[$index] ) ? $dimsByPage[$index] : false;
}
/**
diff --git a/includes/media/DjVuImage.php b/includes/media/DjVuImage.php
index e8faa70a..dac76fad 100644
--- a/includes/media/DjVuImage.php
+++ b/includes/media/DjVuImage.php
@@ -123,9 +123,9 @@ class DjVuImage {
}
function getInfo() {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$file = fopen( $this->mFilename, 'rb' );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $file === false ) {
wfDebug( __METHOD__ . ": missing or failed file read\n" );
@@ -150,7 +150,7 @@ class DjVuImage {
wfDebug( __METHOD__ . ": not a DjVu file\n" );
} elseif ( $subtype == 'DJVU' ) {
// Single-page document
- $info = $this->getPageInfo( $file, $formLength );
+ $info = $this->getPageInfo( $file );
} elseif ( $subtype == 'DJVM' ) {
// Multi-page document
$info = $this->getMultiPageInfo( $file, $formLength );
@@ -202,7 +202,7 @@ class DjVuImage {
if ( $subtype == 'DJVU' ) {
wfDebug( __METHOD__ . ": found first subpage\n" );
- return $this->getPageInfo( $file, $length );
+ return $this->getPageInfo( $file );
}
$this->skipChunk( $file, $length - 4 );
} else {
@@ -216,7 +216,7 @@ class DjVuImage {
return false;
}
- private function getPageInfo( $file, $formLength ) {
+ private function getPageInfo( $file ) {
list( $chunk, $length ) = $this->readChunk( $file );
if ( $chunk != 'INFO' ) {
wfDebug( __METHOD__ . ": expected INFO chunk, got '$chunk'\n" );
diff --git a/includes/media/Exif.php b/includes/media/Exif.php
index 33868689..b4cc43e5 100644
--- a/includes/media/Exif.php
+++ b/includes/media/Exif.php
@@ -294,9 +294,9 @@ class Exif {
$this->debugFile( $this->basename, __FUNCTION__, true );
if ( function_exists( 'exif_read_data' ) ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$data = exif_read_data( $this->file, 0, true );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
} else {
throw new MWException( "Internal error: exif_read_data not present. " .
"\$wgShowEXIF may be incorrectly set or not checked by an extension." );
@@ -471,17 +471,17 @@ class Exif {
break;
}
if ( $charset ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$val = iconv( $charset, 'UTF-8//IGNORE', $val );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
} else {
// if valid utf-8, assume that, otherwise assume windows-1252
$valCopy = $val;
UtfNormal\Validator::quickIsNFCVerify( $valCopy ); //validates $valCopy.
if ( $valCopy !== $val ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$val = iconv( 'Windows-1252', 'UTF-8//IGNORE', $val );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
}
diff --git a/includes/media/ExifBitmap.php b/includes/media/ExifBitmap.php
index f56a947f..5ba5c68c 100644
--- a/includes/media/ExifBitmap.php
+++ b/includes/media/ExifBitmap.php
@@ -30,6 +30,7 @@
class ExifBitmapHandler extends BitmapHandler {
const BROKEN_FILE = '-1'; // error extracting metadata
const OLD_BROKEN_FILE = '0'; // outdated error extracting metadata.
+ const SRGB_ICC_PROFILE_NAME = 'IEC 61966-2.1 Default RGB colour space - sRGB';
function convertMetadataVersion( $metadata, $version = 1 ) {
// basically flattens arrays.
@@ -100,9 +101,9 @@ class ExifBitmapHandler extends BitmapHandler {
if ( $metadata === self::BROKEN_FILE ) {
return self::METADATA_GOOD;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$exif = unserialize( $metadata );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !isset( $exif['MEDIAWIKI_EXIF_VERSION'] )
|| $exif['MEDIAWIKI_EXIF_VERSION'] != Exif::version()
) {
@@ -224,9 +225,9 @@ class ExifBitmapHandler extends BitmapHandler {
if ( !$data ) {
return 0;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$data = unserialize( $data );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( isset( $data['Orientation'] ) ) {
# See http://sylvana.net/jpegcrop/exif_orientation.html
switch ( $data['Orientation'] ) {
@@ -243,4 +244,73 @@ class ExifBitmapHandler extends BitmapHandler {
return 0;
}
+
+ protected function transformImageMagick( $image, $params ) {
+ global $wgUseTinyRGBForJPGThumbnails;
+
+ $ret = parent::transformImageMagick( $image, $params );
+
+ if ( $ret ) {
+ return $ret;
+ }
+
+ if ( $params['mimeType'] === 'image/jpeg' && $wgUseTinyRGBForJPGThumbnails ) {
+ // T100976 If the profile embedded in the JPG is sRGB, swap it for the smaller
+ // (and free) TinyRGB
+
+ $this->swapICCProfile(
+ $params['dstPath'],
+ self::SRGB_ICC_PROFILE_NAME,
+ realpath( __DIR__ ) . '/tinyrgb.icc'
+ );
+ }
+
+ return false;
+ }
+
+ /**
+ * Swaps an embedded ICC profile for another, if found. Depends on exiftool, no-op if not installed.
+ * @param string $filepath File to be manipulated (will be overwritten)
+ * @param string $oldProfileString Exact name of color profile to look for (the one that will be replaced)
+ * @param string $profileFilepath ICC profile file to apply to the file
+ * @since 1.26
+ * @return bool
+ */
+ public function swapICCProfile( $filepath, $oldProfileString, $profileFilepath ) {
+ global $wgExiftool;
+
+ if ( !$wgExiftool || !is_executable( $wgExiftool ) ) {
+ return false;
+ }
+
+ $cmd = wfEscapeShellArg( $wgExiftool,
+ '-DeviceModelDesc',
+ '-S',
+ '-T',
+ $filepath
+ );
+
+ $output = wfShellExecWithStderr( $cmd, $retval );
+
+ if ( $retval !== 0 || strcasecmp( trim( $output ), $oldProfileString ) !== 0 ) {
+ // We can't establish that this file has the expected ICC profile, don't process it
+ return false;
+ }
+
+ $cmd = wfEscapeShellArg( $wgExiftool,
+ '-overwrite_original',
+ '-icc_profile<=' . $profileFilepath,
+ $filepath
+ );
+
+ $output = wfShellExecWithStderr( $cmd, $retval );
+
+ if ( $retval !== 0 ) {
+ $this->logErrorForExternalProcess( $retval, $output, $cmd );
+
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/includes/media/FormatMetadata.php b/includes/media/FormatMetadata.php
index 501bb9c2..0fee8cc0 100644
--- a/includes/media/FormatMetadata.php
+++ b/includes/media/FormatMetadata.php
@@ -706,7 +706,7 @@ class FormatMetadata extends ContextSource {
break;
case 'GPSDOP':
- // See http://en.wikipedia.org/wiki/Dilution_of_precision_(GPS)
+ // See https://en.wikipedia.org/wiki/Dilution_of_precision_(GPS)
if ( $val <= 2 ) {
$val = $this->exifMsg( $tag, 'excellent', $this->formatNum( $val ) );
} elseif ( $val <= 5 ) {
@@ -1004,28 +1004,6 @@ class FormatMetadata extends ContextSource {
}
/**
- * Flatten an array, using the user language for any messages.
- *
- * @param array $vals Array of values
- * @param string $type Type of array (either lang, ul, ol).
- * lang = language assoc array with keys being the lang code
- * ul = unordered list, ol = ordered list
- * type can also come from the '_type' member of $vals.
- * @param bool $noHtml If to avoid returning anything resembling HTML.
- * (Ugly hack for backwards compatibility with old MediaWiki).
- * @param bool|IContextSource $context
- * @return string Single value (in wiki-syntax).
- */
- public static function flattenArray( $vals, $type = 'ul', $noHtml = false, $context = false ) {
- $obj = new FormatMetadata;
- if ( $context ) {
- $obj->setContext( $context );
- }
-
- return $obj->flattenArrayReal( $vals, $type, $noHtml );
- }
-
- /**
* A function to collapse multivalued tags into a single value.
* This turns an array of (for example) authors into a bulleted list.
*
@@ -1305,7 +1283,7 @@ class FormatMetadata extends ContextSource {
*/
private function gcd( $a, $b ) {
/*
- // http://en.wikipedia.org/wiki/Euclidean_algorithm
+ // https://en.wikipedia.org/wiki/Euclidean_algorithm
// Recursive form would be:
if( $b == 0 )
return $a;
@@ -1597,7 +1575,6 @@ class FormatMetadata extends ContextSource {
// If revision deleted, exit immediately
if ( $file->isDeleted( File::DELETED_FILE ) ) {
-
return array();
}
@@ -1755,8 +1732,9 @@ class FormatMetadata extends ContextSource {
}
/**
- * Turns an XMP-style multivalue array into a single value by dropping all but the first value.
- * If the value is not a multivalue array (or a multivalue array inside a multilang array), it is returned unchanged.
+ * Turns an XMP-style multivalue array into a single value by dropping all but the first
+ * value. If the value is not a multivalue array (or a multivalue array inside a multilang
+ * array), it is returned unchanged.
* See mediawiki.org/wiki/Manual:File_metadata_handling#Multi-language_array_format
* @param mixed $value
* @return mixed The value, or the first value if there were multiple ones
@@ -1765,7 +1743,8 @@ class FormatMetadata extends ContextSource {
protected function resolveMultivalueValue( $value ) {
if ( !is_array( $value ) ) {
return $value;
- } elseif ( isset( $value['_type'] ) && $value['_type'] === 'lang' ) { // if this is a multilang array, process fields separately
+ } elseif ( isset( $value['_type'] ) && $value['_type'] === 'lang' ) {
+ // if this is a multilang array, process fields separately
$newValue = array();
foreach ( $value as $k => $v ) {
$newValue[$k] = $this->resolveMultivalueValue( $v );
diff --git a/includes/media/GIF.php b/includes/media/GIF.php
index e3621fbd..94aca615 100644
--- a/includes/media/GIF.php
+++ b/includes/media/GIF.php
@@ -131,9 +131,9 @@ class GIFHandler extends BitmapHandler {
return self::METADATA_GOOD;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$data = unserialize( $metadata );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$data || !is_array( $data ) ) {
wfDebug( __METHOD__ . " invalid GIF metadata\n" );
@@ -161,9 +161,9 @@ class GIFHandler extends BitmapHandler {
$original = parent::getLongDesc( $image );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$metadata = unserialize( $image->getMetadata() );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$metadata || $metadata['frameCount'] <= 1 ) {
return $original;
diff --git a/includes/media/GIFMetadataExtractor.php b/includes/media/GIFMetadataExtractor.php
index 5c370465..6ee23cda 100644
--- a/includes/media/GIFMetadataExtractor.php
+++ b/includes/media/GIFMetadataExtractor.php
@@ -161,9 +161,9 @@ class GIFMetadataExtractor {
UtfNormal\Validator::quickIsNFCVerify( $dataCopy );
if ( $dataCopy !== $data ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$data = iconv( 'windows-1252', 'UTF-8', $data );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
$commentCount = count( $comment );
diff --git a/includes/media/IPTC.php b/includes/media/IPTC.php
index 0eb27cc8..c3d58b8b 100644
--- a/includes/media/IPTC.php
+++ b/includes/media/IPTC.php
@@ -445,9 +445,9 @@ class IPTC {
*/
private static function convIPTCHelper( $data, $charset ) {
if ( $charset ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$data = iconv( $charset, "UTF-8//IGNORE", $data );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $data === false ) {
$data = "";
wfDebugLog( 'iptc', __METHOD__ . " Error converting iptc data charset $charset to utf-8" );
diff --git a/includes/media/ImageHandler.php b/includes/media/ImageHandler.php
index 968e4243..db74bb35 100644
--- a/includes/media/ImageHandler.php
+++ b/includes/media/ImageHandler.php
@@ -201,9 +201,9 @@ abstract class ImageHandler extends MediaHandler {
}
function getImageSize( $image, $path ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$gis = getimagesize( $path );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $gis;
}
diff --git a/includes/media/Jpeg.php b/includes/media/Jpeg.php
index 5463922b..040ff96e 100644
--- a/includes/media/Jpeg.php
+++ b/includes/media/Jpeg.php
@@ -137,7 +137,7 @@ class JpegHandler extends ExifBitmapHandler {
$rotation = ( $params['rotation'] + $this->getRotation( $file ) ) % 360;
- if ( $wgJpegTran && is_file( $wgJpegTran ) ) {
+ if ( $wgJpegTran && is_executable( $wgJpegTran ) ) {
$cmd = wfEscapeShellArg( $wgJpegTran ) .
" -rotate " . wfEscapeShellArg( $rotation ) .
" -outfile " . wfEscapeShellArg( $params['dstPath'] ) .
diff --git a/includes/media/JpegMetadataExtractor.php b/includes/media/JpegMetadataExtractor.php
index ae4af8d1..5069f180 100644
--- a/includes/media/JpegMetadataExtractor.php
+++ b/includes/media/JpegMetadataExtractor.php
@@ -102,9 +102,9 @@ class JpegMetadataExtractor {
// turns $com to valid utf-8.
// thus if no change, its utf-8, otherwise its something else.
if ( $com !== $oldCom ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$com = $oldCom = iconv( 'windows-1252', 'UTF-8//IGNORE', $oldCom );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
// Try it again, if its still not a valid string, then probably
// binary junk or some really weird encoding, so don't extract.
diff --git a/includes/media/MediaHandler.php b/includes/media/MediaHandler.php
index 33aed34f..3a59996c 100644
--- a/includes/media/MediaHandler.php
+++ b/includes/media/MediaHandler.php
@@ -181,9 +181,9 @@ abstract class MediaHandler {
if ( !is_array( $metadata ) ) {
//unserialize to keep return parameter consistent.
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ret = unserialize( $metadata );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $ret;
}
diff --git a/includes/media/MediaTransformInvalidParametersException.php b/includes/media/MediaTransformInvalidParametersException.php
index 15a2ca55..6f9c2916 100644
--- a/includes/media/MediaTransformInvalidParametersException.php
+++ b/includes/media/MediaTransformInvalidParametersException.php
@@ -23,4 +23,5 @@
*
* @ingroup Exception
*/
-class MediaTransformInvalidParametersException extends MWException {}
+class MediaTransformInvalidParametersException extends MWException {
+}
diff --git a/includes/media/PNG.php b/includes/media/PNG.php
index 5f1aca57..c3f08325 100644
--- a/includes/media/PNG.php
+++ b/includes/media/PNG.php
@@ -118,9 +118,9 @@ class PNGHandler extends BitmapHandler {
return self::METADATA_GOOD;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$data = unserialize( $metadata );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$data || !is_array( $data ) ) {
wfDebug( __METHOD__ . " invalid png metadata\n" );
@@ -147,9 +147,9 @@ class PNGHandler extends BitmapHandler {
global $wgLang;
$original = parent::getLongDesc( $image );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$metadata = unserialize( $image->getMetadata() );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$metadata || $metadata['frameCount'] <= 0 ) {
return $original;
diff --git a/includes/media/PNGMetadataExtractor.php b/includes/media/PNGMetadataExtractor.php
index bccd36c1..ac92460e 100644
--- a/includes/media/PNGMetadataExtractor.php
+++ b/includes/media/PNGMetadataExtractor.php
@@ -201,9 +201,9 @@ class PNGMetadataExtractor {
// if compressed
if ( $items[2] == "\x01" ) {
if ( function_exists( 'gzuncompress' ) && $items[4] === "\x00" ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$items[5] = gzuncompress( $items[5] );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $items[5] === false ) {
// decompression failed
@@ -245,9 +245,9 @@ class PNGMetadataExtractor {
fseek( $fh, self::$crcSize, SEEK_CUR );
continue;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$content = iconv( 'ISO-8859-1', 'UTF-8', $content );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $content === false ) {
throw new Exception( __METHOD__ . ": Read error (error with iconv)" );
@@ -285,9 +285,9 @@ class PNGMetadataExtractor {
continue;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$content = gzuncompress( $content );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $content === false ) {
// decompression failed
@@ -296,9 +296,9 @@ class PNGMetadataExtractor {
continue;
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$content = iconv( 'ISO-8859-1', 'UTF-8', $content );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $content === false ) {
throw new Exception( __METHOD__ . ": Read error (error with iconv)" );
diff --git a/includes/media/SVG.php b/includes/media/SVG.php
index 8fdfa474..1118598f 100644
--- a/includes/media/SVG.php
+++ b/includes/media/SVG.php
@@ -95,7 +95,7 @@ class SvgHandler extends ImageHandler {
$metadata = $this->unpackMetadata( $metadata );
if ( isset( $metadata['translations'] ) ) {
foreach ( $metadata['translations'] as $lang => $langType ) {
- if ( $langType === SvgReader::LANG_FULL_MATCH ) {
+ if ( $langType === SVGReader::LANG_FULL_MATCH ) {
$langList[] = $lang;
}
}
@@ -205,11 +205,12 @@ class SvgHandler extends ImageHandler {
$tmpDir = wfTempDir() . '/svg_' . wfRandomString( 24 );
$lnPath = "$tmpDir/" . basename( $srcPath );
$ok = mkdir( $tmpDir, 0771 ) && symlink( $srcPath, $lnPath );
+ /** @noinspection PhpUnusedLocalVariableInspection */
$cleaner = new ScopedCallback( function () use ( $tmpDir, $lnPath ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
unlink( $lnPath );
rmdir( $tmpDir );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
} );
if ( !$ok ) {
wfDebugLog( 'thumbnail',
@@ -307,9 +308,9 @@ class SvgHandler extends ImageHandler {
*/
function getImageSize( $file, $path, $metadata = false ) {
if ( $metadata === false ) {
- $metadata = $file->getMetaData();
+ $metadata = $file->getMetadata();
}
- $metadata = $this->unpackMetaData( $metadata );
+ $metadata = $this->unpackMetadata( $metadata );
if ( isset( $metadata['width'] ) && isset( $metadata['height'] ) ) {
return array( $metadata['width'], $metadata['height'], 'SVG',
@@ -375,9 +376,9 @@ class SvgHandler extends ImageHandler {
}
function unpackMetadata( $metadata ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$unser = unserialize( $metadata );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( isset( $unser['version'] ) && $unser['version'] == self::SVG_METADATA_VERSION ) {
return $unser;
} else {
diff --git a/includes/media/SVGMetadataExtractor.php b/includes/media/SVGMetadataExtractor.php
index 2037c331..1ec2f814 100644
--- a/includes/media/SVGMetadataExtractor.php
+++ b/includes/media/SVGMetadataExtractor.php
@@ -108,17 +108,17 @@ class SVGReader {
// Because we cut off the end of the svg making an invalid one. Complicated
// try catch thing to make sure warnings get restored. Seems like there should
// be a better way.
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
try {
$this->read();
} catch ( Exception $e ) {
// Note, if this happens, the width/height will be taken to be 0x0.
// Should we consider it the default 512x512 instead?
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
libxml_disable_entity_loader( $oldDisable );
throw $e;
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
libxml_disable_entity_loader( $oldDisable );
}
@@ -262,7 +262,6 @@ class SVGReader {
} elseif ( $this->reader->namespaceURI == self::NS_SVG
&& $this->reader->nodeType == XMLReader::ELEMENT
) {
-
$sysLang = $this->reader->getAttribute( 'systemLanguage' );
if ( !is_null( $sysLang ) && $sysLang !== '' ) {
// See http://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute
@@ -320,16 +319,6 @@ class SVGReader {
}
}
- // @todo FIXME: Unused, remove?
- private function warn( $data ) {
- wfDebug( "SVGReader: $data\n" );
- }
-
- // @todo FIXME: Unused, remove?
- private function notice( $data ) {
- wfDebug( "SVGReader WARN: $data\n" );
- }
-
/**
* Parse the attributes of an SVG element
*
diff --git a/includes/media/TransformationalImageHandler.php b/includes/media/TransformationalImageHandler.php
index fd8d81d2..15753a96 100644
--- a/includes/media/TransformationalImageHandler.php
+++ b/includes/media/TransformationalImageHandler.php
@@ -167,7 +167,7 @@ abstract class TransformationalImageHandler extends ImageHandler {
return $this->getClientScalingThumbnailImage( $image, $scalerParams );
}
- if ( !$this->isImageAreaOkForThumbnaling( $image, $params ) ) {
+ if ( $image->isTransformedLocally() && !$this->isImageAreaOkForThumbnaling( $image, $params ) ) {
global $wgMaxImageArea;
return new TransformTooBigImageAreaError( $params, $wgMaxImageArea );
}
diff --git a/includes/media/WebP.php b/includes/media/WebP.php
new file mode 100644
index 00000000..ff4dcee2
--- /dev/null
+++ b/includes/media/WebP.php
@@ -0,0 +1,306 @@
+<?php
+/**
+ * Handler for Google's WebP format <https://developers.google.com/speed/webp/>
+ *
+ * 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 Media
+ */
+
+/**
+ * Handler for Google's WebP format <https://developers.google.com/speed/webp/>
+ *
+ * @ingroup Media
+ */
+class WebPHandler extends BitmapHandler {
+ const BROKEN_FILE = '0'; // value to store in img_metadata if error extracting metadata.
+ /**
+ * @var int Minimum chunk header size to be able to read all header types
+ */
+ const MINIMUM_CHUNK_HEADER_LENGTH = 18;
+ /**
+ * @var int version of the metadata stored in db records
+ */
+ const _MW_WEBP_VERSION = 1;
+
+ const VP8X_ICC = 32;
+ const VP8X_ALPHA = 16;
+ const VP8X_EXIF = 8;
+ const VP8X_XMP = 4;
+ const VP8X_ANIM = 2;
+
+ public function getMetadata( $image, $filename ) {
+ $parsedWebPData = self::extractMetadata( $filename );
+ if ( !$parsedWebPData ) {
+ return self::BROKEN_FILE;
+ }
+
+ $parsedWebPData['metadata']['_MW_WEBP_VERSION'] = self::_MW_WEBP_VERSION;
+ return serialize( $parsedWebPData );
+ }
+
+ public function getMetadataType( $image ) {
+ return 'parsed-webp';
+ }
+
+ public function isMetadataValid( $image, $metadata ) {
+ if ( $metadata === self::BROKEN_FILE ) {
+ // Do not repetitivly regenerate metadata on broken file.
+ return self::METADATA_GOOD;
+ }
+
+ wfSuppressWarnings();
+ $data = unserialize( $metadata );
+ wfRestoreWarnings();
+
+ if ( !$data || !is_array( $data ) ) {
+ wfDebug( __METHOD__ . " invalid WebP metadata\n" );
+
+ return self::METADATA_BAD;
+ }
+
+ if ( !isset( $data['metadata']['_MW_WEBP_VERSION'] )
+ || $data['metadata']['_MW_WEBP_VERSION'] != self::_MW_WEBP_VERSION
+ ) {
+ wfDebug( __METHOD__ . " old but compatible WebP metadata\n" );
+
+ return self::METADATA_COMPATIBLE;
+ }
+ return self::METADATA_GOOD;
+ }
+
+ /**
+ * Extracts the image size and WebP type from a file
+ *
+ * @param string $chunks Chunks as extracted by RiffExtractor
+ * @return array|bool Header data array with entries 'compression', 'width' and 'height',
+ * where 'compression' can be 'lossy', 'lossless', 'animated' or 'unknown'. False if
+ * file is not a valid WebP file.
+ */
+ public static function extractMetadata( $filename ) {
+ wfDebugLog( 'WebP', __METHOD__ . ": Extracting metadata from $filename\n" );
+
+ $info = RiffExtractor::findChunksFromFile( $filename, 100 );
+ if ( $info === false ) {
+ wfDebugLog( 'WebP', __METHOD__ . ": Not a valid RIFF file\n" );
+ return false;
+ }
+
+ if ( $info['fourCC'] != 'WEBP' ) {
+ wfDebugLog( 'WebP', __METHOD__ . ': FourCC was not WEBP: ' .
+ bin2hex( $info['fourCC'] ) . " \n" );
+ return false;
+ }
+
+ $metadata = self::extractMetadataFromChunks( $info['chunks'], $filename );
+ if ( !$metadata ) {
+ wfDebugLog( 'WebP', __METHOD__ . ": No VP8 chunks found\n" );
+ return false;
+ }
+
+ return $metadata;
+ }
+
+ /**
+ * Extracts the image size and WebP type from a file based on the chunk list
+ * @param array $chunks Chunks as extracted by RiffExtractor
+ * @return array Header data array with entries 'compression', 'width' and 'height', where
+ * 'compression' can be 'lossy', 'lossless', 'animated' or 'unknown'
+ */
+ public static function extractMetadataFromChunks( $chunks, $filename ) {
+ $vp8Info = array();
+
+ foreach ( $chunks as $chunk ) {
+ if ( !in_array( $chunk['fourCC'], array( 'VP8 ', 'VP8L', 'VP8X' ) ) ) {
+ // Not a chunk containing interesting metadata
+ continue;
+ }
+
+ $chunkHeader = file_get_contents( $filename, false, null,
+ $chunk['start'], self::MINIMUM_CHUNK_HEADER_LENGTH );
+ wfDebugLog( 'WebP', __METHOD__ . ": {$chunk['fourCC']}\n" );
+
+ switch ( $chunk['fourCC'] ) {
+ case 'VP8 ':
+ return array_merge( $vp8Info,
+ self::decodeLossyChunkHeader( $chunkHeader ) );
+ case 'VP8L':
+ return array_merge( $vp8Info,
+ self::decodeLosslessChunkHeader( $chunkHeader ) );
+ case 'VP8X':
+ $vp8Info = array_merge( $vp8Info,
+ self::decodeExtendedChunkHeader( $chunkHeader ) );
+ // Continue looking for other chunks to improve the metadata
+ break;
+ }
+ }
+ return $vp8Info;
+ }
+
+ /**
+ * Decodes a lossy chunk header
+ * @param string $header Header string
+ * @return boolean|array See WebPHandler::decodeHeader
+ */
+ protected static function decodeLossyChunkHeader( $header ) {
+ // Bytes 0-3 are 'VP8 '
+ // Bytes 4-7 are the VP8 stream size
+ // Bytes 8-10 are the frame tag
+ // Bytes 11-13 are 0x9D 0x01 0x2A called the sync code
+ $syncCode = substr( $header, 11, 3 );
+ if ( $syncCode != "\x9D\x01\x2A" ) {
+ wfDebugLog( 'WebP', __METHOD__ . ': Invalid sync code: ' .
+ bin2hex( $syncCode ) . "\n" );
+ return array();
+ }
+ // Bytes 14-17 are image size
+ $imageSize = unpack( 'v2', substr( $header, 14, 4 ) );
+ // Image sizes are 14 bit, 2 MSB are scaling parameters which are ignored here
+ return array(
+ 'compression' => 'lossy',
+ 'width' => $imageSize[1] & 0x3FFF,
+ 'height' => $imageSize[2] & 0x3FFF
+ );
+ }
+
+ /**
+ * Decodes a lossless chunk header
+ * @param string $header Header string
+ * @return boolean|array See WebPHandler::decodeHeader
+ */
+ public static function decodeLosslessChunkHeader( $header ) {
+ // Bytes 0-3 are 'VP8L'
+ // Bytes 4-7 are chunk stream size
+ // Byte 8 is 0x2F called the signature
+ if ( $header{8} != "\x2F" ) {
+ wfDebugLog( 'WebP', __METHOD__ . ': Invalid signature: ' .
+ bin2hex( $header{8} ) . "\n" );
+ return array();
+ }
+ // Bytes 9-12 contain the image size
+ // Bits 0-13 are width-1; bits 15-27 are height-1
+ $imageSize = unpack( 'C4', substr( $header, 9, 4 ) );
+ return array(
+ 'compression' => 'lossless',
+ 'width' => ( $imageSize[1] | ( ( $imageSize[2] & 0x3F ) << 8 ) ) + 1,
+ 'height' => ( ( ( $imageSize[2] & 0xC0 ) >> 6 ) |
+ ( $imageSize[3] << 2 ) | ( ( $imageSize[4] & 0x03 ) << 10 ) ) + 1
+ );
+ }
+
+ /**
+ * Decodes an extended chunk header
+ * @param string $header Header string
+ * @return boolean|array See WebPHandler::decodeHeader
+ */
+ public static function decodeExtendedChunkHeader( $header ) {
+ // Bytes 0-3 are 'VP8X'
+ // Byte 4-7 are chunk length
+ // Byte 8-11 are a flag bytes
+ $flags = unpack( 'c', substr( $header, 8, 1 ) );
+
+ // Byte 12-17 are image size (24 bits)
+ $width = unpack( 'V', substr( $header, 12, 3 ) . "\x00" );
+ $height = unpack( 'V', substr( $header, 15, 3 ) . "\x00" );
+
+ return array(
+ 'compression' => 'unknown',
+ 'animated' => ( $flags[1] & self::VP8X_ANIM ) == self::VP8X_ANIM,
+ 'transparency' => ( $flags[1] & self::VP8X_ALPHA ) == self::VP8X_ALPHA,
+ 'width' => ( $width[1] & 0xFFFFFF ) + 1,
+ 'height' => ( $height[1] & 0xFFFFFF ) + 1
+ );
+ }
+
+ public function getImageSize( $file, $path, $metadata = false ) {
+ if ( $file === null ) {
+ $metadata = self::getMetadata( $file, $path );
+ }
+ if ( $metadata === false ) {
+ $metadata = $file->getMetadata();
+ }
+
+ wfSuppressWarnings();
+ $metadata = unserialize( $metadata );
+ wfRestoreWarnings();
+
+ if ( $metadata == false ) {
+ return false;
+ }
+ return array( $metadata['width'], $metadata['height'] );
+ }
+
+ /**
+ * @param $file
+ * @return bool True, not all browsers support WebP
+ */
+ public function mustRender( $file ) {
+ return true;
+ }
+
+ /**
+ * @param $file
+ * @return bool False if we are unable to render this image
+ */
+ public function canRender( $file ) {
+ if ( self::isAnimatedImage( $file ) ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param File $image
+ * @return bool
+ */
+ public function isAnimatedImage( $image ) {
+ $ser = $image->getMetadata();
+ if ( $ser ) {
+ $metadata = unserialize( $ser );
+ if ( isset( $metadata['animated'] ) && $metadata['animated'] === true ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function canAnimateThumbnail( $file ) {
+ return false;
+ }
+
+ /**
+ * Render files as PNG
+ *
+ * @param $ext
+ * @param $mime
+ * @param $params
+ * @return array
+ */
+ public function getThumbType( $ext, $mime, $params = null ) {
+ return array( 'png', 'image/png' );
+ }
+
+ /**
+ * Must use "im" for XCF
+ *
+ * @return string
+ */
+ protected function getScalerType( $dstPath, $checkDstPath = true ) {
+ return 'im';
+ }
+}
diff --git a/includes/media/XCF.php b/includes/media/XCF.php
index 6544d5cf..16e11dc4 100644
--- a/includes/media/XCF.php
+++ b/includes/media/XCF.php
@@ -3,7 +3,7 @@
* Handler for the Gimp's native file format (XCF)
*
* Overview:
- * http://en.wikipedia.org/wiki/XCF_(file_format)
+ * https://en.wikipedia.org/wiki/XCF_(file_format)
* Specification in Gnome repository:
* http://svn.gnome.org/viewvc/gimp/trunk/devel-docs/xcf.txt?view=markup
*
@@ -222,9 +222,9 @@ class XCFHandler extends BitmapHandler {
* @return bool
*/
public function canRender( $file ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$xcfMeta = unserialize( $file->getMetadata() );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( isset( $xcfMeta['colorType'] ) && $xcfMeta['colorType'] === 'index-coloured' ) {
return false;
}
diff --git a/includes/media/XMP.php b/includes/media/XMP.php
index 50f04ae9..64a7e8a8 100644
--- a/includes/media/XMP.php
+++ b/includes/media/XMP.php
@@ -21,6 +21,10 @@
* @ingroup Media
*/
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+
/**
* Class for reading xmp data containing properties relevant to
* images, and spitting out an array that FormatMetadata accepts.
@@ -46,7 +50,7 @@
* read rdf.
*
*/
-class XMPReader {
+class XMPReader implements LoggerAwareInterface {
/** @var array XMP item configuration array */
protected $items;
@@ -121,15 +125,25 @@ class XMPReader {
const PARSABLE_NO = 3;
/**
+ * @var LoggerInterface
+ */
+ private $logger;
+
+ /**
* Constructor.
*
* Primary job is to initialize the XMLParser
*/
- function __construct() {
+ function __construct( LoggerInterface $logger = null ) {
if ( !function_exists( 'xml_parser_create_ns' ) ) {
// this should already be checked by this point
- throw new MWException( 'XMP support requires XML Parser' );
+ throw new RuntimeException( 'XMP support requires XML Parser' );
+ }
+ if ( $logger ) {
+ $this->setLogger( $logger );
+ } else {
+ $this->setLogger( new NullLogger() );
}
$this->items = XMPInfo::getItems();
@@ -137,16 +151,31 @@ class XMPReader {
$this->resetXMLParser();
}
+ public function setLogger( LoggerInterface $logger ) {
+ $this->logger = $logger;
+ }
+
+ /**
+ * free the XML parser.
+ *
+ * @note It is unclear to me if we really need to do this ourselves
+ * or if php garbage collection will automatically free the xmlParser
+ * when it is no longer needed.
+ */
+ private function destroyXMLParser() {
+ if ( $this->xmlParser ) {
+ xml_parser_free( $this->xmlParser );
+ $this->xmlParser = null;
+ }
+ }
+
/**
* Main use is if a single item has multiple xmp documents describing it.
* For example in jpeg's with extendedXMP
*/
private function resetXMLParser() {
- if ( $this->xmlParser ) {
- //is this needed?
- xml_parser_free( $this->xmlParser );
- }
+ $this->destroyXMLParser();
$this->xmlParser = xml_parser_create_ns( 'UTF-8', ' ' );
xml_parser_set_option( $this->xmlParser, XML_OPTION_CASE_FOLDING, 0 );
@@ -162,15 +191,6 @@ class XMPReader {
$this->xmlParsableBuffer = '';
}
- /** Destroy the xml parser
- *
- * Not sure if this is actually needed.
- */
- function __destruct() {
- // not sure if this is needed.
- xml_parser_free( $this->xmlParser );
- }
-
/**
* Check if this instance supports using this class
*/
@@ -195,8 +215,6 @@ class XMPReader {
$data = $this->results;
- Hooks::run( 'XMPGetResults', array( &$data ) );
-
if ( isset( $data['xmp-special']['AuthorsPosition'] )
&& is_string( $data['xmp-special']['AuthorsPosition'] )
&& isset( $data['xmp-general']['Artist'][0] )
@@ -278,12 +296,11 @@ class XMPReader {
*
* @param string $content XMP data
* @param bool $allOfIt If this is all the data (true) or if its split up (false). Default true
- * @param bool $reset Does xml parser need to be reset. Default false
- * @throws MWException
+ * @throws RuntimeException
* @return bool Success.
*/
- public function parse( $content, $allOfIt = true, $reset = false ) {
- if ( $reset ) {
+ public function parse( $content, $allOfIt = true ) {
+ if ( !$this->xmlParser ) {
$this->resetXMLParser();
}
try {
@@ -313,7 +330,7 @@ class XMPReader {
break;
default:
//this should be impossible to get to
- throw new MWException( "Invalid BOM" );
+ throw new RuntimeException( "Invalid BOM" );
}
} else {
// standard specifically says, if no bom assume utf-8
@@ -322,16 +339,16 @@ class XMPReader {
}
if ( $this->charset !== 'UTF-8' ) {
//don't convert if already utf-8
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$content = iconv( $this->charset, 'UTF-8//IGNORE', $content );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
// Ensure the XMP block does not have an xml doctype declaration, which
// could declare entities unsafe to parse with xml_parse (T85848/T71210).
if ( $this->parsable !== self::PARSABLE_OK ) {
if ( $this->parsable === self::PARSABLE_NO ) {
- throw new Exception( 'Unsafe doctype declaration in XML.' );
+ throw new RuntimeException( 'Unsafe doctype declaration in XML.' );
}
$content = $this->xmlParsableBuffer . $content;
@@ -344,27 +361,49 @@ class XMPReader {
$msg = ( $this->parsable === self::PARSABLE_NO ) ?
'Unsafe doctype declaration in XML.' :
'No root element found in XML.';
- throw new Exception( $msg );
+ throw new RuntimeException( $msg );
}
}
$ok = xml_parse( $this->xmlParser, $content, $allOfIt );
if ( !$ok ) {
- $error = xml_error_string( xml_get_error_code( $this->xmlParser ) );
- $where = 'line: ' . xml_get_current_line_number( $this->xmlParser )
- . ' column: ' . xml_get_current_column_number( $this->xmlParser )
- . ' byte offset: ' . xml_get_current_byte_index( $this->xmlParser );
-
- wfDebugLog( 'XMP', "XMPReader::parse : Error reading XMP content: $error ($where)" );
+ $code = xml_get_error_code( $this->xmlParser );
+ $error = xml_error_string( $code );
+ $line = xml_get_current_line_number( $this->xmlParser );
+ $col = xml_get_current_column_number( $this->xmlParser );
+ $offset = xml_get_current_byte_index( $this->xmlParser );
+
+ $this->logger->warning(
+ '{method} : Error reading XMP content: {error} ' .
+ '(line: {line} column: {column} byte offset: {offset})',
+ array(
+ 'method' => __METHOD__,
+ 'error_code' => $code,
+ 'error' => $error,
+ 'line' => $line,
+ 'column' => $col,
+ 'offset' => $offset,
+ 'content' => $content,
+ ) );
$this->results = array(); // blank if error.
+ $this->destroyXMLParser();
return false;
}
} catch ( Exception $e ) {
- wfDebugLog( 'XMP', 'XMP parse error: ' . $e );
+ $this->logger->warning(
+ '{method} Exception caught while parsing: ' . $e->getMessage(),
+ array(
+ 'method' => __METHOD__,
+ 'exception' => $e,
+ 'content' => $content,
+ )
+ );
$this->results = array();
-
return false;
}
+ if ( $allOfIt ) {
+ $this->destroyXMLParser();
+ }
return true;
}
@@ -383,7 +422,7 @@ class XMPReader {
if ( !isset( $this->results['xmp-special']['HasExtendedXMP'] )
|| $this->results['xmp-special']['HasExtendedXMP'] !== $guid
) {
- wfDebugLog( 'XMP', __METHOD__ .
+ $this->logger->info( __METHOD__ .
" Ignoring XMPExtended block due to wrong guid (guid= '$guid')" );
return false;
@@ -391,7 +430,7 @@ class XMPReader {
$len = unpack( 'Nlength/Noffset', substr( $content, 32, 8 ) );
if ( !$len || $len['length'] < 4 || $len['offset'] < 0 || $len['offset'] > $len['length'] ) {
- wfDebugLog( 'XMP', __METHOD__ . 'Error reading extended XMP block, invalid length or offset.' );
+ $this->logger->info( __METHOD__ . 'Error reading extended XMP block, invalid length or offset.' );
return false;
}
@@ -408,7 +447,7 @@ class XMPReader {
// > 128k, and be in the wrong order is very low...
if ( $len['offset'] !== $this->extendedXMPOffset ) {
- wfDebugLog( 'XMP', __METHOD__ . 'Ignoring XMPExtended block due to wrong order. (Offset was '
+ $this->logger->info( __METHOD__ . 'Ignoring XMPExtended block due to wrong order. (Offset was '
. $len['offset'] . ' but expected ' . $this->extendedXMPOffset . ')' );
return false;
@@ -430,7 +469,7 @@ class XMPReader {
$atEnd = false;
}
- wfDebugLog( 'XMP', __METHOD__ . 'Parsing a XMPExtended block' );
+ $this->logger->debug( __METHOD__ . 'Parsing a XMPExtended block' );
return $this->parse( $actualContent, $atEnd );
}
@@ -449,7 +488,7 @@ class XMPReader {
*
* @param XMLParser $parser XMLParser reference to the xml parser
* @param string $data Character data
- * @throws MWException On invalid data
+ * @throws RuntimeException On invalid data
*/
function char( $parser, $data ) {
@@ -459,7 +498,7 @@ class XMPReader {
}
if ( !isset( $this->mode[0] ) ) {
- throw new MWException( 'Unexpected character data before first rdf:Description element' );
+ throw new RuntimeException( 'Unexpected character data before first rdf:Description element' );
}
if ( $this->mode[0] === self::MODE_IGNORE ) {
@@ -469,7 +508,7 @@ class XMPReader {
if ( $this->mode[0] !== self::MODE_SIMPLE
&& $this->mode[0] !== self::MODE_QDESC
) {
- throw new MWException( 'character data where not expected. (mode ' . $this->mode[0] . ')' );
+ throw new RuntimeException( 'character data where not expected. (mode ' . $this->mode[0] . ')' );
}
// to check, how does this handle w.s.
@@ -501,6 +540,7 @@ class XMPReader {
);
$oldDisable = libxml_disable_entity_loader( true );
+ /** @noinspection PhpUnusedLocalVariableInspection */
$reset = new ScopedCallback(
'libxml_disable_entity_loader',
array( $oldDisable )
@@ -509,7 +549,7 @@ class XMPReader {
// Even with LIBXML_NOWARNING set, XMLReader::read gives a warning
// when parsing truncated XML, which causes unit tests to fail.
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
while ( $reader->read() ) {
if ( $reader->nodeType === XMLReader::ELEMENT ) {
// Reached the first element without hitting a doctype declaration
@@ -523,7 +563,7 @@ class XMPReader {
break;
}
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !is_null( $result ) ) {
return $result;
@@ -597,7 +637,7 @@ class XMPReader {
* This method is called when we hit the "</exif:ISOSpeedRatings>" tag.
*
* @param string $elm Namespace . space . tag name.
- * @throws MWException
+ * @throws RuntimeException
*/
private function endElementNested( $elm ) {
@@ -607,35 +647,38 @@ class XMPReader {
&& !( $elm === self::NS_RDF . ' Description'
&& $this->mode[0] === self::MODE_STRUCT )
) {
- throw new MWException( "nesting mismatch. got a </$elm> but expected a </" .
+ throw new RuntimeException( "nesting mismatch. got a </$elm> but expected a </" .
$this->curItem[0] . '>' );
}
// Validate structures.
list( $ns, $tag ) = explode( ' ', $elm, 2 );
if ( isset( $this->items[$ns][$tag]['validate'] ) ) {
-
$info =& $this->items[$ns][$tag];
$finalName = isset( $info['map_name'] )
? $info['map_name'] : $tag;
- $validate = is_array( $info['validate'] ) ? $info['validate']
- : array( 'XMPValidate', $info['validate'] );
+ if ( is_array( $info['validate'] ) ) {
+ $validate = $info['validate'];
+ } else {
+ $validator = new XMPValidate( $this->logger );
+ $validate = array( $validator, $info['validate'] );
+ }
if ( !isset( $this->results['xmp-' . $info['map_group']][$finalName] ) ) {
// This can happen if all the members of the struct failed validation.
- wfDebugLog( 'XMP', __METHOD__ . " <$ns:$tag> has no valid members." );
+ $this->logger->debug( __METHOD__ . " <$ns:$tag> has no valid members." );
} elseif ( is_callable( $validate ) ) {
$val =& $this->results['xmp-' . $info['map_group']][$finalName];
call_user_func_array( $validate, array( $info, &$val, false ) );
if ( is_null( $val ) ) {
// the idea being the validation function will unset the variable if
// its invalid.
- wfDebugLog( 'XMP', __METHOD__ . " <$ns:$tag> failed validation." );
+ $this->logger->info( __METHOD__ . " <$ns:$tag> failed validation." );
unset( $this->results['xmp-' . $info['map_group']][$finalName] );
}
} else {
- wfDebugLog( 'XMP', __METHOD__ . " Validation function for $finalName ("
+ $this->logger->warning( __METHOD__ . " Validation function for $finalName ("
. $validate[0] . '::' . $validate[1] . '()) is not callable.' );
}
}
@@ -664,7 +707,7 @@ class XMPReader {
* hit the "</rdf:li>")
*
* @param string $elm Namespace . ' ' . element name
- * @throws MWException
+ * @throws RuntimeException
*/
private function endElementModeLi( $elm ) {
@@ -676,7 +719,7 @@ class XMPReader {
array_shift( $this->mode );
if ( !isset( $this->results['xmp-' . $info['map_group']][$finalName] ) ) {
- wfDebugLog( 'XMP', __METHOD__ . " Empty compund element $finalName." );
+ $this->logger->debug( __METHOD__ . " Empty compund element $finalName." );
return;
}
@@ -691,7 +734,7 @@ class XMPReader {
$this->results['xmp-' . $info['map_group']][$finalName]['_type'] = 'lang';
}
} else {
- throw new MWException( __METHOD__ . " expected </rdf:seq> or </rdf:bag> but instead got $elm." );
+ throw new RuntimeException( __METHOD__ . " expected </rdf:seq> or </rdf:bag> but instead got $elm." );
}
}
@@ -729,7 +772,7 @@ class XMPReader {
*
* @param XMLParser $parser
* @param string $elm Namespace . ' ' . element name
- * @throws MWException
+ * @throws RuntimeException
*/
function endElement( $parser, $elm ) {
if ( $elm === ( self::NS_RDF . ' RDF' )
@@ -743,7 +786,7 @@ class XMPReader {
if ( $elm === self::NS_RDF . ' type' ) {
// these aren't really supported properly yet.
// However, it appears they almost never used.
- wfDebugLog( 'XMP', __METHOD__ . ' encountered <rdf:type>' );
+ $this->logger->info( __METHOD__ . ' encountered <rdf:type>' );
}
if ( strpos( $elm, ' ' ) === false ) {
@@ -751,7 +794,7 @@ class XMPReader {
// However, there is a bug in an adobe product
// that forgets the namespace on some things.
// (Luckily they are unimportant things).
- wfDebugLog( 'XMP', __METHOD__ . " Encountered </$elm> which has no namespace. Skipping." );
+ $this->logger->info( __METHOD__ . " Encountered </$elm> which has no namespace. Skipping." );
return;
}
@@ -759,13 +802,13 @@ class XMPReader {
if ( count( $this->mode[0] ) === 0 ) {
// This should never ever happen and means
// there is a pretty major bug in this class.
- throw new MWException( 'Encountered end element with no mode' );
+ throw new RuntimeException( 'Encountered end element with no mode' );
}
if ( count( $this->curItem ) == 0 && $this->mode[0] !== self::MODE_INITIAL ) {
// just to be paranoid. Should always have a curItem, except for initially
// (aka during MODE_INITAL).
- throw new MWException( "Hit end element </$elm> but no curItem" );
+ throw new RuntimeException( "Hit end element </$elm> but no curItem" );
}
switch ( $this->mode[0] ) {
@@ -786,7 +829,7 @@ class XMPReader {
if ( $elm === self::NS_RDF . ' Description' ) {
array_shift( $this->mode );
} else {
- throw new MWException( 'Element ended unexpectedly while in MODE_INITIAL' );
+ throw new RuntimeException( 'Element ended unexpectedly while in MODE_INITIAL' );
}
break;
case self::MODE_LI:
@@ -797,7 +840,7 @@ class XMPReader {
$this->endElementModeQDesc( $elm );
break;
default:
- wfDebugLog( 'XMP', __METHOD__ . " no mode (elm = $elm)" );
+ $this->logger->warning( __METHOD__ . " no mode (elm = $elm)" );
break;
}
}
@@ -825,13 +868,13 @@ class XMPReader {
* this should always be <rdf:Bag>
*
* @param string $elm Namespace . ' ' . tag
- * @throws MWException If we have an element that's not <rdf:Bag>
+ * @throws RuntimeException If we have an element that's not <rdf:Bag>
*/
private function startElementModeBag( $elm ) {
if ( $elm === self::NS_RDF . ' Bag' ) {
array_unshift( $this->mode, self::MODE_LI );
} else {
- throw new MWException( "Expected <rdf:Bag> but got $elm." );
+ throw new RuntimeException( "Expected <rdf:Bag> but got $elm." );
}
}
@@ -840,18 +883,18 @@ class XMPReader {
* this should always be <rdf:Seq>
*
* @param string $elm Namespace . ' ' . tag
- * @throws MWException If we have an element that's not <rdf:Seq>
+ * @throws RuntimeException If we have an element that's not <rdf:Seq>
*/
private function startElementModeSeq( $elm ) {
if ( $elm === self::NS_RDF . ' Seq' ) {
array_unshift( $this->mode, self::MODE_LI );
} elseif ( $elm === self::NS_RDF . ' Bag' ) {
# bug 27105
- wfDebugLog( 'XMP', __METHOD__ . ' Expected an rdf:Seq, but got an rdf:Bag. Pretending'
+ $this->logger->info( __METHOD__ . ' Expected an rdf:Seq, but got an rdf:Bag. Pretending'
. ' it is a Seq, since some buggy software is known to screw this up.' );
array_unshift( $this->mode, self::MODE_LI );
} else {
- throw new MWException( "Expected <rdf:Seq> but got $elm." );
+ throw new RuntimeException( "Expected <rdf:Seq> but got $elm." );
}
}
@@ -867,13 +910,13 @@ class XMPReader {
* we don't care about.
*
* @param string $elm Namespace . ' ' . tag
- * @throws MWException If we have an element that's not <rdf:Alt>
+ * @throws RuntimeException If we have an element that's not <rdf:Alt>
*/
private function startElementModeLang( $elm ) {
if ( $elm === self::NS_RDF . ' Alt' ) {
array_unshift( $this->mode, self::MODE_LI_LANG );
} else {
- throw new MWException( "Expected <rdf:Seq> but got $elm." );
+ throw new RuntimeException( "Expected <rdf:Seq> but got $elm." );
}
}
@@ -893,7 +936,7 @@ class XMPReader {
*
* @param string $elm Namespace and tag names separated by space.
* @param array $attribs Attributes of the element.
- * @throws MWException
+ * @throws RuntimeException
*/
private function startElementModeSimple( $elm, $attribs ) {
if ( $elm === self::NS_RDF . ' Description' ) {
@@ -907,10 +950,10 @@ class XMPReader {
}
} elseif ( $elm === self::NS_RDF . ' value' ) {
// This should not be here.
- throw new MWException( __METHOD__ . ' Encountered <rdf:value> where it was unexpected.' );
+ throw new RuntimeException( __METHOD__ . ' Encountered <rdf:value> where it was unexpected.' );
} else {
// something else we don't recognize, like a qualifier maybe.
- wfDebugLog( 'XMP', __METHOD__ .
+ $this->logger->info( __METHOD__ .
" Encountered element <$elm> where only expecting character data as value of " .
$this->curItem[0] );
array_unshift( $this->mode, self::MODE_IGNORE );
@@ -952,7 +995,7 @@ class XMPReader {
* @param string $ns Namespace
* @param string $tag Tag name (without namespace prefix)
* @param array $attribs Array of attributes
- * @throws MWException
+ * @throws RuntimeException
*/
private function startElementModeInitial( $ns, $tag, $attribs ) {
if ( $ns !== self::NS_RDF ) {
@@ -964,7 +1007,7 @@ class XMPReader {
// a child of a struct), then something weird is
// happening, so ignore this element and its children.
- wfDebugLog( 'XMP', "Encountered <$ns:$tag> outside"
+ $this->logger->warning( "Encountered <$ns:$tag> outside"
. " of its expected parent. Ignoring." );
array_unshift( $this->mode, self::MODE_IGNORE );
@@ -982,11 +1025,11 @@ class XMPReader {
if ( $this->charContent !== false ) {
// Something weird.
// Should not happen in valid XMP.
- throw new MWException( 'tag nested in non-whitespace characters.' );
+ throw new RuntimeException( 'tag nested in non-whitespace characters.' );
}
} else {
// This element is not on our list of allowed elements so ignore.
- wfDebugLog( 'XMP', __METHOD__ . " Ignoring unrecognized element <$ns:$tag>." );
+ $this->logger->debug( __METHOD__ . " Ignoring unrecognized element <$ns:$tag>." );
array_unshift( $this->mode, self::MODE_IGNORE );
array_unshift( $this->curItem, $ns . ' ' . $tag );
@@ -1014,7 +1057,7 @@ class XMPReader {
* @param string $ns Namespace
* @param string $tag Tag name (no ns)
* @param array $attribs Array of attribs w/ values.
- * @throws MWException
+ * @throws RuntimeException
*/
private function startElementModeStruct( $ns, $tag, $attribs ) {
if ( $ns !== self::NS_RDF ) {
@@ -1025,7 +1068,7 @@ class XMPReader {
) {
// This assumes that we don't have inter-namespace nesting
// which we don't in all the properties we're interested in.
- throw new MWException( " <$tag> appeared nested in <" . $this->ancestorStruct
+ throw new RuntimeException( " <$tag> appeared nested in <" . $this->ancestorStruct
. "> where it is not allowed." );
}
array_unshift( $this->mode, $this->items[$ns][$tag]['mode'] );
@@ -1033,7 +1076,7 @@ class XMPReader {
if ( $this->charContent !== false ) {
// Something weird.
// Should not happen in valid XMP.
- throw new MWException( "tag <$tag> nested in non-whitespace characters (" .
+ throw new RuntimeException( "tag <$tag> nested in non-whitespace characters (" .
$this->charContent . ")." );
}
} else {
@@ -1062,17 +1105,17 @@ class XMPReader {
*
* @param string $elm Namespace . ' ' . tagname
* @param array $attribs Attributes. (needed for BAGSTRUCTS)
- * @throws MWException If gets a tag other than <rdf:li>
+ * @throws RuntimeException If gets a tag other than <rdf:li>
*/
private function startElementModeLi( $elm, $attribs ) {
if ( ( $elm ) !== self::NS_RDF . ' li' ) {
- throw new MWException( "<rdf:li> expected but got $elm." );
+ throw new RuntimeException( "<rdf:li> expected but got $elm." );
}
if ( !isset( $this->mode[1] ) ) {
// This should never ever ever happen. Checking for it
// to be paranoid.
- throw new MWException( 'In mode Li, but no 2xPrevious mode!' );
+ throw new RuntimeException( 'In mode Li, but no 2xPrevious mode!' );
}
if ( $this->mode[1] === self::MODE_BAGSTRUCT ) {
@@ -1083,7 +1126,7 @@ class XMPReader {
if ( !isset( $this->curItem[1] ) ) {
// be paranoid.
- throw new MWException( 'Can not find parent of BAGSTRUCT.' );
+ throw new RuntimeException( 'Can not find parent of BAGSTRUCT.' );
}
list( $curNS, $curTag ) = explode( ' ', $this->curItem[1] );
$this->ancestorStruct = isset( $this->items[$curNS][$curTag]['map_name'] )
@@ -1112,16 +1155,16 @@ class XMPReader {
*
* @param string $elm Namespace . ' ' . tag
* @param array $attribs Array of elements (most importantly xml:lang)
- * @throws MWException If gets a tag other than <rdf:li> or if no xml:lang
+ * @throws RuntimeException If gets a tag other than <rdf:li> or if no xml:lang
*/
private function startElementModeLiLang( $elm, $attribs ) {
if ( $elm !== self::NS_RDF . ' li' ) {
- throw new MWException( __METHOD__ . " <rdf:li> expected but got $elm." );
+ throw new RuntimeException( __METHOD__ . " <rdf:li> expected but got $elm." );
}
if ( !isset( $attribs[self::NS_XML . ' lang'] )
|| !preg_match( '/^[-A-Za-z0-9]{2,}$/D', $attribs[self::NS_XML . ' lang'] )
) {
- throw new MWException( __METHOD__
+ throw new RuntimeException( __METHOD__
. " <rdf:li> did not contain, or has invalid xml:lang attribute in lang alternative" );
}
@@ -1143,7 +1186,7 @@ class XMPReader {
* @param XMLParser $parser
* @param string $elm Namespace "<space>" element
* @param array $attribs Attribute name => value
- * @throws MWException
+ * @throws RuntimeException
*/
function startElement( $parser, $elm, $attribs ) {
@@ -1166,12 +1209,12 @@ class XMPReader {
//
// also it seems as if exiv2 and exiftool do not support
// this either (That or I misunderstand the standard)
- wfDebugLog( 'XMP', __METHOD__ . ' Encountered <rdf:type> which isn\'t currently supported' );
+ $this->logger->info( __METHOD__ . ' Encountered <rdf:type> which isn\'t currently supported' );
}
if ( strpos( $elm, ' ' ) === false ) {
// This probably shouldn't happen.
- wfDebugLog( 'XMP', __METHOD__ . " Encountered <$elm> which has no namespace. Skipping." );
+ $this->logger->info( __METHOD__ . " Encountered <$elm> which has no namespace. Skipping." );
return;
}
@@ -1180,7 +1223,7 @@ class XMPReader {
if ( count( $this->mode ) === 0 ) {
// This should not happen.
- throw new MWException( 'Error extracting XMP, '
+ throw new RuntimeException( 'Error extracting XMP, '
. "encountered <$elm> with no mode" );
}
@@ -1217,7 +1260,7 @@ class XMPReader {
$this->startElementModeQDesc( $elm );
break;
default:
- throw new MWException( 'StartElement in unknown mode: ' . $this->mode[0] );
+ throw new RuntimeException( 'StartElement in unknown mode: ' . $this->mode[0] );
}
}
@@ -1236,7 +1279,7 @@ class XMPReader {
* @codingStandardsIgnoreEnd
*
* @param array $attribs Array attribute=>value
- * @throws MWException
+ * @throws RuntimeException
*/
private function doAttribs( $attribs ) {
// first check for rdf:parseType attribute, as that can change
@@ -1253,7 +1296,7 @@ class XMPReader {
if ( strpos( $name, ' ' ) === false ) {
// This shouldn't happen, but so far some old software forgets namespace
// on rdf:about.
- wfDebugLog( 'XMP', __METHOD__ . ' Encountered non-namespaced attribute: '
+ $this->logger->info( __METHOD__ . ' Encountered non-namespaced attribute: '
. " $name=\"$val\". Skipping. " );
continue;
}
@@ -1266,12 +1309,12 @@ class XMPReader {
}
} elseif ( isset( $this->items[$ns][$tag] ) ) {
if ( $this->mode[0] === self::MODE_SIMPLE ) {
- throw new MWException( __METHOD__
+ throw new RuntimeException( __METHOD__
. " $ns:$tag found as attribute where not allowed" );
}
$this->saveValue( $ns, $tag, $val );
} else {
- wfDebugLog( 'XMP', __METHOD__ . " Ignoring unrecognized element <$ns:$tag>." );
+ $this->logger->debug( __METHOD__ . " Ignoring unrecognized element <$ns:$tag>." );
}
}
}
@@ -1293,20 +1336,24 @@ class XMPReader {
$finalName = isset( $info['map_name'] )
? $info['map_name'] : $tag;
if ( isset( $info['validate'] ) ) {
- $validate = is_array( $info['validate'] ) ? $info['validate']
- : array( 'XMPValidate', $info['validate'] );
+ if ( is_array( $info['validate'] ) ) {
+ $validate = $info['validate'];
+ } else {
+ $validator = new XMPValidate( $this->logger );
+ $validate = array( $validator, $info['validate'] );
+ }
if ( is_callable( $validate ) ) {
call_user_func_array( $validate, array( $info, &$val, true ) );
// the reasoning behind using &$val instead of using the return value
// is to be consistent between here and validating structures.
if ( is_null( $val ) ) {
- wfDebugLog( 'XMP', __METHOD__ . " <$ns:$tag> failed validation." );
+ $this->logger->info( __METHOD__ . " <$ns:$tag> failed validation." );
return;
}
} else {
- wfDebugLog( 'XMP', __METHOD__ . " Validation function for $finalName ("
+ $this->logger->warning( __METHOD__ . " Validation function for $finalName ("
. $validate[0] . '::' . $validate[1] . '()) is not callable.' );
}
}
diff --git a/includes/media/XMPInfo.php b/includes/media/XMPInfo.php
index e0a491cb..1d8d7771 100644
--- a/includes/media/XMPInfo.php
+++ b/includes/media/XMPInfo.php
@@ -31,18 +31,9 @@ class XMPInfo {
* @return array XMP item configuration array.
*/
public static function getItems() {
- if ( !self::$ranHooks ) {
- // This is for if someone makes a custom metadata extension.
- // For example, a medical wiki might want to decode DICOM xmp properties.
- Hooks::run( 'XMPGetInfo', array( &self::$items ) );
- self::$ranHooks = true; // Only want to do this once.
- }
-
return self::$items;
}
- static private $ranHooks = false;
-
/**
* XMPInfo::$items keeps a list of all the items
* we are interested to extract, as well as
@@ -57,7 +48,7 @@ class XMPInfo {
* * mode - What type of item (self::MODE_SIMPLE usually, see above for
* all values).
* * validate - Method to validate input. Could also post-process the
- * input. A string value is assumed to be a static method of
+ * input. A string value is assumed to be a method of
* XMPValidate. Can also take a array( 'className', 'methodName' ).
* * choices - Array of potential values (format of 'value' => true ).
* Only used with validateClosed.
diff --git a/includes/media/XMPValidate.php b/includes/media/XMPValidate.php
index 0fa60117..55e8ce79 100644
--- a/includes/media/XMPValidate.php
+++ b/includes/media/XMPValidate.php
@@ -21,6 +21,9 @@
* @ingroup Media
*/
+use Psr\Log\LoggerInterface;
+use Psr\Log\LoggerAwareInterface;
+
/**
* This contains some static methods for
* validating XMP properties. See XMPInfo and XMPReader classes.
@@ -40,7 +43,20 @@
* @see http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart1.pdf starting at pg 28
* @see http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart2.pdf starting at pg 11
*/
-class XMPValidate {
+class XMPValidate implements LoggerAwareInterface {
+
+ /**
+ * @var LoggerInterface
+ */
+ private $logger;
+
+ public function __construct( LoggerInterface $logger ) {
+ $this->setLogger( $logger );
+ }
+
+ public function setLogger( LoggerInterface $logger ) {
+ $this->logger = $logger;
+ }
/**
* Function to validate boolean properties ( True or False )
*
@@ -48,13 +64,13 @@ class XMPValidate {
* @param mixed &$val Current value to validate
* @param bool $standalone If this is a simple property or array
*/
- public static function validateBoolean( $info, &$val, $standalone ) {
+ public function validateBoolean( $info, &$val, $standalone ) {
if ( !$standalone ) {
// this only validates standalone properties, not arrays, etc
return;
}
if ( $val !== 'True' && $val !== 'False' ) {
- wfDebugLog( 'XMP', __METHOD__ . " Expected True or False but got $val" );
+ $this->debug->info( __METHOD__ . " Expected True or False but got $val" );
$val = null;
}
}
@@ -66,13 +82,13 @@ class XMPValidate {
* @param mixed &$val Current value to validate
* @param bool $standalone If this is a simple property or array
*/
- public static function validateRational( $info, &$val, $standalone ) {
+ public function validateRational( $info, &$val, $standalone ) {
if ( !$standalone ) {
// this only validates standalone properties, not arrays, etc
return;
}
if ( !preg_match( '/^(?:-?\d+)\/(?:\d+[1-9]|[1-9]\d*)$/D', $val ) ) {
- wfDebugLog( 'XMP', __METHOD__ . " Expected rational but got $val" );
+ $this->logger->info( __METHOD__ . " Expected rational but got $val" );
$val = null;
}
}
@@ -87,7 +103,7 @@ class XMPValidate {
* @param mixed &$val Current value to validate
* @param bool $standalone If this is a simple property or array
*/
- public static function validateRating( $info, &$val, $standalone ) {
+ public function validateRating( $info, &$val, $standalone ) {
if ( !$standalone ) {
// this only validates standalone properties, not arrays, etc
return;
@@ -95,7 +111,7 @@ class XMPValidate {
if ( !preg_match( '/^[-+]?\d*(?:\.?\d*)$/D', $val )
|| !is_numeric( $val )
) {
- wfDebugLog( 'XMP', __METHOD__ . " Expected rating but got $val" );
+ $this->logger->info( __METHOD__ . " Expected rating but got $val" );
$val = null;
return;
@@ -105,13 +121,13 @@ class XMPValidate {
// We do < 0 here instead of < -1 here, since
// the values between 0 and -1 are also illegal
// as -1 is meant as a special reject rating.
- wfDebugLog( 'XMP', __METHOD__ . " Rating too low, setting to -1 (Rejected)" );
+ $this->logger->info( __METHOD__ . " Rating too low, setting to -1 (Rejected)" );
$val = '-1';
return;
}
if ( $nVal > 5 ) {
- wfDebugLog( 'XMP', __METHOD__ . " Rating too high, setting to 5" );
+ $this->logger->info( __METHOD__ . " Rating too high, setting to 5" );
$val = '5';
return;
@@ -126,13 +142,13 @@ class XMPValidate {
* @param mixed &$val Current value to validate
* @param bool $standalone If this is a simple property or array
*/
- public static function validateInteger( $info, &$val, $standalone ) {
+ public function validateInteger( $info, &$val, $standalone ) {
if ( !$standalone ) {
// this only validates standalone properties, not arrays, etc
return;
}
if ( !preg_match( '/^[-+]?\d+$/D', $val ) ) {
- wfDebugLog( 'XMP', __METHOD__ . " Expected integer but got $val" );
+ $this->logger->info( __METHOD__ . " Expected integer but got $val" );
$val = null;
}
}
@@ -145,7 +161,7 @@ class XMPValidate {
* @param mixed &$val Current value to validate
* @param bool $standalone If this is a simple property or array
*/
- public static function validateClosed( $info, &$val, $standalone ) {
+ public function validateClosed( $info, &$val, $standalone ) {
if ( !$standalone ) {
// this only validates standalone properties, not arrays, etc
return;
@@ -163,7 +179,7 @@ class XMPValidate {
}
if ( !isset( $info['choices'][$val] ) && !$inRange ) {
- wfDebugLog( 'XMP', __METHOD__ . " Expected closed choice, but got $val" );
+ $this->logger->info( __METHOD__ . " Expected closed choice, but got $val" );
$val = null;
}
}
@@ -175,7 +191,7 @@ class XMPValidate {
* @param mixed &$val Current value to validate
* @param bool $standalone If this is a simple property or array
*/
- public static function validateFlash( $info, &$val, $standalone ) {
+ public function validateFlash( $info, &$val, $standalone ) {
if ( $standalone ) {
// this only validates flash structs, not individual properties
return;
@@ -186,7 +202,7 @@ class XMPValidate {
&& isset( $val['RedEyeMode'] )
&& isset( $val['Return'] )
) ) {
- wfDebugLog( 'XMP', __METHOD__ . " Flash structure did not have all the required components" );
+ $this->logger->info( __METHOD__ . " Flash structure did not have all the required components" );
$val = null;
} else {
$val = ( "\0" | ( $val['Fired'] === 'True' )
@@ -209,14 +225,14 @@ class XMPValidate {
* @param mixed &$val Current value to validate
* @param bool $standalone If this is a simple property or array
*/
- public static function validateLangCode( $info, &$val, $standalone ) {
+ public function validateLangCode( $info, &$val, $standalone ) {
if ( !$standalone ) {
// this only validates standalone properties, not arrays, etc
return;
}
if ( !preg_match( '/^[-A-Za-z0-9]{2,}$/D', $val ) ) {
//this is a rather naive check.
- wfDebugLog( 'XMP', __METHOD__ . " Expected Lang code but got $val" );
+ $this->logger->info( __METHOD__ . " Expected Lang code but got $val" );
$val = null;
}
}
@@ -238,7 +254,7 @@ class XMPValidate {
* 2011:04.
* @param bool $standalone If this is a simple property or array
*/
- public static function validateDate( $info, &$val, $standalone ) {
+ public function validateDate( $info, &$val, $standalone ) {
if ( !$standalone ) {
// this only validates standalone properties, not arrays, etc
return;
@@ -252,7 +268,7 @@ class XMPValidate {
) {
// @codingStandardsIgnoreEnd
- wfDebugLog( 'XMP', __METHOD__ . " Expected date but got $val" );
+ $this->logger->info( __METHOD__ . " Expected date but got $val" );
$val = null;
} else {
/*
@@ -270,7 +286,7 @@ class XMPValidate {
* some programs convert between metadata formats.
*/
if ( $res[1] === '0000' ) {
- wfDebugLog( 'XMP', __METHOD__ . " Invalid date (year 0): $val" );
+ $this->logger->info( __METHOD__ . " Invalid date (year 0): $val" );
$val = null;
return;
@@ -339,7 +355,7 @@ class XMPValidate {
* or DDD,MM.mmk form
* @param bool $standalone If its a simple prop (should always be true)
*/
- public static function validateGPS( $info, &$val, $standalone ) {
+ public function validateGPS( $info, &$val, $standalone ) {
if ( !$standalone ) {
return;
}
@@ -371,7 +387,7 @@ class XMPValidate {
return;
} else {
- wfDebugLog( 'XMP', __METHOD__
+ $this->logger->info( __METHOD__
. " Expected GPSCoordinate, but got $val." );
$val = null;
diff --git a/includes/media/tinyrgb.icc b/includes/media/tinyrgb.icc
new file mode 100644
index 00000000..eab973f5
--- /dev/null
+++ b/includes/media/tinyrgb.icc
Binary files differ
diff --git a/includes/mime.info b/includes/mime.info
index 243e2802..840b9d81 100644
--- a/includes/mime.info
+++ b/includes/mime.info
@@ -9,7 +9,7 @@
image/gif [BITMAP]
image/png image/x-png [BITMAP]
image/ief [BITMAP]
-image/jpeg [BITMAP]
+image/jpeg image/pjpeg [BITMAP]
image/jp2 [BITMAP]
image/xbm [BITMAP]
image/tiff [BITMAP]
diff --git a/includes/objectcache/MemcachedBagOStuff.php b/includes/objectcache/MemcachedBagOStuff.php
index 83bee700..e545aa55 100644
--- a/includes/objectcache/MemcachedBagOStuff.php
+++ b/includes/objectcache/MemcachedBagOStuff.php
@@ -57,12 +57,7 @@ class MemcachedBagOStuff extends BagOStuff {
return $params;
}
- /**
- * @param string $key
- * @param mixed $casToken [optional]
- * @return mixed
- */
- public function get( $key, &$casToken = null ) {
+ public function get( $key, &$casToken = null, $flags = 0 ) {
return $this->client->get( $this->encodeKey( $key ), $casToken );
}
@@ -183,4 +178,12 @@ class MemcachedBagOStuff extends BagOStuff {
protected function debugLog( $text ) {
$this->logger->debug( $text );
}
+
+ public function modifySimpleRelayEvent( array $event ) {
+ if ( array_key_exists( 'val', $event ) ) {
+ $event['flg'] = 0; // data is not serialized nor gzipped (for memcached driver)
+ }
+
+ return $event;
+ }
}
diff --git a/includes/objectcache/MemcachedClient.php b/includes/objectcache/MemcachedClient.php
index bc4a00b2..5010b899 100644
--- a/includes/objectcache/MemcachedClient.php
+++ b/includes/objectcache/MemcachedClient.php
@@ -94,6 +94,11 @@ class MWMemcached {
*/
const COMPRESSED = 2;
+ /**
+ * Flag: indicates data is an integer
+ */
+ const INTVAL = 4;
+
// }}}
/**
@@ -745,13 +750,13 @@ class MWMemcached {
$timeout = $this->_connect_timeout;
$errno = $errstr = null;
for ( $i = 0; !$sock && $i < $this->_connect_attempts; $i++ ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
if ( $this->_persistent == 1 ) {
$sock = pfsockopen( $ip, $port, $errno, $errstr, $timeout );
} else {
$sock = fsockopen( $ip, $port, $errno, $errstr, $timeout );
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
if ( !$sock ) {
$this->_error_log( "Error connecting to $host: $errstr\n" );
@@ -979,6 +984,8 @@ class MWMemcached {
*/
if ( $flags & self::SERIALIZED ) {
$ret[$rkey] = unserialize( $ret[$rkey] );
+ } elseif ( $flags & self::INTVAL ) {
+ $ret[$rkey] = intval( $ret[$rkey] );
}
}
@@ -1027,7 +1034,9 @@ class MWMemcached {
$flags = 0;
- if ( !is_scalar( $val ) ) {
+ if ( is_int( $val ) ) {
+ $flags |= self::INTVAL;
+ } elseif ( !is_scalar( $val ) ) {
$val = serialize( $val );
$flags |= self::SERIALIZED;
if ( $this->_debug ) {
diff --git a/includes/objectcache/MemcachedPeclBagOStuff.php b/includes/objectcache/MemcachedPeclBagOStuff.php
index f2c49281..1b2c8db6 100644
--- a/includes/objectcache/MemcachedPeclBagOStuff.php
+++ b/includes/objectcache/MemcachedPeclBagOStuff.php
@@ -115,12 +115,7 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
$this->client->addServers( $servers );
}
- /**
- * @param string $key
- * @param float $casToken [optional]
- * @return mixed
- */
- public function get( $key, &$casToken = null ) {
+ public function get( $key, &$casToken = null, $flags = 0 ) {
$this->debugLog( "get($key)" );
$result = $this->client->get( $this->encodeKey( $key ), null, $casToken );
$result = $this->checkResult( $key, $result );
@@ -238,15 +233,16 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
return $result;
}
- /**
- * @param array $keys
- * @return array
- */
- public function getMulti( array $keys ) {
+ public function getMulti( array $keys, $flags = 0 ) {
$this->debugLog( 'getMulti(' . implode( ', ', $keys ) . ')' );
$callback = array( $this, 'encodeKey' );
- $result = $this->client->getMulti( array_map( $callback, $keys ) );
- $result = $result ?: array(); // must be an array
+ $encodedResult = $this->client->getMulti( array_map( $callback, $keys ) );
+ $encodedResult = $encodedResult ?: array(); // must be an array
+ $result = array();
+ foreach ( $encodedResult as $key => $value ) {
+ $key = $this->decodeKey( $key );
+ $result[$key] = $value;
+ }
return $this->checkResult( false, $result );
}
diff --git a/includes/objectcache/MemcachedPhpBagOStuff.php b/includes/objectcache/MemcachedPhpBagOStuff.php
index 6fba61ba..6f0ba588 100644
--- a/includes/objectcache/MemcachedPhpBagOStuff.php
+++ b/includes/objectcache/MemcachedPhpBagOStuff.php
@@ -57,13 +57,15 @@ class MemcachedPhpBagOStuff extends MemcachedBagOStuff {
$this->client->set_debug( $debug );
}
- /**
- * @param array $keys
- * @return array
- */
- public function getMulti( array $keys ) {
+ public function getMulti( array $keys, $flags = 0 ) {
$callback = array( $this, 'encodeKey' );
- return $this->client->get_multi( array_map( $callback, $keys ) );
+ $encodedResult = $this->client->get_multi( array_map( $callback, $keys ) );
+ $result = array();
+ foreach ( $encodedResult as $key => $value ) {
+ $key = $this->decodeKey( $key );
+ $result[$key] = $value;
+ }
+ return $result;
}
/**
diff --git a/includes/objectcache/MultiWriteBagOStuff.php b/includes/objectcache/MultiWriteBagOStuff.php
index be54e4d3..1a52930e 100644
--- a/includes/objectcache/MultiWriteBagOStuff.php
+++ b/includes/objectcache/MultiWriteBagOStuff.php
@@ -29,29 +29,48 @@
* @ingroup Cache
*/
class MultiWriteBagOStuff extends BagOStuff {
- /** @var array BagOStuff[] */
+ /** @var BagOStuff[] */
protected $caches;
+ /** @var bool Use async secondary writes */
+ protected $asyncWrites = false;
/**
- * Constructor. Parameters are:
- *
- * - caches: This should have a numbered array of cache parameter
- * structures, in the style required by $wgObjectCaches. See
- * the documentation of $wgObjectCaches for more detail.
+ * $params include:
+ * - caches: This should have a numbered array of cache parameter
+ * structures, in the style required by $wgObjectCaches. See
+ * the documentation of $wgObjectCaches for more detail.
+ * BagOStuff objects can also be used as values.
+ * The first cache is the primary one, being the first to
+ * be read in the fallback chain. Writes happen to all stores
+ * in the order they are defined. However, lock()/unlock() calls
+ * only use the primary store.
+ * - replication: Either 'sync' or 'async'. This controls whether writes to
+ * secondary stores are deferred when possible. Async writes
+ * require the HHVM register_postsend_function() function.
+ * Async writes can increase the chance of some race conditions
+ * or cause keys to expire seconds later than expected. It is
+ * safe to use for modules when cached values: are immutable,
+ * invalidation uses logical TTLs, invalidation uses etag/timestamp
+ * validation against the DB, or merge() is used to handle races.
*
* @param array $params
* @throws InvalidArgumentException
*/
public function __construct( $params ) {
parent::__construct( $params );
- if ( !isset( $params['caches'] ) ) {
- throw new InvalidArgumentException( __METHOD__ . ': the caches parameter is required' );
+
+ if ( empty( $params['caches'] ) || !is_array( $params['caches'] ) ) {
+ throw new InvalidArgumentException( __METHOD__ . ': "caches" parameter must be an array of caches' );
}
$this->caches = array();
foreach ( $params['caches'] as $cacheInfo ) {
- $this->caches[] = ObjectCache::newFromParams( $cacheInfo );
+ $this->caches[] = ( $cacheInfo instanceof BagOStuff )
+ ? $cacheInfo
+ : ObjectCache::newFromParams( $cacheInfo );
}
+
+ $this->asyncWrites = isset( $params['replication'] ) && $params['replication'] === 'async';
}
/**
@@ -61,14 +80,9 @@ class MultiWriteBagOStuff extends BagOStuff {
$this->doWrite( 'setDebug', $debug );
}
- /**
- * @param string $key
- * @param mixed $casToken [optional]
- * @return bool|mixed
- */
- public function get( $key, &$casToken = null ) {
+ public function get( $key, &$casToken = null, $flags = 0 ) {
foreach ( $this->caches as $cache ) {
- $value = $cache->get( $key );
+ $value = $cache->get( $key, $casToken, $flags );
if ( $value !== false ) {
return $value;
}
@@ -126,15 +140,12 @@ class MultiWriteBagOStuff extends BagOStuff {
* @param string $key
* @param int $timeout
* @param int $expiry
+ * @param string $rclass
* @return bool
*/
- public function lock( $key, $timeout = 6, $expiry = 6 ) {
+ public function lock( $key, $timeout = 6, $expiry = 6, $rclass = '' ) {
// Lock only the first cache, to avoid deadlocks
- if ( isset( $this->caches[0] ) ) {
- return $this->caches[0]->lock( $key, $timeout, $expiry );
- } else {
- return true;
- }
+ return $this->caches[0]->lock( $key, $timeout, $expiry, $rclass );
}
/**
@@ -142,11 +153,7 @@ class MultiWriteBagOStuff extends BagOStuff {
* @return bool
*/
public function unlock( $key ) {
- if ( isset( $this->caches[0] ) ) {
- return $this->caches[0]->unlock( $key );
- } else {
- return true;
- }
+ return $this->caches[0]->unlock( $key );
}
/**
@@ -161,13 +168,11 @@ class MultiWriteBagOStuff extends BagOStuff {
}
public function getLastError() {
- return isset( $this->caches[0] ) ? $this->caches[0]->getLastError() : self::ERR_NONE;
+ return $this->caches[0]->getLastError();
}
public function clearLastError() {
- if ( isset( $this->caches[0] ) ) {
- $this->caches[0]->clearLastError();
- }
+ $this->caches[0]->clearLastError();
}
/**
@@ -179,11 +184,25 @@ class MultiWriteBagOStuff extends BagOStuff {
$args = func_get_args();
array_shift( $args );
- foreach ( $this->caches as $cache ) {
- if ( !call_user_func_array( array( $cache, $method ), $args ) ) {
- $ret = false;
+ foreach ( $this->caches as $i => $cache ) {
+ if ( $i == 0 || !$this->asyncWrites ) {
+ // First store or in sync mode: write now and get result
+ if ( !call_user_func_array( array( $cache, $method ), $args ) ) {
+ $ret = false;
+ }
+ } else {
+ // Secondary write in async mode: do not block this HTTP request
+ $logger = $this->logger;
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $cache, $method, $args, $logger ) {
+ if ( !call_user_func_array( array( $cache, $method ), $args ) ) {
+ $logger->warning( "Async $method op failed" );
+ }
+ }
+ );
}
}
+
return $ret;
}
@@ -202,6 +221,7 @@ class MultiWriteBagOStuff extends BagOStuff {
$ret = true;
}
}
+
return $ret;
}
}
diff --git a/includes/objectcache/ObjectCache.php b/includes/objectcache/ObjectCache.php
index 2e47e24a..60191057 100644
--- a/includes/objectcache/ObjectCache.php
+++ b/includes/objectcache/ObjectCache.php
@@ -26,44 +26,94 @@ use MediaWiki\Logger\LoggerFactory;
/**
* Functions to get cache objects
*
+ * The word "cache" has two main dictionary meanings, and both
+ * are used in this factory class. They are:
+ *
+ * - a) Cache (the computer science definition).
+ * A place to store copies or computations on existing data for
+ * higher access speeds.
+ * - b) Storage.
+ * A place to store lightweight data that is not canonically
+ * stored anywhere else (e.g. a "hoard" of objects).
+ *
+ * The former should always use strongly consistent stores, so callers don't
+ * have to deal with stale reads. The later may be eventually consistent, but
+ * callers can use BagOStuff:READ_LATEST to see the latest available data.
+ *
+ * Primary entry points:
+ *
+ * - ObjectCache::newAccelerator( $fallbackType )
+ * Purpose: Cache.
+ * Stored only on the individual web server.
+ * Not associated with other servers.
+ *
+ * - wfGetMainCache()
+ * Purpose: Cache.
+ * Stored centrally within the local data-center.
+ * Not replicated to other DCs.
+ * Also known as $wgMemc. Configured by $wgMainCacheType.
+ *
+ * - ObjectCache::getMainWANInstance()
+ * Purpose: Cache.
+ * Stored in the local data-center's main cache (uses different cache keys).
+ * Delete events are broadcasted to other DCs. See WANObjectCache for details.
+ *
+ * - ObjectCache::getMainStashInstance()
+ * Purpose: Ephemeral storage.
+ * Stored centrally within the local data-center.
+ * Changes are replicated to other DCs (eventually consistent).
+ * To retrieve the latest value (e.g. not from a slave), use BagOStuff:READ_LATEST.
+ * This store may be subject to LRU style evictions.
+ *
+ * - wfGetCache( $cacheType )
+ * Get a specific cache type by key in $wgObjectCaches.
+ *
* @ingroup Cache
*/
class ObjectCache {
+ /** @var Array Map of (id => BagOStuff) */
public static $instances = array();
+ /** @var Array Map of (id => WANObjectCache) */
+ public static $wanInstances = array();
+
/**
* Get a cached instance of the specified type of cache object.
*
- * @param string $id
- *
+ * @param string $id A key in $wgObjectCaches.
* @return BagOStuff
*/
- static function getInstance( $id ) {
- if ( isset( self::$instances[$id] ) ) {
- return self::$instances[$id];
+ public static function getInstance( $id ) {
+ if ( !isset( self::$instances[$id] ) ) {
+ self::$instances[$id] = self::newFromId( $id );
}
- $object = self::newFromId( $id );
- self::$instances[$id] = $object;
- return $object;
+ return self::$instances[$id];
}
/**
- * Clear all the cached instances.
+ * Get a cached instance of the specified type of WAN cache object.
+ *
+ * @since 1.26
+ * @param string $id A key in $wgWANObjectCaches.
+ * @return WANObjectCache
*/
- static function clear() {
- self::$instances = array();
+ public static function getWANInstance( $id ) {
+ if ( !isset( self::$wanInstances[$id] ) ) {
+ self::$wanInstances[$id] = self::newWANCacheFromId( $id );
+ }
+
+ return self::$wanInstances[$id];
}
/**
* Create a new cache object of the specified type.
*
- * @param string $id
- *
- * @throws MWException
+ * @param string $id A key in $wgObjectCaches.
* @return BagOStuff
+ * @throws MWException
*/
- static function newFromId( $id ) {
+ public static function newFromId( $id ) {
global $wgObjectCaches;
if ( !isset( $wgObjectCaches[$id] ) ) {
@@ -75,14 +125,17 @@ class ObjectCache {
}
/**
- * Create a new cache object from parameters
- *
- * @param array $params
+ * Create a new cache object from parameters.
*
- * @throws MWException
+ * @param array $params Must have 'factory' or 'class' property.
+ * - factory: Callback passed $params that returns BagOStuff.
+ * - class: BagOStuff subclass constructed with $params.
+ * - loggroup: Alias to set 'logger' key with LoggerFactory group.
+ * - .. Other parameters passed to factory or class.
* @return BagOStuff
+ * @throws MWException
*/
- static function newFromParams( $params ) {
+ public static function newFromParams( $params ) {
if ( isset( $params['loggroup'] ) ) {
$params['logger'] = LoggerFactory::getInstance( $params['loggroup'] );
} else {
@@ -103,7 +156,7 @@ class ObjectCache {
}
/**
- * Factory function referenced from DefaultSettings.php for CACHE_ANYTHING
+ * Factory function for CACHE_ANYTHING (referenced from DefaultSettings.php)
*
* CACHE_ANYTHING means that stuff has to be cached, not caching is not an option.
* If a caching method is configured for any of the main caches ($wgMainCacheType,
@@ -111,10 +164,11 @@ class ObjectCache {
* be an alias to the configured cache choice for that.
* If no cache choice is configured (by default $wgMainCacheType is CACHE_NONE),
* then CACHE_ANYTHING will forward to CACHE_DB.
+ *
* @param array $params
* @return BagOStuff
*/
- static function newAnything( $params ) {
+ public static function newAnything( $params ) {
global $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType;
$candidates = array( $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType );
foreach ( $candidates as $candidate ) {
@@ -126,17 +180,20 @@ class ObjectCache {
}
/**
- * Factory function referenced from DefaultSettings.php for CACHE_ACCEL.
+ * Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
*
* This will look for any APC style server-local cache.
* A fallback cache can be specified if none is found.
*
- * @param array $params
+ * @param array $params [optional]
* @param int|string $fallback Fallback cache, e.g. (CACHE_NONE, "hash") (since 1.24)
- * @throws MWException
* @return BagOStuff
+ * @throws MWException
*/
- static function newAccelerator( $params, $fallback = null ) {
+ public static function newAccelerator( $params = array(), $fallback = null ) {
+ if ( !is_array( $params ) && $fallback === null ) {
+ $fallback = $params;
+ }
if ( function_exists( 'apc_fetch' ) ) {
$id = 'apc';
} elseif ( function_exists( 'xcache_get' ) && wfIniGetBool( 'xcache.var_size' ) ) {
@@ -144,11 +201,11 @@ class ObjectCache {
} elseif ( function_exists( 'wincache_ucache_get' ) ) {
$id = 'wincache';
} else {
- if ( $fallback !== null ) {
- return self::newFromId( $fallback );
+ if ( $fallback === null ) {
+ throw new MWException( 'CACHE_ACCEL requested but no suitable object ' .
+ 'cache is present. You may want to install APC.' );
}
- throw new MWException( "CACHE_ACCEL requested but no suitable object " .
- "cache is present. You may want to install APC." );
+ $id = $fallback;
}
return self::newFromId( $id );
}
@@ -161,10 +218,78 @@ class ObjectCache {
* switching between the two clients randomly would be disastrous.
*
* @param array $params
- *
* @return MemcachedPhpBagOStuff
*/
- static function newMemcached( $params ) {
+ public static function newMemcached( $params ) {
return new MemcachedPhpBagOStuff( $params );
}
+
+ /**
+ * Create a new cache object of the specified type.
+ *
+ * @since 1.26
+ * @param string $id A key in $wgWANObjectCaches.
+ * @return WANObjectCache
+ * @throws MWException
+ */
+ public static function newWANCacheFromId( $id ) {
+ global $wgWANObjectCaches;
+
+ if ( !isset( $wgWANObjectCaches[$id] ) ) {
+ throw new MWException( "Invalid object cache type \"$id\" requested. " .
+ "It is not present in \$wgWANObjectCaches." );
+ }
+
+ $params = $wgWANObjectCaches[$id];
+ $class = $params['relayerConfig']['class'];
+ $params['relayer'] = new $class( $params['relayerConfig'] );
+ $params['cache'] = self::newFromId( $params['cacheId'] );
+ $class = $params['class'];
+
+ return new $class( $params );
+ }
+
+ /**
+ * Get the main WAN cache object.
+ *
+ * @since 1.26
+ * @return WANObjectCache
+ */
+ public static function getMainWANInstance() {
+ global $wgMainWANCache;
+
+ return self::getWANInstance( $wgMainWANCache );
+ }
+
+ /**
+ * Get the cache object for the main stash.
+ *
+ * Stash objects are BagOStuff instances suitable for storing light
+ * weight data that is not canonically stored elsewhere (such as RDBMS).
+ * Stashes should be configured to propagate changes to all data-centers.
+ *
+ * Callers should be prepared for:
+ * - a) Writes to be slower in non-"primary" (e.g. HTTP GET/HEAD only) DCs
+ * - b) Reads to be eventually consistent, e.g. for get()/getMulti()
+ * In general, this means avoiding updates on idempotent HTTP requests and
+ * avoiding an assumption of perfect serializability (or accepting anomalies).
+ * Reads may be eventually consistent or data might rollback as nodes flap.
+ * Callers can use BagOStuff:READ_LATEST to see the latest available data.
+ *
+ * @return BagOStuff
+ * @since 1.26
+ */
+ public static function getMainStashInstance() {
+ global $wgMainStash;
+
+ return self::getInstance( $wgMainStash );
+ }
+
+ /**
+ * Clear all the cached instances.
+ */
+ public static function clear() {
+ self::$instances = array();
+ self::$wanInstances = array();
+ }
}
diff --git a/includes/objectcache/ObjectCacheSessionHandler.php b/includes/objectcache/ObjectCacheSessionHandler.php
index 789f1e3b..2a5d6955 100644
--- a/includes/objectcache/ObjectCacheSessionHandler.php
+++ b/includes/objectcache/ObjectCacheSessionHandler.php
@@ -21,6 +21,8 @@
* @ingroup Cache
*/
+use MediaWiki\Logger\LoggerFactory;
+
/**
* Session storage in object cache.
* Used if $wgSessionsInObjectCache is true.
@@ -106,7 +108,11 @@ class ObjectCacheSessionHandler {
* @return mixed Session data
*/
static function read( $id ) {
+ $stime = microtime( true );
$data = self::getCache()->get( self::getKey( $id ) );
+ $real = microtime( true ) - $stime;
+
+ RequestContext::getMain()->getStats()->timing( "session.read", 1000 * $real );
self::$hashCache = array( $id => self::getHash( $data ) );
@@ -127,7 +133,11 @@ class ObjectCacheSessionHandler {
if ( !isset( self::$hashCache[$id] )
|| self::getHash( $data ) !== self::$hashCache[$id]
) {
+ $stime = microtime( true );
self::getCache()->set( self::getKey( $id ), $data, $wgObjectCacheSessionExpiry );
+ $real = microtime( true ) - $stime;
+
+ RequestContext::getMain()->getStats()->timing( "session.write", 1000 * $real );
}
return true;
@@ -140,7 +150,11 @@ class ObjectCacheSessionHandler {
* @return bool Success
*/
static function destroy( $id ) {
+ $stime = microtime( true );
self::getCache()->delete( self::getKey( $id ) );
+ $real = microtime( true ) - $stime;
+
+ RequestContext::getMain()->getStats()->timing( "session.destroy", 1000 * $real );
return true;
}
@@ -157,10 +171,37 @@ class ObjectCacheSessionHandler {
}
/**
- * Shutdown function. See the comment inside ObjectCacheSessionHandler::install
- * for rationale.
+ * Shutdown function.
+ * See the comment inside ObjectCacheSessionHandler::install for rationale.
*/
static function handleShutdown() {
session_write_close();
}
+
+ /**
+ * Pre-emptive session renewal function
+ */
+ static function renewCurrentSession() {
+ global $wgObjectCacheSessionExpiry;
+
+ // Once a session is at half TTL, renew it
+ $window = $wgObjectCacheSessionExpiry / 2;
+ $logger = LoggerFactory::getInstance( 'SessionHandler' );
+
+ $now = microtime( true );
+ // Session are only written in object stores when $_SESSION changes,
+ // which also renews the TTL ($wgObjectCacheSessionExpiry). If a user
+ // is active but not causing session data changes, it may suddenly
+ // expire as they view a form, blocking the first submission.
+ // Make a dummy change every so often to avoid this.
+ if ( !isset( $_SESSION['wsExpiresUnix'] ) ) {
+ $_SESSION['wsExpiresUnix'] = $now + $wgObjectCacheSessionExpiry;
+
+ $logger->info( "Set expiry for session " . session_id(), array() );
+ } elseif ( ( $now + $window ) > $_SESSION['wsExpiresUnix'] ) {
+ $_SESSION['wsExpiresUnix'] = $now + $wgObjectCacheSessionExpiry;
+
+ $logger->info( "Renewed session " . session_id(), array() );
+ }
+ }
}
diff --git a/includes/objectcache/RedisBagOStuff.php b/includes/objectcache/RedisBagOStuff.php
index de3511df..7d9903fe 100644
--- a/includes/objectcache/RedisBagOStuff.php
+++ b/includes/objectcache/RedisBagOStuff.php
@@ -20,11 +20,18 @@
* @file
*/
+/**
+ * Redis-based caching module for redis server >= 2.6.12
+ *
+ * @note: avoid use of Redis::MULTI transactions for twemproxy support
+ */
class RedisBagOStuff extends BagOStuff {
/** @var RedisConnectionPool */
protected $redisPool;
/** @var array List of server names */
protected $servers;
+ /** @var array Map of (tag => server name) */
+ protected $serverTagMap;
/** @var bool */
protected $automaticFailover;
@@ -34,7 +41,8 @@ class RedisBagOStuff extends BagOStuff {
* - servers: An array of server names. A server name may be a hostname,
* a hostname/port combination or the absolute path of a UNIX socket.
* If a hostname is specified but no port, the standard port number
- * 6379 will be used. Required.
+ * 6379 will be used. Arrays keys can be used to specify the tag to
+ * hash on in place of the host/port. Required.
*
* - connectTimeout: The timeout for new connections, in seconds. Optional,
* default is 1 second.
@@ -66,6 +74,10 @@ class RedisBagOStuff extends BagOStuff {
$this->redisPool = RedisConnectionPool::singleton( $redisConf );
$this->servers = $params['servers'];
+ foreach ( $this->servers as $key => $server ) {
+ $this->serverTagMap[is_int( $key ) ? $server : $key] = $server;
+ }
+
if ( isset( $params['automaticFailover'] ) ) {
$this->automaticFailover = $params['automaticFailover'];
} else {
@@ -73,8 +85,7 @@ class RedisBagOStuff extends BagOStuff {
}
}
- public function get( $key, &$casToken = null ) {
-
+ public function get( $key, &$casToken = null, $flags = 0 ) {
list( $server, $conn ) = $this->getConnection( $key );
if ( !$conn ) {
return false;
@@ -93,7 +104,6 @@ class RedisBagOStuff extends BagOStuff {
}
public function set( $key, $value, $expiry = 0 ) {
-
list( $server, $conn ) = $this->getConnection( $key );
if ( !$conn ) {
return false;
@@ -115,41 +125,7 @@ class RedisBagOStuff extends BagOStuff {
return $result;
}
- protected function cas( $casToken, $key, $value, $expiry = 0 ) {
-
- list( $server, $conn ) = $this->getConnection( $key );
- if ( !$conn ) {
- return false;
- }
- $expiry = $this->convertToRelative( $expiry );
- try {
- $conn->watch( $key );
-
- if ( $this->serialize( $this->get( $key ) ) !== $casToken ) {
- $conn->unwatch();
- return false;
- }
-
- // multi()/exec() will fail atomically if the key changed since watch()
- $conn->multi();
- if ( $expiry ) {
- $conn->setex( $key, $expiry, $this->serialize( $value ) );
- } else {
- // No expiry, that is very different from zero expiry in Redis
- $conn->set( $key, $this->serialize( $value ) );
- }
- $result = ( $conn->exec() == array( true ) );
- } catch ( RedisException $e ) {
- $result = false;
- $this->handleException( $conn, $e );
- }
-
- $this->logRequest( 'cas', $key, $server, $result );
- return $result;
- }
-
public function delete( $key ) {
-
list( $server, $conn ) = $this->getConnection( $key );
if ( !$conn ) {
return false;
@@ -167,8 +143,7 @@ class RedisBagOStuff extends BagOStuff {
return $result;
}
- public function getMulti( array $keys ) {
-
+ public function getMulti( array $keys, $flags = 0 ) {
$batches = array();
$conns = array();
foreach ( $keys as $key ) {
@@ -213,7 +188,6 @@ class RedisBagOStuff extends BagOStuff {
* @return bool
*/
public function setMulti( array $data, $expiry = 0 ) {
-
$batches = array();
$conns = array();
foreach ( $data as $key => $value ) {
@@ -257,10 +231,7 @@ class RedisBagOStuff extends BagOStuff {
return $result;
}
-
-
public function add( $key, $value, $expiry = 0 ) {
-
list( $server, $conn ) = $this->getConnection( $key );
if ( !$conn ) {
return false;
@@ -268,10 +239,11 @@ class RedisBagOStuff extends BagOStuff {
$expiry = $this->convertToRelative( $expiry );
try {
if ( $expiry ) {
- $conn->multi();
- $conn->setnx( $key, $this->serialize( $value ) );
- $conn->expire( $key, $expiry );
- $result = ( $conn->exec() == array( true, true ) );
+ $result = $conn->set(
+ $key,
+ $this->serialize( $value ),
+ array( 'nx', 'ex' => $expiry )
+ );
} else {
$result = $conn->setnx( $key, $this->serialize( $value ) );
}
@@ -297,7 +269,6 @@ class RedisBagOStuff extends BagOStuff {
* @return int|bool New value or false on failure
*/
public function incr( $key, $value = 1 ) {
-
list( $server, $conn ) = $this->getConnection( $key );
if ( !$conn ) {
return false;
@@ -306,6 +277,7 @@ class RedisBagOStuff extends BagOStuff {
return null;
}
try {
+ // @FIXME: on races, the key may have a 0 TTL
$result = $conn->incrBy( $key, $value );
} catch ( RedisException $e ) {
$result = false;
@@ -316,12 +288,12 @@ class RedisBagOStuff extends BagOStuff {
return $result;
}
- public function merge( $key, $callback, $exptime = 0, $attempts = 10 ) {
- if ( !is_callable( $callback ) ) {
- throw new Exception( "Got invalid callback." );
+ public function modifySimpleRelayEvent( array $event ) {
+ if ( array_key_exists( 'val', $event ) ) {
+ $event['val'] = serialize( $event['val'] ); // this class uses PHP serialization
}
- return $this->mergeViaCas( $key, $callback, $exptime, $attempts );
+ return $event;
}
/**
@@ -348,27 +320,65 @@ class RedisBagOStuff extends BagOStuff {
* @return array (server, RedisConnRef) or (false, false)
*/
protected function getConnection( $key ) {
- if ( count( $this->servers ) === 1 ) {
- $candidates = $this->servers;
- } else {
- $candidates = $this->servers;
+ $candidates = array_keys( $this->serverTagMap );
+
+ if ( count( $this->servers ) > 1 ) {
ArrayUtils::consistentHashSort( $candidates, $key, '/' );
if ( !$this->automaticFailover ) {
$candidates = array_slice( $candidates, 0, 1 );
}
}
- foreach ( $candidates as $server ) {
+ while ( ( $tag = array_shift( $candidates ) ) !== null ) {
+ $server = $this->serverTagMap[$tag];
$conn = $this->redisPool->getConnection( $server );
- if ( $conn ) {
- return array( $server, $conn );
+ if ( !$conn ) {
+ continue;
}
+
+ // If automatic failover is enabled, check that the server's link
+ // to its master (if any) is up -- but only if there are other
+ // viable candidates left to consider. Also, getMasterLinkStatus()
+ // does not work with twemproxy, though $candidates will be empty
+ // by now in such cases.
+ if ( $this->automaticFailover && $candidates ) {
+ try {
+ if ( $this->getMasterLinkStatus( $conn ) === 'down' ) {
+ // If the master cannot be reached, fail-over to the next server.
+ // If masters are in data-center A, and slaves in data-center B,
+ // this helps avoid the case were fail-over happens in A but not
+ // to the corresponding server in B (e.g. read/write mismatch).
+ continue;
+ }
+ } catch ( RedisException $e ) {
+ // Server is not accepting commands
+ $this->handleException( $conn, $e );
+ continue;
+ }
+ }
+
+ return array( $server, $conn );
}
+
$this->setLastError( BagOStuff::ERR_UNREACHABLE );
+
return array( false, false );
}
/**
+ * Check the master link status of a Redis server that is configured as a slave.
+ * @param RedisConnRef $conn
+ * @return string|null Master link status (either 'up' or 'down'), or null
+ * if the server is not a slave.
+ */
+ protected function getMasterLinkStatus( RedisConnRef $conn ) {
+ $info = $conn->info();
+ return isset( $info['master_link_status'] )
+ ? $info['master_link_status']
+ : null;
+ }
+
+ /**
* Log a fatal error
* @param string $msg
*/
diff --git a/includes/objectcache/SqlBagOStuff.php b/includes/objectcache/SqlBagOStuff.php
index 82eeb842..e08fec99 100644
--- a/includes/objectcache/SqlBagOStuff.php
+++ b/includes/objectcache/SqlBagOStuff.php
@@ -30,6 +30,7 @@ class SqlBagOStuff extends BagOStuff {
/** @var LoadBalancer */
protected $lb;
+ /** @var array */
protected $serverInfos;
/** @var array */
@@ -53,6 +54,9 @@ class SqlBagOStuff extends BagOStuff {
/** @var string */
protected $tableName = 'objectcache';
+ /** @var bool */
+ protected $slaveOnly = false;
+
/** @var array UNIX timestamps */
protected $connFailureTimes = array();
@@ -84,6 +88,10 @@ class SqlBagOStuff extends BagOStuff {
* required to hold the largest shard index. Data will be
* distributed across all tables by key hash. This is for
* MySQL bugs 61735 and 61736.
+ * - slaveOnly: Whether to only use slave DBs and avoid triggering
+ * garbage collection logic of expired items. This only
+ * makes sense if the primary DB is used and only if get()
+ * calls will be used. This is used by ReplicatedBagOStuff.
*
* @param array $params
*/
@@ -112,6 +120,7 @@ class SqlBagOStuff extends BagOStuff {
if ( isset( $params['shards'] ) ) {
$this->shards = intval( $params['shards'] );
}
+ $this->slaveOnly = !empty( $params['slaveOnly'] );
}
/**
@@ -155,12 +164,13 @@ class SqlBagOStuff extends BagOStuff {
* However, SQLite has an opposite behavior. And PostgreSQL needs to know
* if we are in transaction or no
*/
- if ( wfGetDB( DB_MASTER )->getType() == 'mysql' ) {
+ $index = $this->slaveOnly ? DB_SLAVE : DB_MASTER;
+ if ( wfGetDB( $index )->getType() == 'mysql' ) {
$this->lb = wfGetLBFactory()->newMainLB();
- $db = $this->lb->getConnection( DB_MASTER );
+ $db = $this->lb->getConnection( $index );
$db->clearFlag( DBO_TRX ); // auto-commit mode
} else {
- $db = wfGetDB( DB_MASTER );
+ $db = wfGetDB( $index );
}
}
if ( $wgDebugDBTransactions ) {
@@ -210,12 +220,7 @@ class SqlBagOStuff extends BagOStuff {
}
}
- /**
- * @param string $key
- * @param mixed $casToken [optional]
- * @return mixed
- */
- public function get( $key, &$casToken = null ) {
+ public function get( $key, &$casToken = null, $flags = 0 ) {
$values = $this->getMulti( array( $key ) );
if ( array_key_exists( $key, $values ) ) {
$casToken = $values[$key];
@@ -224,11 +229,7 @@ class SqlBagOStuff extends BagOStuff {
return false;
}
- /**
- * @param array $keys
- * @return array
- */
- public function getMulti( array $keys ) {
+ public function getMulti( array $keys, $flags = 0 ) {
$values = array(); // array of (key => value)
$keysByTable = array();
@@ -274,12 +275,7 @@ class SqlBagOStuff extends BagOStuff {
try {
$db = $this->getDB( $row->serverIndex );
if ( $this->isExpired( $db, $row->exptime ) ) { // MISS
- $this->debug( "get: key has expired, deleting" );
- # Put the expiry time in the WHERE condition to avoid deleting a
- # newly-inserted value
- $db->delete( $row->tableName,
- array( 'keyname' => $key, 'exptime' => $row->exptime ),
- __METHOD__ );
+ $this->debug( "get: key has expired" );
} else { // HIT
$values[$key] = $this->unserialize( $db->decodeBlob( $row->value ) );
}
@@ -358,8 +354,6 @@ class SqlBagOStuff extends BagOStuff {
return $result;
}
-
-
/**
* @param string $key
* @param mixed $value
@@ -367,37 +361,7 @@ class SqlBagOStuff extends BagOStuff {
* @return bool
*/
public function set( $key, $value, $exptime = 0 ) {
- list( $serverIndex, $tableName ) = $this->getTableByKey( $key );
- try {
- $db = $this->getDB( $serverIndex );
- $exptime = intval( $exptime );
-
- if ( $exptime < 0 ) {
- $exptime = 0;
- }
-
- if ( $exptime == 0 ) {
- $encExpiry = $this->getMaxDateTime( $db );
- } else {
- $exptime = $this->convertExpiry( $exptime );
- $encExpiry = $db->timestamp( $exptime );
- }
- // (bug 24425) use a replace if the db supports it instead of
- // delete/insert to avoid clashes with conflicting keynames
- $db->replace(
- $tableName,
- array( 'keyname' ),
- array(
- 'keyname' => $key,
- 'value' => $db->encodeBlob( $this->serialize( $value ) ),
- 'exptime' => $encExpiry
- ), __METHOD__ );
- } catch ( DBError $e ) {
- $this->handleWriteError( $e, $serverIndex );
- return false;
- }
-
- return true;
+ return $this->setMulti( array( $key => $value ), $exptime );
}
/**
@@ -546,7 +510,7 @@ class SqlBagOStuff extends BagOStuff {
}
protected function garbageCollect() {
- if ( !$this->purgePeriod ) {
+ if ( !$this->purgePeriod || $this->slaveOnly ) {
// Disabled
return;
}
@@ -688,9 +652,9 @@ class SqlBagOStuff extends BagOStuff {
*/
protected function unserialize( $serial ) {
if ( function_exists( 'gzinflate' ) ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$decomp = gzinflate( $serial );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( false !== $decomp ) {
$serial = $decomp;
@@ -758,6 +722,8 @@ class SqlBagOStuff extends BagOStuff {
* @param int $serverIndex
*/
protected function markServerDown( $exception, $serverIndex ) {
+ unset( $this->conns[$serverIndex] ); // bug T103435
+
if ( isset( $this->connFailureTimes[$serverIndex] ) ) {
if ( time() - $this->connFailureTimes[$serverIndex] >= 60 ) {
unset( $this->connFailureTimes[$serverIndex] );
diff --git a/includes/page/Article.php b/includes/page/Article.php
index 4cde5ad8..56b9520a 100644
--- a/includes/page/Article.php
+++ b/includes/page/Article.php
@@ -333,7 +333,9 @@ class Article implements Page {
* @return string|bool String containing article contents, or false if null
* @deprecated since 1.21, use WikiPage::getContent() instead
*/
- function fetchContent() { #BC cruft!
+ function fetchContent() {
+ // BC cruft!
+
ContentHandler::deprecated( __METHOD__, '1.21' );
if ( $this->mContentLoaded && $this->mContent ) {
@@ -572,7 +574,7 @@ class Article implements Page {
}
# Should the parser cache be used?
- $useParserCache = $this->mPage->isParserCacheUsed( $parserOptions, $oldid );
+ $useParserCache = $this->mPage->shouldCheckParserCache( $parserOptions, $oldid );
wfDebug( 'Article::view using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
if ( $user->getStubThreshold() ) {
$this->getContext()->getStats()->increment( 'pcache_miss_stub' );
@@ -998,7 +1000,7 @@ class Article implements Page {
$outputPage->addModules( 'mediawiki.action.view.redirect' );
// Add a <link rel="canonical"> tag
- $outputPage->setCanonicalUrl( $this->getTitle()->getLocalURL() );
+ $outputPage->setCanonicalUrl( $this->getTitle()->getCanonicalURL() );
// Tell the output object that the user arrived at this article through a redirect
$outputPage->setRedirectedFrom( $this->mRedirectedFrom );
@@ -1089,11 +1091,6 @@ class Article implements Page {
// to get the recentchanges row belonging to that entry
// (with rc_new = 1).
- // Check for cached results
- if ( $cache->get( wfMemcKey( 'NotPatrollablePage', $this->getTitle()->getArticleID() ) ) ) {
- return false;
- }
-
if ( $this->mRevision
&& !RecentChange::isInRCLifespan( $this->mRevision->getTimestamp(), 21600 )
) {
@@ -1102,6 +1099,12 @@ class Article implements Page {
return false;
}
+ // Check for cached results
+ $key = wfMemcKey( 'NotPatrollablePage', $this->getTitle()->getArticleID() );
+ if ( $cache->get( $key ) ) {
+ return false;
+ }
+
$dbr = wfGetDB( DB_SLAVE );
$oldestRevisionTimestamp = $dbr->selectField(
'revision',
@@ -1119,20 +1122,30 @@ class Article implements Page {
'rc_new' => 1,
'rc_timestamp' => $oldestRevisionTimestamp,
'rc_namespace' => $this->getTitle()->getNamespace(),
- 'rc_cur_id' => $this->getTitle()->getArticleID(),
- 'rc_patrolled' => 0
+ 'rc_cur_id' => $this->getTitle()->getArticleID()
),
__METHOD__,
array( 'USE INDEX' => 'new_name_timestamp' )
);
+ } else {
+ // Cache the information we gathered above in case we can't patrol
+ // Don't cache in case we can patrol as this could change
+ $cache->set( $key, '1' );
}
if ( !$rc ) {
- // No RC entry around
+ // Don't cache: This can be hit if the page gets accessed very fast after
+ // its creation or in case we have high slave lag. In case the revision is
+ // too old, we will already return above.
+ return false;
+ }
+
+ if ( $rc->getAttribute( 'rc_patrolled' ) ) {
+ // Patrolled RC entry around
// Cache the information we gathered above in case we can't patrol
// Don't cache in case we can patrol as this could change
- $cache->set( wfMemcKey( 'NotPatrollablePage', $this->getTitle()->getArticleID() ), '1' );
+ $cache->set( $key, '1' );
return false;
}
@@ -1222,23 +1235,38 @@ class Article implements Page {
Hooks::run( 'ShowMissingArticle', array( $this ) );
- // Give extensions a chance to hide their (unrelated) log entries
- $logTypes = array( 'delete', 'move' );
- $conds = array( "log_action != 'revision'" );
- Hooks::run( 'Article::MissingArticleConditions', array( &$conds, $logTypes ) );
-
- # Show delete and move logs
- LogEventsList::showLogExtract( $outputPage, $logTypes, $title, '',
- array( 'lim' => 10,
- 'conds' => $conds,
- 'showIfEmpty' => false,
- 'msgKey' => array( 'moveddeleted-notice' ) )
- );
+ # Show delete and move logs if there were any such events.
+ # The logging query can DOS the site when bots/crawlers cause 404 floods,
+ # so be careful showing this. 404 pages must be cheap as they are hard to cache.
+ $cache = ObjectCache::getMainStashInstance();
+ $key = wfMemcKey( 'page-recent-delete', md5( $title->getPrefixedText() ) );
+ $loggedIn = $this->getContext()->getUser()->isLoggedIn();
+ if ( $loggedIn || $cache->get( $key ) ) {
+ $logTypes = array( 'delete', 'move' );
+ $conds = array( "log_action != 'revision'" );
+ // Give extensions a chance to hide their (unrelated) log entries
+ Hooks::run( 'Article::MissingArticleConditions', array( &$conds, $logTypes ) );
+ LogEventsList::showLogExtract(
+ $outputPage,
+ $logTypes,
+ $title,
+ '',
+ array(
+ 'lim' => 10,
+ 'conds' => $conds,
+ 'showIfEmpty' => false,
+ 'msgKey' => array( $loggedIn
+ ? 'moveddeleted-notice'
+ : 'moveddeleted-notice-recent'
+ )
+ )
+ );
+ }
if ( !$this->mPage->hasViewableContent() && $wgSend404Code && !$validUserPage ) {
// If there's no backing content, send a 404 Not Found
// for better machine handling of broken links.
- $this->getContext()->getRequest()->response()->header( "HTTP/1.1 404 Not Found" );
+ $this->getContext()->getRequest()->response()->statusHeader( 404 );
}
// Also apply the robot policy for nonexisting pages (even if a 404 was used for sanity)
@@ -1254,22 +1282,28 @@ class Article implements Page {
# Show error message
$oldid = $this->getOldID();
- if ( $oldid ) {
- $text = wfMessage( 'missing-revision', $oldid )->plain();
- } elseif ( $title->getNamespace() === NS_MEDIAWIKI ) {
- // Use the default message text
- $text = $title->getDefaultMessageText();
- } elseif ( $title->quickUserCan( 'create', $this->getContext()->getUser() )
- && $title->quickUserCan( 'edit', $this->getContext()->getUser() )
- ) {
- $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
- $text = wfMessage( $message )->plain();
+ if ( !$oldid && $title->getNamespace() === NS_MEDIAWIKI && $title->hasSourceText() ) {
+ $outputPage->addParserOutput( $this->getContentObject()->getParserOutput( $title ) );
} else {
- $text = wfMessage( 'noarticletext-nopermission' )->plain();
- }
- $text = "<div class='noarticletext'>\n$text\n</div>";
+ if ( $oldid ) {
+ $text = wfMessage( 'missing-revision', $oldid )->plain();
+ } elseif ( $title->quickUserCan( 'create', $this->getContext()->getUser() )
+ && $title->quickUserCan( 'edit', $this->getContext()->getUser() )
+ ) {
+ $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon';
+ $text = wfMessage( $message )->plain();
+ } else {
+ $text = wfMessage( 'noarticletext-nopermission' )->plain();
+ }
- $outputPage->addWikiText( $text );
+ $dir = $this->getContext()->getLanguage()->getDir();
+ $lang = $this->getContext()->getLanguage()->getCode();
+ $outputPage->addWikiText( Xml::openElement( 'div', array(
+ 'class' => "noarticletext mw-content-$dir",
+ 'dir' => $dir,
+ 'lang' => $lang,
+ ) ) . "\n$text\n</div>" );
+ }
}
/**
@@ -1704,10 +1738,8 @@ class Article implements Page {
if ( $user->isAllowed( 'suppressrevision' ) ) {
$suppress = Html::openElement( 'div', array( 'id' => 'wpDeleteSuppressRow' ) ) .
- "<strong>" .
- Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
- 'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '4' ) ) .
- "</strong>" .
+ Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
+ 'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '4' ) ) .
Html::closeElement( 'div' );
} else {
$suppress = '';
@@ -1772,9 +1804,8 @@ class Article implements Page {
Xml::closeElement( 'form' );
if ( $user->isAllowed( 'editinterface' ) ) {
- $dropdownTitle = Title::makeTitle( NS_MEDIAWIKI, 'Deletereason-dropdown' );
- $link = Linker::link(
- $dropdownTitle,
+ $link = Linker::linkKnown(
+ $ctx->msg( 'deletereason-dropdown' )->inContentLanguage()->getTitle(),
wfMessage( 'delete-edit-reasonlist' )->escaped(),
array(),
array( 'action' => 'edit' )
@@ -1796,8 +1827,10 @@ class Article implements Page {
*/
public function doDelete( $reason, $suppress = false ) {
$error = '';
- $outputPage = $this->getContext()->getOutput();
- $status = $this->mPage->doDeleteArticleReal( $reason, $suppress, 0, true, $error );
+ $context = $this->getContext();
+ $outputPage = $context->getOutput();
+ $user = $context->getUser();
+ $status = $this->mPage->doDeleteArticleReal( $reason, $suppress, 0, true, $error, $user );
if ( $status->isGood() ) {
$deleted = $this->getTitle()->getPrefixedText();
diff --git a/includes/page/ImagePage.php b/includes/page/ImagePage.php
index 8f635cfa..9b9e3cbd 100644
--- a/includes/page/ImagePage.php
+++ b/includes/page/ImagePage.php
@@ -219,6 +219,9 @@ class ImagePage extends Article {
}
// always show the local local Filepage.css, bug 29277
$out->addModuleStyles( 'filepage' );
+
+ // Add MediaWiki styles for a file page
+ $out->addModuleStyles( 'mediawiki.action.view.filepage' );
}
/**
@@ -296,7 +299,7 @@ class ImagePage extends Article {
}
protected function openShowImage() {
- global $wgEnableUploads, $wgSend404Code;
+ global $wgEnableUploads, $wgSend404Code, $wgSVGMaxSize;
$this->loadFile();
$out = $this->getContext()->getOutput();
@@ -351,7 +354,7 @@ class ImagePage extends Article {
);
$linktext = $this->getContext()->msg( 'show-big-image' )->escaped();
- $thumbSizes = $this->getThumbSizes( $width, $height, $width_orig, $height_orig );
+ $thumbSizes = $this->getThumbSizes( $width_orig, $height_orig );
# Generate thumbnails or thumbnail links as needed...
$otherSizes = array();
foreach ( $thumbSizes as $size ) {
@@ -361,10 +364,12 @@ class ImagePage extends Article {
// the current thumbnail's size ($width/$height)
// since that is added to the message separately, so
// it can be denoted as the current size being shown.
- // Vectorized images are "infinitely" big, so all thumb
- // sizes are shown.
+ // Vectorized images are limited by $wgSVGMaxSize big,
+ // so all thumbs less than or equal that are shown.
if ( ( ( $size[0] <= $width_orig && $size[1] <= $height_orig )
- || $this->displayImg->isVectorized() )
+ || ( $this->displayImg->isVectorized()
+ && max( $size[0], $size[1] ) <= $wgSVGMaxSize )
+ )
&& $size[0] != $width && $size[1] != $height
) {
$sizeLink = $this->makeSizeLink( $params, $size[0], $size[1] );
@@ -614,8 +619,8 @@ EOT
$out->wrapWikiMsg( "<div id='mw-imagepage-nofile' class='plainlinks'>\n$1\n</div>", $nofile );
if ( !$this->getID() && $wgSend404Code ) {
// If there is no image, no shared image, and no description page,
- // output a 404, to be consistent with articles.
- $request->response()->header( 'HTTP/1.1 404 Not Found' );
+ // output a 404, to be consistent with Article::showMissingArticle.
+ $request->response()->statusHeader( 404 );
}
}
$out->setFileVersion( $this->displayImg );
@@ -704,10 +709,10 @@ EOT
$out->addHTML( "<ul>\n" );
# "Upload a new version of this file" link
- $canUpload = $this->getTitle()->userCan( 'upload', $this->getContext()->getUser() );
+ $canUpload = $this->getTitle()->quickUserCan( 'upload', $this->getContext()->getUser() );
if ( $canUpload && UploadBase::userCanReUpload(
$this->getContext()->getUser(),
- $this->mPage->getFile()->name )
+ $this->mPage->getFile() )
) {
$ulink = Linker::makeExternalLink(
$this->getUploadUrl(),
@@ -1515,6 +1520,18 @@ class ImageHistoryPseudoPager extends ReverseChronologicalPager {
$s = '';
$this->doQuery();
if ( count( $this->mHist ) ) {
+ if ( $this->mImg->isLocal() ) {
+ // Do a batch existence check for user pages and talkpages
+ $linkBatch = new LinkBatch();
+ for ( $i = $this->mRange[0]; $i <= $this->mRange[1]; $i++ ) {
+ $file = $this->mHist[$i];
+ $user = $file->getUser( 'text' );
+ $linkBatch->add( NS_USER, $user );
+ $linkBatch->add( NS_USER_TALK, $user );
+ }
+ $linkBatch->execute();
+ }
+
$list = new ImageHistoryList( $this->mImagePage );
# Generate prev/next links
$navLink = $this->getNavigationBar();
diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php
index 7c789249..d1cec60b 100644
--- a/includes/page/WikiPage.php
+++ b/includes/page/WikiPage.php
@@ -361,18 +361,18 @@ class WikiPage implements Page, IDBAccessObject {
return;
}
- if ( $from === self::READ_LOCKING ) {
- $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle, array( 'FOR UPDATE' ) );
- } elseif ( $from === self::READ_LATEST ) {
- $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
- } elseif ( $from === self::READ_NORMAL ) {
- $data = $this->pageDataFromTitle( wfGetDB( DB_SLAVE ), $this->mTitle );
+ if ( is_int( $from ) ) {
+ list( $index, $opts ) = DBAccessObjectUtils::getDBOptions( $from );
+ $data = $this->pageDataFromTitle( wfGetDB( $index ), $this->mTitle, $opts );
+
if ( !$data
+ && $index == DB_SLAVE
&& wfGetLB()->getServerCount() > 1
&& wfGetLB()->hasOrMadeRecentMasterChanges()
) {
$from = self::READ_LATEST;
- $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
+ list( $index, $opts ) = DBAccessObjectUtils::getDBOptions( $from );
+ $data = $this->pageDataFromTitle( wfGetDB( $index ), $this->mTitle, $opts );
}
} else {
// No idea from where the caller got this data, assume slave database.
@@ -1082,16 +1082,13 @@ class WikiPage implements Page, IDBAccessObject {
* Should the parser cache be used?
*
* @param ParserOptions $parserOptions ParserOptions to check
- * @param int $oldid
+ * @param int $oldId
* @return bool
*/
- public function isParserCacheUsed( ParserOptions $parserOptions, $oldid ) {
- global $wgEnableParserCache;
-
- return $wgEnableParserCache
- && $parserOptions->getStubThreshold() == 0
+ public function shouldCheckParserCache( ParserOptions $parserOptions, $oldId ) {
+ return $parserOptions->getStubThreshold() == 0
&& $this->exists()
- && ( $oldid === null || $oldid === 0 || $oldid === $this->getLatest() )
+ && ( $oldId === null || $oldId === 0 || $oldId === $this->getLatest() )
&& $this->getContentHandler()->isParserCacheSupported();
}
@@ -1108,10 +1105,10 @@ class WikiPage implements Page, IDBAccessObject {
*/
public function getParserOutput( ParserOptions $parserOptions, $oldid = null ) {
- $useParserCache = $this->isParserCacheUsed( $parserOptions, $oldid );
+ $useParserCache = $this->shouldCheckParserCache( $parserOptions, $oldid );
wfDebug( __METHOD__ . ': using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
if ( $parserOptions->getStubThreshold() ) {
- wfIncrStats( 'pcache_miss_stub' );
+ wfIncrStats( 'pcache.miss.stub' );
}
if ( $useParserCache ) {
@@ -1143,7 +1140,12 @@ class WikiPage implements Page, IDBAccessObject {
Hooks::run( 'PageViewUpdates', array( $this, $user ) );
// Update newtalk / watchlist notification status
- $user->clearNotification( $this->mTitle, $oldid );
+ try {
+ $user->clearNotification( $this->mTitle, $oldid );
+ } catch ( DBError $e ) {
+ // Avoid outage if the master is not reachable
+ MWExceptionHandler::logException( $e );
+ }
}
/**
@@ -1151,28 +1153,24 @@ class WikiPage implements Page, IDBAccessObject {
* @return bool
*/
public function doPurge() {
- global $wgUseSquid;
-
if ( !Hooks::run( 'ArticlePurge', array( &$this ) ) ) {
return false;
}
- // Invalidate the cache
- $this->mTitle->invalidateCache();
-
- if ( $wgUseSquid ) {
- // Commit the transaction before the purge is sent
- $dbw = wfGetDB( DB_MASTER );
- $dbw->commit( __METHOD__ );
-
- // Send purge
- $update = SquidUpdate::newSimplePurge( $this->mTitle );
- $update->doUpdate();
- }
+ $title = $this->mTitle;
+ wfGetDB( DB_MASTER )->onTransactionIdle( function() use ( $title ) {
+ global $wgUseSquid;
+ // Invalidate the cache in auto-commit mode
+ $title->invalidateCache();
+ if ( $wgUseSquid ) {
+ // Send purge now that page_touched update was committed above
+ $update = SquidUpdate::newSimplePurge( $title );
+ $update->doUpdate();
+ }
+ } );
if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
// @todo move this logic to MessageCache
-
if ( $this->exists() ) {
// NOTE: use transclusion text for messages.
// This is consistent with MessageCache::getMsgFromNamespace()
@@ -1189,6 +1187,7 @@ class WikiPage implements Page, IDBAccessObject {
MessageCache::singleton()->replace( $this->mTitle->getDBkey(), $text );
}
+
return true;
}
@@ -1200,10 +1199,9 @@ class WikiPage implements Page, IDBAccessObject {
* Best if all done inside a transaction.
*
* @param DatabaseBase $dbw
- * @return int The newly created page_id key, or false if the title already existed
+ * @return int|bool The newly created page_id key; false if the title already existed
*/
public function insertOn( $dbw ) {
-
$page_id = $dbw->nextSequenceValue( 'page_page_id_seq' );
$dbw->insert( 'page', array(
'page_id' => $page_id,
@@ -1224,9 +1222,11 @@ class WikiPage implements Page, IDBAccessObject {
$newid = $dbw->insertId();
$this->mId = $newid;
$this->mTitle->resetArticleID( $newid );
- }
- return $affected ? $newid : false;
+ return $newid;
+ } else {
+ return false;
+ }
}
/**
@@ -1265,10 +1265,9 @@ class WikiPage implements Page, IDBAccessObject {
$conditions['page_latest'] = $lastRevision;
}
- $now = wfTimestampNow();
$row = array( /* SET */
'page_latest' => $revision->getId(),
- 'page_touched' => $dbw->timestamp( $now ),
+ 'page_touched' => $dbw->timestamp( $revision->getTimestamp() ),
'page_is_new' => ( $lastRevision === 0 ) ? 1 : 0,
'page_is_redirect' => $rt !== null ? 1 : 0,
'page_len' => $len,
@@ -1690,6 +1689,7 @@ class WikiPage implements Page, IDBAccessObject {
* revision: The revision object for the inserted revision, or null.
*
* @since 1.21
+ * @throws MWException
*/
public function doEditContent( Content $content, $summary, $flags = 0, $baseRevId = false,
User $user = null, $serialFormat = null
@@ -1765,7 +1765,6 @@ class WikiPage implements Page, IDBAccessObject {
$dbw = wfGetDB( DB_MASTER );
$now = wfTimestampNow();
- $this->mTimestamp = $now;
if ( $flags & EDIT_UPDATE ) {
// Update article, but only if changed.
@@ -1801,57 +1800,50 @@ class WikiPage implements Page, IDBAccessObject {
if ( $changed ) {
$dbw->begin( __METHOD__ );
- try {
- $prepStatus = $content->prepareSave( $this, $flags, $oldid, $user );
- $status->merge( $prepStatus );
+ $prepStatus = $content->prepareSave( $this, $flags, $oldid, $user );
+ $status->merge( $prepStatus );
- if ( !$status->isOK() ) {
- $dbw->rollback( __METHOD__ );
+ if ( !$status->isOK() ) {
+ $dbw->rollback( __METHOD__ );
- return $status;
- }
- $revisionId = $revision->insertOn( $dbw );
+ return $status;
+ }
+ $revisionId = $revision->insertOn( $dbw );
- // Update page
- //
- // We check for conflicts by comparing $oldid with the current latest revision ID.
- $ok = $this->updateRevisionOn( $dbw, $revision, $oldid, $oldIsRedirect );
+ // Update page
+ //
+ // We check for conflicts by comparing $oldid with the current latest revision ID.
+ $ok = $this->updateRevisionOn( $dbw, $revision, $oldid, $oldIsRedirect );
- if ( !$ok ) {
- // Belated edit conflict! Run away!!
- $status->fatal( 'edit-conflict' );
+ if ( !$ok ) {
+ // Belated edit conflict! Run away!!
+ $status->fatal( 'edit-conflict' );
- $dbw->rollback( __METHOD__ );
+ $dbw->rollback( __METHOD__ );
- return $status;
- }
+ return $status;
+ }
- Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) );
- // Update recentchanges
- if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
- // Mark as patrolled if the user can do so
- $patrolled = $wgUseRCPatrol && !count(
- $this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) );
- // Add RC row to the DB
- $rc = RecentChange::notifyEdit( $now, $this->mTitle, $isminor, $user, $summary,
- $oldid, $this->getTimestamp(), $bot, '', $oldsize, $newsize,
- $revisionId, $patrolled
- );
+ Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) );
- // Log auto-patrolled edits
- if ( $patrolled ) {
- PatrolLog::record( $rc, true, $user );
- }
- }
- $user->incEditCount();
- } catch ( Exception $e ) {
- $dbw->rollback( __METHOD__ );
- // Question: Would it perhaps be better if this method turned all
- // exceptions into $status's?
- throw $e;
+ // Update recentchanges
+ if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
+ // Mark as patrolled if the user can do so
+ $patrolled = $wgUseRCPatrol && !count(
+ $this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) );
+ // Add RC row to the DB
+ RecentChange::notifyEdit(
+ $now, $this->mTitle, $isminor, $user, $summary,
+ $oldid, $this->getTimestamp(), $bot, '', $oldsize, $newsize,
+ $revisionId, $patrolled
+ );
}
+
+ $user->incEditCount();
+
$dbw->commit( __METHOD__ );
+ $this->mTimestamp = $now;
} else {
// Bug 32948: revision ID must be set to page {{REVISIONID}} and
// related variables correctly
@@ -1873,86 +1865,80 @@ class WikiPage implements Page, IDBAccessObject {
$revision = null;
// Update page_touched, this is usually implicit in the page update
// Other cache updates are done in onArticleEdit()
- $this->mTitle->invalidateCache();
+ $this->mTitle->invalidateCache( $now );
}
} else {
// Create new article
$status->value['new'] = true;
$dbw->begin( __METHOD__ );
- try {
- $prepStatus = $content->prepareSave( $this, $flags, $oldid, $user );
- $status->merge( $prepStatus );
+ $prepStatus = $content->prepareSave( $this, $flags, $oldid, $user );
+ $status->merge( $prepStatus );
- if ( !$status->isOK() ) {
- $dbw->rollback( __METHOD__ );
+ if ( !$status->isOK() ) {
+ $dbw->rollback( __METHOD__ );
- return $status;
- }
+ return $status;
+ }
- $status->merge( $prepStatus );
+ $status->merge( $prepStatus );
- // Add the page record; stake our claim on this title!
- // This will return false if the article already exists
- $newid = $this->insertOn( $dbw );
+ // Add the page record; stake our claim on this title!
+ // This will return false if the article already exists
+ $newid = $this->insertOn( $dbw );
- if ( $newid === false ) {
- $dbw->rollback( __METHOD__ );
- $status->fatal( 'edit-already-exists' );
+ if ( $newid === false ) {
+ $dbw->rollback( __METHOD__ );
+ $status->fatal( 'edit-already-exists' );
- return $status;
- }
+ return $status;
+ }
- // Save the revision text...
- $revision = new Revision( array(
- 'page' => $newid,
- 'title' => $this->getTitle(), // for determining the default content model
- 'comment' => $summary,
- 'minor_edit' => $isminor,
- 'text' => $serialized,
- 'len' => $newsize,
- 'user' => $user->getId(),
- 'user_text' => $user->getName(),
- 'timestamp' => $now,
- 'content_model' => $content->getModel(),
- 'content_format' => $serialFormat,
- ) );
- $revisionId = $revision->insertOn( $dbw );
+ // Save the revision text...
+ $revision = new Revision( array(
+ 'page' => $newid,
+ 'title' => $this->getTitle(), // for determining the default content model
+ 'comment' => $summary,
+ 'minor_edit' => $isminor,
+ 'text' => $serialized,
+ 'len' => $newsize,
+ 'user' => $user->getId(),
+ 'user_text' => $user->getName(),
+ 'timestamp' => $now,
+ 'content_model' => $content->getModel(),
+ 'content_format' => $serialFormat,
+ ) );
+ $revisionId = $revision->insertOn( $dbw );
- // Bug 37225: use accessor to get the text as Revision may trim it
- $content = $revision->getContent(); // sanity; get normalized version
+ // Bug 37225: use accessor to get the text as Revision may trim it
+ $content = $revision->getContent(); // sanity; get normalized version
- if ( $content ) {
- $newsize = $content->getSize();
- }
+ if ( $content ) {
+ $newsize = $content->getSize();
+ }
- // Update the page record with revision data
- $this->updateRevisionOn( $dbw, $revision, 0 );
+ // Update the page record with revision data
+ $this->updateRevisionOn( $dbw, $revision, 0 );
- Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
+ Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
- // Update recentchanges
- if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
- // Mark as patrolled if the user can do so
- $patrolled = ( $wgUseRCPatrol || $wgUseNPPatrol ) && !count(
- $this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) );
- // Add RC row to the DB
- $rc = RecentChange::notifyNew( $now, $this->mTitle, $isminor, $user, $summary, $bot,
- '', $newsize, $revisionId, $patrolled );
+ // Update recentchanges
+ if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
+ // Mark as patrolled if the user can do so
+ $patrolled = ( $wgUseRCPatrol || $wgUseNPPatrol ) && !count(
+ $this->mTitle->getUserPermissionsErrors( 'autopatrol', $user ) );
+ // Add RC row to the DB
+ RecentChange::notifyNew(
+ $now, $this->mTitle, $isminor, $user, $summary, $bot,
+ '', $newsize, $revisionId, $patrolled
+ );
+ }
- // Log auto-patrolled edits
- if ( $patrolled ) {
- PatrolLog::record( $rc, true, $user );
- }
- }
- $user->incEditCount();
+ $user->incEditCount();
- } catch ( Exception $e ) {
- $dbw->rollback( __METHOD__ );
- throw $e;
- }
$dbw->commit( __METHOD__ );
+ $this->mTimestamp = $now;
// Update links, etc.
$this->doEditUpdates( $revision, $user, array( 'created' => true ) );
@@ -1973,13 +1959,13 @@ class WikiPage implements Page, IDBAccessObject {
$status->value['revision'] = $revision;
$hook_args = array( &$this, &$user, $content, $summary,
- $flags & EDIT_MINOR, null, null, &$flags, $revision, &$status, $baseRevId );
+ $flags & EDIT_MINOR, null, null, &$flags, $revision, &$status, $baseRevId );
ContentHandler::runLegacyHooks( 'ArticleSaveComplete', $hook_args );
Hooks::run( 'PageContentSaveComplete', $hook_args );
// Promote user to any groups they meet the criteria for
- $dbw->onTransactionIdle( function () use ( $user ) {
+ DeferredUpdates::addCallableUpdate( function () use ( $user ) {
$user->addAutopromoteOnceGroups( 'onEdit' );
$user->addAutopromoteOnceGroups( 'onView' ); // b/c
} );
@@ -2079,7 +2065,7 @@ class WikiPage implements Page, IDBAccessObject {
}
// The edit may have already been prepared via api.php?action=stashedit
- $cachedEdit = $useCache && $wgAjaxEditStash
+ $cachedEdit = $useCache && $wgAjaxEditStash && !$user->isAllowed( 'bot' )
? ApiStashEdit::checkCache( $this->getTitle(), $content, $user )
: false;
@@ -2164,8 +2150,6 @@ class WikiPage implements Page, IDBAccessObject {
* - 'no-change': don't update the article count, ever
*/
public function doEditUpdates( Revision $revision, User $user, array $options = array() ) {
- global $wgEnableParserCache;
-
$options += array(
'changed' => true,
'created' => false,
@@ -2185,31 +2169,30 @@ class WikiPage implements Page, IDBAccessObject {
$editInfo = $this->mPreparedEdit;
}
- // Save it to the parser cache
- if ( $wgEnableParserCache ) {
- $parserCache = ParserCache::singleton();
- $parserCache->save(
- $editInfo->output, $this, $editInfo->popts, $editInfo->timestamp, $editInfo->revid
- );
- }
+ // Save it to the parser cache.
+ // Make sure the cache time matches page_touched to avoid double parsing.
+ ParserCache::singleton()->save(
+ $editInfo->output, $this, $editInfo->popts,
+ $revision->getTimestamp(), $editInfo->revid
+ );
// Update the links tables and other secondary data
if ( $content ) {
$recursive = $options['changed']; // bug 50785
$updates = $content->getSecondaryDataUpdates(
$this->getTitle(), null, $recursive, $editInfo->output );
- DataUpdate::runUpdates( $updates );
+ foreach ( $updates as $update ) {
+ DeferredUpdates::addUpdate( $update );
+ }
}
Hooks::run( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
if ( Hooks::run( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) {
- JobQueueGroup::singleton()->push( array(
- // Flush old entries from the `recentchanges` table
- RecentChangesUpdateJob::newPurgeJob(),
- // Update the cached list of active users
- RecentChangesUpdateJob::newCacheUpdateJob()
- ) );
+ // Flush old entries from the `recentchanges` table
+ if ( mt_rand( 0, 9 ) == 0 ) {
+ JobQueueGroup::singleton()->lazyPush( RecentChangesUpdateJob::newPurgeJob() );
+ }
}
if ( !$this->exists() ) {
@@ -2276,9 +2259,8 @@ class WikiPage implements Page, IDBAccessObject {
if ( $options['created'] ) {
self::onArticleCreate( $this->mTitle );
} elseif ( $options['changed'] ) { // bug 50785
- self::onArticleEdit( $this->mTitle );
+ self::onArticleEdit( $this->mTitle, $revision );
}
-
}
/**
@@ -2375,8 +2357,8 @@ class WikiPage implements Page, IDBAccessObject {
$dbw = wfGetDB( DB_MASTER );
foreach ( $restrictionTypes as $action ) {
- if ( !isset( $expiry[$action] ) ) {
- $expiry[$action] = $dbw->getInfinity();
+ if ( !isset( $expiry[$action] ) || $expiry[$action] === $dbw->getInfinity() ) {
+ $expiry[$action] = 'infinity';
}
if ( !isset( $limit[$action] ) ) {
$limit[$action] = '';
@@ -2616,10 +2598,8 @@ class WikiPage implements Page, IDBAccessObject {
*/
protected function formatExpiry( $expiry ) {
global $wgContLang;
- $dbr = wfGetDB( DB_SLAVE );
- $encodedExpiry = $dbr->encodeExpiry( $expiry );
- if ( $encodedExpiry != 'infinity' ) {
+ if ( $expiry != 'infinity' ) {
return wfMessage(
'protect-expiring',
$wgContLang->timeanddate( $expiry, false, false ),
@@ -2784,9 +2764,16 @@ class WikiPage implements Page, IDBAccessObject {
$dbw->begin( __METHOD__ );
if ( $id == 0 ) {
- $this->loadPageData( 'forupdate' );
+ // T98706: lock the page from various other updates but avoid using
+ // WikiPage::READ_LOCKING as that will carry over the FOR UPDATE to
+ // the revisions queries (which also JOIN on user). Only lock the page
+ // row and CAS check on page_latest to see if the trx snapshot matches.
+ $latest = $this->lock();
+
+ $this->loadPageData( WikiPage::READ_LATEST );
$id = $this->getID();
- if ( $id == 0 ) {
+ if ( $id == 0 || $this->getLatest() != $latest ) {
+ // Page not there or trx snapshot is stale
$dbw->rollback( __METHOD__ );
$status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
return $status;
@@ -2868,7 +2855,7 @@ class WikiPage implements Page, IDBAccessObject {
// Clone the title, so we have the information we need when we log
$logTitle = clone $this->mTitle;
- // Log the deletion, if the page was suppressed, log it at Oversight instead
+ // Log the deletion, if the page was suppressed, put it in the suppression log instead
$logtype = $suppress ? 'suppress' : 'delete';
$logEntry = new ManualLogEntry( $logtype, 'delete' );
@@ -2886,6 +2873,10 @@ class WikiPage implements Page, IDBAccessObject {
$dbw->commit( __METHOD__ );
}
+ // Show log excerpt on 404 pages rather than just a link
+ $key = wfMemcKey( 'page-recent-delete', md5( $logTitle->getPrefixedText() ) );
+ ObjectCache::getMainStashInstance()->set( $key, 1, 86400 );
+
$this->doDeleteUpdates( $id, $content );
Hooks::run( 'ArticleDeleteComplete', array( &$this, &$user, $reason, $id, $content, $logEntry ) );
@@ -2894,6 +2885,24 @@ class WikiPage implements Page, IDBAccessObject {
}
/**
+ * Lock the page row for this title and return page_latest (or 0)
+ *
+ * @return integer
+ */
+ protected function lock() {
+ return (int)wfGetDB( DB_MASTER )->selectField(
+ 'page',
+ 'page_latest',
+ array(
+ 'page_namespace' => $this->getTitle()->getNamespace(),
+ 'page_title' => $this->getTitle()->getDBkey()
+ ),
+ __METHOD__,
+ array( 'FOR UPDATE' )
+ );
+ }
+
+ /**
* Do some database updates after deletion
*
* @param int $id The page_id value of the page being deleted
@@ -3021,7 +3030,7 @@ class WikiPage implements Page, IDBAccessObject {
) );
}
- // Get the last edit not by this guy...
+ // Get the last edit not by this person...
// Note: these may not be public values
$user = intval( $current->getUser( Revision::RAW ) );
$user_text = $dbw->addQuotes( $current->getUserText( Revision::RAW ) );
@@ -3043,29 +3052,6 @@ class WikiPage implements Page, IDBAccessObject {
return array( array( 'notvisiblerev' ) );
}
- // Set patrolling and bot flag on the edits, which gets rollbacked.
- // This is done before the rollback edit to have patrolling also on failure (bug 62157).
- $set = array();
- if ( $bot && $guser->isAllowed( 'markbotedits' ) ) {
- // Mark all reverted edits as bot
- $set['rc_bot'] = 1;
- }
-
- if ( $wgUseRCPatrol ) {
- // Mark all reverted edits as patrolled
- $set['rc_patrolled'] = 1;
- }
-
- if ( count( $set ) ) {
- $dbw->update( 'recentchanges', $set,
- array( /* WHERE */
- 'rc_cur_id' => $current->getPage(),
- 'rc_user_text' => $current->getUserText(),
- 'rc_timestamp > ' . $dbw->addQuotes( $s->rev_timestamp ),
- ), __METHOD__
- );
- }
-
// Generate the edit summary if necessary
$target = Revision::newFromId( $s->rev_id, Revision::READ_LATEST );
if ( empty( $summary ) ) {
@@ -3114,6 +3100,30 @@ class WikiPage implements Page, IDBAccessObject {
$guser
);
+ // Set patrolling and bot flag on the edits, which gets rollbacked.
+ // This is done even on edit failure to have patrolling in that case (bug 62157).
+ $set = array();
+ if ( $bot && $guser->isAllowed( 'markbotedits' ) ) {
+ // Mark all reverted edits as bot
+ $set['rc_bot'] = 1;
+ }
+
+ if ( $wgUseRCPatrol ) {
+ // Mark all reverted edits as patrolled
+ $set['rc_patrolled'] = 1;
+ }
+
+ if ( count( $set ) ) {
+ $dbw->update( 'recentchanges', $set,
+ array( /* WHERE */
+ 'rc_cur_id' => $current->getPage(),
+ 'rc_user_text' => $current->getUserText(),
+ 'rc_timestamp > ' . $dbw->addQuotes( $s->rev_timestamp ),
+ ),
+ __METHOD__
+ );
+ }
+
if ( !$status->isOK() ) {
return $status->getErrorsArray();
}
@@ -3157,7 +3167,6 @@ class WikiPage implements Page, IDBAccessObject {
// Update existence markers on article/talk tabs...
$other = $title->getOtherPage();
- $other->invalidateCache();
$other->purgeSquid();
$title->touchLinks();
@@ -3174,7 +3183,6 @@ class WikiPage implements Page, IDBAccessObject {
// Update existence markers on article/talk tabs...
$other = $title->getOtherPage();
- $other->invalidateCache();
$other->purgeSquid();
$title->touchLinks();
@@ -3211,20 +3219,24 @@ class WikiPage implements Page, IDBAccessObject {
* Purge caches on page update etc
*
* @param Title $title
+ * @param Revision|null $revision Revision that was just saved, may be null
*/
- public static function onArticleEdit( Title $title ) {
+ public static function onArticleEdit( Title $title, Revision $revision = null ) {
// Invalidate caches of articles which include this page
- DeferredUpdates::addHTMLCacheUpdate( $title, 'templatelinks' );
+ DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'templatelinks' ) );
// Invalidate the caches of all pages which redirect here
- DeferredUpdates::addHTMLCacheUpdate( $title, 'redirect' );
+ DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'redirect' ) );
// Purge squid for this page only
$title->purgeSquid();
-
// Clear file cache for this page only
HTMLFileCache::clearFileCache( $title );
- InfoAction::invalidateCache( $title );
+
+ $revid = $revision ? $revision->getId() : null;
+ DeferredUpdates::addCallableUpdate( function() use ( $title, $revid ) {
+ InfoAction::invalidateCache( $title, $revid );
+ } );
}
/**#@-*/
@@ -3411,13 +3423,14 @@ class WikiPage implements Page, IDBAccessObject {
// Check if the last link refresh was before page_touched
if ( $this->getLinksTimestamp() < $this->getTouched() ) {
- JobQueueGroup::singleton()->push( EnqueueJob::newFromLocalJobs(
- new JobSpecification( 'refreshLinks', $params, array(), $this->mTitle )
+ $params['isOpportunistic'] = true;
+ $params['rootJobTimestamp'] = $parserOutput->getCacheTime();
+
+ JobQueueGroup::singleton()->lazyPush( EnqueueJob::newFromLocalJobs(
+ new JobSpecification( 'refreshLinks', $params,
+ array( 'removeDuplicates' => true ), $this->mTitle )
) );
- return;
}
-
- return;
}
/**
diff --git a/includes/pager/ReverseChronologicalPager.php b/includes/pager/ReverseChronologicalPager.php
index 4f8c438d..ee6e26c0 100644
--- a/includes/pager/ReverseChronologicalPager.php
+++ b/includes/pager/ReverseChronologicalPager.php
@@ -113,6 +113,10 @@ abstract class ReverseChronologicalPager extends IndexPager {
$ymd = 20320101;
}
- $this->mOffset = $this->mDb->timestamp( "${ymd}000000" );
+ // Treat the given time in the wiki timezone and get a UTC timestamp for the database lookup
+ $timestamp = MWTimestamp::getInstance( "${ymd}000000" );
+ $timestamp->setTimeZone( $this->getConfig()->get( 'Localtimezone' ) );
+
+ $this->mOffset = $this->mDb->timestamp( $timestamp->getTimestamp() );
}
}
diff --git a/includes/pager/TablePager.php b/includes/pager/TablePager.php
index 80955398..ea619f1a 100644
--- a/includes/pager/TablePager.php
+++ b/includes/pager/TablePager.php
@@ -234,6 +234,13 @@ abstract class TablePager extends IndexPager {
}
/**
+ * @return stdClass
+ */
+ protected function getCurrentRow() {
+ return $this->mCurrentRow;
+ }
+
+ /**
* Get any extra attributes to be applied to the given cell. Don't
* take this as an excuse to hardcode styles; use classes and
* CSS instead. Row context is available in $this->mCurrentRow
diff --git a/includes/parser/CacheTime.php b/includes/parser/CacheTime.php
index 950c0d46..c4506897 100644
--- a/includes/parser/CacheTime.php
+++ b/includes/parser/CacheTime.php
@@ -47,7 +47,7 @@ class CacheTime {
/**
* setCacheTime() sets the timestamp expressing when the page has been rendered.
* This does not control expiry, see updateCacheExpiry() for that!
- * @param string $t
+ * @param string $t TS_MW timestamp
* @return string
*/
public function setCacheTime( $t ) {
diff --git a/includes/parser/CoreParserFunctions.php b/includes/parser/CoreParserFunctions.php
index 830a68fc..7639e2f8 100644
--- a/includes/parser/CoreParserFunctions.php
+++ b/includes/parser/CoreParserFunctions.php
@@ -41,7 +41,7 @@ class CoreParserFunctions {
$noHashFunctions = array(
'ns', 'nse', 'urlencode', 'lcfirst', 'ucfirst', 'lc', 'uc',
'localurl', 'localurle', 'fullurl', 'fullurle', 'canonicalurl',
- 'canonicalurle', 'formatnum', 'grammar', 'gender', 'plural',
+ 'canonicalurle', 'formatnum', 'grammar', 'gender', 'plural', 'bidi',
'numberofpages', 'numberofusers', 'numberofactiveusers',
'numberofarticles', 'numberoffiles', 'numberofadmins',
'numberingroup', 'numberofedits', 'language',
@@ -88,9 +88,13 @@ class CoreParserFunctions {
if ( strval( $part1 ) !== '' ) {
$args = array_slice( func_get_args(), 2 );
$message = wfMessage( $part1, $args )
- ->inLanguage( $parser->getOptions()->getUserLangObj() )->plain();
-
- return array( $message, 'noparse' => false );
+ ->inLanguage( $parser->getOptions()->getUserLangObj() );
+ if ( !$message->exists() ) {
+ // When message does not exists, the message name is surrounded by angle
+ // and can result in a tag, therefore escape the angles
+ return $message->escaped();
+ }
+ return array( $message->plain(), 'noparse' => false );
} else {
return array( 'found' => false );
}
@@ -178,7 +182,9 @@ class CoreParserFunctions {
default:
$func = 'urlencode';
}
- return $parser->markerSkipCallback( $s, $func );
+ // See T105242, where the choice to kill markers and various
+ // other options were discussed.
+ return $func( $parser->killMarkers( $s ) );
}
public static function lcfirst( $parser, $s = '' ) {
@@ -354,6 +360,15 @@ class CoreParserFunctions {
}
/**
+ * @param Parser $parser
+ * @param string $text
+ * @return string
+ */
+ public static function bidi( $parser, $text = '' ) {
+ return $parser->getFunctionLang()->embedBidi( $text );
+ }
+
+ /**
* Override the title of the page when viewed, provided we've been given a
* title which will normalise to the canonical title
*
diff --git a/includes/parser/LinkHolderArray.php b/includes/parser/LinkHolderArray.php
index 7026c5ce..b4ca7c8e 100644
--- a/includes/parser/LinkHolderArray.php
+++ b/includes/parser/LinkHolderArray.php
@@ -560,7 +560,6 @@ class LinkHolderArray {
// for each found variants, figure out link holders and replace
foreach ( $varRes as $s ) {
-
$variantTitle = Title::makeTitle( $s->page_namespace, $s->page_title );
$varPdbk = $variantTitle->getPrefixedDBkey();
$vardbk = $variantTitle->getDBkey();
diff --git a/includes/parser/MWTidy.php b/includes/parser/MWTidy.php
index d446ccf6..807842b6 100644
--- a/includes/parser/MWTidy.php
+++ b/includes/parser/MWTidy.php
@@ -22,93 +22,6 @@
*/
/**
- * Class used to hide mw:editsection tokens from Tidy so that it doesn't break them
- * or break on them. This is a bit of a hack for now, but hopefully in the future
- * we may create a real postprocessor or something that will replace this.
- * It's called wrapper because for now it basically takes over MWTidy::tidy's task
- * of wrapping the text in a xhtml block
- *
- * This re-uses some of the parser's UNIQ tricks, though some of it is private so it's
- * duplicated. Perhaps we should create an abstract marker hiding class.
- *
- * @ingroup Parser
- */
-class MWTidyWrapper {
-
- /**
- * @var ReplacementArray
- */
- protected $mTokens;
-
- protected $mUniqPrefix;
-
- protected $mMarkerIndex;
-
- public function __construct() {
- $this->mTokens = null;
- $this->mUniqPrefix = null;
- }
-
- /**
- * @param string $text
- * @return string
- */
- public function getWrapped( $text ) {
- $this->mTokens = new ReplacementArray;
- $this->mUniqPrefix = "\x7fUNIQ" .
- dechex( mt_rand( 0, 0x7fffffff ) ) . dechex( mt_rand( 0, 0x7fffffff ) );
- $this->mMarkerIndex = 0;
-
- // Replace <mw:editsection> elements with placeholders
- $wrappedtext = preg_replace_callback( ParserOutput::EDITSECTION_REGEX,
- array( &$this, 'replaceCallback' ), $text );
- // ...and <mw:toc> markers
- $wrappedtext = preg_replace_callback( '/\<\\/?mw:toc\>/',
- array( &$this, 'replaceCallback' ), $wrappedtext );
- // ... and <math> tags
- $wrappedtext = preg_replace_callback( '/\<math(.*?)\<\\/math\>/s',
- array( &$this, 'replaceCallback' ), $wrappedtext );
- // Modify inline Microdata <link> and <meta> elements so they say <html-link> and <html-meta> so
- // we can trick Tidy into not stripping them out by including them in tidy's new-empty-tags config
- $wrappedtext = preg_replace( '!<(link|meta)([^>]*?)(/{0,1}>)!', '<html-$1$2$3', $wrappedtext );
-
- // Wrap the whole thing in a doctype and body for Tidy.
- $wrappedtext = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' .
- ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>' .
- '<head><title>test</title></head><body>' . $wrappedtext . '</body></html>';
-
- return $wrappedtext;
- }
-
- /**
- * @param array $m
- *
- * @return string
- */
- public function replaceCallback( $m ) {
- $marker = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}" . Parser::MARKER_SUFFIX;
- $this->mMarkerIndex++;
- $this->mTokens->setPair( $marker, $m[0] );
- return $marker;
- }
-
- /**
- * @param string $text
- * @return string
- */
- public function postprocess( $text ) {
- // Revert <html-{link,meta}> back to <{link,meta}>
- $text = preg_replace( '!<html-(link|meta)([^>]*?)(/{0,1}>)!', '<$1$2$3', $text );
-
- // Restore the contents of placeholder tokens
- $text = $this->mTokens->replace( $text );
-
- return $text;
- }
-
-}
-
-/**
* Class to interact with HTML tidy
*
* Either the external tidy program or the in-process tidy extension
@@ -118,32 +31,24 @@ class MWTidyWrapper {
* @ingroup Parser
*/
class MWTidy {
+ private static $instance;
+
/**
- * Interface with html tidy, used if $wgUseTidy = true.
+ * Interface with html tidy.
* If tidy isn't able to correct the markup, the original will be
* returned in all its glory with a warning comment appended.
*
- * @param string $text Hideous HTML input
+ * @param string $text HTML input fragment. This should not contain a
+ * <body> or <html> tag.
* @return string Corrected HTML output
*/
public static function tidy( $text ) {
- $wrapper = new MWTidyWrapper;
- $wrappedtext = $wrapper->getWrapped( $text );
-
- $retVal = null;
- $correctedtext = self::clean( $wrappedtext, false, $retVal );
-
- if ( $retVal < 0 ) {
- wfDebug( "Possible tidy configuration error!\n" );
- return $text . "\n<!-- Tidy was unable to run -->\n";
- } elseif ( is_null( $correctedtext ) ) {
- wfDebug( "Tidy error detected!\n" );
- return $text . "\n<!-- Tidy found serious XHTML errors -->\n";
+ $driver = self::singleton();
+ if ( !$driver ) {
+ throw new MWException( __METHOD__.
+ ': tidy is disabled, caller should have checked MWTidy::isEnabled()' );
}
-
- $correctedtext = $wrapper->postprocess( $correctedtext ); // restore any hidden tokens
-
- return $correctedtext;
+ return $driver->tidy( $text );
}
/**
@@ -154,170 +59,80 @@ class MWTidy {
* @return bool Whether the HTML is valid
*/
public static function checkErrors( $text, &$errorStr = null ) {
- $retval = 0;
- $errorStr = self::clean( $text, true, $retval );
- return ( $retval < 0 && $errorStr == '' ) || $retval == 0;
+ $driver = self::singleton();
+ if ( !$driver ) {
+ throw new MWException( __METHOD__.
+ ': tidy is disabled, caller should have checked MWTidy::isEnabled()' );
+ }
+ if ( $driver->supportsValidate() ) {
+ return $driver->validate( $text, $errorStr );
+ } else {
+ throw new MWException( __METHOD__ . ": error text return from HHVM tidy is not supported" );
+ }
}
- /**
- * Perform a clean/repair operation
- * @param string $text HTML to check
- * @param bool $stderr Whether to read result from STDERR rather than STDOUT
- * @param int &$retval Exit code (-1 on internal error)
- * @return null|string
- * @throws MWException
- */
- private static function clean( $text, $stderr = false, &$retval = null ) {
- global $wgTidyInternal;
+ public static function isEnabled() {
+ return self::singleton() !== false;
+ }
- if ( $wgTidyInternal ) {
- if ( wfIsHHVM() ) {
- if ( $stderr ) {
- throw new MWException( __METHOD__ . ": error text return from HHVM tidy is not supported" );
+ protected static function singleton() {
+ global $wgUseTidy, $wgTidyInternal, $wgTidyConf, $wgDebugTidy, $wgTidyConfig,
+ $wgTidyBin, $wgTidyOpts;
+
+ if ( self::$instance === null ) {
+ if ( $wgTidyConfig !== null ) {
+ $config = $wgTidyConfig;
+ } elseif ( $wgUseTidy ) {
+ // b/c configuration
+ $config = array(
+ 'tidyConfigFile' => $wgTidyConf,
+ 'debugComment' => $wgDebugTidy,
+ 'tidyBin' => $wgTidyBin,
+ 'tidyCommandLine' => $wgTidyOpts );
+ if ( $wgTidyInternal ) {
+ if ( wfIsHHVM() ) {
+ $config['driver'] = 'RaggettInternalHHVM';
+ } else {
+ $config['driver'] = 'RaggettInternalPHP';
+ }
+ } else {
+ $config['driver'] = 'RaggettExternal';
}
- return self::hhvmClean( $text, $retval );
} else {
- return self::phpClean( $text, $stderr, $retval );
+ return false;
}
- } else {
- return self::externalClean( $text, $stderr, $retval );
- }
- }
-
- /**
- * Spawn an external HTML tidy process and get corrected markup back from it.
- * Also called in OutputHandler.php for full page validation
- *
- * @param string $text HTML to check
- * @param bool $stderr Whether to read result from STDERR rather than STDOUT
- * @param int &$retval Exit code (-1 on internal error)
- * @return string|null
- */
- private static function externalClean( $text, $stderr = false, &$retval = null ) {
- global $wgTidyConf, $wgTidyBin, $wgTidyOpts;
-
- $cleansource = '';
- $opts = ' -utf8';
-
- if ( $stderr ) {
- $descriptorspec = array(
- 0 => array( 'pipe', 'r' ),
- 1 => array( 'file', wfGetNull(), 'a' ),
- 2 => array( 'pipe', 'w' )
- );
- } else {
- $descriptorspec = array(
- 0 => array( 'pipe', 'r' ),
- 1 => array( 'pipe', 'w' ),
- 2 => array( 'file', wfGetNull(), 'a' )
- );
- }
-
- $readpipe = $stderr ? 2 : 1;
- $pipes = array();
-
- $process = proc_open(
- "$wgTidyBin -config $wgTidyConf $wgTidyOpts$opts", $descriptorspec, $pipes );
-
- //NOTE: At least on linux, the process will be created even if tidy is not installed.
- // This means that missing tidy will be treated as a validation failure.
-
- if ( is_resource( $process ) ) {
- // Theoretically, this style of communication could cause a deadlock
- // here. If the stdout buffer fills up, then writes to stdin could
- // block. This doesn't appear to happen with tidy, because tidy only
- // writes to stdout after it's finished reading from stdin. Search
- // for tidyParseStdin and tidySaveStdout in console/tidy.c
- fwrite( $pipes[0], $text );
- fclose( $pipes[0] );
- while ( !feof( $pipes[$readpipe] ) ) {
- $cleansource .= fgets( $pipes[$readpipe], 1024 );
+ switch ( $config['driver'] ) {
+ case 'RaggettInternalHHVM':
+ self::$instance = new MediaWiki\Tidy\RaggettInternalHHVM( $config );
+ break;
+ case 'RaggettInternalPHP':
+ self::$instance = new MediaWiki\Tidy\RaggettInternalPHP( $config );
+ break;
+ case 'RaggettExternal':
+ self::$instance = new MediaWiki\Tidy\RaggettExternal( $config );
+ break;
+ case 'Html5Depurate':
+ self::$instance = new MediaWiki\Tidy\Html5Depurate( $config );
+ break;
+ default:
+ throw new MWException( "Invalid tidy driver: \"{$config['driver']}\"" );
}
- fclose( $pipes[$readpipe] );
- $retval = proc_close( $process );
- } else {
- wfWarn( "Unable to start external tidy process" );
- $retval = -1;
}
-
- if ( !$stderr && $cleansource == '' && $text != '' ) {
- // Some kind of error happened, so we couldn't get the corrected text.
- // Just give up; we'll use the source text and append a warning.
- $cleansource = null;
- }
-
- return $cleansource;
+ return self::$instance;
}
/**
- * Use the HTML tidy extension to use the tidy library in-process,
- * saving the overhead of spawning a new process.
- *
- * @param string $text HTML to check
- * @param bool $stderr Whether to read result from error status instead of output
- * @param int &$retval Exit code (-1 on internal error)
- * @return string|null
+ * Set the driver to be used. This is for testing.
+ * @param TidyDriverBase|false|null $instance
*/
- private static function phpClean( $text, $stderr = false, &$retval = null ) {
- global $wgTidyConf, $wgDebugTidy;
-
- if ( ( !wfIsHHVM() && !class_exists( 'tidy' ) ) ||
- ( wfIsHHVM() && !function_exists( 'tidy_repair_string' ) )
- ) {
- wfWarn( "Unable to load internal tidy class." );
- $retval = -1;
-
- return null;
- }
-
- $tidy = new tidy;
- $tidy->parseString( $text, $wgTidyConf, 'utf8' );
-
- if ( $stderr ) {
- $retval = $tidy->getStatus();
- return $tidy->errorBuffer;
- }
-
- $tidy->cleanRepair();
- $retval = $tidy->getStatus();
- if ( $retval == 2 ) {
- // 2 is magic number for fatal error
- // http://www.php.net/manual/en/function.tidy-get-status.php
- $cleansource = null;
- } else {
- $cleansource = tidy_get_output( $tidy );
- if ( $wgDebugTidy && $retval > 0 ) {
- $cleansource .= "<!--\nTidy reports:\n" .
- str_replace( '-->', '--&gt;', $tidy->errorBuffer ) .
- "\n-->";
- }
- }
-
- return $cleansource;
+ public static function setInstance( $instance ) {
+ self::$instance = $instance;
}
/**
- * Use the tidy extension for HHVM from
- * https://github.com/wikimedia/mediawiki-php-tidy
- *
- * This currently does not support the object-oriented interface, but
- * tidy_repair_string() can be used for the most common tasks.
- *
- * @param string $text HTML to check
- * @param int &$retval Exit code (-1 on internal error)
- * @return string|null
+ * Destroy the current singleton instance
*/
- private static function hhvmClean( $text, &$retval ) {
- global $wgTidyConf;
-
- $cleansource = tidy_repair_string( $text, $wgTidyConf, 'utf8' );
- if ( $cleansource === false ) {
- $cleansource = null;
- $retval = -1;
- } else {
- $retval = 0;
- }
-
- return $cleansource;
+ public static function destroySingleton() {
+ self::$instance = null;
}
}
diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php
index ace63a09..c07a08ac 100644
--- a/includes/parser/Parser.php
+++ b/includes/parser/Parser.php
@@ -87,7 +87,11 @@ class Parser {
# \p{Zs} is unicode 'separator, space' category. It covers the space 0x20
# as well as U+3000 is IDEOGRAPHIC SPACE for bug 19052
const EXT_LINK_URL_CLASS = '[^][<>"\\x00-\\x20\\x7F\p{Zs}]';
- const EXT_IMAGE_REGEX = '/^(http:\/\/|https:\/\/)([^][<>"\\x00-\\x20\\x7F\p{Zs}]+)
+ # Simplified expression to match an IPv4 or IPv6 address, or
+ # 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}])';
+ # RegExp to make image URLs (embeds IPv6 part of EXT_LINK_ADDR)
+ const EXT_IMAGE_REGEX = '/^(http:\/\/|https:\/\/)((?:\\[(?i:[0-9a-f:.]+)\\])?[^][<>"\\x00-\\x20\\x7F\p{Zs}]+)
\\/([A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF]+)\\.((?i)gif|png|jpg|jpeg)$/Sxu';
# Regular expression for a non-newline space
@@ -114,8 +118,20 @@ class Parser {
const OT_MSG = 3;
const OT_PLAIN = 4; # like extractSections() - portions of the original are returned unchanged.
- # Marker Suffix needs to be accessible staticly.
+ /**
+ * @var string Prefix and suffix for temporary replacement strings
+ * for the multipass parser.
+ *
+ * \x7f should never appear in input as it's disallowed in XML.
+ * Using it at the front also gives us a little extra robustness
+ * since it shouldn't match when butted up against identifier-like
+ * string constructs.
+ *
+ * Must not consist of all title characters, or else it will change
+ * the behavior of <nowiki> in a link.
+ */
const MARKER_SUFFIX = "-QINU\x7f";
+ const MARKER_PREFIX = "\x7fUNIQ-";
# Markers used for wrapping the table of contents
const TOC_START = '<mw:toc>';
@@ -206,9 +222,10 @@ class Parser {
public $mInputSize = false; # For {{PAGESIZE}} on current page.
/**
- * @var string
- */
- public $mUniqPrefix;
+ * @var string Deprecated accessor for the strip marker prefix.
+ * @deprecated since 1.26; use Parser::MARKER_PREFIX instead.
+ **/
+ public $mUniqPrefix = Parser::MARKER_PREFIX;
/**
* @var array Array with the language name of each language link (i.e. the
@@ -241,7 +258,8 @@ class Parser {
$this->mConf = $conf;
$this->mUrlProtocols = wfUrlProtocols();
$this->mExtLinkBracketedRegex = '/\[(((?i)' . $this->mUrlProtocols . ')' .
- self::EXT_LINK_URL_CLASS . '+)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F]*?)\]/Su';
+ self::EXT_LINK_ADDR .
+ self::EXT_LINK_URL_CLASS . '*)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F]*?)\]/Su';
if ( isset( $conf['preprocessorClass'] ) ) {
$this->mPreprocessorClass = $conf['preprocessorClass'];
} elseif ( defined( 'HPHP_VERSION' ) ) {
@@ -336,18 +354,7 @@ class Parser {
$this->mLangLinkLanguages = array();
$this->currentRevisionCache = null;
- /**
- * Prefix for temporary replacement strings for the multipass parser.
- * \x07 should never appear in input as it's disallowed in XML.
- * Using it at the front also gives us a little extra robustness
- * since it shouldn't match when butted up against identifier-like
- * string constructs.
- *
- * Must not consist of all title characters, or else it will change
- * the behavior of <nowiki> in a link.
- */
- $this->mUniqPrefix = "\x7fUNIQ" . self::getRandomString();
- $this->mStripState = new StripState( $this->mUniqPrefix );
+ $this->mStripState = new StripState;
# Clear these on every parse, bug 4549
$this->mTplRedirCache = $this->mTplDomCache = array();
@@ -399,6 +406,9 @@ class Parser {
global $wgShowHostnames;
if ( $clearState ) {
+ // We use U+007F DELETE to construct strip markers, so we have to make
+ // sure that this character does not occur in the input text.
+ $text = strtr( $text, "\x7f", "?" );
$magicScopeVariable = $this->lock();
}
@@ -410,11 +420,6 @@ class Parser {
$this->mOutput->resetParseStartTime();
}
- # Remove the strip marker tag prefix from the input, if present.
- if ( $clearState ) {
- $text = str_replace( $this->mUniqPrefix, '', $text );
- }
-
$oldRevisionId = $this->mRevisionId;
$oldRevisionObject = $this->mRevisionObject;
$oldRevisionTimestamp = $this->mRevisionTimestamp;
@@ -504,6 +509,9 @@ class Parser {
if ( $wgShowHostnames ) {
$limitReport .= 'Parsed by ' . wfHostname() . "\n";
}
+ $limitReport .= 'Cached time: ' . $this->mOutput->getCacheTime() . "\n";
+ $limitReport .= 'Cache expiry: ' . $this->mOutput->getCacheExpiry() . "\n";
+ $limitReport .= 'Dynamic content: ' . ( $this->mOutput->hasDynamicContent() ? 'true' : 'false' ) . "\n";
foreach ( $this->mOutput->getLimitReportData() as $key => $value ) {
if ( Hooks::run( 'ParserLimitReportFormat',
array( $key, &$value, &$limitReport, false, false )
@@ -686,8 +694,10 @@ class Parser {
* Get a random string
*
* @return string
+ * @deprecated since 1.26; use wfRandomString() instead.
*/
public static function getRandomString() {
+ wfDeprecated( __METHOD__, '1.26' );
return wfRandomString( 16 );
}
@@ -705,18 +715,11 @@ class Parser {
* Accessor for mUniqPrefix.
*
* @return string
+ * @deprecated since 1.26; use Parser::MARKER_PREFIX instead.
*/
public function uniqPrefix() {
- if ( !isset( $this->mUniqPrefix ) ) {
- # @todo FIXME: This is probably *horribly wrong*
- # LanguageConverter seems to want $wgParser's uniqPrefix, however
- # if this is called for a parser cache hit, the parser may not
- # have ever been initialized in the first place.
- # Not really sure what the heck is supposed to be going on here.
- return '';
- # throw new MWException( "Accessing uninitialized mUniqPrefix" );
- }
- return $this->mUniqPrefix;
+ wfDeprecated( __METHOD__, '1.26' );
+ return self::MARKER_PREFIX;
}
/**
@@ -907,10 +910,14 @@ class Parser {
* @param array $elements List of element names. Comments are always extracted.
* @param string $text Source text string.
* @param array $matches Out parameter, Array: extracted tags
- * @param string $uniq_prefix
+ * @param string|null $uniq_prefix
* @return string Stripped text
+ * @since 1.26 The uniq_prefix argument is deprecated.
*/
- public static function extractTagsAndParams( $elements, $text, &$matches, $uniq_prefix = '' ) {
+ public static function extractTagsAndParams( $elements, $text, &$matches, $uniq_prefix = null ) {
+ if ( $uniq_prefix !== null ) {
+ wfDeprecated( __METHOD__ . ' called with $prefix argument', '1.26' );
+ }
static $n = 1;
$stripped = '';
$matches = array();
@@ -938,7 +945,7 @@ class Parser {
$inside = $p[4];
}
- $marker = "$uniq_prefix-$element-" . sprintf( '%08X', $n++ ) . self::MARKER_SUFFIX;
+ $marker = self::MARKER_PREFIX . "-$element-" . sprintf( '%08X', $n++ ) . self::MARKER_SUFFIX;
$stripped .= $marker;
if ( $close === '/>' ) {
@@ -991,10 +998,10 @@ class Parser {
* @return string
*/
public function insertStripItem( $text ) {
- $rnd = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}-" . self::MARKER_SUFFIX;
+ $marker = self::MARKER_PREFIX . "-item-{$this->mMarkerIndex}-" . self::MARKER_SUFFIX;
$this->mMarkerIndex++;
- $this->mStripState->addGeneral( $rnd, $text );
- return $rnd;
+ $this->mStripState->addGeneral( $marker, $text );
+ return $marker;
}
/**
@@ -1024,9 +1031,10 @@ class Parser {
}
$first_character = $line[0];
+ $first_two = substr( $line, 0, 2 );
$matches = array();
- if ( preg_match( '/^(:*)\{\|(.*)$/', $line, $matches ) ) {
+ if ( preg_match( '/^(:*)\s*\{\|(.*)$/', $line, $matches ) ) {
# First check if we are starting a new table
$indent_level = strlen( $matches[1] );
@@ -1043,7 +1051,7 @@ class Parser {
# Don't do any of the following
$out .= $outLine . "\n";
continue;
- } elseif ( substr( $line, 0, 2 ) === '|}' ) {
+ } elseif ( $first_two === '|}' ) {
# We are ending a table
$line = '</table>' . substr( $line, 2 );
$last_tag = array_pop( $last_tag_history );
@@ -1061,7 +1069,7 @@ class Parser {
}
array_pop( $tr_attributes );
$outLine = $line . str_repeat( '</dd></dl>', $indent_level );
- } elseif ( substr( $line, 0, 2 ) === '|-' ) {
+ } elseif ( $first_two === '|-' ) {
# Now we have a table row
$line = preg_replace( '#^\|-+#', '', $line );
@@ -1090,16 +1098,16 @@ class Parser {
array_push( $last_tag_history, '' );
} elseif ( $first_character === '|'
|| $first_character === '!'
- || substr( $line, 0, 2 ) === '|+'
+ || $first_two === '|+'
) {
# This might be cell elements, td, th or captions
- if ( substr( $line, 0, 2 ) === '|+' ) {
+ if ( $first_two === '|+' ) {
$first_character = '+';
+ $line = substr( $line, 2 );
+ } else {
$line = substr( $line, 1 );
}
- $line = substr( $line, 1 );
-
if ( $first_character === '!' ) {
$line = str_replace( '!!', '||', $line );
}
@@ -1257,7 +1265,7 @@ class Parser {
# replaceInternalLinks may sometimes leave behind
# absolute URLs, which have to be masked to hide them from replaceExternalLinks
- $text = str_replace( $this->mUniqPrefix . 'NOPARSE', '', $text );
+ $text = str_replace( self::MARKER_PREFIX . 'NOPARSE', '', $text );
$text = $this->doMagicLinks( $text );
$text = $this->formatHeadings( $text, $origText, $isMain );
@@ -1275,10 +1283,12 @@ class Parser {
* @return string
*/
private function internalParseHalfParsed( $text, $isMain = true, $linestart = true ) {
- global $wgUseTidy, $wgAlwaysUseTidy;
-
$text = $this->mStripState->unstripGeneral( $text );
+ if ( $isMain ) {
+ Hooks::run( 'ParserAfterUnstrip', array( &$this, &$text ) );
+ }
+
# Clean up special characters, only run once, next-to-last before doBlockLevels
$fixtags = array(
# french spaces, last one Guillemet-left
@@ -1323,7 +1333,7 @@ class Parser {
$text = Sanitizer::normalizeCharReferences( $text );
- if ( ( $wgUseTidy && $this->mOptions->getTidy() ) || $wgAlwaysUseTidy ) {
+ if ( MWTidy::isEnabled() && $this->mOptions->getTidy() ) {
$text = MWTidy::tidy( $text );
} else {
# attempt to sanitize at least some nesting problems
@@ -1374,20 +1384,23 @@ class Parser {
public function doMagicLinks( $text ) {
$prots = wfUrlProtocolsWithoutProtRel();
$urlChar = self::EXT_LINK_URL_CLASS;
+ $addr = self::EXT_LINK_ADDR;
$space = self::SPACE_NOT_NL; # non-newline space
$spdash = "(?:-|$space)"; # a dash or a non-newline space
$spaces = "$space++"; # possessive match of 1 or more spaces
$text = preg_replace_callback(
- '!(?: # Start cases
- (<a[ \t\r\n>].*?</a>) | # m[1]: Skip link text
- (<.*?>) | # m[2]: Skip stuff inside HTML elements' . "
- (\b(?i:$prots)$urlChar+) | # m[3]: Free external links
- \b(?:RFC|PMID) $spaces # m[4]: RFC or PMID, capture number
+ '!(?: # Start cases
+ (<a[ \t\r\n>].*?</a>) | # m[1]: Skip link text
+ (<.*?>) | # m[2]: Skip stuff inside
+ # HTML elements' . "
+ (\b(?i:$prots)($addr$urlChar*)) | # m[3]: Free external links
+ # m[4]: Post-protocol path
+ \b(?:RFC|PMID) $spaces # m[5]: RFC or PMID, capture number
([0-9]+)\b |
- \bISBN $spaces ( # m[5]: ISBN, capture number
- (?: 97[89] $spdash? )? # optional 13-digit ISBN prefix
- (?: [0-9] $spdash? ){9} # 9 digits with opt. delimiters
- [0-9Xx] # check digit
+ \bISBN $spaces ( # m[6]: ISBN, capture number
+ (?: 97[89] $spdash? )? # optional 13-digit ISBN prefix
+ (?: [0-9] $spdash? ){9} # 9 digits with opt. delimiters
+ [0-9Xx] # check digit
)\b
)!xu", array( &$this, 'magicLinkCallback' ), $text );
return $text;
@@ -1407,35 +1420,35 @@ class Parser {
return $m[0];
} elseif ( isset( $m[3] ) && $m[3] !== '' ) {
# Free external link
- return $this->makeFreeExternalLink( $m[0] );
- } elseif ( isset( $m[4] ) && $m[4] !== '' ) {
+ return $this->makeFreeExternalLink( $m[0], strlen( $m[4] ) );
+ } elseif ( isset( $m[5] ) && $m[5] !== '' ) {
# RFC or PMID
if ( substr( $m[0], 0, 3 ) === 'RFC' ) {
$keyword = 'RFC';
$urlmsg = 'rfcurl';
$cssClass = 'mw-magiclink-rfc';
- $id = $m[4];
+ $id = $m[5];
} elseif ( substr( $m[0], 0, 4 ) === 'PMID' ) {
$keyword = 'PMID';
$urlmsg = 'pubmedurl';
$cssClass = 'mw-magiclink-pmid';
- $id = $m[4];
+ $id = $m[5];
} else {
throw new MWException( __METHOD__ . ': unrecognised match type "' .
substr( $m[0], 0, 20 ) . '"' );
}
$url = wfMessage( $urlmsg, $id )->inContentLanguage()->text();
return Linker::makeExternalLink( $url, "{$keyword} {$id}", true, $cssClass );
- } elseif ( isset( $m[5] ) && $m[5] !== '' ) {
+ } elseif ( isset( $m[6] ) && $m[6] !== '' ) {
# ISBN
- $isbn = $m[5];
+ $isbn = $m[6];
$space = self::SPACE_NOT_NL; # non-newline space
$isbn = preg_replace( "/$space/", ' ', $isbn );
$num = strtr( $isbn, array(
'-' => '',
' ' => '',
'x' => 'X',
- ));
+ ) );
$titleObj = SpecialPage::getTitleFor( 'Booksources', $num );
return '<a href="' .
htmlspecialchars( $titleObj->getLocalURL() ) .
@@ -1449,11 +1462,12 @@ class Parser {
* Make a free external link, given a user-supplied URL
*
* @param string $url
- *
+ * @param int $numPostProto
+ * The number of characters after the protocol.
* @return string HTML
* @private
*/
- public function makeFreeExternalLink( $url ) {
+ public function makeFreeExternalLink( $url, $numPostProto ) {
$trail = '';
@@ -1478,7 +1492,7 @@ class Parser {
# Don't break a trailing HTML entity by moving the ; into $trail
# This is in hot code, so use substr_compare to avoid having to
# create a new string object for the comparison
- if ( $numSepChars && substr_compare( $url, ";", -$numSepChars, 1 ) === 0) {
+ if ( $numSepChars && substr_compare( $url, ";", -$numSepChars, 1 ) === 0 ) {
# more optimization: instead of running preg_match with a $
# anchor, which can be slow, do the match on the reversed
# string starting at the desired offset.
@@ -1492,6 +1506,12 @@ class Parser {
$url = substr( $url, 0, -$numSepChars );
}
+ # Verify that we still have a real URL after trail removal, and
+ # not just lone protocol
+ if ( strlen( $trail ) >= $numPostProto ) {
+ return $url . $trail;
+ }
+
$url = Sanitizer::cleanUrl( $url );
# Is this an external image?
@@ -1609,12 +1629,10 @@ class Parser {
$firstspace = $i;
}
} elseif ( $x2 === ' ' ) {
- if ( $firstsingleletterword == -1 ) {
- $firstsingleletterword = $i;
- // if $firstsingleletterword is set, we don't
- // look at the other options, so we can bail early.
- break;
- }
+ $firstsingleletterword = $i;
+ // if $firstsingleletterword is set, we don't
+ // look at the other options, so we can bail early.
+ break;
} else {
if ( $firstmultiletterword == -1 ) {
$firstmultiletterword = $i;
@@ -2143,7 +2161,8 @@ class Parser {
$link = substr( $link, 1 );
}
- $nt = Title::newFromText( $this->mStripState->unstripNoWiki( $link ) );
+ $unstrip = $this->mStripState->unstripNoWiki( $link );
+ $nt = is_string( $unstrip ) ? Title::newFromText( $unstrip ) : null;
if ( $nt === null ) {
$s .= $prefix . '[[' . $line;
continue;
@@ -2351,7 +2370,7 @@ class Parser {
*/
public function armorLinks( $text ) {
return preg_replace( '/\b((?i)' . $this->mUrlProtocols . ')/',
- "{$this->mUniqPrefix}NOPARSE$1", $text );
+ self::MARKER_PREFIX . "NOPARSE$1", $text );
}
/**
@@ -2623,7 +2642,7 @@ class Parser {
$closematch = preg_match(
'/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
. '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
- . $this->mUniqPrefix
+ . self::MARKER_PREFIX
. '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS',
$t
);
@@ -3305,7 +3324,8 @@ class Parser {
*/
public function replaceVariables( $text, $frame = false, $argsOnly = false ) {
# Is there any text? Also, Prevent too big inclusions!
- if ( strlen( $text ) < 1 || strlen( $text ) > $this->mOptions->getMaxIncludeSize() ) {
+ $textSize = strlen( $text );
+ if ( $textSize < 1 || $textSize > $this->mOptions->getMaxIncludeSize() ) {
return $text;
}
@@ -3435,7 +3455,6 @@ class Parser {
# SUBST
if ( !$found ) {
-
$substMatch = $this->mSubstWords->matchStartAndRemove( $part1 );
# Possibilities for substMatch: "subst", "safesubst" or FALSE
@@ -3493,7 +3512,6 @@ class Parser {
# Parser functions
if ( !$found ) {
-
$colonPos = strpos( $part1, ':' );
if ( $colonPos !== false ) {
$func = substr( $part1, 0, $colonPos );
@@ -3892,7 +3910,11 @@ class Parser {
// Defaults to Parser::statelessFetchTemplate()
$templateCb = $this->mOptions->getTemplateCallback();
$stuff = call_user_func( $templateCb, $title, $this );
+ // We use U+007F DELETE to distinguish strip markers from regular text.
$text = $stuff['text'];
+ if ( is_string( $stuff['text'] ) ) {
+ $text = strtr( $text, "\x7f", "?" );
+ }
$finalTitle = isset( $stuff['finalTitle'] ) ? $stuff['finalTitle'] : $title;
if ( isset( $stuff['deps'] ) ) {
foreach ( $stuff['deps'] as $dep ) {
@@ -4186,7 +4208,7 @@ class Parser {
$name = $frame->expand( $params['name'] );
$attrText = !isset( $params['attr'] ) ? null : $frame->expand( $params['attr'] );
$content = !isset( $params['inner'] ) ? null : $frame->expand( $params['inner'] );
- $marker = "{$this->mUniqPrefix}-$name-"
+ $marker = self::MARKER_PREFIX . "-$name-"
. sprintf( '%08X', $this->mMarkerIndex++ ) . self::MARKER_SUFFIX;
$isFunctionTag = isset( $this->mFunctionTagHooks[strtolower( $name )] ) &&
@@ -4431,7 +4453,7 @@ class Parser {
$prevlevel = 0;
$toclevel = 0;
$prevtoclevel = 0;
- $markerRegex = "{$this->mUniqPrefix}-h-(\d+)-" . self::MARKER_SUFFIX;
+ $markerRegex = self::MARKER_PREFIX . "-h-(\d+)-" . self::MARKER_SUFFIX;
$baseTitleText = $this->mTitle->getPrefixedDBkey();
$oldType = $this->mOutputType;
$this->setOutputType( self::OT_WIKI );
@@ -4442,7 +4464,9 @@ class Parser {
$tocraw = array();
$refers = array();
- foreach ( $matches[3] as $headline ) {
+ $headlines = $numMatches !== false ? $matches[3] : array();
+
+ foreach ( $headlines as $headline ) {
$isTemplate = false;
$titleText = false;
$sectionIndex = false;
@@ -4547,6 +4571,12 @@ class Parser {
array( '', '<$1>' ),
$safeHeadline
);
+
+ # Strip '<span></span>', which is the result from the above if
+ # <span id="foo"></span> is used to produce an additional anchor
+ # for a section.
+ $tocline = str_replace( '<span></span>', '', $tocline );
+
$tocline = trim( $tocline );
# For the anchor, strip out HTML-y stuff period
@@ -5068,7 +5098,7 @@ class Parser {
* in the Parser class.
*
* This interface (introduced r61913) appears to be undocumented, but
- * 'markerName' is used by some core tag hooks to override which strip
+ * 'markerType' is used by some core tag hooks to override which strip
* array their results are placed in. **Use great caution if attempting
* this interface, as it is not documented and injudicious use could smash
* private variables.**
@@ -5391,9 +5421,10 @@ class Parser {
case 'gallery-internal-link':
$linkValue = strip_tags( $this->replaceLinkHoldersText( $match ) );
$chars = self::EXT_LINK_URL_CLASS;
+ $addr = self::EXT_LINK_ADDR;
$prots = $this->mUrlProtocols;
//check to see if link matches an absolute url, if not then it must be a wiki link.
- if ( preg_match( "/^($prots)$chars+$/u", $linkValue ) ) {
+ if ( preg_match( "/^($prots)$addr$chars*$/u", $linkValue ) ) {
$link = $linkValue;
} else {
$localLinkTitle = Title::newFromText( $linkValue );
@@ -5575,13 +5606,14 @@ class Parser {
break;
case 'link':
$chars = self::EXT_LINK_URL_CLASS;
+ $addr = self::EXT_LINK_ADDR;
$prots = $this->mUrlProtocols;
if ( $value === '' ) {
$paramName = 'no-link';
$value = true;
$validated = true;
} elseif ( preg_match( "/^((?i)$prots)/", $value ) ) {
- if ( preg_match( "/^((?i)$prots)$chars+$/u", $value, $m ) ) {
+ if ( preg_match( "/^((?i)$prots)$addr$chars*$/u", $value, $m ) ) {
$paramName = 'link-url';
$this->mOutput->addExternalLink( $value );
if ( $this->mOptions->getExternalLinkTarget() ) {
@@ -5770,7 +5802,7 @@ class Parser {
public function replaceTransparentTags( $text ) {
$matches = array();
$elements = array_keys( $this->mTransparentTagHooks );
- $text = self::extractTagsAndParams( $elements, $text, $matches, $this->mUniqPrefix );
+ $text = self::extractTagsAndParams( $elements, $text, $matches );
$replacements = array();
foreach ( $matches as $marker => $data ) {
@@ -6229,7 +6261,7 @@ class Parser {
$i = 0;
$out = '';
while ( $i < strlen( $s ) ) {
- $markerStart = strpos( $s, $this->mUniqPrefix, $i );
+ $markerStart = strpos( $s, self::MARKER_PREFIX, $i );
if ( $markerStart === false ) {
$out .= call_user_func( $callback, substr( $s, $i ) );
break;
@@ -6420,4 +6452,15 @@ class Parser {
return $this;
}
}
+
+ /**
+ * Set's up the PHP implementation of OOUI for use in this request
+ * and instructs OutputPage to enable OOUI for itself.
+ *
+ * @since 1.26
+ */
+ public function enableOOUI() {
+ OutputPage::setupOOUI();
+ $this->mOutput->setEnableOOUI( true );
+ }
}
diff --git a/includes/parser/ParserCache.php b/includes/parser/ParserCache.php
index bc8e4a69..abff5435 100644
--- a/includes/parser/ParserCache.php
+++ b/includes/parser/ParserCache.php
@@ -26,7 +26,7 @@
* @todo document
*/
class ParserCache {
- /** @var MWMemcached */
+ /** @var BagOStuff */
private $mMemc;
/**
* Get an instance of this object
@@ -44,20 +44,19 @@ class ParserCache {
/**
* Setup a cache pathway with a given back-end storage mechanism.
- * May be a memcached client or a BagOStuff derivative.
*
- * @param MWMemcached $memCached
+ * This class use an invalidation strategy that is compatible with
+ * MultiWriteBagOStuff in async replication mode.
+ *
+ * @param BagOStuff $memCached
* @throws MWException
*/
- protected function __construct( $memCached ) {
- if ( !$memCached ) {
- throw new MWException( "Tried to create a ParserCache with an invalid memcached" );
- }
+ protected function __construct( BagOStuff $memCached ) {
$this->mMemc = $memCached;
}
/**
- * @param Article $article
+ * @param WikiPage $article
* @param string $hash
* @return mixed|string
*/
@@ -73,7 +72,7 @@ class ParserCache {
}
/**
- * @param Article $article
+ * @param WikiPage $article
* @return mixed|string
*/
protected function getOptionsKey( $article ) {
@@ -91,7 +90,7 @@ class ParserCache {
* English preferences. That's why we take into account *all* user
* options. (r70809 CR)
*
- * @param Article $article
+ * @param WikiPage $article
* @param ParserOptions $popts
* @return string
*/
@@ -103,7 +102,7 @@ class ParserCache {
/**
* Retrieve the ParserOutput from ParserCache, even if it's outdated.
- * @param Article $article
+ * @param WikiPage $article
* @param ParserOptions $popts
* @return ParserOutput|bool False on failure
*/
@@ -126,7 +125,7 @@ class ParserCache {
*
* @todo Document parameter $useOutdated
*
- * @param Article $article
+ * @param WikiPage $article
* @param ParserOptions $popts
* @param bool $useOutdated (default true)
* @return bool|mixed|string
@@ -141,15 +140,15 @@ class ParserCache {
// Determine the options which affect this article
$optionsKey = $this->mMemc->get( $this->getOptionsKey( $article ) );
- if ( $optionsKey != false ) {
+ if ( $optionsKey instanceof CacheTime ) {
if ( !$useOutdated && $optionsKey->expired( $article->getTouched() ) ) {
- wfIncrStats( "pcache_miss_expired" );
+ wfIncrStats( "pcache.miss.expired" );
$cacheTime = $optionsKey->getCacheTime();
wfDebug( "Parser options key expired, touched " . $article->getTouched()
. ", epoch $wgCacheEpoch, cached $cacheTime\n" );
return false;
} elseif ( $optionsKey->isDifferentRevision( $article->getLatest() ) ) {
- wfIncrStats( "pcache_miss_revid" );
+ wfIncrStats( "pcache.miss.revid" );
$revId = $article->getLatest();
$cachedRevId = $optionsKey->getCacheRevisionId();
wfDebug( "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n" );
@@ -176,7 +175,7 @@ class ParserCache {
* Retrieve the ParserOutput from ParserCache.
* false if not found or outdated.
*
- * @param Article $article
+ * @param WikiPage|Article $article
* @param ParserOptions $popts
* @param bool $useOutdated (default false)
*
@@ -195,14 +194,14 @@ class ParserCache {
$parserOutputKey = $this->getKey( $article, $popts, $useOutdated );
if ( $parserOutputKey === false ) {
- wfIncrStats( 'pcache_miss_absent' );
+ wfIncrStats( 'pcache.miss.absent' );
return false;
}
$value = $this->mMemc->get( $parserOutputKey );
if ( !$value ) {
wfDebug( "ParserOutput cache miss.\n" );
- wfIncrStats( "pcache_miss_absent" );
+ wfIncrStats( "pcache.miss.absent" );
return false;
}
@@ -213,20 +212,28 @@ class ParserCache {
// key. Force it here. See bug 31445.
$value->setEditSectionTokens( $popts->getEditSection() );
+ $wikiPage = method_exists( $article, 'getPage' )
+ ? $article->getPage()
+ : $article;
+
if ( !$useOutdated && $value->expired( $touched ) ) {
- wfIncrStats( "pcache_miss_expired" );
+ wfIncrStats( "pcache.miss.expired" );
$cacheTime = $value->getCacheTime();
wfDebug( "ParserOutput key expired, touched $touched, "
. "epoch $wgCacheEpoch, cached $cacheTime\n" );
$value = false;
} elseif ( $value->isDifferentRevision( $article->getLatest() ) ) {
- wfIncrStats( "pcache_miss_revid" );
+ wfIncrStats( "pcache.miss.revid" );
$revId = $article->getLatest();
$cachedRevId = $value->getCacheRevisionId();
wfDebug( "ParserOutput key is for an old revision, latest $revId, cached $cachedRevId\n" );
$value = false;
+ } elseif ( Hooks::run( 'RejectParserCacheValue', array( $value, $wikiPage, $popts ) ) === false ) {
+ wfIncrStats( 'pcache.miss.rejected' );
+ wfDebug( "ParserOutput key valid, but rejected by RejectParserCacheValue hook handler.\n" );
+ $value = false;
} else {
- wfIncrStats( "pcache_hit" );
+ wfIncrStats( "pcache.hit" );
}
return $value;
@@ -276,6 +283,8 @@ class ParserCache {
// ...and its pointer
$this->mMemc->set( $this->getOptionsKey( $page ), $optionsKey, $expire );
+
+ Hooks::run( 'ParserCacheSaveComplete', array( $this, $parserOutput, $page->getTitle(), $popts, $revId ) );
} else {
wfDebug( "Parser output was marked as uncacheable and has not been saved.\n" );
}
diff --git a/includes/parser/ParserDiffTest.php b/includes/parser/ParserDiffTest.php
index 174c1d61..32f5d068 100644
--- a/includes/parser/ParserDiffTest.php
+++ b/includes/parser/ParserDiffTest.php
@@ -29,7 +29,6 @@ class ParserDiffTest
public $parsers;
public $conf;
public $shortOutput = false;
- public $dtUniqPrefix;
public function __construct( $conf ) {
if ( !isset( $conf['parsers'] ) ) {
@@ -43,12 +42,6 @@ class ParserDiffTest
return;
}
- global $wgHooks;
- static $doneHook = false;
- if ( !$doneHook ) {
- $doneHook = true;
- $wgHooks['ParserClearState'][] = array( $this, 'onClearState' );
- }
if ( isset( $this->conf['shortOutput'] ) ) {
$this->shortOutput = $this->conf['shortOutput'];
}
@@ -126,18 +119,4 @@ class ParserDiffTest
$parser->setFunctionHook( $id, $callback, $flags );
}
}
-
- /**
- * @param Parser $parser
- * @return bool
- */
- public function onClearState( &$parser ) {
- // hack marker prefixes to get identical output
- if ( !isset( $this->dtUniqPrefix ) ) {
- $this->dtUniqPrefix = $parser->uniqPrefix();
- } else {
- $parser->mUniqPrefix = $this->dtUniqPrefix;
- }
- return true;
- }
}
diff --git a/includes/parser/ParserOptions.php b/includes/parser/ParserOptions.php
index 100656d1..1073aed8 100644
--- a/includes/parser/ParserOptions.php
+++ b/includes/parser/ParserOptions.php
@@ -34,145 +34,145 @@ class ParserOptions {
/**
* Interlanguage links are removed and returned in an array
*/
- public $mInterwikiMagic;
+ private $mInterwikiMagic;
/**
* Allow external images inline?
*/
- public $mAllowExternalImages;
+ private $mAllowExternalImages;
/**
* If not, any exception?
*/
- public $mAllowExternalImagesFrom;
+ private $mAllowExternalImagesFrom;
/**
* If not or it doesn't match, should we check an on-wiki whitelist?
*/
- public $mEnableImageWhitelist;
+ private $mEnableImageWhitelist;
/**
* Date format index
*/
- public $mDateFormat = null;
+ private $mDateFormat = null;
/**
* Create "edit section" links?
*/
- public $mEditSection = true;
+ private $mEditSection = true;
/**
* Allow inclusion of special pages?
*/
- public $mAllowSpecialInclusion;
+ private $mAllowSpecialInclusion;
/**
* Use tidy to cleanup output HTML?
*/
- public $mTidy = false;
+ private $mTidy = false;
/**
* Which lang to call for PLURAL and GRAMMAR
*/
- public $mInterfaceMessage = false;
+ private $mInterfaceMessage = false;
/**
* Overrides $mInterfaceMessage with arbitrary language
*/
- public $mTargetLanguage = null;
+ private $mTargetLanguage = null;
/**
* Maximum size of template expansions, in bytes
*/
- public $mMaxIncludeSize;
+ private $mMaxIncludeSize;
/**
* Maximum number of nodes touched by PPFrame::expand()
*/
- public $mMaxPPNodeCount;
+ private $mMaxPPNodeCount;
/**
* Maximum number of nodes generated by Preprocessor::preprocessToObj()
*/
- public $mMaxGeneratedPPNodeCount;
+ private $mMaxGeneratedPPNodeCount;
/**
* Maximum recursion depth in PPFrame::expand()
*/
- public $mMaxPPExpandDepth;
+ private $mMaxPPExpandDepth;
/**
* Maximum recursion depth for templates within templates
*/
- public $mMaxTemplateDepth;
+ private $mMaxTemplateDepth;
/**
* Maximum number of calls per parse to expensive parser functions
*/
- public $mExpensiveParserFunctionLimit;
+ private $mExpensiveParserFunctionLimit;
/**
* Remove HTML comments. ONLY APPLIES TO PREPROCESS OPERATIONS
*/
- public $mRemoveComments = true;
+ private $mRemoveComments = true;
/**
* Callback for current revision fetching. Used as first argument to call_user_func().
*/
- public $mCurrentRevisionCallback =
+ private $mCurrentRevisionCallback =
array( 'Parser', 'statelessFetchRevision' );
/**
* Callback for template fetching. Used as first argument to call_user_func().
*/
- public $mTemplateCallback =
+ private $mTemplateCallback =
array( 'Parser', 'statelessFetchTemplate' );
/**
* Enable limit report in an HTML comment on output
*/
- public $mEnableLimitReport = false;
+ private $mEnableLimitReport = false;
/**
* Timestamp used for {{CURRENTDAY}} etc.
*/
- public $mTimestamp;
+ private $mTimestamp;
/**
* Target attribute for external links
*/
- public $mExternalLinkTarget;
+ private $mExternalLinkTarget;
/**
* Clean up signature texts?
* @see Parser::cleanSig
*/
- public $mCleanSignatures;
+ private $mCleanSignatures;
/**
* Transform wiki markup when saving the page?
*/
- public $mPreSaveTransform = true;
+ private $mPreSaveTransform = true;
/**
* Whether content conversion should be disabled
*/
- public $mDisableContentConversion;
+ private $mDisableContentConversion;
/**
* Whether title conversion should be disabled
*/
- public $mDisableTitleConversion;
+ private $mDisableTitleConversion;
/**
* Automatically number headings?
*/
- public $mNumberHeadings;
+ private $mNumberHeadings;
/**
* Thumb size preferred by the user.
*/
- public $mThumbSize;
+ private $mThumbSize;
/**
* Maximum article size of an article to be marked as "stub"
@@ -182,38 +182,38 @@ class ParserOptions {
/**
* Language object of the User language.
*/
- public $mUserLang;
+ private $mUserLang;
/**
* @var User
* Stored user object
*/
- public $mUser;
+ private $mUser;
/**
* Parsing the page for a "preview" operation?
*/
- public $mIsPreview = false;
+ private $mIsPreview = false;
/**
* Parsing the page for a "preview" operation on a single section?
*/
- public $mIsSectionPreview = false;
+ private $mIsSectionPreview = false;
/**
* Parsing the printable version of the page?
*/
- public $mIsPrintable = false;
+ private $mIsPrintable = false;
/**
* Extra key that should be present in the caching key.
*/
- public $mExtraKey = '';
+ private $mExtraKey = '';
/**
* Function to be called when an option is accessed.
*/
- protected $onAccessCallback = null;
+ private $onAccessCallback = null;
/**
* If the page being parsed is a redirect, this should hold the redirect
@@ -372,16 +372,17 @@ class ParserOptions {
}
/**
- * Get the user language used by the parser for this page.
+ * Get the user language used by the parser for this page and split the parser cache.
*
- * You shouldn't use this. Really. $parser->getFunctionLang() is all you need.
+ * @warning: Calling this causes the parser cache to be fragmented by user language!
+ * To avoid cache fragmentation, output should not depend on the user language.
+ * Use Parser::getFunctionLang() or Parser::getTargetLanguage() instead!
*
- * To avoid side-effects where the page will be rendered based on the language
- * of the user who last saved, this function will triger a cache fragmentation.
- * Usage of this method is discouraged for that reason.
- *
- * When saving, this will return the default language instead of the user's.
+ * @note This function will trigger a cache fragmentation by recording the
+ * 'userlang' option, see optionUsed(). This is done to avoid cache pollution
+ * when the page is rendered based on the language of the user.
*
+ * @note When saving, this will return the default language instead of the user's.
* {{int: }} uses this which used to produce inconsistent link tables (bug 14404).
*
* @return Language
@@ -395,6 +396,12 @@ class ParserOptions {
/**
* Same as getUserLangObj() but returns a string instead.
*
+ * @warning: Calling this causes the parser cache to be fragmented by user language!
+ * To avoid cache fragmentation, output should not depend on the user language.
+ * Use Parser::getFunctionLang() or Parser::getTargetLanguage() instead!
+ *
+ * @see getUserLangObj()
+ *
* @return string Language code
* @since 1.17
*/
@@ -700,6 +707,10 @@ class ParserOptions {
/**
* Called when an option is accessed.
+ * Calls the watcher that was set using registerWatcher().
+ * Typically, the watcher callback is ParserOutput::registerOption().
+ * The information registered that way will be used by ParserCache::save().
+ *
* @param string $optionName Name of the option
*/
public function optionUsed( $optionName ) {
@@ -791,6 +802,10 @@ class ParserOptions {
$confstr .= $wgRenderHashAppend;
+ // @note: as of Feb 2015, core never sets the editsection flag, since it uses
+ // <mw:editsection> tags to inject editsections on the fly. However, extensions
+ // may be using it by calling ParserOption::optionUsed resp. ParserOutput::registerOption
+ // directly. At least Wikibase does at this point in time.
if ( !in_array( 'editsection', $forOptions ) ) {
$confstr .= '!*';
} elseif ( !$this->mEditSection ) {
diff --git a/includes/parser/ParserOutput.php b/includes/parser/ParserOutput.php
index 65b527c8..2eb1dc9f 100644
--- a/includes/parser/ParserOutput.php
+++ b/includes/parser/ParserOutput.php
@@ -41,7 +41,6 @@ class ParserOutput extends CacheTime {
$mModules = array(), # Modules to be loaded by the resource loader
$mModuleScripts = array(), # Modules of which only the JS will be loaded by the resource loader
$mModuleStyles = array(), # Modules of which only the CSSS will be loaded by the resource loader
- $mModuleMessages = array(), # Modules of which only the messages will be loaded by the resource loader
$mJsConfigVars = array(), # JavaScript config variable for mw.config combined with this page
$mOutputHooks = array(), # Hook tags as per $wgParserOutputHooks
$mWarnings = array(), # Warning text to be returned to the user. Wikitext formatted, in the key only
@@ -50,7 +49,8 @@ class ParserOutput extends CacheTime {
$mProperties = array(), # Name/value pairs to be cached in the DB
$mTOCHTML = '', # HTML of the TOC
$mTimestamp, # Timestamp of the revision
- $mTOCEnabled = true; # Whether TOC should be shown, can't override __NOTOC__
+ $mTOCEnabled = true, # Whether TOC should be shown, can't override __NOTOC__
+ $mEnableOOUI = false; # Whether OOUI should be enabled
private $mIndexPolicy = ''; # 'index' or 'noindex'? Any other value will result in no change.
private $mAccessedOptions = array(); # List of ParserOptions (stored in the keys)
private $mExtensionData = array(); # extra data used by extensions
@@ -104,7 +104,7 @@ class ParserOutput extends CacheTime {
$text = str_replace( array( Parser::TOC_START, Parser::TOC_END ), '', $text );
} else {
$text = preg_replace(
- '#' . preg_quote( Parser::TOC_START ) . '.*?' . preg_quote( Parser::TOC_END ) . '#s',
+ '#' . preg_quote( Parser::TOC_START, '#' ) . '.*?' . preg_quote( Parser::TOC_END, '#' ) . '#s',
'',
$text
);
@@ -191,8 +191,13 @@ class ParserOutput extends CacheTime {
return $this->mModuleStyles;
}
+ /**
+ * @deprecated since 1.26 Obsolete
+ * @return array
+ */
public function getModuleMessages() {
- return $this->mModuleMessages;
+ wfDeprecated( __METHOD__, '1.26' );
+ return array();
}
/** @since 1.23 */
@@ -228,6 +233,10 @@ class ParserOutput extends CacheTime {
return $this->mTOCEnabled;
}
+ public function getEnableOOUI() {
+ return $this->mEnableOOUI;
+ }
+
public function setText( $text ) {
return wfSetVar( $this->mText, $text );
}
@@ -279,6 +288,17 @@ class ParserOutput extends CacheTime {
$this->mIndicators[$id] = $content;
}
+ /**
+ * Enables OOUI, if true, in any OutputPage instance this ParserOutput
+ * object is added to.
+ *
+ * @since 1.26
+ * @param bool $enable If OOUI should be enabled or not
+ */
+ public function setEnableOOUI( $enable = false ) {
+ $this->mEnableOOUI = $enable;
+ }
+
public function addLanguageLink( $t ) {
$this->mLanguageLinks[] = $t;
}
@@ -445,8 +465,12 @@ class ParserOutput extends CacheTime {
$this->mModuleStyles = array_merge( $this->mModuleStyles, (array)$modules );
}
+ /**
+ * @deprecated since 1.26 Use addModules() instead
+ * @param string|array $modules
+ */
public function addModuleMessages( $modules ) {
- $this->mModuleMessages = array_merge( $this->mModuleMessages, (array)$modules );
+ wfDeprecated( __METHOD__, '1.26' );
}
/**
@@ -476,7 +500,6 @@ class ParserOutput extends CacheTime {
$this->addModules( $out->getModules() );
$this->addModuleScripts( $out->getModuleScripts() );
$this->addModuleStyles( $out->getModuleStyles() );
- $this->addModuleMessages( $out->getModuleMessages() );
$this->addJsConfigVars( $out->getJsConfigVars() );
$this->mHeadItems = array_merge( $this->mHeadItems, $out->getHeadItemsArray() );
@@ -663,6 +686,8 @@ class ParserOutput extends CacheTime {
/**
* Tags a parser option for use in the cache key for this parser output.
* Registered as a watcher at ParserOptions::registerWatcher() by Parser::clearState().
+ * The information gathered here is available via getUsedOptions(),
+ * and is used by ParserCache::save().
*
* @see ParserCache::getKey
* @see ParserCache::save
diff --git a/includes/parser/Preprocessor_DOM.php b/includes/parser/Preprocessor_DOM.php
index 0351f2a8..8a09be83 100644
--- a/includes/parser/Preprocessor_DOM.php
+++ b/includes/parser/Preprocessor_DOM.php
@@ -87,9 +87,9 @@ class Preprocessor_DOM implements Preprocessor {
$xml .= "</list>";
$dom = new DOMDocument();
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$result = $dom->loadXML( $xml );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$result ) {
// Try running the XML through UtfNormal to get rid of invalid characters
$xml = UtfNormal\Validator::cleanUp( $xml );
@@ -154,7 +154,6 @@ class Preprocessor_DOM implements Preprocessor {
$cacheable = ( $wgPreprocessorCacheThreshold !== false
&& strlen( $text ) > $wgPreprocessorCacheThreshold );
if ( $cacheable ) {
-
$cacheKey = wfMemcKey( 'preprocess-xml', md5( $text ), $flags );
$cacheValue = $wgMemc->get( $cacheKey );
if ( $cacheValue ) {
@@ -186,9 +185,9 @@ class Preprocessor_DOM implements Preprocessor {
}
$dom = new DOMDocument;
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$result = $dom->loadXML( $xml );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$result ) {
// Try running the XML through UtfNormal to get rid of invalid characters
$xml = UtfNormal\Validator::cleanUp( $xml );
@@ -853,7 +852,8 @@ class PPDStackElement {
$close, // Matching closing character
$count, // Number of opening characters found (number of "=" for heading)
$parts, // Array of PPDPart objects describing pipe-separated parts.
- $lineStart; // True if the open char appeared at the start of the input line. Not set for headings.
+ $lineStart; // True if the open char appeared at the start of the input line.
+ // Not set for headings.
public $partClass = 'PPDPart';
@@ -1029,6 +1029,10 @@ class PPFrame_DOM implements PPFrame {
$index = $nameNodes->item( 0 )->attributes->getNamedItem( 'index' )->textContent;
$index = $index - $indexOffset;
if ( isset( $namedArgs[$index] ) || isset( $numberedArgs[$index] ) ) {
+ $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
+ wfEscapeWikiText( $this->title ),
+ wfEscapeWikiText( $title ),
+ wfEscapeWikiText( $index ) )->text() );
$this->parser->addTrackingCategory( 'duplicate-args-category' );
}
$numberedArgs[$index] = $value->item( 0 );
@@ -1037,6 +1041,10 @@ class PPFrame_DOM implements PPFrame {
// Named parameter
$name = trim( $this->expand( $nameNodes->item( 0 ), PPFrame::STRIP_COMMENTS ) );
if ( isset( $namedArgs[$name] ) || isset( $numberedArgs[$name] ) ) {
+ $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
+ wfEscapeWikiText( $this->title ),
+ wfEscapeWikiText( $title ),
+ wfEscapeWikiText( $name ) )->text() );
$this->parser->addTrackingCategory( 'duplicate-args-category' );
}
$namedArgs[$name] = $value->item( 0 );
@@ -1195,9 +1203,11 @@ class PPFrame_DOM implements PPFrame {
} elseif ( $contextNode->nodeName == 'comment' ) {
# HTML-style comment
# Remove it in HTML, pre+remove and STRIP_COMMENTS modes
- if ( $this->parser->ot['html']
+ # Not in RECOVER_COMMENTS mode (msgnw) though.
+ if ( ( $this->parser->ot['html']
|| ( $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() )
|| ( $flags & PPFrame::STRIP_COMMENTS )
+ ) && !( $flags & PPFrame::RECOVER_COMMENTS )
) {
$out .= '';
} elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
@@ -1263,7 +1273,7 @@ class PPFrame_DOM implements PPFrame {
$titleText = $this->title->getPrefixedDBkey();
$this->parser->mHeadings[] = array( $titleText, $headingIndex );
$serial = count( $this->parser->mHeadings ) - 1;
- $marker = "{$this->parser->mUniqPrefix}-h-$serial-" . Parser::MARKER_SUFFIX;
+ $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX;
$count = $contextNode->getAttribute( 'level' );
$s = substr( $s, 0, $count ) . $marker . substr( $s, $count );
$this->parser->mStripState->addGeneral( $marker, '' );
diff --git a/includes/parser/Preprocessor_Hash.php b/includes/parser/Preprocessor_Hash.php
index af91ad47..9429e442 100644
--- a/includes/parser/Preprocessor_Hash.php
+++ b/includes/parser/Preprocessor_Hash.php
@@ -112,7 +112,6 @@ class Preprocessor_Hash implements Preprocessor {
* @return PPNode_Hash_Tree
*/
public function preprocessToObj( $text, $flags = 0 ) {
-
// Check cache.
global $wgMemc, $wgPreprocessorCacheThreshold;
@@ -120,7 +119,6 @@ class Preprocessor_Hash implements Preprocessor {
&& strlen( $text ) > $wgPreprocessorCacheThreshold;
if ( $cacheable ) {
-
$cacheKey = wfMemcKey( 'preprocess-hash', md5( $text ), $flags );
$cacheValue = $wgMemc->get( $cacheKey );
if ( $cacheValue ) {
@@ -736,8 +734,12 @@ class Preprocessor_Hash implements Preprocessor {
// Cache
if ( $cacheable ) {
$cacheValue = sprintf( "%08d", self::CACHE_VERSION ) . serialize( $rootNode );
- $wgMemc->set( $cacheKey, $cacheValue, 86400 );
- wfDebugLog( "Preprocessor", "Saved preprocessor Hash to memcached (key $cacheKey)" );
+
+ // T111289: Cache values should not exceed 1 Mb, but they do.
+ if ( strlen( $cacheValue ) <= 1e6 ) {
+ $wgMemc->set( $cacheKey, $cacheValue, 86400 );
+ wfDebugLog( "Preprocessor", "Saved preprocessor Hash to memcached (key $cacheKey)" );
+ }
}
return $rootNode;
@@ -972,6 +974,10 @@ class PPFrame_Hash implements PPFrame {
// Numbered parameter
$index = $bits['index'] - $indexOffset;
if ( isset( $namedArgs[$index] ) || isset( $numberedArgs[$index] ) ) {
+ $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
+ wfEscapeWikiText( $this->title ),
+ wfEscapeWikiText( $title ),
+ wfEscapeWikiText( $index ) )->text() );
$this->parser->addTrackingCategory( 'duplicate-args-category' );
}
$numberedArgs[$index] = $bits['value'];
@@ -980,6 +986,10 @@ class PPFrame_Hash implements PPFrame {
// Named parameter
$name = trim( $this->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
if ( isset( $namedArgs[$name] ) || isset( $numberedArgs[$name] ) ) {
+ $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
+ wfEscapeWikiText( $this->title ),
+ wfEscapeWikiText( $title ),
+ wfEscapeWikiText( $name ) )->text() );
$this->parser->addTrackingCategory( 'duplicate-args-category' );
}
$namedArgs[$name] = $bits['value'];
@@ -1118,9 +1128,11 @@ class PPFrame_Hash implements PPFrame {
} elseif ( $contextNode->name == 'comment' ) {
# HTML-style comment
# Remove it in HTML, pre+remove and STRIP_COMMENTS modes
- if ( $this->parser->ot['html']
+ # Not in RECOVER_COMMENTS mode (msgnw) though.
+ if ( ( $this->parser->ot['html']
|| ( $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() )
|| ( $flags & PPFrame::STRIP_COMMENTS )
+ ) && !( $flags & PPFrame::RECOVER_COMMENTS )
) {
$out .= '';
} elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
@@ -1177,7 +1189,7 @@ class PPFrame_Hash implements PPFrame {
$titleText = $this->title->getPrefixedDBkey();
$this->parser->mHeadings[] = array( $titleText, $bits['i'] );
$serial = count( $this->parser->mHeadings ) - 1;
- $marker = "{$this->parser->mUniqPrefix}-h-$serial-" . Parser::MARKER_SUFFIX;
+ $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX;
$s = substr( $s, 0, $bits['level'] ) . $marker . substr( $s, $bits['level'] );
$this->parser->mStripState->addGeneral( $marker, '' );
$out .= $s;
diff --git a/includes/parser/StripState.php b/includes/parser/StripState.php
index 51ae42dc..b11dc8c3 100644
--- a/includes/parser/StripState.php
+++ b/includes/parser/StripState.php
@@ -37,15 +37,20 @@ class StripState {
const UNSTRIP_RECURSION_LIMIT = 20;
/**
- * @param string $prefix
+ * @param string|null $prefix
+ * @since 1.26 The prefix argument should be omitted, as the strip marker
+ * prefix string is now a constant.
*/
- public function __construct( $prefix ) {
- $this->prefix = $prefix;
+ public function __construct( $prefix = null ) {
+ if ( $prefix !== null ) {
+ wfDeprecated( __METHOD__ . ' with called with $prefix argument' .
+ ' (call with no arguments instead)', '1.26' );
+ }
$this->data = array(
'nowiki' => array(),
'general' => array()
);
- $this->regex = "/{$this->prefix}([^\x7f]+)" . Parser::MARKER_SUFFIX . '/';
+ $this->regex = '/' . Parser::MARKER_PREFIX . "([^\x7f]+)" . Parser::MARKER_SUFFIX . '/';
$this->circularRefGuard = array();
}
@@ -144,7 +149,11 @@ class StripState {
}
$this->circularRefGuard[$marker] = true;
$this->recursionLevel++;
- $ret = $this->unstripType( $this->tempType, $this->data[$this->tempType][$marker] );
+ $value = $this->data[$this->tempType][$marker];
+ if ( $value instanceof Closure ) {
+ $value = $value();
+ }
+ $ret = $this->unstripType( $this->tempType, $value );
$this->recursionLevel--;
unset( $this->circularRefGuard[$marker] );
return $ret;
@@ -162,10 +171,10 @@ class StripState {
* @return StripState
*/
public function getSubState( $text ) {
- $subState = new StripState( $this->prefix );
+ $subState = new StripState();
$pos = 0;
while ( true ) {
- $startPos = strpos( $text, $this->prefix, $pos );
+ $startPos = strpos( $text, Parser::MARKER_PREFIX, $pos );
$endPos = strpos( $text, Parser::MARKER_SUFFIX, $pos );
if ( $startPos === false || $endPos === false ) {
break;
@@ -198,7 +207,7 @@ class StripState {
* @return array
*/
public function merge( $otherState, $texts ) {
- $mergePrefix = Parser::getRandomString();
+ $mergePrefix = wfRandomString( 16 );
foreach ( $otherState->data as $type => $items ) {
foreach ( $items as $key => $value ) {
@@ -218,7 +227,7 @@ class StripState {
*/
protected function mergeCallback( $m ) {
$key = $m[1];
- return "{$this->prefix}{$this->tempMergePrefix}-$key" . Parser::MARKER_SUFFIX;
+ return Parser::MARKER_PREFIX . $this->tempMergePrefix . '-' . $key . Parser::MARKER_SUFFIX;
}
/**
diff --git a/includes/password/EncryptedPassword.php b/includes/password/EncryptedPassword.php
index 39da32d1..6723793c 100644
--- a/includes/password/EncryptedPassword.php
+++ b/includes/password/EncryptedPassword.php
@@ -47,7 +47,7 @@ class EncryptedPassword extends ParameterizedPassword {
$secret, 0, base64_decode( $this->args[0] )
) );
} else {
- $underlyingPassword = $this->factory->newFromType( $this->config['underlying'], $this->config );
+ $underlyingPassword = $this->factory->newFromType( $this->config['underlying'] );
}
$underlyingPassword->crypt( $password );
diff --git a/includes/password/PasswordPolicyChecks.php b/includes/password/PasswordPolicyChecks.php
new file mode 100644
index 00000000..eb4a9582
--- /dev/null
+++ b/includes/password/PasswordPolicyChecks.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Password policy checks
+ *
+ * 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
+ */
+
+/**
+ * Functions to check passwords against a policy requirement
+ * @since 1.26
+ */
+class PasswordPolicyChecks {
+
+ /**
+ * Check password is longer than minimum, not fatal
+ * @param int $policyVal minimal length
+ * @param User $user
+ * @param string $password
+ * @return Status error if $password is shorter than $policyVal
+ */
+ public static function checkMinimalPasswordLength( $policyVal, User $user, $password ) {
+ $status = Status::newGood();
+ if ( $policyVal > strlen( $password ) ) {
+ $status->error( 'passwordtooshort', $policyVal );
+ }
+ return $status;
+ }
+
+ /**
+ * Check password is longer than minimum, fatal
+ * @param int $policyVal minimal length
+ * @param User $user
+ * @param string $password
+ * @return Status fatal if $password is shorter than $policyVal
+ */
+ public static function checkMinimumPasswordLengthToLogin( $policyVal, User $user, $password ) {
+ $status = Status::newGood();
+ if ( $policyVal > strlen( $password ) ) {
+ $status->fatal( 'passwordtooshort', $policyVal );
+ }
+ return $status;
+ }
+
+ /**
+ * Check password is shorter than maximum, fatal
+ * @param int $policyVal maximum length
+ * @param User $user
+ * @param string $password
+ * @return Status fatal if $password is shorter than $policyVal
+ */
+ public static function checkMaximalPasswordLength( $policyVal, User $user, $password ) {
+ $status = Status::newGood();
+ if ( $policyVal < strlen( $password ) ) {
+ $status->fatal( 'passwordtoolong', $policyVal );
+ }
+ return $status;
+ }
+
+ /**
+ * Check if username and password match
+ * @param bool $policyVal true to force compliance.
+ * @param User $user
+ * @param string $password
+ * @return Status error if username and password match, and policy is true
+ */
+ public static function checkPasswordCannotMatchUsername( $policyVal, User $user, $password ) {
+ global $wgContLang;
+ $status = Status::newGood();
+ $username = $user->getName();
+ if ( $policyVal && $wgContLang->lc( $password ) === $wgContLang->lc( $username ) ) {
+ $status->error( 'password-name-match' );
+ }
+ return $status;
+ }
+
+ /**
+ * Check if username and password are on a blacklist
+ * @param bool $policyVal true to force compliance.
+ * @param User $user
+ * @param string $password
+ * @return Status error if username and password match, and policy is true
+ */
+ public static function checkPasswordCannotMatchBlacklist( $policyVal, User $user, $password ) {
+ static $blockedLogins = array(
+ 'Useruser' => 'Passpass', 'Useruser1' => 'Passpass1', # r75589
+ 'Apitestsysop' => 'testpass', 'Apitestuser' => 'testpass' # r75605
+ );
+
+ $status = Status::newGood();
+ $username = $user->getName();
+ if ( $policyVal
+ && isset( $blockedLogins[$username] )
+ && $password == $blockedLogins[$username]
+ ) {
+ $status->error( 'password-login-forbidden' );
+ }
+ return $status;
+ }
+
+}
diff --git a/includes/password/UserPasswordPolicy.php b/includes/password/UserPasswordPolicy.php
new file mode 100644
index 00000000..d57adb8e
--- /dev/null
+++ b/includes/password/UserPasswordPolicy.php
@@ -0,0 +1,201 @@
+<?php
+/**
+ * Password policy checking for a user
+ *
+ * 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
+ */
+
+/**
+ * Check if a user's password complies with any password policies that apply to that
+ * user, based on the user's group membership.
+ * @since 1.26
+ */
+class UserPasswordPolicy {
+
+ /**
+ * @var array
+ */
+ private $policies;
+
+ /**
+ * Mapping of statements to the function that will test the password for compliance. The
+ * checking functions take the policy value, the user, and password, and return a Status
+ * object indicating compliance.
+ * @var array
+ */
+ private $policyCheckFunctions;
+
+ /**
+ * @param array $policies
+ * @param array $checks mapping statement to its checking function. Checking functions are
+ * called with the policy value for this user, the user object, and the password to check.
+ */
+ public function __construct( array $policies, array $checks ) {
+ if ( !isset( $policies['default'] ) ) {
+ throw new InvalidArgumentException(
+ 'Must include a \'default\' password policy'
+ );
+ }
+ $this->policies = $policies;
+
+ foreach ( $checks as $statement => $check ) {
+ if ( !is_callable( $check ) ) {
+ throw new InvalidArgumentException(
+ "Policy check functions must be callable. '$statement' isn't callable."
+ );
+ }
+ $this->policyCheckFunctions[$statement] = $check;
+ }
+ }
+
+ /**
+ * Check if a passwords meets the effective password policy for a User.
+ * @param User $user who's policy we are checking
+ * @param string $password the password to check
+ * @param string $purpose one of 'login', 'create', 'reset'
+ * @return Status error to indicate the password didn't meet the policy, or fatal to
+ * indicate the user shouldn't be allowed to login.
+ */
+ public function checkUserPassword( User $user, $password, $purpose = 'login' ) {
+ $effectivePolicy = $this->getPoliciesForUser( $user, $purpose );
+ return $this->checkPolicies(
+ $user,
+ $password,
+ $effectivePolicy,
+ $this->policyCheckFunctions
+ );
+ }
+
+ /**
+ * Check if a passwords meets the effective password policy for a User, using a set
+ * of groups they may or may not belong to. This function does not use the DB, so can
+ * be used in the installer.
+ * @param User $user who's policy we are checking
+ * @param string $password the password to check
+ * @param array $groups list of groups to which we assume the user belongs
+ * @return Status error to indicate the password didn't meet the policy, or fatal to
+ * indicate the user shouldn't be allowed to login.
+ */
+ public function checkUserPasswordForGroups( User $user, $password, array $groups ) {
+ $effectivePolicy = self::getPoliciesForGroups(
+ $this->policies,
+ $groups,
+ $this->policies['default']
+ );
+ return $this->checkPolicies(
+ $user,
+ $password,
+ $effectivePolicy,
+ $this->policyCheckFunctions
+ );
+ }
+
+ /**
+ * @param User $user
+ * @param string $password
+ * @param array $policies
+ * @param array $policyCheckFunctions
+ * @return Status
+ */
+ private function checkPolicies( User $user, $password, $policies, $policyCheckFunctions ) {
+ $status = Status::newGood();
+ foreach ( $policies as $policy => $value ) {
+ if ( !isset( $policyCheckFunctions[$policy] ) ) {
+ throw new DomainException( "Invalid password policy config. No check defined for '$policy'." );
+ }
+ $status->merge(
+ call_user_func(
+ $policyCheckFunctions[$policy],
+ $value,
+ $user,
+ $password
+ )
+ );
+ }
+ return $status;
+ }
+
+ /**
+ * Get the policy for a user, based on their group membership. Public so
+ * UI elements can access and inform the user.
+ * @param User $user
+ * @param string $purpose one of 'login', 'create', 'reset'
+ * @return array the effective policy for $user
+ */
+ public function getPoliciesForUser( User $user, $purpose = 'login' ) {
+ $effectivePolicy = $this->policies['default'];
+ if ( $purpose !== 'create' ) {
+ $effectivePolicy = self::getPoliciesForGroups(
+ $this->policies,
+ $user->getEffectiveGroups(),
+ $this->policies['default']
+ );
+ }
+
+ Hooks::run( 'PasswordPoliciesForUser', array( $user, &$effectivePolicy, $purpose ) );
+
+ return $effectivePolicy;
+ }
+
+ /**
+ * Utility function to get the effective policy from a list of policies, based
+ * on a list of groups.
+ * @param array $policies list of policies to consider
+ * @param array $userGroups the groups from which we calculate the effective policy
+ * @param array $defaultPolicy the default policy to start from
+ * @return array effective policy
+ */
+ public static function getPoliciesForGroups( array $policies, array $userGroups,
+ array $defaultPolicy
+ ) {
+ $effectivePolicy = $defaultPolicy;
+ foreach ( $policies as $group => $policy ) {
+ if ( in_array( $group, $userGroups ) ) {
+ $effectivePolicy = self::maxOfPolicies(
+ $effectivePolicy,
+ $policies[$group]
+ );
+ }
+ }
+
+ return $effectivePolicy;
+ }
+
+ /**
+ * Utility function to get a policy that is the most restrictive of $p1 and $p2. For
+ * simplicity, we setup the policy values so the maximum value is always more restrictive.
+ * @param array $p1
+ * @param array $p2
+ * @return array containing the more restrictive values of $p1 and $p2
+ */
+ public static function maxOfPolicies( array $p1, array $p2 ) {
+ $ret = array();
+ $keys = array_merge( array_keys( $p1 ), array_keys( $p2 ) );
+ foreach ( $keys as $key ) {
+ if ( !isset( $p1[$key] ) ) {
+ $ret[$key] = $p2[$key];
+ } elseif ( !isset( $p2[$key] ) ) {
+ $ret[$key] = $p1[$key];
+ } else {
+ $ret[$key] = max( $p1[$key], $p2[$key] );
+ }
+ }
+ return $ret;
+ }
+
+}
diff --git a/includes/poolcounter/PoolCounter.php b/includes/poolcounter/PoolCounter.php
index 5692d731..1ec14aa1 100644
--- a/includes/poolcounter/PoolCounter.php
+++ b/includes/poolcounter/PoolCounter.php
@@ -192,10 +192,11 @@ abstract class PoolCounter {
}
/**
- * Given a key (any string) and the number of lots, returns a slot number (an integer from the [0..($slots-1)] range).
- * This is used for a global limit on the number of instances of a given type that can acquire a lock.
- * The hashing is deterministic so that PoolCounter::$workers is always an upper limit of how many instances with
- * the same key can acquire a lock.
+ * Given a key (any string) and the number of lots, returns a slot number (an integer from
+ * the [0..($slots-1)] range). This is used for a global limit on the number of instances of
+ * a given type that can acquire a lock. The hashing is deterministic so that
+ * PoolCounter::$workers is always an upper limit of how many instances with the same key
+ * can acquire a lock.
*
* @param string $key PoolCounter instance key (any string)
* @param int $slots The number of slots (max allowed value is 65536)
diff --git a/includes/poolcounter/PoolCounterRedis.php b/includes/poolcounter/PoolCounterRedis.php
index 98797a30..d7357cfe 100644
--- a/includes/poolcounter/PoolCounterRedis.php
+++ b/includes/poolcounter/PoolCounterRedis.php
@@ -76,7 +76,7 @@ class PoolCounterRedis extends PoolCounter {
const AWAKE_ONE = 1; // wake-up if when a slot can be taken from an existing process
const AWAKE_ALL = 2; // wake-up if an existing process finishes and wake up such others
- /** @var array List of active PoolCounterRedis objects in this script */
+ /** @var PoolCounterRedis[] List of active PoolCounterRedis objects in this script */
protected static $active = null;
function __construct( $conf, $type, $key ) {
@@ -121,7 +121,6 @@ class PoolCounterRedis extends PoolCounter {
}
function acquireForMe() {
-
$status = $this->precheckAcquire();
if ( !$status->isGood() ) {
return $status;
@@ -131,7 +130,6 @@ class PoolCounterRedis extends PoolCounter {
}
function acquireForAnyone() {
-
$status = $this->precheckAcquire();
if ( !$status->isGood() ) {
return $status;
@@ -141,7 +139,6 @@ class PoolCounterRedis extends PoolCounter {
}
function release() {
-
if ( $this->slot === null ) {
return Status::newGood( PoolCounter::NOT_LOCKED ); // not locked
}
@@ -190,7 +187,7 @@ class PoolCounterRedis extends PoolCounter {
return 1
LUA;
try {
- $res = $conn->luaEval( $script,
+ $conn->luaEval( $script,
array(
$this->getSlotListKey(),
$this->getSlotRTimeSetKey(),
diff --git a/includes/poolcounter/PoolWorkArticleView.php b/includes/poolcounter/PoolWorkArticleView.php
index a702d2e8..d601467d 100644
--- a/includes/poolcounter/PoolWorkArticleView.php
+++ b/includes/poolcounter/PoolWorkArticleView.php
@@ -142,8 +142,12 @@ class PoolWorkArticleView extends PoolCounterWork {
// Timing hack
if ( $time > 3 ) {
- wfDebugLog( 'slow-parse', sprintf( "%-5.2f %s", $time,
- $this->page->getTitle()->getPrefixedDBkey() ) );
+ // TODO: Use Parser's logger (once it has one)
+ $logger = MediaWiki\Logger\LoggerFactory::getInstance( 'slow-parse' );
+ $logger->info( '{time} {title}', array(
+ 'time' => number_format( $time, 2 ),
+ 'title' => $this->page->getTitle()->getPrefixedDBkey(),
+ ) );
}
if ( $this->cacheable && $this->parserOutput->isCacheable() && $isCurrent ) {
diff --git a/includes/profiler/ProfileSection.php b/includes/profiler/ProfileSection.php
index 68ef6680..d787edb7 100644
--- a/includes/profiler/ProfileSection.php
+++ b/includes/profiler/ProfileSection.php
@@ -35,9 +35,10 @@ class ProfileSection {
* the same moment that the function to be profiled terminates.
*
* This is typically called like:
- * <code>$section = new ProfileSection( __METHOD__ );</code>
+ * @code$section = new ProfileSection( __METHOD__ );@endcode
*
* @param string $name Name of the function to profile
*/
- public function __construct( $name ) {}
+ public function __construct( $name ) {
+ }
}
diff --git a/includes/profiler/Profiler.php b/includes/profiler/Profiler.php
index dbf80fa1..9fd5a364 100644
--- a/includes/profiler/Profiler.php
+++ b/includes/profiler/Profiler.php
@@ -145,8 +145,11 @@ abstract class Profiler {
}
// Kept BC for now, remove when possible
- public function profileIn( $functionname ) {}
- public function profileOut( $functionname ) {}
+ public function profileIn( $functionname ) {
+ }
+
+ public function profileOut( $functionname ) {
+ }
/**
* Mark the start of a custom profiling frame (e.g. DB queries).
@@ -231,6 +234,21 @@ abstract class Profiler {
}
/**
+ * Output current data to the page output if configured to do so
+ *
+ * @throws MWException
+ * @since 1.26
+ */
+ public function logDataPageOutputOnly() {
+ foreach ( $this->getOutputs() as $output ) {
+ if ( $output instanceof ProfilerOutputText ) {
+ $stats = $this->getFunctionStats();
+ $output->log( $stats );
+ }
+ }
+ }
+
+ /**
* Get the content type sent out to the client.
* Used for profilers that output instead of store data.
* @return string
@@ -279,9 +297,9 @@ abstract class Profiler {
* @return array List of method entries arrays, each having:
* - name : method name
* - calls : the number of invoking calls
- * - real : real time ellapsed (ms)
+ * - real : real time elapsed (ms)
* - %real : percent real time
- * - cpu : CPU time ellapsed (ms)
+ * - cpu : CPU time elapsed (ms)
* - %cpu : percent CPU time
* - memory : memory used (bytes)
* - %memory : percent memory used
diff --git a/includes/profiler/ProfilerFunctions.php b/includes/profiler/ProfilerFunctions.php
index 4984e77d..6c584532 100644
--- a/includes/profiler/ProfilerFunctions.php
+++ b/includes/profiler/ProfilerFunctions.php
@@ -32,7 +32,7 @@
function wfGetRusage() {
if ( !function_exists( 'getrusage' ) ) {
return false;
- } elseif ( defined ( 'HHVM_VERSION' ) ) {
+ } elseif ( defined( 'HHVM_VERSION' ) ) {
return getrusage( 2 /* RUSAGE_THREAD */ );
} else {
return getrusage( 0 /* RUSAGE_SELF */ );
diff --git a/includes/profiler/ProfilerStub.php b/includes/profiler/ProfilerStub.php
index 244b4e4b..3fe9cddb 100644
--- a/includes/profiler/ProfilerStub.php
+++ b/includes/profiler/ProfilerStub.php
@@ -46,4 +46,7 @@ class ProfilerStub extends Profiler {
public function logData() {
}
+
+ public function logDataPageOutputOnly() {
+ }
}
diff --git a/includes/profiler/ProfilerXhprof.php b/includes/profiler/ProfilerXhprof.php
index f36cdc1a..5f7fc002 100644
--- a/includes/profiler/ProfilerXhprof.php
+++ b/includes/profiler/ProfilerXhprof.php
@@ -40,12 +40,8 @@
*
* To restrict the functions for which profiling data is collected, you can
* use either a whitelist ($wgProfiler['include']) or a blacklist
- * ($wgProfiler['exclude']) containing an array of function names. The
- * blacklist functionality is built into HHVM and will completely exclude the
- * named functions from profiling collection. The whitelist is implemented by
- * Xhprof class which will filter the data collected by XHProf before reporting.
- * See documentation for the Xhprof class and the XHProf extension for
- * additional information.
+ * ($wgProfiler['exclude']) containing an array of function names.
+ * Shell-style patterns are also accepted.
*
* @author Bryan Davis <bd808@wikimedia.org>
* @copyright © 2014 Bryan Davis and Wikimedia Foundation.
@@ -77,7 +73,8 @@ class ProfilerXhprof extends Profiler {
}
public function scopedProfileIn( $section ) {
- return $this->sprofiler->scopedProfileIn( $section );
+ $key = 'section.' . ltrim( $section, '.' );
+ return $this->sprofiler->scopedProfileIn( $key );
}
/**
@@ -86,12 +83,43 @@ class ProfilerXhprof extends Profiler {
public function close() {
}
+ /**
+ * Check if a function or section should be excluded from the output.
+ *
+ * @param string $name Function or section name.
+ * @return bool
+ */
+ private function shouldExclude( $name ) {
+ if ( $name === '-total' ) {
+ return true;
+ }
+ if ( !empty( $this->params['include'] ) ) {
+ foreach ( $this->params['include'] as $pattern ) {
+ if ( fnmatch( $pattern, $name, FNM_NOESCAPE ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ if ( !empty( $this->params['exclude'] ) ) {
+ foreach ( $this->params['exclude'] as $pattern ) {
+ if ( fnmatch( $pattern, $name, FNM_NOESCAPE ) ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
public function getFunctionStats() {
$metrics = $this->xhprof->getCompleteMetrics();
$profile = array();
$main = null; // units in ms
foreach ( $metrics as $fname => $stats ) {
+ if ( $this->shouldExclude( $fname ) ) {
+ continue;
+ }
// Convert elapsed times from μs to ms to match interface
$entry = array(
'name' => $fname,
@@ -113,8 +141,7 @@ class ProfilerXhprof extends Profiler {
// Merge in all of the custom profile sections
foreach ( $this->sprofiler->getFunctionStats() as $stats ) {
- if ( $stats['name'] === '-total' ) {
- // Discard section profiler running totals
+ if ( $this->shouldExclude( $stats['name'] ) ) {
continue;
}
diff --git a/includes/profiler/SectionProfiler.php b/includes/profiler/SectionProfiler.php
index 245022df..63940bc9 100644
--- a/includes/profiler/SectionProfiler.php
+++ b/includes/profiler/SectionProfiler.php
@@ -89,9 +89,9 @@ class SectionProfiler {
* @return array List of method entries arrays, each having:
* - name : method name
* - calls : the number of invoking calls
- * - real : real time ellapsed (ms)
+ * - real : real time elapsed (ms)
* - %real : percent real time
- * - cpu : real time ellapsed (ms)
+ * - cpu : real time elapsed (ms)
* - %cpu : percent real time
* - memory : memory used (bytes)
* - %memory : percent memory used
@@ -451,15 +451,14 @@ class SectionProfiler {
}
/**
- * Get the initial time of the request, based either on $wgRequestTime or
- * $wgRUstart. Will return null if not able to find data.
+ * Get the initial time of the request, based on getrusage()
*
* @param string|bool $metric Metric to use, with the following possibilities:
* - user: User CPU time (without system calls)
* - cpu: Total CPU time (user and system calls)
* - wall (or any other string): elapsed time
* - false (default): will fall back to default metric
- * @return float|null
+ * @return float
*/
protected function getTime( $metric = 'wall' ) {
if ( $metric === 'cpu' || $metric === 'user' ) {
diff --git a/includes/profiler/TransactionProfiler.php b/includes/profiler/TransactionProfiler.php
index f02d66f8..46d6119b 100644
--- a/includes/profiler/TransactionProfiler.php
+++ b/includes/profiler/TransactionProfiler.php
@@ -25,6 +25,7 @@
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\NullLogger;
+
/**
* Helper class that detects high-contention DB queries via profiling calls
*
@@ -52,11 +53,13 @@ class TransactionProfiler implements LoggerAwareInterface {
);
/** @var array */
protected $expect = array(
- 'writes' => INF,
- 'queries' => INF,
- 'conns' => INF,
- 'masterConns' => INF,
- 'maxAffected' => INF
+ 'writes' => INF,
+ 'queries' => INF,
+ 'conns' => INF,
+ 'masterConns' => INF,
+ 'maxAffected' => INF,
+ 'readQueryTime' => INF,
+ 'writeQueryTime' => INF
);
/** @var array */
protected $expectBy = array();
@@ -77,7 +80,7 @@ class TransactionProfiler implements LoggerAwareInterface {
/**
* Set performance expectations
*
- * With conflicting expect, the most specific ones will be used
+ * With conflicting expectations, the most narrow ones will be used
*
* @param string $event (writes,queries,conns,mConns)
* @param integer $value Maximum count of the event
@@ -94,6 +97,21 @@ class TransactionProfiler implements LoggerAwareInterface {
}
/**
+ * Set multiple performance expectations
+ *
+ * With conflicting expectations, the most narrow ones will be used
+ *
+ * @param array $expects Map of (event => limit)
+ * @param $fname
+ * @since 1.26
+ */
+ public function setExpectations( array $expects, $fname ) {
+ foreach ( $expects as $event => $value ) {
+ $this->setExpectation( $event, $value, $fname );
+ }
+ }
+
+ /**
* Reset performance expectations and hit counters
*
* @since 1.25
@@ -170,7 +188,8 @@ class TransactionProfiler implements LoggerAwareInterface {
$elapsed = ( $eTime - $sTime );
if ( $isWrite && $n > $this->expect['maxAffected'] ) {
- $this->logger->info( "Query affected $n row(s):\n" . $query . "\n" . wfBacktrace( true ) );
+ $this->logger->info( "Query affected $n row(s):\n" . $query . "\n" .
+ wfBacktrace( true ) );
}
// Report when too many writes/queries happen...
@@ -180,6 +199,13 @@ class TransactionProfiler implements LoggerAwareInterface {
if ( $isWrite && $this->hits['writes']++ == $this->expect['writes'] ) {
$this->reportExpectationViolated( 'writes', $query );
}
+ // Report slow queries...
+ if ( !$isWrite && $elapsed > $this->expect['readQueryTime'] ) {
+ $this->reportExpectationViolated( 'readQueryTime', $query );
+ }
+ if ( $isWrite && $elapsed > $this->expect['writeQueryTime'] ) {
+ $this->reportExpectationViolated( 'writeQueryTime', $query );
+ }
if ( !$this->dbTrxHoldingLocks ) {
// Short-circuit
@@ -220,13 +246,23 @@ class TransactionProfiler implements LoggerAwareInterface {
* @param string $server DB server
* @param string $db DB name
* @param string $id ID string of transaction
+ * @param float $writeTime Time spent in write queries
*/
- public function transactionWritingOut( $server, $db, $id ) {
+ public function transactionWritingOut( $server, $db, $id, $writeTime = 0.0 ) {
$name = "{$server} ({$db}) (TRX#$id)";
if ( !isset( $this->dbTrxMethodTimes[$name] ) ) {
$this->logger->info( "Detected no transaction for '$name' - out of sync." );
return;
}
+
+ $slow = false;
+
+ // Warn if too much time was spend writing...
+ if ( $writeTime > $this->expect['writeQueryTime'] ) {
+ $this->reportExpectationViolated( 'writeQueryTime',
+ "[transaction $id writes to {$server} ({$db})]" );
+ $slow = true;
+ }
// Fill in the last non-query period...
$lastQuery = end( $this->dbTrxMethodTimes[$name] );
if ( $lastQuery ) {
@@ -237,7 +273,6 @@ class TransactionProfiler implements LoggerAwareInterface {
}
}
// Check for any slow queries or non-query periods...
- $slow = false;
foreach ( $this->dbTrxMethodTimes[$name] as $info ) {
$elapsed = ( $info[2] - $info[1] );
if ( $elapsed >= $this->dbLockThreshold ) {
@@ -268,7 +303,8 @@ class TransactionProfiler implements LoggerAwareInterface {
$n = $this->expect[$expect];
$by = $this->expectBy[$expect];
$this->logger->info(
- "[{$wgRequest->getMethod()}] Expectation ($expect <= $n) by $by not met:\n$query\n" . wfBacktrace( true )
+ "[{$wgRequest->getMethod()}] Expectation ($expect <= $n) by $by not met:\n$query\n" .
+ wfBacktrace( true )
);
}
}
diff --git a/includes/profiler/output/ProfilerOutputDump.php b/includes/profiler/output/ProfilerOutputDump.php
index bf4b85c2..09f56887 100644
--- a/includes/profiler/output/ProfilerOutputDump.php
+++ b/includes/profiler/output/ProfilerOutputDump.php
@@ -45,7 +45,11 @@ class ProfilerOutputDump extends ProfilerOutput {
public function log( array $stats ) {
$data = $this->collector->getRawData();
- $filename = sprintf( "%s/%s.%s%s", $this->params['outputDir'], uniqid(), $this->collector->getProfileID(), $this->suffix );
+ $filename = sprintf( "%s/%s.%s%s",
+ $this->params['outputDir'],
+ uniqid(),
+ $this->collector->getProfileID(),
+ $this->suffix );
file_put_contents( $filename, serialize( $data ) );
}
}
diff --git a/includes/profiler/output/ProfilerOutputStats.php b/includes/profiler/output/ProfilerOutputStats.php
index ef6ef7c9..52aa54ac 100644
--- a/includes/profiler/output/ProfilerOutputStats.php
+++ b/includes/profiler/output/ProfilerOutputStats.php
@@ -37,13 +37,11 @@ class ProfilerOutputStats extends ProfilerOutput {
* @param array $stats
*/
public function log( array $stats ) {
+ $prefix = isset( $this->params['prefix'] ) ? $this->params['prefix'] : '';
$contextStats = $this->collector->getContext()->getStats();
foreach ( $stats as $stat ) {
- // Sanitize the key
- $key = str_replace( '::', '.', $stat['name'] );
- $key = preg_replace( '/[^a-z.]+/i', '_', $key );
- $key = trim( $key, '_.' );
+ $key = "{$prefix}.{$stat['name']}";
// Convert fractional seconds to whole milliseconds
$cpu = round( $stat['cpu'] * 1000 );
diff --git a/includes/profiler/output/ProfilerOutputText.php b/includes/profiler/output/ProfilerOutputText.php
index 67527798..dc24f181 100644
--- a/includes/profiler/output/ProfilerOutputText.php
+++ b/includes/profiler/output/ProfilerOutputText.php
@@ -35,7 +35,7 @@ class ProfilerOutputText extends ProfilerOutput {
parent::__construct( $collector, $params );
$this->thresholdMs = isset( $params['thresholdMs'] )
? $params['thresholdMs']
- : .25;
+ : 1.0;
}
public function log( array $stats ) {
if ( $this->collector->getTemplated() ) {
diff --git a/includes/profiler/output/ProfilerOutputUdp.php b/includes/profiler/output/ProfilerOutputUdp.php
index 7da03c11..a5626779 100644
--- a/includes/profiler/output/ProfilerOutputUdp.php
+++ b/includes/profiler/output/ProfilerOutputUdp.php
@@ -23,7 +23,7 @@
/**
* ProfilerSimpleUDP class, that sends out messages for 'udpprofile' daemon
- * (see http://git.wikimedia.org/tree/operations%2Fsoftware.git/master/udpprofile)
+ * (see https://git.wikimedia.org/tree/operations%2Fsoftware.git/master/udpprofile)
*
* @ingroup Profiler
* @since 1.25
diff --git a/includes/rcfeed/MachineReadableRCFeedFormatter.php b/includes/rcfeed/MachineReadableRCFeedFormatter.php
index 519606ca..f524361a 100644
--- a/includes/rcfeed/MachineReadableRCFeedFormatter.php
+++ b/includes/rcfeed/MachineReadableRCFeedFormatter.php
@@ -90,9 +90,7 @@ abstract class MachineReadableRCFeedFormatter implements RCFeedFormatter {
$packet['log_type'] = $rc->getAttribute( 'rc_log_type' );
$packet['log_action'] = $rc->getAttribute( 'rc_log_action' );
if ( $rc->getAttribute( 'rc_params' ) ) {
- wfSuppressWarnings();
- $params = unserialize( $rc->getAttribute( 'rc_params' ) );
- wfRestoreWarnings();
+ $params = $rc->parseParams();
if (
// If it's an actual serialised false...
$rc->getAttribute( 'rc_params' ) == serialize( false ) ||
diff --git a/includes/rcfeed/RCFeedFormatter.php b/includes/rcfeed/RCFeedFormatter.php
index 2f156598..f7e62ee6 100644
--- a/includes/rcfeed/RCFeedFormatter.php
+++ b/includes/rcfeed/RCFeedFormatter.php
@@ -32,7 +32,8 @@ interface RCFeedFormatter {
* @param RecentChange $rc The RecentChange object showing what sort
* of event has taken place.
* @param string|null $actionComment
- * @return string The text to send.
+ * @return string|null The text to send. If the formatter returns null,
+ * the line will not be sent.
*/
public function getLine( array $feed, RecentChange $rc, $actionComment );
}
diff --git a/includes/registration/CoreVersionChecker.php b/includes/registration/CoreVersionChecker.php
new file mode 100644
index 00000000..f64d826d
--- /dev/null
+++ b/includes/registration/CoreVersionChecker.php
@@ -0,0 +1,68 @@
+<?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
+ */
+
+use Composer\Semver\VersionParser;
+use Composer\Semver\Constraint\Constraint;
+
+/**
+ * @since 1.26
+ */
+class CoreVersionChecker {
+
+ /**
+ * @var Constraint|bool representing $wgVersion
+ */
+ private $coreVersion = false;
+
+ /**
+ * @var VersionParser
+ */
+ private $versionParser;
+
+ /**
+ * @param string $coreVersion Current version of core
+ */
+ public function __construct( $coreVersion ) {
+ $this->versionParser = new VersionParser();
+ try {
+ $this->coreVersion = new Constraint(
+ '==',
+ $this->versionParser->normalize( $coreVersion )
+ );
+ } catch ( UnexpectedValueException $e ) {
+ // Non-parsable version, don't fatal.
+ }
+ }
+
+ /**
+ * Check that the provided constraint is compatible with the current version of core
+ *
+ * @param string $constraint Something like ">= 1.26"
+ * @return bool
+ */
+ public function check( $constraint ) {
+ if ( $this->coreVersion === false ) {
+ // Couldn't parse the core version, so we can't check anything
+ return true;
+ }
+
+ return $this->versionParser->parseConstraints( $constraint )
+ ->matches( $this->coreVersion );
+ }
+}
diff --git a/includes/registration/ExtensionProcessor.php b/includes/registration/ExtensionProcessor.php
index 0b594b42..a286f6bf 100644
--- a/includes/registration/ExtensionProcessor.php
+++ b/includes/registration/ExtensionProcessor.php
@@ -62,6 +62,8 @@ class ExtensionProcessor implements Processor {
'wgExtraGenderNamespaces' => 'array_plus',
'wgNamespacesWithSubpages' => 'array_plus',
'wgNamespaceContentModels' => 'array_plus',
+ 'wgNamespaceProtection' => 'array_plus',
+ 'wgCapitalLinkOverrides' => 'array_plus',
);
/**
@@ -144,9 +146,10 @@ class ExtensionProcessor implements Processor {
/**
* @param string $path
* @param array $info
+ * @param int $version manifest_version for info
* @return array
*/
- public function extractInfo( $path, array $info ) {
+ public function extractInfo( $path, array $info, $version ) {
$this->extractConfig( $info );
$this->extractHooks( $info );
$dir = dirname( $path );
@@ -189,6 +192,16 @@ class ExtensionProcessor implements Processor {
);
}
+ public function getRequirements( array $info ) {
+ $requirements = array();
+ $key = ExtensionRegistry::MEDIAWIKI_CORE;
+ if ( isset( $info['requires'][$key] ) ) {
+ $requirements[$key] = $info['requires'][$key];
+ }
+
+ return $requirements;
+ }
+
protected function extractHooks( array $info ) {
if ( isset( $info['Hooks'] ) ) {
foreach ( $info['Hooks'] as $name => $value ) {
@@ -222,6 +235,12 @@ class ExtensionProcessor implements Processor {
if ( isset( $ns['defaultcontentmodel'] ) ) {
$this->globals['wgNamespaceContentModels'][$id] = $ns['defaultcontentmodel'];
}
+ if ( isset( $ns['protection'] ) ) {
+ $this->globals['wgNamespaceProtection'][$id] = $ns['protection'];
+ }
+ if ( isset( $ns['capitallinkoverride'] ) ) {
+ $this->globals['wgCapitalLinkOverrides'][$id] = $ns['capitallinkoverride'];
+ }
}
}
}
@@ -320,10 +339,14 @@ class ExtensionProcessor implements Processor {
/**
* @param string $name
- * @param mixed $value
+ * @param array $value
* @param array &$array
+ * @throws InvalidArgumentException
*/
protected function storeToArray( $name, $value, &$array ) {
+ if ( !is_array( $value ) ) {
+ throw new InvalidArgumentException( "The value for '$name' should be an array" );
+ }
if ( isset( $array[$name] ) ) {
$array[$name] = array_merge_recursive( $array[$name], $value );
} else {
diff --git a/includes/registration/ExtensionRegistry.php b/includes/registration/ExtensionRegistry.php
index 16d83356..23e29d88 100644
--- a/includes/registration/ExtensionRegistry.php
+++ b/includes/registration/ExtensionRegistry.php
@@ -12,6 +12,11 @@
class ExtensionRegistry {
/**
+ * "requires" key that applies to MediaWiki core/$wgVersion
+ */
+ const MEDIAWIKI_CORE = 'MediaWiki';
+
+ /**
* Version of the highest supported manifest version
*/
const MANIFEST_VERSION = 1;
@@ -81,7 +86,7 @@ class ExtensionRegistry {
// we don't want to fail here if $wgObjectCaches is not configured
// properly for APC setup
try {
- $this->cache = ObjectCache::newAccelerator( array() );
+ $this->cache = ObjectCache::newAccelerator();
} catch ( MWException $e ) {
$this->cache = new EmptyBagOStuff();
}
@@ -156,20 +161,52 @@ class ExtensionRegistry {
* @throws Exception
*/
public function readFromQueue( array $queue ) {
- $data = array( 'globals' => array( 'wgAutoloadClasses' => array() ) );
+ global $wgVersion;
$autoloadClasses = array();
$processor = new ExtensionProcessor();
+ $incompatible = array();
+ $coreVersionParser = new CoreVersionChecker( $wgVersion );
foreach ( $queue as $path => $mtime ) {
$json = file_get_contents( $path );
+ if ( $json === false ) {
+ throw new Exception( "Unable to read $path, does it exist?" );
+ }
$info = json_decode( $json, /* $assoc = */ true );
if ( !is_array( $info ) ) {
throw new Exception( "$path is not a valid JSON file." );
}
+ if ( !isset( $info['manifest_version'] ) ) {
+ // For backwards-compatability, assume a version of 1
+ $info['manifest_version'] = 1;
+ }
+ $version = $info['manifest_version'];
+ if ( $version < self::OLDEST_MANIFEST_VERSION || $version > self::MANIFEST_VERSION ) {
+ throw new Exception( "$path: unsupported manifest_version: {$version}" );
+ }
$autoload = $this->processAutoLoader( dirname( $path ), $info );
// Set up the autoloader now so custom processors will work
$GLOBALS['wgAutoloadClasses'] += $autoload;
$autoloadClasses += $autoload;
- $processor->extractInfo( $path, $info );
+ // Check any constraints against MediaWiki core
+ $requires = $processor->getRequirements( $info );
+ if ( isset( $requires[self::MEDIAWIKI_CORE] )
+ && !$coreVersionParser->check( $requires[self::MEDIAWIKI_CORE] )
+ ) {
+ // Doesn't match, mark it as incompatible.
+ $incompatible[] = "{$info['name']} is not compatible with the current "
+ . "MediaWiki core (version {$wgVersion}), it requires: ". $requires[self::MEDIAWIKI_CORE]
+ . '.';
+ continue;
+ }
+ // Compatible, read and extract info
+ $processor->extractInfo( $path, $info, $version );
+ }
+ if ( $incompatible ) {
+ if ( count( $incompatible ) === 1 ) {
+ throw new Exception( $incompatible[0] );
+ } else {
+ throw new Exception( implode( "\n", $incompatible ) );
+ }
}
$data = $processor->getExtractedInfo();
// Need to set this so we can += to it later
@@ -212,14 +249,7 @@ class ExtensionRegistry {
$GLOBALS[$key] = array_merge_recursive( $GLOBALS[$key], $val );
break;
case 'array_plus_2d':
- // First merge items that are in both arrays
- foreach ( $GLOBALS[$key] as $name => &$groupVal ) {
- if ( isset( $val[$name] ) ) {
- $groupVal += $val[$name];
- }
- }
- // Now add items that didn't exist yet
- $GLOBALS[$key] += $val;
+ $GLOBALS[$key] = wfArrayPlus2d( $GLOBALS[$key], $val );
break;
case 'array_plus':
$GLOBALS[$key] += $val;
diff --git a/includes/registration/Processor.php b/includes/registration/Processor.php
index e930fd3e..e5669d27 100644
--- a/includes/registration/Processor.php
+++ b/includes/registration/Processor.php
@@ -16,12 +16,28 @@ interface Processor {
*
* @param string $path Absolute path of JSON file
* @param array $info
+ * @param int $version manifest_version for info
* @return array "credits" information to store
*/
- public function extractInfo( $path, array $info );
+ public function extractInfo( $path, array $info, $version );
/**
- * @return array With 'globals', 'defines', 'callbacks', 'credits' keys.
+ * @return array With following keys:
+ * 'globals' - variables to be set to $GLOBALS
+ * 'defines' - constants to define
+ * 'callbacks' - functions to be executed by the registry
+ * 'credits' - metadata to be stored by registry
+ * 'attributes' - registration info which isn't a global variable
*/
public function getExtractedInfo();
+
+ /**
+ * Get the requirements for the provided info
+ *
+ * @since 1.26
+ * @param array $info
+ * @return array Where keys are the name to have a constraint on,
+ * like 'MediaWiki'. Values are a constraint string like "1.26.1".
+ */
+ public function getRequirements( array $info );
}
diff --git a/includes/resourceloader/DerivativeResourceLoaderContext.php b/includes/resourceloader/DerivativeResourceLoaderContext.php
index 5784f2a0..59675372 100644
--- a/includes/resourceloader/DerivativeResourceLoaderContext.php
+++ b/includes/resourceloader/DerivativeResourceLoaderContext.php
@@ -28,32 +28,32 @@
* @since 1.24
*/
class DerivativeResourceLoaderContext extends ResourceLoaderContext {
+ const INHERIT_VALUE = -1;
/**
* @var ResourceLoaderContext
*/
private $context;
- protected $modules;
- protected $language;
- protected $direction;
- protected $skin;
- protected $user;
- protected $debug;
- protected $only;
- protected $version;
- protected $hash;
- protected $raw;
+
+ protected $modules = self::INHERIT_VALUE;
+ protected $language = self::INHERIT_VALUE;
+ protected $direction = self::INHERIT_VALUE;
+ protected $skin = self::INHERIT_VALUE;
+ protected $user = self::INHERIT_VALUE;
+ protected $debug = self::INHERIT_VALUE;
+ protected $only = self::INHERIT_VALUE;
+ protected $version = self::INHERIT_VALUE;
+ protected $raw = self::INHERIT_VALUE;
public function __construct( ResourceLoaderContext $context ) {
$this->context = $context;
}
public function getModules() {
- if ( !is_null( $this->modules ) ) {
- return $this->modules;
- } else {
+ if ( $this->modules === self::INHERIT_VALUE ) {
return $this->context->getModules();
}
+ return $this->modules;
}
/**
@@ -64,11 +64,10 @@ class DerivativeResourceLoaderContext extends ResourceLoaderContext {
}
public function getLanguage() {
- if ( !is_null( $this->language ) ) {
- return $this->language;
- } else {
+ if ( $this->language === self::INHERIT_VALUE ) {
return $this->context->getLanguage();
}
+ return $this->language;
}
/**
@@ -76,16 +75,19 @@ class DerivativeResourceLoaderContext extends ResourceLoaderContext {
*/
public function setLanguage( $language ) {
$this->language = $language;
- $this->direction = null; // Invalidate direction since it might be based on language
+ // Invalidate direction since it is based on language
+ $this->direction = null;
$this->hash = null;
}
public function getDirection() {
- if ( !is_null( $this->direction ) ) {
- return $this->direction;
- } else {
+ if ( $this->direction === self::INHERIT_VALUE ) {
return $this->context->getDirection();
}
+ if ( $this->direction === null ) {
+ $this->direction = Language::factory( $this->getLanguage() )->getDir();
+ }
+ return $this->direction;
}
/**
@@ -97,11 +99,10 @@ class DerivativeResourceLoaderContext extends ResourceLoaderContext {
}
public function getSkin() {
- if ( !is_null( $this->skin ) ) {
- return $this->skin;
- } else {
+ if ( $this->skin === self::INHERIT_VALUE ) {
return $this->context->getSkin();
}
+ return $this->skin;
}
/**
@@ -113,11 +114,10 @@ class DerivativeResourceLoaderContext extends ResourceLoaderContext {
}
public function getUser() {
- if ( !is_null( $this->user ) ) {
- return $this->user;
- } else {
+ if ( $this->user === self::INHERIT_VALUE ) {
return $this->context->getUser();
}
+ return $this->user;
}
/**
@@ -130,11 +130,10 @@ class DerivativeResourceLoaderContext extends ResourceLoaderContext {
}
public function getDebug() {
- if ( !is_null( $this->debug ) ) {
- return $this->debug;
- } else {
+ if ( $this->debug === self::INHERIT_VALUE ) {
return $this->context->getDebug();
}
+ return $this->debug;
}
/**
@@ -146,15 +145,14 @@ class DerivativeResourceLoaderContext extends ResourceLoaderContext {
}
public function getOnly() {
- if ( !is_null( $this->only ) ) {
- return $this->only;
- } else {
+ if ( $this->only === self::INHERIT_VALUE ) {
return $this->context->getOnly();
}
+ return $this->only;
}
/**
- * @param string $only
+ * @param string|null $only
*/
public function setOnly( $only ) {
$this->only = $only;
@@ -162,15 +160,14 @@ class DerivativeResourceLoaderContext extends ResourceLoaderContext {
}
public function getVersion() {
- if ( !is_null( $this->version ) ) {
- return $this->version;
- } else {
+ if ( $this->version === self::INHERIT_VALUE ) {
return $this->context->getVersion();
}
+ return $this->version;
}
/**
- * @param string $version
+ * @param string|null $version
*/
public function setVersion( $version ) {
$this->version = $version;
@@ -178,11 +175,10 @@ class DerivativeResourceLoaderContext extends ResourceLoaderContext {
}
public function getRaw() {
- if ( !is_null( $this->raw ) ) {
- return $this->raw;
- } else {
+ if ( $this->raw === self::INHERIT_VALUE ) {
return $this->context->getRaw();
}
+ return $this->raw;
}
/**
diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php
index 150ccd07..c8ece147 100644
--- a/includes/resourceloader/ResourceLoader.php
+++ b/includes/resourceloader/ResourceLoader.php
@@ -22,13 +22,18 @@
* @author Trevor Parscal
*/
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+use WrappedString\WrappedString;
+
/**
* Dynamic JavaScript and CSS resource loading system.
*
* Most of the documentation is on the MediaWiki documentation wiki starting at:
* https://www.mediawiki.org/wiki/ResourceLoader
*/
-class ResourceLoader {
+class ResourceLoader implements LoggerAwareInterface {
/** @var int */
protected static $filterCacheVersion = 7;
@@ -78,6 +83,11 @@ class ResourceLoader {
protected $blobStore;
/**
+ * @var LoggerInterface
+ */
+ private $logger;
+
+ /**
* Load information stored in the database about modules.
*
* This method grabs modules dependencies from the database and updates modules
@@ -169,74 +179,98 @@ class ResourceLoader {
*
* @param string $filter Name of filter to run
* @param string $data Text to filter, such as JavaScript or CSS text
- * @param string $cacheReport Whether to include the cache key report
+ * @param array $options For back-compat, can also be the boolean value for "cacheReport". Keys:
+ * - (bool) cache: Whether to allow caching this data. Default: true.
+ * - (bool) cacheReport: Whether to include the "cache key" report comment. Default: false.
* @return string Filtered data, or a comment containing an error message
*/
- public function filter( $filter, $data, $cacheReport = true ) {
+ public function filter( $filter, $data, $options = array() ) {
+ // Back-compat
+ if ( is_bool( $options ) ) {
+ $options = array( 'cacheReport' => $options );
+ }
+ // Defaults
+ $options += array( 'cache' => true, 'cacheReport' => false );
+ $stats = RequestContext::getMain()->getStats();
- // For empty/whitespace-only data or for unknown filters, don't perform
- // any caching or processing
- if ( trim( $data ) === '' || !in_array( $filter, array( 'minify-js', 'minify-css' ) ) ) {
+ // Don't filter empty content
+ if ( trim( $data ) === '' ) {
return $data;
}
- // Try for cache hit
- // Use CACHE_ANYTHING since filtering is very slow compared to DB queries
- $key = wfMemcKey( 'resourceloader', 'filter', $filter, self::$filterCacheVersion, md5( $data ) );
- $cache = wfGetCache( CACHE_ANYTHING );
- $cacheEntry = $cache->get( $key );
- if ( is_string( $cacheEntry ) ) {
- wfIncrStats( "rl-$filter-cache-hits" );
- return $cacheEntry;
+ if ( !in_array( $filter, array( 'minify-js', 'minify-css' ) ) ) {
+ $this->logger->warning( 'Invalid filter {filter}', array(
+ 'filter' => $filter
+ ) );
+ return $data;
}
- $result = '';
- // Run the filter - we've already verified one of these will work
- try {
- wfIncrStats( "rl-$filter-cache-misses" );
- switch ( $filter ) {
- case 'minify-js':
- $result = JavaScriptMinifier::minify( $data,
- $this->config->get( 'ResourceLoaderMinifierStatementsOnOwnLine' ),
- $this->config->get( 'ResourceLoaderMinifierMaxLineLength' )
- );
- if ( $cacheReport ) {
- $result .= "\n/* cache key: $key */";
- }
- break;
- case 'minify-css':
- $result = CSSMin::minify( $data );
- if ( $cacheReport ) {
- $result .= "\n/* cache key: $key */";
- }
- break;
+ if ( !$options['cache'] ) {
+ $result = self::applyFilter( $filter, $data, $this->config );
+ } else {
+ $key = wfGlobalCacheKey( 'resourceloader', 'filter', $filter, self::$filterCacheVersion, md5( $data ) );
+ $cache = ObjectCache::newAccelerator( CACHE_ANYTHING );
+ $cacheEntry = $cache->get( $key );
+ if ( is_string( $cacheEntry ) ) {
+ $stats->increment( "resourceloader_cache.$filter.hit" );
+ return $cacheEntry;
+ }
+ $result = '';
+ try {
+ $statStart = microtime( true );
+ $result = self::applyFilter( $filter, $data, $this->config );
+ $statTiming = microtime( true ) - $statStart;
+ $stats->increment( "resourceloader_cache.$filter.miss" );
+ $stats->timing( "resourceloader_cache.$filter.timing", 1000 * $statTiming );
+ if ( $options['cacheReport'] ) {
+ $result .= "\n/* cache key: $key */";
+ }
+ // Set a TTL since HHVM's APC doesn't have any limitation or eviction logic.
+ $cache->set( $key, $result, 24 * 3600 );
+ } catch ( Exception $e ) {
+ MWExceptionHandler::logException( $e );
+ $this->logger->warning( 'Minification failed: {exception}', array(
+ 'exception' => $e
+ ) );
+ $this->errors[] = self::formatExceptionNoComment( $e );
}
-
- // Save filtered text to Memcached
- $cache->set( $key, $result );
- } catch ( Exception $e ) {
- MWExceptionHandler::logException( $e );
- wfDebugLog( 'resourceloader', __METHOD__ . ": minification failed: $e" );
- $this->errors[] = self::formatExceptionNoComment( $e );
}
return $result;
}
+ private static function applyFilter( $filter, $data, Config $config ) {
+ switch ( $filter ) {
+ case 'minify-js':
+ return JavaScriptMinifier::minify( $data,
+ $config->get( 'ResourceLoaderMinifierStatementsOnOwnLine' ),
+ $config->get( 'ResourceLoaderMinifierMaxLineLength' )
+ );
+ case 'minify-css':
+ return CSSMin::minify( $data );
+ }
+
+ return $data;
+ }
+
/* Methods */
/**
* Register core modules and runs registration hooks.
* @param Config|null $config
*/
- public function __construct( Config $config = null ) {
+ public function __construct( Config $config = null, LoggerInterface $logger = null ) {
global $IP;
- if ( $config === null ) {
- wfDebug( __METHOD__ . ' was called without providing a Config instance' );
- $config = ConfigFactory::getDefaultInstance()->makeConfig( 'main' );
+ if ( !$logger ) {
+ $logger = new NullLogger();
}
+ $this->setLogger( $logger );
+ if ( !$config ) {
+ $this->logger->debug( __METHOD__ . ' was called without providing a Config instance' );
+ $config = ConfigFactory::getDefaultInstance()->makeConfig( 'main' );
+ }
$this->config = $config;
// Add 'local' source first
@@ -247,9 +281,10 @@ class ResourceLoader {
// Register core modules
$this->register( include "$IP/resources/Resources.php" );
+ $this->register( include "$IP/resources/ResourcesOOUI.php" );
// Register extension modules
- Hooks::run( 'ResourceLoaderRegisterModules', array( &$this ) );
$this->register( $config->get( 'ResourceModules' ) );
+ Hooks::run( 'ResourceLoaderRegisterModules', array( &$this ) );
if ( $config->get( 'EnableJavaScriptTest' ) === true ) {
$this->registerTestModules();
@@ -265,9 +300,21 @@ class ResourceLoader {
return $this->config;
}
+ public function setLogger( LoggerInterface $logger ) {
+ $this->logger = $logger;
+ }
+
+ /**
+ * @since 1.26
+ * @return MessageBlobStore
+ */
+ public function getMessageBlobStore() {
+ return $this->blobStore;
+ }
+
/**
- * @param MessageBlobStore $blobStore
* @since 1.25
+ * @param MessageBlobStore $blobStore
*/
public function setMessageBlobStore( MessageBlobStore $blobStore ) {
$this->blobStore = $blobStore;
@@ -566,19 +613,44 @@ class ResourceLoader {
}
/**
+ * @since 1.26
+ * @param string $value
+ * @return string Hash
+ */
+ public static function makeHash( $value ) {
+ // Use base64 to output more entropy in a more compact string (default hex is only base16).
+ // The first 8 chars of a base64 encoded digest represent the same binary as
+ // the first 12 chars of a hex encoded digest.
+ return substr( base64_encode( sha1( $value, true ) ), 0, 8 );
+ }
+
+ /**
+ * Helper method to get and combine versions of multiple modules.
+ *
+ * @since 1.26
+ * @param ResourceLoaderContext $context
+ * @param array $modules List of ResourceLoaderModule objects
+ * @return string Hash
+ */
+ public function getCombinedVersion( ResourceLoaderContext $context, Array $modules ) {
+ if ( !$modules ) {
+ return '';
+ }
+ // Support: PHP 5.3 ("$this" for anonymous functions was added in PHP 5.4.0)
+ // http://php.net/functions.anonymous
+ $rl = $this;
+ $hashes = array_map( function ( $module ) use ( $rl, $context ) {
+ return $rl->getModule( $module )->getVersionHash( $context );
+ }, $modules );
+ return self::makeHash( implode( $hashes ) );
+ }
+
+ /**
* Output a response to a load request, including the content-type header.
*
* @param ResourceLoaderContext $context Context in which a response should be formed
*/
public function respond( ResourceLoaderContext $context ) {
- // Use file cache if enabled and available...
- if ( $this->config->get( 'UseFileCache' ) ) {
- $fileCache = ResourceFileCache::newFromContext( $context );
- if ( $this->tryRespondFromFileCache( $fileCache, $context ) ) {
- return; // output handled
- }
- }
-
// Buffer output to catch warnings. Normally we'd use ob_clean() on the
// top-level output buffer to clear warnings, but that breaks when ob_gzhandler
// is used: ob_clean() will clear the GZIP header in that case and it won't come
@@ -597,7 +669,7 @@ class ResourceLoader {
// Do not allow private modules to be loaded from the web.
// This is a security issue, see bug 34907.
if ( $module->getGroup() === 'private' ) {
- wfDebugLog( 'resourceloader', __METHOD__ . ": request for private module '$name' denied" );
+ $this->logger->debug( "Request for private module '$name' denied" );
$this->errors[] = "Cannot show private module \"$name\"";
continue;
}
@@ -607,37 +679,46 @@ class ResourceLoader {
}
}
- // Preload information needed to the mtime calculation below
try {
+ // Preload for getCombinedVersion()
$this->preloadModuleInfo( array_keys( $modules ), $context );
} catch ( Exception $e ) {
MWExceptionHandler::logException( $e );
- wfDebugLog( 'resourceloader', __METHOD__ . ": preloading module info failed: $e" );
+ $this->logger->warning( 'Preloading module info failed: {exception}', array(
+ 'exception' => $e
+ ) );
$this->errors[] = self::formatExceptionNoComment( $e );
}
- // To send Last-Modified and support If-Modified-Since, we need to detect
- // the last modified time
- $mtime = wfTimestamp( TS_UNIX, $this->config->get( 'CacheEpoch' ) );
- foreach ( $modules as $module ) {
- /**
- * @var $module ResourceLoaderModule
- */
- try {
- // Calculate maximum modified time
- $mtime = max( $mtime, $module->getModifiedTime( $context ) );
- } catch ( Exception $e ) {
- MWExceptionHandler::logException( $e );
- wfDebugLog( 'resourceloader', __METHOD__ . ": calculating maximum modified time failed: $e" );
- $this->errors[] = self::formatExceptionNoComment( $e );
- }
+ // Combine versions to propagate cache invalidation
+ $versionHash = '';
+ try {
+ $versionHash = $this->getCombinedVersion( $context, array_keys( $modules ) );
+ } catch ( Exception $e ) {
+ MWExceptionHandler::logException( $e );
+ $this->logger->warning( 'Calculating version hash failed: {exception}', array(
+ 'exception' => $e
+ ) );
+ $this->errors[] = self::formatExceptionNoComment( $e );
}
- // If there's an If-Modified-Since header, respond with a 304 appropriately
- if ( $this->tryRespondLastModified( $context, $mtime ) ) {
+ // See RFC 2616 § 3.11 Entity Tags
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11
+ $etag = 'W/"' . $versionHash . '"';
+
+ // Try the client-side cache first
+ if ( $this->tryRespondNotModified( $context, $etag ) ) {
return; // output handled (buffers cleared)
}
+ // Use file cache if enabled and available...
+ if ( $this->config->get( 'UseFileCache' ) ) {
+ $fileCache = ResourceFileCache::newFromContext( $context );
+ if ( $this->tryRespondFromFileCache( $fileCache, $context, $etag ) ) {
+ return; // output handled
+ }
+ }
+
// Generate a response
$response = $this->makeModuleResponse( $context, $modules, $missing );
@@ -659,26 +740,25 @@ class ResourceLoader {
}
}
- // Send content type and cache related headers
- $this->sendResponseHeaders( $context, $mtime, (bool)$this->errors );
+ $this->sendResponseHeaders( $context, $etag, (bool)$this->errors );
// Remove the output buffer and output the response
ob_end_clean();
if ( $context->getImageObj() && $this->errors ) {
// We can't show both the error messages and the response when it's an image.
- $errorText = '';
- foreach ( $this->errors as $error ) {
- $errorText .= $error . "\n";
- }
- $response = $errorText;
+ $response = implode( "\n\n", $this->errors );
} elseif ( $this->errors ) {
- // Prepend comments indicating errors
- $errorText = '';
- foreach ( $this->errors as $error ) {
- $errorText .= self::makeComment( $error );
+ $errorText = implode( "\n\n", $this->errors );
+ $errorResponse = self::makeComment( $errorText );
+ if ( $context->shouldIncludeScripts() ) {
+ $errorResponse .= 'if (window.console && console.error) {'
+ . Xml::encodeJsCall( 'console.error', array( $errorText ) )
+ . "}\n";
}
- $response = $errorText . $response;
+
+ // Prepend error info to the response
+ $response = $errorResponse . $response;
}
$this->errors = array();
@@ -687,13 +767,16 @@ class ResourceLoader {
}
/**
- * Send content type and last modified headers to the client.
+ * Send main response headers to the client.
+ *
+ * Deals with Content-Type, CORS (for stylesheets), and caching.
+ *
* @param ResourceLoaderContext $context
- * @param string $mtime TS_MW timestamp to use for last-modified
+ * @param string $etag ETag header value
* @param bool $errors Whether there are errors in the response
* @return void
*/
- protected function sendResponseHeaders( ResourceLoaderContext $context, $mtime, $errors ) {
+ protected function sendResponseHeaders( ResourceLoaderContext $context, $etag, $errors ) {
$rlMaxage = $this->config->get( 'ResourceLoaderMaxage' );
// If a version wasn't specified we need a shorter expiry time for updates
// to propagate to clients quickly
@@ -720,7 +803,9 @@ class ResourceLoader {
} else {
header( 'Content-Type: text/javascript; charset=utf-8' );
}
- header( 'Last-Modified: ' . wfTimestamp( TS_RFC2822, $mtime ) );
+ // See RFC 2616 § 14.19 ETag
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19
+ header( 'ETag: ' . $etag );
if ( $context->getDebug() ) {
// Do not cache debug responses
header( 'Cache-Control: private, no-cache, must-revalidate' );
@@ -733,39 +818,36 @@ class ResourceLoader {
}
/**
- * Respond with 304 Last Modified if appropiate.
+ * Respond with HTTP 304 Not Modified if appropiate.
*
- * If there's an If-Modified-Since header, respond with a 304 appropriately
+ * If there's an If-None-Match header, respond with a 304 appropriately
* and clear out the output buffer. If the client cache is too old then do nothing.
*
* @param ResourceLoaderContext $context
- * @param string $mtime The TS_MW timestamp to check the header against
- * @return bool True if 304 header sent and output handled
+ * @param string $etag ETag header value
+ * @return bool True if HTTP 304 was sent and output handled
*/
- protected function tryRespondLastModified( ResourceLoaderContext $context, $mtime ) {
- // If there's an If-Modified-Since header, respond with a 304 appropriately
- // Some clients send "timestamp;length=123". Strip the part after the first ';'
- // so we get a valid timestamp.
- $ims = $context->getRequest()->getHeader( 'If-Modified-Since' );
+ protected function tryRespondNotModified( ResourceLoaderContext $context, $etag ) {
+ // See RFC 2616 § 14.26 If-None-Match
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
+ $clientKeys = $context->getRequest()->getHeader( 'If-None-Match', WebRequest::GETHEADER_LIST );
// Never send 304s in debug mode
- if ( $ims !== false && !$context->getDebug() ) {
- $imsTS = strtok( $ims, ';' );
- if ( $mtime <= wfTimestamp( TS_UNIX, $imsTS ) ) {
- // There's another bug in ob_gzhandler (see also the comment at
- // the top of this function) that causes it to gzip even empty
- // responses, meaning it's impossible to produce a truly empty
- // response (because the gzip header is always there). This is
- // a problem because 304 responses have to be completely empty
- // per the HTTP spec, and Firefox behaves buggily when they're not.
- // See also http://bugs.php.net/bug.php?id=51579
- // To work around this, we tear down all output buffering before
- // sending the 304.
- wfResetOutputBuffers( /* $resetGzipEncoding = */ true );
-
- header( 'HTTP/1.0 304 Not Modified' );
- header( 'Status: 304 Not Modified' );
- return true;
- }
+ if ( $clientKeys !== false && !$context->getDebug() && in_array( $etag, $clientKeys ) ) {
+ // There's another bug in ob_gzhandler (see also the comment at
+ // the top of this function) that causes it to gzip even empty
+ // responses, meaning it's impossible to produce a truly empty
+ // response (because the gzip header is always there). This is
+ // a problem because 304 responses have to be completely empty
+ // per the HTTP spec, and Firefox behaves buggily when they're not.
+ // See also http://bugs.php.net/bug.php?id=51579
+ // To work around this, we tear down all output buffering before
+ // sending the 304.
+ wfResetOutputBuffers( /* $resetGzipEncoding = */ true );
+
+ HttpStatus::header( 304 );
+
+ $this->sendResponseHeaders( $context, $etag, false );
+ return true;
}
return false;
}
@@ -775,10 +857,13 @@ class ResourceLoader {
*
* @param ResourceFileCache $fileCache Cache object for this request URL
* @param ResourceLoaderContext $context Context in which to generate a response
+ * @param string $etag ETag header value
* @return bool If this found a cache file and handled the response
*/
protected function tryRespondFromFileCache(
- ResourceFileCache $fileCache, ResourceLoaderContext $context
+ ResourceFileCache $fileCache,
+ ResourceLoaderContext $context,
+ $etag
) {
$rlMaxage = $this->config->get( 'ResourceLoaderMaxage' );
// Buffer output to catch warnings.
@@ -799,16 +884,12 @@ class ResourceLoader {
if ( $good ) {
$ts = $fileCache->cacheTimestamp();
// Send content type and cache headers
- $this->sendResponseHeaders( $context, $ts, false );
- // If there's an If-Modified-Since header, respond with a 304 appropriately
- if ( $this->tryRespondLastModified( $context, $ts ) ) {
- return false; // output handled (buffers cleared)
- }
+ $this->sendResponseHeaders( $context, $etag, false );
$response = $fileCache->fetchText();
// Capture any PHP warnings from the output buffer and append them to the
// response in a comment if we're in debug mode.
if ( $context->getDebug() && strlen( $warnings = ob_get_contents() ) ) {
- $response = "/*\n$warnings\n*/\n" . $response;
+ $response = self::makeComment( $warnings ) . $response;
}
// Remove the output buffer and output the response
ob_end_clean();
@@ -854,11 +935,11 @@ class ResourceLoader {
protected static function formatExceptionNoComment( $e ) {
global $wgShowExceptionDetails;
- if ( $wgShowExceptionDetails ) {
- return $e->__toString();
- } else {
- return wfMessage( 'internalerror' )->text();
+ if ( !$wgShowExceptionDetails ) {
+ return 'Internal error';
}
+
+ return $e->__toString();
}
/**
@@ -896,17 +977,14 @@ MESSAGE;
// Pre-fetch blobs
if ( $context->shouldIncludeMessages() ) {
try {
- $blobs = $this->blobStore->get( $this, $modules, $context->getLanguage() );
+ $this->blobStore->get( $this, $modules, $context->getLanguage() );
} catch ( Exception $e ) {
MWExceptionHandler::logException( $e );
- wfDebugLog(
- 'resourceloader',
- __METHOD__ . ": pre-fetching blobs from MessageBlobStore failed: $e"
- );
+ $this->logger->warning( 'Prefetching MessageBlobStore failed: {exception}', array(
+ 'exception' => $e
+ ) );
$this->errors[] = self::formatExceptionNoComment( $e );
}
- } else {
- $blobs = array();
}
foreach ( $missing as $name ) {
@@ -916,116 +994,43 @@ MESSAGE;
// Generate output
$isRaw = false;
foreach ( $modules as $name => $module ) {
- /**
- * @var $module ResourceLoaderModule
- */
-
try {
- $scripts = '';
- if ( $context->shouldIncludeScripts() ) {
- // If we are in debug mode, we'll want to return an array of URLs if possible
- // However, we can't do this if the module doesn't support it
- // We also can't do this if there is an only= parameter, because we have to give
- // the module a way to return a load.php URL without causing an infinite loop
- if ( $context->getDebug() && !$context->getOnly() && $module->supportsURLLoading() ) {
- $scripts = $module->getScriptURLsForDebug( $context );
- } else {
- $scripts = $module->getScript( $context );
- // rtrim() because there are usually a few line breaks
- // after the last ';'. A new line at EOF, a new line
- // added by ResourceLoaderFileModule::readScriptFiles, etc.
- if ( is_string( $scripts )
- && strlen( $scripts )
- && substr( rtrim( $scripts ), -1 ) !== ';'
- ) {
- // Append semicolon to prevent weird bugs caused by files not
- // terminating their statements right (bug 27054)
- $scripts .= ";\n";
- }
- }
- }
- // Styles
- $styles = array();
- if ( $context->shouldIncludeStyles() ) {
- // Don't create empty stylesheets like array( '' => '' ) for modules
- // that don't *have* any stylesheets (bug 38024).
- $stylePairs = $module->getStyles( $context );
- if ( count( $stylePairs ) ) {
- // If we are in debug mode without &only= set, we'll want to return an array of URLs
- // See comment near shouldIncludeScripts() for more details
- if ( $context->getDebug() && !$context->getOnly() && $module->supportsURLLoading() ) {
- $styles = array(
- 'url' => $module->getStyleURLsForDebug( $context )
- );
- } else {
- // Minify CSS before embedding in mw.loader.implement call
- // (unless in debug mode)
- if ( !$context->getDebug() ) {
- foreach ( $stylePairs as $media => $style ) {
- // Can be either a string or an array of strings.
- if ( is_array( $style ) ) {
- $stylePairs[$media] = array();
- foreach ( $style as $cssText ) {
- if ( is_string( $cssText ) ) {
- $stylePairs[$media][] = $this->filter( 'minify-css', $cssText );
- }
- }
- } elseif ( is_string( $style ) ) {
- $stylePairs[$media] = $this->filter( 'minify-css', $style );
- }
- }
- }
- // Wrap styles into @media groups as needed and flatten into a numerical array
- $styles = array(
- 'css' => self::makeCombinedStyles( $stylePairs )
- );
- }
- }
- }
-
- // Messages
- $messagesBlob = isset( $blobs[$name] ) ? $blobs[$name] : '{}';
+ $content = $module->getModuleContent( $context );
// Append output
switch ( $context->getOnly() ) {
case 'scripts':
+ $scripts = $content['scripts'];
if ( is_string( $scripts ) ) {
// Load scripts raw...
$out .= $scripts;
} elseif ( is_array( $scripts ) ) {
// ...except when $scripts is an array of URLs
- $out .= self::makeLoaderImplementScript( $name, $scripts, array(), array() );
+ $out .= self::makeLoaderImplementScript( $name, $scripts, array(), array(), array() );
}
break;
case 'styles':
+ $styles = $content['styles'];
// We no longer seperate into media, they are all combined now with
// custom media type groups into @media .. {} sections as part of the css string.
// Module returns either an empty array or a numerical array with css strings.
$out .= isset( $styles['css'] ) ? implode( '', $styles['css'] ) : '';
break;
- case 'messages':
- $out .= self::makeMessageSetScript( new XmlJsCode( $messagesBlob ) );
- break;
- case 'templates':
- $out .= Xml::encodeJsCall(
- 'mw.templates.set',
- array( $name, (object)$module->getTemplates() ),
- ResourceLoader::inDebugMode()
- );
- break;
default:
$out .= self::makeLoaderImplementScript(
$name,
- $scripts,
- $styles,
- new XmlJsCode( $messagesBlob ),
- $module->getTemplates()
+ isset( $content['scripts'] ) ? $content['scripts'] : '',
+ isset( $content['styles'] ) ? $content['styles'] : array(),
+ isset( $content['messagesBlob'] ) ? new XmlJsCode( $content['messagesBlob'] ) : array(),
+ isset( $content['templates'] ) ? $content['templates'] : array()
);
break;
}
} catch ( Exception $e ) {
MWExceptionHandler::logException( $e );
- wfDebugLog( 'resourceloader', __METHOD__ . ": generating module package failed: $e" );
+ $this->logger->warning( 'Generating module package failed: {exception}', array(
+ 'exception' => $e
+ ) );
$this->errors[] = self::formatExceptionNoComment( $e );
// Respond to client with error-state instead of module implementation
@@ -1056,11 +1061,19 @@ MESSAGE;
}
}
+ $enableFilterCache = true;
+ if ( count( $modules ) === 1 && reset( $modules ) instanceof ResourceLoaderUserTokensModule ) {
+ // If we're building the embedded user.tokens, don't cache (T84960)
+ $enableFilterCache = false;
+ }
+
if ( !$context->getDebug() ) {
if ( $context->getOnly() === 'styles' ) {
$out = $this->filter( 'minify-css', $out );
} else {
- $out = $this->filter( 'minify-js', $out );
+ $out = $this->filter( 'minify-js', $out, array(
+ 'cache' => $enableFilterCache
+ ) );
}
}
@@ -1084,11 +1097,22 @@ MESSAGE;
* @throws MWException
* @return string
*/
- public static function makeLoaderImplementScript( $name, $scripts, $styles,
- $messages, $templates
+ public static function makeLoaderImplementScript(
+ $name, $scripts, $styles, $messages, $templates
) {
if ( is_string( $scripts ) ) {
- $scripts = new XmlJsCode( "function ( $, jQuery ) {\n{$scripts}\n}" );
+ // Site and user module are a legacy scripts that run in the global scope (no closure).
+ // Transportation as string instructs mw.loader.implement to use globalEval.
+ if ( $name === 'site' || $name === 'user' ) {
+ // Minify manually because the general makeModuleResponse() minification won't be
+ // effective here due to the script being a string instead of a function. (T107377)
+ if ( !ResourceLoader::inDebugMode() ) {
+ $scripts = self::applyFilter( 'minify-js', $scripts,
+ ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) );
+ }
+ } else {
+ $scripts = new XmlJsCode( "function ( $, jQuery ) {\n{$scripts}\n}" );
+ }
} elseif ( !is_array( $scripts ) ) {
throw new MWException( 'Invalid scripts error. Array of URLs or string of code expected.' );
}
@@ -1098,9 +1122,9 @@ MESSAGE;
$module = array(
$name,
$scripts,
- (object) $styles,
- (object) $messages,
- (object) $templates,
+ (object)$styles,
+ (object)$messages,
+ (object)$templates,
);
self::trimArray( $module );
@@ -1193,7 +1217,7 @@ MESSAGE;
* and $group as supplied.
*
* @param string $name Module name
- * @param int $version Module version number as a timestamp
+ * @param string $version Module version hash
* @param array $dependencies List of module names on which this module depends
* @param string $group Group which the module is in.
* @param string $source Source of the module, or 'local' if not foreign.
@@ -1265,7 +1289,7 @@ MESSAGE;
* Registers modules with the given names and parameters.
*
* @param string $name Module name
- * @param int $version Module version number as a timestamp
+ * @param string $version Module version hash
* @param array $dependencies List of module names on which this module depends
* @param string $group Group which the module is in
* @param string $source Source of the module, or 'local' if not foreign
@@ -1346,11 +1370,30 @@ MESSAGE;
* Returns JS code which runs given JS code if the client-side framework is
* present.
*
+ * @deprecated since 1.25; use makeInlineScript instead
* @param string $script JavaScript code
* @return string
*/
public static function makeLoaderConditionalScript( $script ) {
- return "if(window.mw){\n" . trim( $script ) . "\n}";
+ return "window.RLQ = window.RLQ || []; window.RLQ.push( function () {\n" . trim( $script ) . "\n} );";
+ }
+
+ /**
+ * Construct an inline script tag with given JS code.
+ *
+ * The code will be wrapped in a closure, and it will be executed by ResourceLoader
+ * only if the client has adequate support for MediaWiki JavaScript code.
+ *
+ * @param string $script JavaScript code
+ * @return WrappedString HTML
+ */
+ public static function makeInlineScript( $script ) {
+ $js = self::makeLoaderConditionalScript( $script );
+ return new WrappedString(
+ Html::inlineScript( $js ),
+ "<script>window.RLQ = window.RLQ || []; window.RLQ.push( function () {\n",
+ "\n} );</script>"
+ );
}
/**
@@ -1361,11 +1404,13 @@ MESSAGE;
* @return string
*/
public static function makeConfigSetScript( array $configuration ) {
- return Xml::encodeJsCall(
- 'mw.config.set',
- array( $configuration ),
- ResourceLoader::inDebugMode()
- );
+ if ( ResourceLoader::inDebugMode() ) {
+ return Xml::encodeJsCall( 'mw.config.set', array( $configuration ), true );
+ }
+
+ $config = RequestContext::getMain()->getConfig();
+ $js = Xml::encodeJsCall( 'mw.config.set', array( $configuration ), false );
+ return self::applyFilter( 'minify-js', $js, $config );
}
/**
@@ -1427,7 +1472,7 @@ MESSAGE;
* @param string $source Name of the ResourceLoader source
* @param ResourceLoaderContext $context
* @param array $extraQuery
- * @return string URL to load.php. May be protocol-relative (if $wgLoadScript is procol-relative)
+ * @return string URL to load.php. May be protocol-relative if $wgLoadScript is, too.
*/
public function createLoaderURL( $source, ResourceLoaderContext $context,
$extraQuery = array()
@@ -1435,14 +1480,12 @@ MESSAGE;
$query = self::createLoaderQuery( $context, $extraQuery );
$script = $this->getLoadScript( $source );
- // Prevent the IE6 extension check from being triggered (bug 28840)
- // by appending a character that's invalid in Windows extensions ('*')
- return wfExpandUrl( wfAppendQuery( $script, $query ) . '&*', PROTO_RELATIVE );
+ return wfAppendQuery( $script, $query );
}
/**
* Build a load.php URL
- * @deprecated since 1.24, use createLoaderURL instead
+ * @deprecated since 1.24 Use createLoaderURL() instead
* @param array $modules Array of module names (strings)
* @param string $lang Language code
* @param string $skin Skin name
@@ -1453,7 +1496,7 @@ MESSAGE;
* @param bool $printable Printable mode
* @param bool $handheld Handheld mode
* @param array $extraQuery Extra query parameters to add
- * @return string URL to load.php. May be protocol-relative (if $wgLoadScript is procol-relative)
+ * @return string URL to load.php. May be protocol-relative if $wgLoadScript is, too.
*/
public static function makeLoaderURL( $modules, $lang, $skin, $user = null,
$version = null, $debug = false, $only = null, $printable = false,
@@ -1465,9 +1508,7 @@ MESSAGE;
$only, $printable, $handheld, $extraQuery
);
- // Prevent the IE6 extension check from being triggered (bug 28840)
- // by appending a character that's invalid in Windows extensions ('*')
- return wfExpandUrl( wfAppendQuery( $wgLoadScript, $query ) . '&*', PROTO_RELATIVE );
+ return wfAppendQuery( $wgLoadScript, $query );
}
/**
@@ -1562,27 +1603,23 @@ MESSAGE;
* @param Config $config
* @throws MWException
* @since 1.22
- * @return lessc
+ * @return Less_Parser
*/
public static function getLessCompiler( Config $config ) {
// When called from the installer, it is possible that a required PHP extension
// is missing (at least for now; see bug 47564). If this is the case, throw an
// exception (caught by the installer) to prevent a fatal error later on.
- if ( !class_exists( 'lessc' ) ) {
- throw new MWException( 'MediaWiki requires the lessphp compiler' );
- }
- if ( !function_exists( 'ctype_digit' ) ) {
- throw new MWException( 'lessc requires the Ctype extension' );
+ if ( !class_exists( 'Less_Parser' ) ) {
+ throw new MWException( 'MediaWiki requires the less.php parser' );
}
- $less = new lessc();
- $less->setPreserveComments( true );
- $less->setVariables( self::getLessVars( $config ) );
- $less->setImportDir( $config->get( 'ResourceLoaderLESSImportPaths' ) );
- foreach ( $config->get( 'ResourceLoaderLESSFunctions' ) as $name => $func ) {
- $less->registerFunction( $name, $func );
- }
- return $less;
+ $parser = new Less_Parser;
+ $parser->ModifyVars( self::getLessVars( $config ) );
+ $parser->SetImportDirs( array_fill_keys( $config->get( 'ResourceLoaderLESSImportPaths' ), '' ) );
+ $parser->SetOption( 'relativeUrls', false );
+ $parser->SetCacheDir( $config->get( 'CacheDirectory' ) ?: wfTempDir() );
+
+ return $parser;
}
/**
diff --git a/includes/resourceloader/ResourceLoaderContext.php b/includes/resourceloader/ResourceLoaderContext.php
index a6a7d347..2e1752a6 100644
--- a/includes/resourceloader/ResourceLoaderContext.php
+++ b/includes/resourceloader/ResourceLoaderContext.php
@@ -22,6 +22,8 @@
* @author Roan Kattouw
*/
+use MediaWiki\Logger\LoggerFactory;
+
/**
* Object passed around to modules which contains information about the state
* of a specific loader request
@@ -57,24 +59,26 @@ class ResourceLoaderContext {
$this->resourceLoader = $resourceLoader;
$this->request = $request;
- // Interpret request
// List of modules
$modules = $request->getVal( 'modules' );
$this->modules = $modules ? self::expandModuleNames( $modules ) : array();
+
// Various parameters
- $this->skin = $request->getVal( 'skin' );
$this->user = $request->getVal( 'user' );
$this->debug = $request->getFuzzyBool(
- 'debug', $resourceLoader->getConfig()->get( 'ResourceLoaderDebug' )
+ 'debug',
+ $resourceLoader->getConfig()->get( 'ResourceLoaderDebug' )
);
- $this->only = $request->getVal( 'only' );
- $this->version = $request->getVal( 'version' );
+ $this->only = $request->getVal( 'only', null );
+ $this->version = $request->getVal( 'version', null );
$this->raw = $request->getFuzzyBool( 'raw' );
+
// Image requests
$this->image = $request->getVal( 'image' );
$this->variant = $request->getVal( 'variant' );
$this->format = $request->getVal( 'format' );
+ $this->skin = $request->getVal( 'skin' );
$skinnames = Skin::getSkinNames();
// If no skin is specified, or we don't recognize the skin, use the default skin
if ( !$this->skin || !isset( $skinnames[$this->skin] ) ) {
@@ -123,7 +127,8 @@ class ResourceLoaderContext {
*/
public static function newDummyContext() {
return new self( new ResourceLoader(
- ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
+ ConfigFactory::getDefaultInstance()->makeConfig( 'main' ),
+ LoggerFactory::getInstance( 'resourceloader' )
), new FauxRequest( array() ) );
}
@@ -154,7 +159,7 @@ class ResourceLoaderContext {
public function getLanguage() {
if ( $this->language === null ) {
// Must be a valid language code after this point (bug 62849)
- $this->language = RequestContext::sanitizeLangCode( $this->request->getVal( 'lang' ) );
+ $this->language = RequestContext::sanitizeLangCode( $this->getRequest()->getVal( 'lang' ) );
}
return $this->language;
}
@@ -164,7 +169,7 @@ class ResourceLoaderContext {
*/
public function getDirection() {
if ( $this->direction === null ) {
- $this->direction = $this->request->getVal( 'dir' );
+ $this->direction = $this->getRequest()->getVal( 'dir' );
if ( !$this->direction ) {
// Determine directionality based on user language (bug 6100)
$this->direction = Language::factory( $this->getLanguage() )->getDir();
@@ -174,7 +179,7 @@ class ResourceLoaderContext {
}
/**
- * @return string|null
+ * @return string
*/
public function getSkin() {
return $this->skin;
@@ -227,6 +232,8 @@ class ResourceLoaderContext {
}
/**
+ * @see ResourceLoaderModule::getVersionHash
+ * @see OutputPage::makeResourceLoaderLink
* @return string|null
*/
public function getVersion() {
@@ -285,7 +292,7 @@ class ResourceLoaderContext {
return $this->imageObj;
}
- $image = $module->getImage( $this->image );
+ $image = $module->getImage( $this->image, $this );
if ( !$image ) {
return $this->imageObj;
}
@@ -300,21 +307,21 @@ class ResourceLoaderContext {
* @return bool
*/
public function shouldIncludeScripts() {
- return is_null( $this->getOnly() ) || $this->getOnly() === 'scripts';
+ return $this->getOnly() === null || $this->getOnly() === 'scripts';
}
/**
* @return bool
*/
public function shouldIncludeStyles() {
- return is_null( $this->getOnly() ) || $this->getOnly() === 'styles';
+ return $this->getOnly() === null || $this->getOnly() === 'styles';
}
/**
* @return bool
*/
public function shouldIncludeMessages() {
- return is_null( $this->getOnly() ) || $this->getOnly() === 'messages';
+ return $this->getOnly() === null;
}
/**
diff --git a/includes/resourceloader/ResourceLoaderEditToolbarModule.php b/includes/resourceloader/ResourceLoaderEditToolbarModule.php
index d79174cd..da729fdc 100644
--- a/includes/resourceloader/ResourceLoaderEditToolbarModule.php
+++ b/includes/resourceloader/ResourceLoaderEditToolbarModule.php
@@ -56,7 +56,7 @@ class ResourceLoaderEditToolbarModule extends ResourceLoaderFileModule {
// This is very conveniently formatted and we can pass it right through
$vars = $language->getImageFiles();
- // lessc tries to be helpful and parse our variables as LESS source code
+ // less.php tries to be helpful and parse our variables as LESS source code
foreach ( $vars as $key => &$value ) {
$value = self::cssSerializeString( $value );
}
@@ -65,25 +65,10 @@ class ResourceLoaderEditToolbarModule extends ResourceLoaderFileModule {
}
/**
- * @param ResourceLoaderContext $context
- * @return int UNIX timestamp
- */
- public function getModifiedTime( ResourceLoaderContext $context ) {
- return max(
- parent::getModifiedTime( $context ),
- $this->getHashMtime( $context )
- );
- }
-
- /**
- * @param ResourceLoaderContext $context
- * @return string Hash
+ * @return bool
*/
- public function getModifiedHash( ResourceLoaderContext $context ) {
- return md5(
- parent::getModifiedHash( $context ) .
- serialize( $this->getLessVars( $context ) )
- );
+ public function enableModuleContentVersion() {
+ return true;
}
/**
@@ -93,11 +78,11 @@ class ResourceLoaderEditToolbarModule extends ResourceLoaderFileModule {
*
* @throws MWException
* @param ResourceLoaderContext $context
- * @return lessc
+ * @return Less_Parser
*/
protected function getLessCompiler( ResourceLoaderContext $context = null ) {
- $compiler = parent::getLessCompiler();
- $compiler->setVariables( $this->getLessVars( $context ) );
- return $compiler;
+ $parser = parent::getLessCompiler();
+ $parser->ModifyVars( $this->getLessVars( $context ) );
+ return $parser;
}
}
diff --git a/includes/resourceloader/ResourceLoaderFileModule.php b/includes/resourceloader/ResourceLoaderFileModule.php
index 671098e1..7fbc1cb4 100644
--- a/includes/resourceloader/ResourceLoaderFileModule.php
+++ b/includes/resourceloader/ResourceLoaderFileModule.php
@@ -144,15 +144,6 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
protected $hasGeneratedStyles = false;
/**
- * @var array Cache for mtime
- * @par Usage:
- * @code
- * array( [hash] => [mtime], [hash] => [mtime], ... )
- * @endcode
- */
- protected $modifiedTime = array();
-
- /**
* @var array Place where readStyleFile() tracks file dependencies
* @par Usage:
* @code
@@ -161,6 +152,12 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
*/
protected $localFileRefs = array();
+ /**
+ * @var array Place where readStyleFile() tracks file dependencies for non-existent files.
+ * Used in tests to detect missing dependencies.
+ */
+ protected $missingLocalFileRefs = array();
+
/* Methods */
/**
@@ -281,8 +278,9 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
$this->{$member} = $option;
break;
// Single strings
- case 'group':
case 'position':
+ $this->isPositionDefined = true;
+ case 'group':
case 'skipFunction':
$this->{$member} = (string)$option;
break;
@@ -486,10 +484,10 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
/**
* Gets list of names of modules this module depends on.
- *
+ * @param ResourceLoaderContext context
* @return array List of module names
*/
- public function getDependencies() {
+ public function getDependencies( ResourceLoaderContext $context = null ) {
return $this->dependencies;
}
@@ -522,24 +520,28 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
}
/**
- * Get the last modified timestamp of this module.
+ * Disable module content versioning.
*
- * Last modified timestamps are calculated from the highest last modified
- * timestamp of this module's constituent files as well as the files it
- * depends on. This function is context-sensitive, only performing
- * calculations on files relevant to the given language, skin and debug
- * mode.
+ * This class uses getDefinitionSummary() instead, to avoid filesystem overhead
+ * involved with building the full module content inside a startup request.
*
- * @param ResourceLoaderContext $context Context in which to calculate
- * the modified time
- * @return int UNIX timestamp
- * @see ResourceLoaderModule::getFileDependencies
+ * @return bool
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
- if ( isset( $this->modifiedTime[$context->getHash()] ) ) {
- return $this->modifiedTime[$context->getHash()];
- }
+ public function enableModuleContentVersion() {
+ return false;
+ }
+ /**
+ * Helper method to gather file hashes for getDefinitionSummary.
+ *
+ * This function is context-sensitive, only computing hashes of files relevant to the
+ * given language, skin, etc.
+ *
+ * @see ResourceLoaderModule::getFileDependencies
+ * @param ResourceLoaderContext $context
+ * @return array
+ */
+ protected function getFileHashes( ResourceLoaderContext $context ) {
$files = array();
// Flatten style files into $files
@@ -578,22 +580,10 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
// entry point Less file we already know about.
$files = array_values( array_unique( $files ) );
- // If a module is nothing but a list of dependencies, we need to avoid
- // giving max() an empty array
- if ( count( $files ) === 0 ) {
- $this->modifiedTime[$context->getHash()] = 1;
- return $this->modifiedTime[$context->getHash()];
- }
-
- $filesMtime = max( array_map( array( __CLASS__, 'safeFilemtime' ), $files ) );
-
- $this->modifiedTime[$context->getHash()] = max(
- $filesMtime,
- $this->getMsgBlobMtime( $context->getLanguage() ),
- $this->getDefinitionMtime( $context )
- );
-
- return $this->modifiedTime[$context->getHash()];
+ // Don't include keys or file paths here, only the hashes. Including that would needlessly
+ // cause global cache invalidation when files move or if e.g. the MediaWiki path changes.
+ // Any significant ordering is already detected by the definition summary.
+ return array_map( array( __CLASS__, 'safeFileHash' ), $files );
}
/**
@@ -604,7 +594,17 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
*/
public function getDefinitionSummary( ResourceLoaderContext $context ) {
$summary = parent::getDefinitionSummary( $context );
+
+ $options = array();
foreach ( array(
+ // The following properties are omitted because they don't affect the module reponse:
+ // - localBasePath (Per T104950; Changes when absolute directory name changes. If
+ // this affects 'scripts' and other file paths, getFileHashes accounts for that.)
+ // - remoteBasePath (Per T104950)
+ // - dependencies (provided via startup module)
+ // - targets
+ // - group (provided via startup module)
+ // - position (only used by OutputPage)
'scripts',
'debugScripts',
'loaderScripts',
@@ -612,25 +612,23 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
'languageScripts',
'skinScripts',
'skinStyles',
- 'dependencies',
'messages',
- 'targets',
'templates',
- 'group',
- 'position',
'skipFunction',
- 'localBasePath',
- 'remoteBasePath',
'debugRaw',
'raw',
) as $member ) {
- $summary[$member] = $this->{$member};
+ $options[$member] = $this->{$member};
};
+
+ $summary[] = array(
+ 'options' => $options,
+ 'fileHashes' => $this->getFileHashes( $context ),
+ 'msgBlobMtime' => $this->getMsgBlobMtime( $context->getLanguage() ),
+ );
return $summary;
}
- /* Protected Methods */
-
/**
* @param string|ResourceLoaderFilePath $path
* @return string
@@ -925,10 +923,14 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
$localDir = dirname( $localPath );
$remoteDir = dirname( $remotePath );
// Get and register local file references
- $this->localFileRefs = array_merge(
- $this->localFileRefs,
- CSSMin::getLocalFileReferences( $style, $localDir )
- );
+ $localFileRefs = CSSMin::getAllLocalFileReferences( $style, $localDir );
+ foreach ( $localFileRefs as $file ) {
+ if ( file_exists( $file ) ) {
+ $this->localFileRefs[] = $file;
+ } else {
+ $this->missingLocalFileRefs[] = $file;
+ }
+ }
return CSSMin::remap(
$style, $localDir, $remoteDir, true
);
@@ -958,17 +960,17 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
* Keeps track of all used files and adds them to localFileRefs.
*
* @since 1.22
- * @throws Exception If lessc encounters a parse error
+ * @throws Exception If less.php encounters a parse error
* @param string $fileName File path of LESS source
- * @param lessc $compiler Compiler to use, if not default
+ * @param Less_Parser $parser Compiler to use, if not default
* @return string CSS source
*/
protected function compileLessFile( $fileName, $compiler = null ) {
if ( !$compiler ) {
$compiler = $this->getLessCompiler();
}
- $result = $compiler->compileFile( $fileName );
- $this->localFileRefs += array_keys( $compiler->allParsedFiles() );
+ $result = $compiler->parseFile( $fileName )->getCss();
+ $this->localFileRefs += array_keys( $compiler->AllParsedFiles() );
return $result;
}
@@ -980,7 +982,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
* @param ResourceLoaderContext $context
* @throws MWException
* @since 1.24
- * @return lessc
+ * @return Less_Parser
*/
protected function getLessCompiler( ResourceLoaderContext $context = null ) {
return ResourceLoader::getLessCompiler( $this->getConfig() );
diff --git a/includes/resourceloader/ResourceLoaderForeignApiModule.php b/includes/resourceloader/ResourceLoaderForeignApiModule.php
new file mode 100644
index 00000000..7ed08317
--- /dev/null
+++ b/includes/resourceloader/ResourceLoaderForeignApiModule.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * ResourceLoader module for mediawiki.ForeignApi that has dynamically
+ * generated dependencies, via a hook usable by extensions.
+ *
+ * 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
+ */
+
+/**
+ * ResourceLoader module for mediawiki.ForeignApi and its generated data
+ */
+class ResourceLoaderForeignApiModule extends ResourceLoaderFileModule {
+ public function getDependencies( ResourceLoaderContext $context = null ) {
+ $dependencies = $this->dependencies;
+ Hooks::run( 'ResourceLoaderForeignApiModules', array( &$dependencies, $context ) );
+ return $dependencies;
+ }
+}
diff --git a/includes/resourceloader/ResourceLoaderImage.php b/includes/resourceloader/ResourceLoaderImage.php
index 12d1e827..2338c902 100644
--- a/includes/resourceloader/ResourceLoaderImage.php
+++ b/includes/resourceloader/ResourceLoaderImage.php
@@ -54,15 +54,16 @@ class ResourceLoaderImage {
$this->variants = $variants;
// Expand shorthands:
- // array( "en,de,fr" => "foo.svg" ) → array( "en" => "foo.svg", "de" => "foo.svg", "fr" => "foo.svg" )
+ // array( "en,de,fr" => "foo.svg" )
+ // → array( "en" => "foo.svg", "de" => "foo.svg", "fr" => "foo.svg" )
if ( is_array( $this->descriptor ) && isset( $this->descriptor['lang'] ) ) {
foreach ( array_keys( $this->descriptor['lang'] ) as $langList ) {
if ( strpos( $langList, ',' ) !== false ) {
$this->descriptor['lang'] += array_fill_keys(
explode( ',', $langList ),
- $this->descriptor['lang'][ $langList ]
+ $this->descriptor['lang'][$langList]
);
- unset( $this->descriptor['lang'][ $langList ] );
+ unset( $this->descriptor['lang'][$langList] );
}
}
}
@@ -75,11 +76,15 @@ class ResourceLoaderImage {
} );
$extensions = array_unique( $extensions );
if ( count( $extensions ) !== 1 ) {
- throw new InvalidArgumentException( "File type for different image files of '$name' not the same" );
+ throw new InvalidArgumentException(
+ "File type for different image files of '$name' not the same"
+ );
}
$ext = $extensions[0];
if ( !isset( self::$fileTypes[$ext] ) ) {
- throw new InvalidArgumentException( "Invalid file type for image files of '$name' (valid: svg, png, gif, jpg)" );
+ throw new InvalidArgumentException(
+ "Invalid file type for image files of '$name' (valid: svg, png, gif, jpg)"
+ );
}
$this->extension = $ext;
}
@@ -117,14 +122,14 @@ class ResourceLoaderImage {
* @param ResourceLoaderContext $context Any context
* @return string
*/
- protected function getPath( ResourceLoaderContext $context ) {
+ public function getPath( ResourceLoaderContext $context ) {
$desc = $this->descriptor;
if ( is_string( $desc ) ) {
return $this->basePath . '/' . $desc;
- } elseif ( isset( $desc['lang'][ $context->getLanguage() ] ) ) {
- return $this->basePath . '/' . $desc['lang'][ $context->getLanguage() ];
- } elseif ( isset( $desc[ $context->getDirection() ] ) ) {
- return $this->basePath . '/' . $desc[ $context->getDirection() ];
+ } elseif ( isset( $desc['lang'][$context->getLanguage()] ) ) {
+ return $this->basePath . '/' . $desc['lang'][$context->getLanguage()];
+ } elseif ( isset( $desc[$context->getDirection()] ) ) {
+ return $this->basePath . '/' . $desc[$context->getDirection()];
} else {
return $this->basePath . '/' . $desc['default'];
}
diff --git a/includes/resourceloader/ResourceLoaderImageModule.php b/includes/resourceloader/ResourceLoaderImageModule.php
index bf6a7dd2..8de87f2e 100644
--- a/includes/resourceloader/ResourceLoaderImageModule.php
+++ b/includes/resourceloader/ResourceLoaderImageModule.php
@@ -28,6 +28,8 @@
*/
class ResourceLoaderImageModule extends ResourceLoaderModule {
+ protected $definition = null;
+
/**
* Local base path, see __construct()
* @var string
@@ -43,6 +45,9 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
protected $selectorWithVariant = '.{prefix}-{name}-{variant}';
protected $targets = array( 'desktop', 'mobile' );
+ /** @var string Position on the page to load this module at */
+ protected $position = 'bottom';
+
/**
* Constructs a new module from an options array.
*
@@ -57,6 +62,8 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
* array(
* // Base path to prepend to all local paths in $options. Defaults to $IP
* 'localBasePath' => [base path],
+ * // Path to JSON file that contains any of the settings below
+ * 'data' => [file path string]
* // CSS class prefix to use in all style rules
* 'prefix' => [CSS class prefix],
* // Alternatively: Format of CSS selector to use in all style rules
@@ -66,21 +73,29 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
* 'selectorWithVariant' => [CSS selector template, variables: {prefix} {name} {variant}],
* // List of variants that may be used for the image files
* 'variants' => array(
+ * [theme name] => array(
* [variant name] => array(
* 'color' => [color string, e.g. '#ffff00'],
* 'global' => [boolean, if true, this variant is available
* for all images of this type],
* ),
+ * ...
+ * ),
* ...
* ),
* // List of image files and their options
* 'images' => array(
- * [file path string],
- * [file path string] => array(
- * 'name' => [image name string, defaults to file name],
+ * [theme name] => array(
+ * [icon name] => array(
+ * 'file' => [file path string or array whose values are file path strings
+ * and whose keys are 'default', 'ltr', 'rtl', a single
+ * language code like 'en', or a list of language codes like
+ * 'en,de,ar'],
* 'variants' => [array of variant name strings, variants
* available for this image],
* ),
+ * ...
+ * ),
* ...
* ),
* )
@@ -90,6 +105,26 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
public function __construct( $options = array(), $localBasePath = null ) {
$this->localBasePath = self::extractLocalBasePath( $options, $localBasePath );
+ $this->definition = $options;
+ }
+
+ /**
+ * Parse definition and external JSON data, if referenced.
+ */
+ protected function loadFromDefinition() {
+ if ( $this->definition === null ) {
+ return;
+ }
+
+ $options = $this->definition;
+ $this->definition = null;
+
+ if ( isset( $options['data'] ) ) {
+ $dataPath = $this->localBasePath . '/' . $options['data'];
+ $data = json_decode( file_get_contents( $dataPath ), true );
+ $options = array_merge( $data, $options );
+ }
+
// Accepted combinations:
// * prefix
// * selector
@@ -99,20 +134,30 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
$prefix = isset( $options['prefix'] ) && $options['prefix'];
$selector = isset( $options['selector'] ) && $options['selector'];
- $selectorWithoutVariant = isset( $options['selectorWithoutVariant'] ) && $options['selectorWithoutVariant'];
- $selectorWithVariant = isset( $options['selectorWithVariant'] ) && $options['selectorWithVariant'];
+ $selectorWithoutVariant = isset( $options['selectorWithoutVariant'] )
+ && $options['selectorWithoutVariant'];
+ $selectorWithVariant = isset( $options['selectorWithVariant'] )
+ && $options['selectorWithVariant'];
if ( $selectorWithoutVariant && !$selectorWithVariant ) {
- throw new InvalidArgumentException( "Given 'selectorWithoutVariant' but no 'selectorWithVariant'." );
+ throw new InvalidArgumentException(
+ "Given 'selectorWithoutVariant' but no 'selectorWithVariant'."
+ );
}
if ( $selectorWithVariant && !$selectorWithoutVariant ) {
- throw new InvalidArgumentException( "Given 'selectorWithVariant' but no 'selectorWithoutVariant'." );
+ throw new InvalidArgumentException(
+ "Given 'selectorWithVariant' but no 'selectorWithoutVariant'."
+ );
}
if ( $selector && $selectorWithVariant ) {
- throw new InvalidArgumentException( "Incompatible 'selector' and 'selectorWithVariant'+'selectorWithoutVariant' given." );
+ throw new InvalidArgumentException(
+ "Incompatible 'selector' and 'selectorWithVariant'+'selectorWithoutVariant' given."
+ );
}
if ( !$prefix && !$selector && !$selectorWithVariant ) {
- throw new InvalidArgumentException( "None of 'prefix', 'selector' or 'selectorWithVariant'+'selectorWithoutVariant' given." );
+ throw new InvalidArgumentException(
+ "None of 'prefix', 'selector' or 'selectorWithVariant'+'selectorWithoutVariant' given."
+ );
}
foreach ( $options as $member => $option ) {
@@ -124,9 +169,22 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
"Invalid list error. '$option' given, array expected."
);
}
+ if ( !isset( $option['default'] ) ) {
+ // Backwards compatibility
+ $option = array( 'default' => $option );
+ }
+ foreach ( $option as $skin => $data ) {
+ if ( !is_array( $option ) ) {
+ throw new InvalidArgumentException(
+ "Invalid list error. '$option' given, array expected."
+ );
+ }
+ }
$this->{$member} = $option;
break;
+ case 'position':
+ $this->isPositionDefined = true;
case 'prefix':
case 'selectorWithoutVariant':
case 'selectorWithVariant':
@@ -144,6 +202,7 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
* @return string
*/
public function getPrefix() {
+ $this->loadFromDefinition();
return $this->prefix;
}
@@ -152,6 +211,7 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
* @return string
*/
public function getSelectors() {
+ $this->loadFromDefinition();
return array(
'selectorWithoutVariant' => $this->selectorWithoutVariant,
'selectorWithVariant' => $this->selectorWithVariant,
@@ -161,31 +221,43 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
/**
* Get a ResourceLoaderImage object for given image.
* @param string $name Image name
+ * @param ResourceLoaderContext $context
* @return ResourceLoaderImage|null
*/
- public function getImage( $name ) {
- $images = $this->getImages();
+ public function getImage( $name, ResourceLoaderContext $context ) {
+ $this->loadFromDefinition();
+ $images = $this->getImages( $context );
return isset( $images[$name] ) ? $images[$name] : null;
}
/**
* Get ResourceLoaderImage objects for all images.
+ * @param ResourceLoaderContext $context
* @return ResourceLoaderImage[] Array keyed by image name
*/
- public function getImages() {
+ public function getImages( ResourceLoaderContext $context ) {
+ $skin = $context->getSkin();
if ( !isset( $this->imageObjects ) ) {
+ $this->loadFromDefinition();
$this->imageObjects = array();
-
- foreach ( $this->images as $name => $options ) {
+ }
+ if ( !isset( $this->imageObjects[$skin] ) ) {
+ $this->imageObjects[$skin] = array();
+ if ( !isset( $this->images[$skin] ) ) {
+ $this->images[$skin] = isset( $this->images['default'] ) ?
+ $this->images['default'] :
+ array();
+ }
+ foreach ( $this->images[$skin] as $name => $options ) {
$fileDescriptor = is_string( $options ) ? $options : $options['file'];
$allowedVariants = array_merge(
is_array( $options ) && isset( $options['variants'] ) ? $options['variants'] : array(),
- $this->getGlobalVariants()
+ $this->getGlobalVariants( $context )
);
- if ( isset( $this->variants ) ) {
+ if ( isset( $this->variants[$skin] ) ) {
$variantConfig = array_intersect_key(
- $this->variants,
+ $this->variants[$skin],
array_fill_keys( $allowedVariants, true )
);
} else {
@@ -199,32 +271,40 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
$this->localBasePath,
$variantConfig
);
- $this->imageObjects[ $image->getName() ] = $image;
+ $this->imageObjects[$skin][$image->getName()] = $image;
}
}
- return $this->imageObjects;
+ return $this->imageObjects[$skin];
}
/**
* Get list of variants in this module that are 'global', i.e., available
* for every image regardless of image options.
+ * @param ResourceLoaderContext $context
* @return string[]
*/
- public function getGlobalVariants() {
+ public function getGlobalVariants( ResourceLoaderContext $context ) {
+ $skin = $context->getSkin();
if ( !isset( $this->globalVariants ) ) {
+ $this->loadFromDefinition();
$this->globalVariants = array();
-
- if ( isset( $this->variants ) ) {
- foreach ( $this->variants as $name => $config ) {
- if ( isset( $config['global'] ) && $config['global'] ) {
- $this->globalVariants[] = $name;
- }
+ }
+ if ( !isset( $this->globalVariants[$skin] ) ) {
+ $this->globalVariants[$skin] = array();
+ if ( !isset( $this->variants[$skin] ) ) {
+ $this->variants[$skin] = isset( $this->variants['default'] ) ?
+ $this->variants['default'] :
+ array();
+ }
+ foreach ( $this->variants[$skin] as $name => $config ) {
+ if ( isset( $config['global'] ) && $config['global'] ) {
+ $this->globalVariants[$skin][] = $name;
}
}
}
- return $this->globalVariants;
+ return $this->globalVariants[$skin];
}
/**
@@ -232,12 +312,14 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
* @return array
*/
public function getStyles( ResourceLoaderContext $context ) {
+ $this->loadFromDefinition();
+
// Build CSS rules
$rules = array();
$script = $context->getResourceLoader()->getLoadScript( $this->getSource() );
$selectors = $this->getSelectors();
- foreach ( $this->getImages() as $name => $image ) {
+ foreach ( $this->getImages( $context ) as $name => $image ) {
$declarations = $this->getCssDeclarations(
$image->getDataUri( $context, null, 'original' ),
$image->getUrl( $context, $script, null, 'rasterized' )
@@ -304,6 +386,48 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
}
/**
+ * Get the definition summary for this module.
+ *
+ * @param ResourceLoaderContext $context
+ * @return array
+ */
+ public function getDefinitionSummary( ResourceLoaderContext $context ) {
+ $this->loadFromDefinition();
+ $summary = parent::getDefinitionSummary( $context );
+ foreach ( array(
+ 'localBasePath',
+ 'images',
+ 'variants',
+ 'prefix',
+ 'selectorWithoutVariant',
+ 'selectorWithVariant',
+ ) as $member ) {
+ $summary[$member] = $this->{$member};
+ };
+ return $summary;
+ }
+
+ /**
+ * Get the last modified timestamp of this module.
+ *
+ * @param ResourceLoaderContext $context Context in which to calculate
+ * the modified time
+ * @return int UNIX timestamp
+ */
+ public function getModifiedTime( ResourceLoaderContext $context ) {
+ $this->loadFromDefinition();
+ $files = array();
+ foreach ( $this->getImages( $context ) as $name => $image ) {
+ $files[] = $image->getPath( $context );
+ }
+
+ $files = array_values( array_unique( $files ) );
+ $filesMtime = max( array_map( array( __CLASS__, 'safeFilemtime' ), $files ) );
+
+ return $filesMtime;
+ }
+
+ /**
* Extract a local base path from module definition information.
*
* @param array $options Module definition
@@ -324,4 +448,17 @@ class ResourceLoaderImageModule extends ResourceLoaderModule {
return $localBasePath;
}
+
+ /**
+ * @return string
+ */
+ public function getPosition() {
+ $this->loadFromDefinition();
+ return $this->position;
+ }
+
+ public function isPositionDefault() {
+ $this->loadFromDefinition();
+ return parent::isPositionDefault();
+ }
}
diff --git a/includes/resourceloader/ResourceLoaderJqueryMsgModule.php b/includes/resourceloader/ResourceLoaderJqueryMsgModule.php
new file mode 100644
index 00000000..f9dfbdc2
--- /dev/null
+++ b/includes/resourceloader/ResourceLoaderJqueryMsgModule.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * ResourceLoader module for mediawiki.jqueryMsg that provides generated data.
+ *
+ * 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
+ * @author Brad Jorsch
+ */
+
+/**
+ * ResourceLoader module for mediawiki.jqueryMsg and its generated data
+ */
+class ResourceLoaderJqueryMsgModule extends ResourceLoaderFileModule {
+
+ /**
+ * @param ResourceLoaderContext $context
+ * @return string JavaScript code
+ */
+ public function getScript( ResourceLoaderContext $context ) {
+ $fileScript = parent::getScript( $context );
+
+ $tagData = Sanitizer::getRecognizedTagData();
+ $parserDefaults = array();
+ $parserDefaults['allowedHtmlElements'] = array_merge(
+ array_keys( $tagData['htmlpairs'] ),
+ array_diff(
+ array_keys( $tagData['htmlsingle'] ),
+ array_keys( $tagData['htmlsingleonly'] )
+ )
+ );
+
+ $dataScript = Xml::encodeJsCall( 'mw.jqueryMsg.setParserDefaults', array( $parserDefaults ) );
+
+ return $fileScript . $dataScript;
+ }
+
+ /**
+ * @param ResourceLoaderContext $context
+ * @return array
+ */
+ public function getScriptURLsForDebug( ResourceLoaderContext $context ) {
+ // Bypass file module urls
+ return ResourceLoaderModule::getScriptURLsForDebug( $context );
+ }
+
+ /**
+ * @return bool
+ */
+ public function enableModuleContentVersion() {
+ return true;
+ }
+}
diff --git a/includes/resourceloader/ResourceLoaderLanguageDataModule.php b/includes/resourceloader/ResourceLoaderLanguageDataModule.php
index 12394536..27c74d74 100644
--- a/includes/resourceloader/ResourceLoaderLanguageDataModule.php
+++ b/includes/resourceloader/ResourceLoaderLanguageDataModule.php
@@ -63,25 +63,17 @@ class ResourceLoaderLanguageDataModule extends ResourceLoaderModule {
}
/**
- * @param ResourceLoaderContext $context
- * @return int UNIX timestamp
+ * @return bool
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
- return max( 1, $this->getHashMtime( $context ) );
+ public function enableModuleContentVersion() {
+ return true;
}
/**
* @param ResourceLoaderContext $context
- * @return string Hash
- */
- public function getModifiedHash( ResourceLoaderContext $context ) {
- return md5( serialize( $this->getData( $context ) ) );
- }
-
- /**
* @return array
*/
- public function getDependencies() {
+ public function getDependencies( ResourceLoaderContext $context = null ) {
return array( 'mediawiki.language.init' );
}
}
diff --git a/includes/resourceloader/ResourceLoaderLanguageNamesModule.php b/includes/resourceloader/ResourceLoaderLanguageNamesModule.php
index 55b1f4b1..081c728c 100644
--- a/includes/resourceloader/ResourceLoaderLanguageNamesModule.php
+++ b/includes/resourceloader/ResourceLoaderLanguageNamesModule.php
@@ -32,7 +32,6 @@ class ResourceLoaderLanguageNamesModule extends ResourceLoaderModule {
protected $targets = array( 'desktop', 'mobile' );
-
/**
* @param ResourceLoaderContext $context
* @return array
@@ -60,24 +59,19 @@ class ResourceLoaderLanguageNamesModule extends ResourceLoaderModule {
);
}
- public function getDependencies() {
- return array( 'mediawiki.language.init' );
- }
-
/**
* @param ResourceLoaderContext $context
- * @return int UNIX timestamp
+ * @return array
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
- return max( 1, $this->getHashMtime( $context ) );
+ public function getDependencies( ResourceLoaderContext $context = null ) {
+ return array( 'mediawiki.language.init' );
}
/**
- * @param ResourceLoaderContext $context
- * @return string Hash
+ * @return bool
*/
- public function getModifiedHash( ResourceLoaderContext $context ) {
- return md5( serialize( $this->getData( $context ) ) );
+ public function enableModuleContentVersion() {
+ return true;
}
}
diff --git a/includes/resourceloader/ResourceLoaderModule.php b/includes/resourceloader/ResourceLoaderModule.php
index ed16521b..1d3ffb55 100644
--- a/includes/resourceloader/ResourceLoaderModule.php
+++ b/includes/resourceloader/ResourceLoaderModule.php
@@ -29,7 +29,6 @@ abstract class ResourceLoaderModule {
# Type of resource
const TYPE_SCRIPTS = 'scripts';
const TYPE_STYLES = 'styles';
- const TYPE_MESSAGES = 'messages';
const TYPE_COMBINED = 'combined';
# sitewide core module like a skin file or jQuery component
@@ -63,6 +62,14 @@ abstract class ResourceLoaderModule {
protected $fileDeps = array();
// In-object cache for message blob mtime
protected $msgBlobMtime = array();
+ // In-object cache for version hash
+ protected $versionHash = array();
+ // In-object cache for module content
+ protected $contents = array();
+
+ // Whether the position returned by getPosition() is defined in the module configuration
+ // and not a default value
+ protected $isPositionDefined = false;
/**
* @var Config
@@ -285,6 +292,19 @@ abstract class ResourceLoaderModule {
}
/**
+ * Whether the position returned by getPosition() is a default value or comes from the module
+ * definition. This method is meant to be short-lived, and is only useful until classes added
+ * via addModuleStyles with a default value define an explicit position. See getModuleStyles()
+ * in OutputPage for the related migration warning.
+ *
+ * @return bool
+ * @since 1.26
+ */
+ public function isPositionDefault() {
+ return !$this->isPositionDefined;
+ }
+
+ /**
* Whether this module's JS expects to work without the client-side ResourceLoader module.
* Returning true from this function will prevent mw.loader.state() call from being
* appended to the bottom of the script.
@@ -313,9 +333,14 @@ abstract class ResourceLoaderModule {
*
* To add dependencies dynamically on the client side, use a custom
* loader script, see getLoaderScript()
+ *
+ * Note: It is expected that $context will be made non-optional in the near
+ * future.
+ *
+ * @param ResourceLoaderContext $context
* @return array List of module names as strings
*/
- public function getDependencies() {
+ public function getDependencies( ResourceLoaderContext $context = null ) {
// Stub, override expected
return array();
}
@@ -361,16 +386,21 @@ abstract class ResourceLoaderModule {
}
$dbr = wfGetDB( DB_SLAVE );
- $deps = $dbr->selectField( 'module_deps', 'md_deps', array(
+ $deps = $dbr->selectField( 'module_deps',
+ 'md_deps',
+ array(
'md_module' => $this->getName(),
'md_skin' => $skin,
- ), __METHOD__
+ ),
+ __METHOD__
);
+
if ( !is_null( $deps ) ) {
$this->fileDeps[$skin] = (array)FormatJson::decode( $deps, true );
} else {
$this->fileDeps[$skin] = array();
}
+
return $this->fileDeps[$skin];
}
@@ -385,8 +415,7 @@ abstract class ResourceLoaderModule {
}
/**
- * Get the last modification timestamp of the message blob for this
- * module in a given language.
+ * Get the last modification timestamp of the messages in this module for a given language.
* @param string $lang Language code
* @return int UNIX timestamp
*/
@@ -397,10 +426,13 @@ abstract class ResourceLoaderModule {
}
$dbr = wfGetDB( DB_SLAVE );
- $msgBlobMtime = $dbr->selectField( 'msg_resource', 'mr_timestamp', array(
+ $msgBlobMtime = $dbr->selectField( 'msg_resource',
+ 'mr_timestamp',
+ array(
'mr_resource' => $this->getName(),
'mr_lang' => $lang
- ), __METHOD__
+ ),
+ __METHOD__
);
// If no blob was found, but the module does have messages, that means we need
// to regenerate it. Return NOW
@@ -422,144 +454,318 @@ abstract class ResourceLoaderModule {
$this->msgBlobMtime[$lang] = $mtime;
}
- /* Abstract Methods */
-
/**
- * Get this module's last modification timestamp for a given
- * combination of language, skin and debug mode flag. This is typically
- * the highest of each of the relevant components' modification
- * timestamps. Whenever anything happens that changes the module's
- * contents for these parameters, the mtime should increase.
- *
- * NOTE: The mtime of the module's messages is NOT automatically included.
- * If you want this to happen, you'll need to call getMsgBlobMtime()
- * yourself and take its result into consideration.
- *
- * NOTE: The mtime of the module's hash is NOT automatically included.
- * If your module provides a getModifiedHash() method, you'll need to call getHashMtime()
- * yourself and take its result into consideration.
+ * Get an array of this module's resources. Ready for serving to the web.
*
- * @param ResourceLoaderContext $context Context object
- * @return int UNIX timestamp
- */
- public function getModifiedTime( ResourceLoaderContext $context ) {
- return 1;
+ * @since 1.26
+ * @param ResourceLoaderContext $context
+ * @return array
+ */
+ public function getModuleContent( ResourceLoaderContext $context ) {
+ $contextHash = $context->getHash();
+ // Cache this expensive operation. This calls builds the scripts, styles, and messages
+ // content which typically involves filesystem and/or database access.
+ if ( !array_key_exists( $contextHash, $this->contents ) ) {
+ $this->contents[$contextHash] = $this->buildContent( $context );
+ }
+ return $this->contents[$contextHash];
}
/**
- * Helper method for calculating when the module's hash (if it has one) changed.
+ * Bundle all resources attached to this module into an array.
*
+ * @since 1.26
* @param ResourceLoaderContext $context
- * @return int UNIX timestamp
- */
- public function getHashMtime( ResourceLoaderContext $context ) {
- $hash = $this->getModifiedHash( $context );
- if ( !is_string( $hash ) ) {
- return 1;
+ * @return array
+ */
+ final protected function buildContent( ResourceLoaderContext $context ) {
+ $rl = $context->getResourceLoader();
+ $stats = RequestContext::getMain()->getStats();
+ $statStart = microtime( true );
+
+ // Only include properties that are relevant to this context (e.g. only=scripts)
+ // and that are non-empty (e.g. don't include "templates" for modules without
+ // templates). This helps prevent invalidating cache for all modules when new
+ // optional properties are introduced.
+ $content = array();
+
+ // Scripts
+ if ( $context->shouldIncludeScripts() ) {
+ // If we are in debug mode, we'll want to return an array of URLs if possible
+ // However, we can't do this if the module doesn't support it
+ // We also can't do this if there is an only= parameter, because we have to give
+ // the module a way to return a load.php URL without causing an infinite loop
+ if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) {
+ $scripts = $this->getScriptURLsForDebug( $context );
+ } else {
+ $scripts = $this->getScript( $context );
+ // rtrim() because there are usually a few line breaks
+ // after the last ';'. A new line at EOF, a new line
+ // added by ResourceLoaderFileModule::readScriptFiles, etc.
+ if ( is_string( $scripts )
+ && strlen( $scripts )
+ && substr( rtrim( $scripts ), -1 ) !== ';'
+ ) {
+ // Append semicolon to prevent weird bugs caused by files not
+ // terminating their statements right (bug 27054)
+ $scripts .= ";\n";
+ }
+ }
+ $content['scripts'] = $scripts;
+ }
+
+ // Styles
+ if ( $context->shouldIncludeStyles() ) {
+ $styles = array();
+ // Don't create empty stylesheets like array( '' => '' ) for modules
+ // that don't *have* any stylesheets (bug 38024).
+ $stylePairs = $this->getStyles( $context );
+ if ( count( $stylePairs ) ) {
+ // If we are in debug mode without &only= set, we'll want to return an array of URLs
+ // See comment near shouldIncludeScripts() for more details
+ if ( $context->getDebug() && !$context->getOnly() && $this->supportsURLLoading() ) {
+ $styles = array(
+ 'url' => $this->getStyleURLsForDebug( $context )
+ );
+ } else {
+ // Minify CSS before embedding in mw.loader.implement call
+ // (unless in debug mode)
+ if ( !$context->getDebug() ) {
+ foreach ( $stylePairs as $media => $style ) {
+ // Can be either a string or an array of strings.
+ if ( is_array( $style ) ) {
+ $stylePairs[$media] = array();
+ foreach ( $style as $cssText ) {
+ if ( is_string( $cssText ) ) {
+ $stylePairs[$media][] =
+ $rl->filter( 'minify-css', $cssText );
+ }
+ }
+ } elseif ( is_string( $style ) ) {
+ $stylePairs[$media] = $rl->filter( 'minify-css', $style );
+ }
+ }
+ }
+ // Wrap styles into @media groups as needed and flatten into a numerical array
+ $styles = array(
+ 'css' => $rl->makeCombinedStyles( $stylePairs )
+ );
+ }
+ }
+ $content['styles'] = $styles;
+ }
+
+ // Messages
+ $blobs = $rl->getMessageBlobStore()->get(
+ $rl,
+ array( $this->getName() => $this ),
+ $context->getLanguage()
+ );
+ if ( isset( $blobs[$this->getName()] ) ) {
+ $content['messagesBlob'] = $blobs[$this->getName()];
}
- // Embed the hash itself in the cache key. This allows for a few nifty things:
- // - During deployment, servers with old and new versions of the code communicating
- // with the same memcached will not override the same key repeatedly increasing
- // the timestamp.
- // - In case of the definition changing and then changing back in a short period of time
- // (e.g. in case of a revert or a corrupt server) the old timestamp and client-side cache
- // url will be re-used.
- // - If different context-combinations (e.g. same skin, same language or some combination
- // thereof) result in the same definition, they will use the same hash and timestamp.
- $cache = wfGetCache( CACHE_ANYTHING );
- $key = wfMemcKey( 'resourceloader', 'hashmtime', $this->getName(), $hash );
-
- $data = $cache->get( $key );
- if ( is_int( $data ) && $data > 0 ) {
- // We've seen this hash before, re-use the timestamp of when we first saw it.
- return $data;
+ $templates = $this->getTemplates();
+ if ( $templates ) {
+ $content['templates'] = $templates;
}
- $timestamp = time();
- $cache->set( $key, $timestamp );
- return $timestamp;
+ $statTiming = microtime( true ) - $statStart;
+ $statName = strtr( $this->getName(), '.', '_' );
+ $stats->timing( "resourceloader_build.all", 1000 * $statTiming );
+ $stats->timing( "resourceloader_build.$statName", 1000 * $statTiming );
+
+ return $content;
}
/**
- * Get the hash for whatever this module may contain.
+ * Get a string identifying the current version of this module in a given context.
+ *
+ * Whenever anything happens that changes the module's response (e.g. scripts, styles, and
+ * messages) this value must change. This value is used to store module responses in cache.
+ * (Both client-side and server-side.)
*
- * This is the method subclasses should implement if they want to make
- * use of getHashMTime() inside getModifiedTime().
+ * It is not recommended to override this directly. Use getDefinitionSummary() instead.
+ * If overridden, one must call the parent getVersionHash(), append data and re-hash.
*
+ * This method should be quick because it is frequently run by ResourceLoaderStartUpModule to
+ * propagate changes to the client and effectively invalidate cache.
+ *
+ * For backward-compatibility, the following optional data providers are automatically included:
+ *
+ * - getModifiedTime()
+ * - getModifiedHash()
+ *
+ * @since 1.26
* @param ResourceLoaderContext $context
- * @return string|null Hash
- */
- public function getModifiedHash( ResourceLoaderContext $context ) {
- return null;
+ * @return string Hash (should use ResourceLoader::makeHash)
+ */
+ public function getVersionHash( ResourceLoaderContext $context ) {
+ // The startup module produces a manifest with versions representing the entire module.
+ // Typically, the request for the startup module itself has only=scripts. That must apply
+ // only to the startup module content, and not to the module version computed here.
+ $context = new DerivativeResourceLoaderContext( $context );
+ $context->setModules( array() );
+ // Version hash must cover all resources, regardless of startup request itself.
+ $context->setOnly( null );
+ // Compute version hash based on content, not debug urls.
+ $context->setDebug( false );
+
+ // Cache this somewhat expensive operation. Especially because some classes
+ // (e.g. startup module) iterate more than once over all modules to get versions.
+ $contextHash = $context->getHash();
+ if ( !array_key_exists( $contextHash, $this->versionHash ) ) {
+
+ if ( $this->enableModuleContentVersion() ) {
+ // Detect changes directly
+ $str = json_encode( $this->getModuleContent( $context ) );
+ } else {
+ // Infer changes based on definition and other metrics
+ $summary = $this->getDefinitionSummary( $context );
+ if ( !isset( $summary['_cacheEpoch'] ) ) {
+ throw new LogicException( 'getDefinitionSummary must call parent method' );
+ }
+ $str = json_encode( $summary );
+
+ $mtime = $this->getModifiedTime( $context );
+ if ( $mtime !== null ) {
+ // Support: MediaWiki 1.25 and earlier
+ $str .= strval( $mtime );
+ }
+
+ $mhash = $this->getModifiedHash( $context );
+ if ( $mhash !== null ) {
+ // Support: MediaWiki 1.25 and earlier
+ $str .= strval( $mhash );
+ }
+ }
+
+ $this->versionHash[$contextHash] = ResourceLoader::makeHash( $str );
+ }
+ return $this->versionHash[$contextHash];
}
/**
- * Helper method for calculating when this module's definition summary was last changed.
+ * Whether to generate version hash based on module content.
*
- * @since 1.23
+ * If a module requires database or file system access to build the module
+ * content, consider disabling this in favour of manually tracking relevant
+ * aspects in getDefinitionSummary(). See getVersionHash() for how this is used.
*
- * @param ResourceLoaderContext $context
- * @return int UNIX timestamp
+ * @return bool
*/
- public function getDefinitionMtime( ResourceLoaderContext $context ) {
- $summary = $this->getDefinitionSummary( $context );
- if ( $summary === null ) {
- return 1;
- }
-
- $hash = md5( json_encode( $summary ) );
- $cache = wfGetCache( CACHE_ANYTHING );
- $key = wfMemcKey( 'resourceloader', 'moduledefinition', $this->getName(), $hash );
-
- $data = $cache->get( $key );
- if ( is_int( $data ) && $data > 0 ) {
- // We've seen this hash before, re-use the timestamp of when we first saw it.
- return $data;
- }
-
- wfDebugLog( 'resourceloader', __METHOD__ . ": New definition for module "
- . "{$this->getName()} in context \"{$context->getHash()}\"" );
-
- $timestamp = time();
- $cache->set( $key, $timestamp );
- return $timestamp;
+ public function enableModuleContentVersion() {
+ return false;
}
/**
* Get the definition summary for this module.
*
- * This is the method subclasses should implement if they want to make
- * use of getDefinitionMTime() inside getModifiedTime().
+ * This is the method subclasses are recommended to use to track values in their
+ * version hash. Call this in getVersionHash() and pass it to e.g. json_encode.
+ *
+ * Subclasses must call the parent getDefinitionSummary() and build on that.
+ * It is recommended that each subclass appends its own new array. This prevents
+ * clashes or accidental overwrites of existing keys and gives each subclass
+ * its own scope for simple array keys.
+ *
+ * @code
+ * $summary = parent::getDefinitionSummary( $context );
+ * $summary[] = array(
+ * 'foo' => 123,
+ * 'bar' => 'quux',
+ * );
+ * return $summary;
+ * @endcode
*
* Return an array containing values from all significant properties of this
- * module's definition. Be sure to include things that are explicitly ordered,
- * in their actaul order (bug 37812).
+ * module's definition.
*
- * Avoid including things that are insiginificant (e.g. order of message
- * keys is insignificant and should be sorted to avoid unnecessary cache
- * invalidation).
+ * Be careful not to normalise too much. Especially preserve the order of things
+ * that carry significance in getScript and getStyles (T39812).
*
- * Avoid including things already considered by other methods inside your
- * getModifiedTime(), such as file mtime timestamps.
+ * Avoid including things that are insiginificant (e.g. order of message keys is
+ * insignificant and should be sorted to avoid unnecessary cache invalidation).
*
- * Serialisation is done using json_encode, which means object state is not
- * taken into account when building the hash. This data structure must only
- * contain arrays and scalars as values (avoid object instances) which means
- * it requires abstraction.
+ * This data structure must exclusively contain arrays and scalars as values (avoid
+ * object instances) to allow simple serialisation using json_encode.
*
- * @since 1.23
+ * If modules have a hash or timestamp from another source, that may be incuded as-is.
*
+ * A number of utility methods are available to help you gather data. These are not
+ * called by default and must be included by the subclass' getDefinitionSummary().
+ *
+ * - getMsgBlobMtime()
+ *
+ * @since 1.23
* @param ResourceLoaderContext $context
* @return array|null
*/
public function getDefinitionSummary( ResourceLoaderContext $context ) {
return array(
- 'class' => get_class( $this ),
+ '_class' => get_class( $this ),
+ '_cacheEpoch' => $this->getConfig()->get( 'CacheEpoch' ),
);
}
/**
+ * Get this module's last modification timestamp for a given context.
+ *
+ * @deprecated since 1.26 Use getDefinitionSummary() instead
+ * @param ResourceLoaderContext $context Context object
+ * @return int|null UNIX timestamp
+ */
+ public function getModifiedTime( ResourceLoaderContext $context ) {
+ return null;
+ }
+
+ /**
+ * Helper method for providing a version hash to getVersionHash().
+ *
+ * @deprecated since 1.26 Use getDefinitionSummary() instead
+ * @param ResourceLoaderContext $context
+ * @return string|null Hash
+ */
+ public function getModifiedHash( ResourceLoaderContext $context ) {
+ return null;
+ }
+
+ /**
+ * Back-compat dummy for old subclass implementations of getModifiedTime().
+ *
+ * This method used to use ObjectCache to track when a hash was first seen. That principle
+ * stems from a time that ResourceLoader could only identify module versions by timestamp.
+ * That is no longer the case. Use getDefinitionSummary() directly.
+ *
+ * @deprecated since 1.26 Superseded by getVersionHash()
+ * @param ResourceLoaderContext $context
+ * @return int UNIX timestamp
+ */
+ public function getHashMtime( ResourceLoaderContext $context ) {
+ if ( !is_string( $this->getModifiedHash( $context ) ) ) {
+ return 1;
+ }
+ // Dummy that is > 1
+ return 2;
+ }
+
+ /**
+ * Back-compat dummy for old subclass implementations of getModifiedTime().
+ *
+ * @since 1.23
+ * @deprecated since 1.26 Superseded by getVersionHash()
+ * @param ResourceLoaderContext $context
+ * @return int UNIX timestamp
+ */
+ public function getDefinitionMtime( ResourceLoaderContext $context ) {
+ if ( $this->getDefinitionSummary( $context ) === null ) {
+ return 1;
+ }
+ // Dummy that is > 1
+ return 2;
+ }
+
+ /**
* Check whether this module is known to be empty. If a child class
* has an easy and cheap way to determine that this module is
* definitely going to be empty, it should override this method to
@@ -587,8 +793,13 @@ abstract class ResourceLoaderModule {
protected function validateScriptFile( $fileName, $contents ) {
if ( $this->getConfig()->get( 'ResourceLoaderValidateJS' ) ) {
// Try for cache hit
- // Use CACHE_ANYTHING since filtering is very slow compared to DB queries
- $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) );
+ // Use CACHE_ANYTHING since parsing JS is much slower than a DB query
+ $key = wfMemcKey(
+ 'resourceloader',
+ 'jsparse',
+ self::$parseCacheVersion,
+ md5( $contents )
+ );
$cache = wfGetCache( CACHE_ANYTHING );
$cacheEntry = $cache->get( $key );
if ( is_string( $cacheEntry ) ) {
@@ -602,7 +813,8 @@ abstract class ResourceLoaderModule {
} catch ( Exception $e ) {
// We'll save this to cache to avoid having to validate broken JS over and over...
$err = $e->getMessage();
- $result = "throw new Error(" . Xml::encodeJsVar( "JavaScript parse error: $err" ) . ");";
+ $result = "mw.log.error(" .
+ Xml::encodeJsVar( "JavaScript parse error: $err" ) . ");";
}
$cache->set( $key, $result );
@@ -623,16 +835,57 @@ abstract class ResourceLoaderModule {
}
/**
- * Safe version of filemtime(), which doesn't throw a PHP warning if the file doesn't exist
- * but returns 1 instead.
- * @param string $filename File name
+ * Safe version of filemtime(), which doesn't throw a PHP warning if the file doesn't exist.
+ * Defaults to 1.
+ *
+ * @param string $filePath File path
* @return int UNIX timestamp
*/
- protected static function safeFilemtime( $filename ) {
- wfSuppressWarnings();
- $mtime = filemtime( $filename ) ?: 1;
- wfRestoreWarnings();
-
+ protected static function safeFilemtime( $filePath ) {
+ MediaWiki\suppressWarnings();
+ $mtime = filemtime( $filePath ) ?: 1;
+ MediaWiki\restoreWarnings();
return $mtime;
}
+
+ /**
+ * Compute a non-cryptographic string hash of a file's contents.
+ * If the file does not exist or cannot be read, returns an empty string.
+ *
+ * @since 1.26 Uses MD4 instead of SHA1.
+ * @param string $filePath File path
+ * @return string Hash
+ */
+ protected static function safeFileHash( $filePath ) {
+ static $cache;
+
+ if ( !$cache ) {
+ $cache = ObjectCache::newAccelerator( CACHE_NONE );
+ }
+
+ MediaWiki\suppressWarnings();
+ $mtime = filemtime( $filePath );
+ MediaWiki\restoreWarnings();
+ if ( !$mtime ) {
+ return '';
+ }
+
+ $cacheKey = wfGlobalCacheKey( 'resourceloader', __METHOD__, $filePath );
+ $cachedHash = $cache->get( $cacheKey );
+ if ( isset( $cachedHash['mtime'] ) && $cachedHash['mtime'] === $mtime ) {
+ return $cachedHash['hash'];
+ }
+
+ MediaWiki\suppressWarnings();
+ $contents = file_get_contents( $filePath );
+ MediaWiki\restoreWarnings();
+ if ( !$contents ) {
+ return '';
+ }
+
+ $hash = hash( 'md4', $contents );
+ $cache->set( $cacheKey, array( 'mtime' => $mtime, 'hash' => $hash ), 60 * 60 * 24 );
+
+ return $hash;
+ }
}
diff --git a/includes/resourceloader/ResourceLoaderOOUIImageModule.php b/includes/resourceloader/ResourceLoaderOOUIImageModule.php
new file mode 100644
index 00000000..8493f9fd
--- /dev/null
+++ b/includes/resourceloader/ResourceLoaderOOUIImageModule.php
@@ -0,0 +1,86 @@
+<?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
+ */
+
+/**
+ * Secret special sauce.
+ *
+ * @since 1.26
+ */
+class ResourceLoaderOOUIImageModule extends ResourceLoaderImageModule {
+ protected function loadFromDefinition() {
+ if ( $this->definition === null ) {
+ return;
+ }
+
+ // Core default themes
+ $themes = array( 'default' => 'mediawiki' );
+ $themes += ExtensionRegistry::getInstance()->getAttribute( 'SkinOOUIThemes' );
+
+ $name = $this->definition['name'];
+ $rootPath = $this->definition['rootPath'];
+
+ $definition = array();
+ foreach ( $themes as $skin => $theme ) {
+ // TODO Allow extensions to specify this path somehow
+ $dataPath = $this->localBasePath . '/' . $rootPath . '/' . $theme . '/' . $name . '.json';
+
+ if ( file_exists( $dataPath ) ) {
+ $data = json_decode( file_get_contents( $dataPath ), true );
+ $fixPath = function ( &$path ) use ( $rootPath, $theme ) {
+ // TODO Allow extensions to specify this path somehow
+ $path = $rootPath . '/' . $theme . '/' . $path;
+ };
+ array_walk( $data['images'], function ( &$value ) use ( $fixPath ) {
+ if ( is_string( $value['file'] ) ) {
+ $fixPath( $value['file'] );
+ } elseif ( is_array( $value['file'] ) ) {
+ array_walk_recursive( $value['file'], $fixPath );
+ }
+ } );
+ } else {
+ $data = array();
+ }
+
+ foreach ( $data as $key => $value ) {
+ switch ( $key ) {
+ case 'images':
+ case 'variants':
+ $definition[$key][$skin] = $data[$key];
+ break;
+
+ default:
+ if ( !isset( $definition[$key] ) ) {
+ $definition[$key] = $data[$key];
+ } elseif ( $definition[$key] !== $data[$key] ) {
+ throw new Exception(
+ "Mismatched OOUI theme definitions are not supported: trying to load $key of $theme theme"
+ );
+ }
+ break;
+ }
+ }
+ }
+
+ // Fields from definition silently override keys from JSON files
+ $this->definition += $definition;
+
+ parent::loadFromDefinition();
+ }
+}
diff --git a/includes/resourceloader/ResourceLoaderRawFileModule.php b/includes/resourceloader/ResourceLoaderRawFileModule.php
new file mode 100644
index 00000000..d9005fa5
--- /dev/null
+++ b/includes/resourceloader/ResourceLoaderRawFileModule.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Module containing files that are loaded without ResourceLoader.
+ *
+ * Primary usecase being "base" modules loaded by the startup module,
+ * such as jquery and the mw.loader client itself. These make use of
+ * ResourceLoaderModule and load.php for convenience but aren't actually
+ * registered in the startup module (as it would have to load itself).
+ *
+ * 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
+ * @author Timo Tijhof
+ */
+
+class ResourceLoaderRawFileModule extends ResourceLoaderFileModule {
+
+ /**
+ * Enable raw mode to omit mw.loader.state() call as mw.loader
+ * does not yet exist when these modules execute.
+ * @var boolean
+ */
+ protected $raw = true;
+
+ /**
+ * Get all JavaScript code.
+ *
+ * @param ResourceLoaderContext $context
+ * @return string JavaScript code
+ */
+ public function getScript( ResourceLoaderContext $context ) {
+ $script = parent::getScript( $context );
+ // Add closure explicitly because raw modules can't be wrapped mw.loader.implement.
+ // Unlike with mw.loader.implement, this closure is immediately invoked.
+ // @see ResourceLoader::makeModuleResponse
+ // @see ResourceLoader::makeLoaderImplementScript
+ return "(function () {\n{$script}\n}());";
+ }
+}
diff --git a/includes/resourceloader/ResourceLoaderSiteModule.php b/includes/resourceloader/ResourceLoaderSiteModule.php
index 19e0baeb..380b7a53 100644
--- a/includes/resourceloader/ResourceLoaderSiteModule.php
+++ b/includes/resourceloader/ResourceLoaderSiteModule.php
@@ -47,13 +47,4 @@ class ResourceLoaderSiteModule extends ResourceLoaderWikiModule {
}
return $pages;
}
-
- /**
- * Get group name
- *
- * @return string
- */
- public function getGroup() {
- return 'site';
- }
}
diff --git a/includes/resourceloader/ResourceLoaderSkinModule.php b/includes/resourceloader/ResourceLoaderSkinModule.php
index 3ba63e68..911d9534 100644
--- a/includes/resourceloader/ResourceLoaderSkinModule.php
+++ b/includes/resourceloader/ResourceLoaderSkinModule.php
@@ -44,13 +44,13 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
'(min-resolution: 1.5dppx), ' .
'(min-resolution: 144dpi)'
][] = '.mw-wiki-logo { background-image: ' .
- CSSMin::buildUrlValue( $logoHD['1.5x'] ) .';' .
+ CSSMin::buildUrlValue( $logoHD['1.5x'] ) . ';' .
'background-size: 135px auto; }';
}
if ( isset( $logoHD['2x'] ) ) {
$styles[
'(-webkit-min-device-pixel-ratio: 2), ' .
- '(min--moz-device-pixel-ratio: 2),'.
+ '(min--moz-device-pixel-ratio: 2),' .
'(min-resolution: 2dppx), ' .
'(min-resolution: 192dpi)'
][] = '.mw-wiki-logo { background-image: ' .
@@ -73,15 +73,6 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
/**
* @param $context ResourceLoaderContext
- * @return int|mixed
- */
- public function getModifiedTime( ResourceLoaderContext $context ) {
- $parentMTime = parent::getModifiedTime( $context );
- return max( $parentMTime, $this->getHashMtime( $context ) );
- }
-
- /**
- * @param $context ResourceLoaderContext
* @return string: Hash
*/
public function getModifiedHash( ResourceLoaderContext $context ) {
diff --git a/includes/resourceloader/ResourceLoaderSpecialCharacterDataModule.php b/includes/resourceloader/ResourceLoaderSpecialCharacterDataModule.php
index 5c917091..8170cb1c 100644
--- a/includes/resourceloader/ResourceLoaderSpecialCharacterDataModule.php
+++ b/includes/resourceloader/ResourceLoaderSpecialCharacterDataModule.php
@@ -35,7 +35,8 @@ class ResourceLoaderSpecialCharacterDataModule extends ResourceLoaderModule {
* @return array
*/
protected function getData() {
- return json_decode( file_get_contents( $this->path ) );
+ global $IP;
+ return json_decode( file_get_contents( "$IP/{$this->path}" ) );
}
/**
@@ -53,25 +54,17 @@ class ResourceLoaderSpecialCharacterDataModule extends ResourceLoaderModule {
}
/**
- * @param ResourceLoaderContext $context
- * @return int UNIX timestamp
+ * @return bool
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
- return static::safeFilemtime( $this->path );
+ public function enableModuleContentVersion() {
+ return true;
}
/**
* @param ResourceLoaderContext $context
- * @return string Hash
- */
- public function getModifiedHash( ResourceLoaderContext $context ) {
- return md5( serialize( $this->getData() ) );
- }
-
- /**
* @return array
*/
- public function getDependencies() {
+ public function getDependencies( ResourceLoaderContext $context = null ) {
return array( 'mediawiki.language' );
}
diff --git a/includes/resourceloader/ResourceLoaderStartUpModule.php b/includes/resourceloader/ResourceLoaderStartUpModule.php
index b2fbae9c..87d8ee20 100644
--- a/includes/resourceloader/ResourceLoaderStartUpModule.php
+++ b/includes/resourceloader/ResourceLoaderStartUpModule.php
@@ -24,14 +24,10 @@
class ResourceLoaderStartUpModule extends ResourceLoaderModule {
- /* Protected Members */
-
- protected $modifiedTime = array();
+ // Cache for getConfigSettings() as it's called by multiple methods
protected $configVars = array();
protected $targets = array( 'desktop', 'mobile' );
- /* Protected Methods */
-
/**
* @param ResourceLoaderContext $context
* @return array
@@ -92,6 +88,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
'wgContentNamespaces' => MWNamespace::getContentNamespaces(),
'wgSiteName' => $conf->get( 'Sitename' ),
'wgDBname' => $conf->get( 'DBname' ),
+ 'wgExtraSignatureNamespaces' => $conf->get( 'ExtraSignatureNamespaces' ),
'wgAvailableSkins' => Skin::getSkinNames(),
'wgExtensionAssetsPath' => $conf->get( 'ExtensionAssetsPath' ),
// MediaWiki sets cookies to have this prefix by default
@@ -104,6 +101,9 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
'wgLegalTitleChars' => Title::convertByteClassToUnicodeClass( Title::legalChars() ),
'wgResourceLoaderStorageVersion' => $conf->get( 'ResourceLoaderStorageVersion' ),
'wgResourceLoaderStorageEnabled' => $conf->get( 'ResourceLoaderStorageEnabled' ),
+ 'wgResourceLoaderLegacyModules' => self::getLegacyModules(),
+ 'wgForeignUploadTargets' => $conf->get( 'ForeignUploadTargets' ),
+ 'wgEnableUploads' => $conf->get( 'EnableUploads' ),
);
Hooks::run( 'ResourceLoaderGetConfigVars', array( &$vars ) );
@@ -159,7 +159,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
* data send to the client.
*
* @param array &$registryData Modules keyed by name with properties:
- * - number 'version'
+ * - string 'version'
* - array 'dependencies'
* - string|null 'group'
* - string 'source'
@@ -191,6 +191,9 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
$resourceLoader = $context->getResourceLoader();
$target = $context->getRequest()->getVal( 'target', 'desktop' );
+ // Bypass target filter if this request is from a unit test context. To prevent misuse in
+ // production, this is only allowed if testing is enabled server-side.
+ $byPassTargetFilter = $this->getConfig()->get( 'EnableJavaScriptTest' ) && $target === 'test';
$out = '';
$registryData = array();
@@ -199,7 +202,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
foreach ( $resourceLoader->getModuleNames() as $name ) {
$module = $resourceLoader->getModule( $name );
$moduleTargets = $module->getTargets();
- if ( !in_array( $target, $moduleTargets ) ) {
+ if ( !$byPassTargetFilter && !in_array( $target, $moduleTargets ) ) {
continue;
}
@@ -210,31 +213,27 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
continue;
}
- // Coerce module timestamp to UNIX timestamp.
- // getModifiedTime() is supposed to return a UNIX timestamp, but custom implementations
- // might forget. TODO: Maybe emit warning?
- $moduleMtime = wfTimestamp( TS_UNIX, $module->getModifiedTime( $context ) );
+ $versionHash = $module->getVersionHash( $context );
+ if ( strlen( $versionHash ) !== 8 ) {
+ // Module implementation either broken or deviated from ResourceLoader::makeHash
+ // Asserted by tests/phpunit/structure/ResourcesTest.
+ $versionHash = ResourceLoader::makeHash( $versionHash );
+ }
$skipFunction = $module->getSkipFunction();
if ( $skipFunction !== null && !ResourceLoader::inDebugMode() ) {
$skipFunction = $resourceLoader->filter( 'minify-js',
$skipFunction,
- // There will potentially be lots of these little string in the registrations
+ // There will potentially be lots of these little strings in the registrations
// manifest, we don't want to blow up the startup module with
- // "/* cache key: ... */" all over it in non-debug mode.
+ // "/* cache key: ... */" all over it.
/* cacheReport = */ false
);
}
- $mtime = max(
- $moduleMtime,
- wfTimestamp( TS_UNIX, $this->getConfig()->get( 'CacheEpoch' ) )
- );
-
$registryData[$name] = array(
- // Convert to numbers as wfTimestamp always returns a string, even for TS_UNIX
- 'version' => (int) $mtime,
- 'dependencies' => $module->getDependencies(),
+ 'version' => $versionHash,
+ 'dependencies' => $module->getDependencies( $context ),
'group' => $module->getGroup(),
'source' => $module->getSource(),
'loader' => $module->getLoaderScript(),
@@ -263,7 +262,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
continue;
}
- // Call mw.loader.register(name, timestamp, dependencies, group, source, skip)
+ // Call mw.loader.register(name, version, dependencies, group, source, skip)
$registrations[] = array(
$name,
$data['version'],
@@ -276,13 +275,11 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
}
// Register modules
- $out .= ResourceLoader::makeLoaderRegisterScript( $registrations );
+ $out .= "\n" . ResourceLoader::makeLoaderRegisterScript( $registrations );
return $out;
}
- /* Methods */
-
/**
* @return bool
*/
@@ -299,6 +296,20 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
return array( 'jquery', 'mediawiki' );
}
+ public static function getLegacyModules() {
+ global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil;
+
+ $legacyModules = array();
+ if ( $wgIncludeLegacyJavaScript ) {
+ $legacyModules[] = 'mediawiki.legacy.wikibits';
+ }
+ if ( $wgPreloadJavaScriptMwUtil ) {
+ $legacyModules[] = 'mediawiki.util';
+ }
+
+ return $legacyModules;
+ }
+
/**
* Get the load URL of the startup modules.
*
@@ -309,24 +320,16 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
* @return string
*/
public static function getStartupModulesUrl( ResourceLoaderContext $context ) {
+ $rl = $context->getResourceLoader();
$moduleNames = self::getStartupModules();
- // Get the latest version
- $loader = $context->getResourceLoader();
- $version = 1;
- foreach ( $moduleNames as $moduleName ) {
- $version = max( $version,
- $loader->getModule( $moduleName )->getModifiedTime( $context )
- );
- }
-
$query = array(
'modules' => ResourceLoader::makePackedModulesString( $moduleNames ),
'only' => 'scripts',
'lang' => $context->getLanguage(),
'skin' => $context->getSkin(),
'debug' => $context->getDebug() ? 'true' : 'false',
- 'version' => wfTimestamp( TS_ISO_8601_BASIC, $version )
+ 'version' => $rl->getCombinedVersion( $context, $moduleNames ),
);
// Ensure uniform query order
ksort( $query );
@@ -339,40 +342,25 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
*/
public function getScript( ResourceLoaderContext $context ) {
global $IP;
+ if ( $context->getOnly() !== 'scripts' ) {
+ return '/* Requires only=script */';
+ }
$out = file_get_contents( "$IP/resources/src/startup.js" );
- if ( $context->getOnly() === 'scripts' ) {
- // Startup function
- $configuration = $this->getConfigSettings( $context );
- $registrations = $this->getModuleRegistrations( $context );
+ $pairs = array_map( function ( $value ) {
+ $value = FormatJson::encode( $value, ResourceLoader::inDebugMode(), FormatJson::ALL_OK );
// Fix indentation
- $registrations = str_replace( "\n", "\n\t", trim( $registrations ) );
- $mwMapJsCall = Xml::encodeJsCall(
- 'mw.Map',
- array( $this->getConfig()->get( 'LegacyJavaScriptGlobals' ) )
- );
- $mwConfigSetJsCall = Xml::encodeJsCall(
- 'mw.config.set',
- array( $configuration ),
- ResourceLoader::inDebugMode()
- );
-
- $out .= "var startUp = function () {\n" .
- "\tmw.config = new " .
- $mwMapJsCall . "\n" .
- "\t$registrations\n" .
- "\t" . $mwConfigSetJsCall .
- "};\n";
-
- // Conditional script injection
- $scriptTag = Html::linkedScript( self::getStartupModulesUrl( $context ) );
- $out .= "if ( isCompatible() ) {\n" .
- "\t" . Xml::encodeJsCall( 'document.write', array( $scriptTag ) ) .
- "\n}";
- }
-
- return $out;
+ $value = str_replace( "\n", "\n\t", $value );
+ return $value;
+ }, array(
+ '$VARS.wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
+ '$VARS.configuration' => $this->getConfigSettings( $context ),
+ '$VARS.baseModulesUri' => self::getStartupModulesUrl( $context ),
+ ) );
+ $pairs['$CODE.registrations()'] = str_replace( "\n", "\n\t", trim( $this->getModuleRegistrations( $context ) ) );
+
+ return strtr( $out, $pairs );
}
/**
@@ -383,59 +371,48 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
}
/**
+ * Get the definition summary for this module.
+ *
* @param ResourceLoaderContext $context
- * @return array|mixed
+ * @return array
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
+ public function getDefinitionSummary( ResourceLoaderContext $context ) {
global $IP;
+ $summary = parent::getDefinitionSummary( $context );
+ $summary[] = array(
+ // Detect changes to variables exposed in mw.config (T30899).
+ 'vars' => $this->getConfigSettings( $context ),
+ // Changes how getScript() creates mw.Map for mw.config
+ 'wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
+ // Detect changes to the module registrations
+ 'moduleHashes' => $this->getAllModuleHashes( $context ),
- $hash = $context->getHash();
- if ( isset( $this->modifiedTime[$hash] ) ) {
- return $this->modifiedTime[$hash];
- }
-
- // Call preloadModuleInfo() on ALL modules as we're about
- // to call getModifiedTime() on all of them
- $loader = $context->getResourceLoader();
- $loader->preloadModuleInfo( $loader->getModuleNames(), $context );
-
- $time = max(
- wfTimestamp( TS_UNIX, $this->getConfig()->get( 'CacheEpoch' ) ),
- filemtime( "$IP/resources/src/startup.js" ),
- $this->getHashMtime( $context )
+ 'fileMtimes' => array(
+ filemtime( "$IP/resources/src/startup.js" ),
+ ),
);
-
- // ATTENTION!: Because of the line below, this is not going to cause
- // infinite recursion - think carefully before making changes to this
- // code!
- // Pre-populate modifiedTime with something because the loop over
- // all modules below includes the startup module (this module).
- $this->modifiedTime[$hash] = 1;
-
- foreach ( $loader->getModuleNames() as $name ) {
- $module = $loader->getModule( $name );
- $time = max( $time, $module->getModifiedTime( $context ) );
- }
-
- $this->modifiedTime[$hash] = $time;
- return $this->modifiedTime[$hash];
+ return $summary;
}
/**
- * Hash of all dynamic data embedded in getScript().
- *
- * Detect changes to mw.config settings embedded in #getScript (bug 28899).
+ * Helper method for getDefinitionSummary().
*
* @param ResourceLoaderContext $context
- * @return string Hash
+ * @return string SHA-1
*/
- public function getModifiedHash( ResourceLoaderContext $context ) {
- $data = array(
- 'vars' => $this->getConfigSettings( $context ),
- 'wgLegacyJavaScriptGlobals' => $this->getConfig()->get( 'LegacyJavaScriptGlobals' ),
- );
-
- return md5( serialize( $data ) );
+ protected function getAllModuleHashes( ResourceLoaderContext $context ) {
+ $rl = $context->getResourceLoader();
+ // Preload for getCombinedVersion()
+ $rl->preloadModuleInfo( $rl->getModuleNames(), $context );
+
+ // ATTENTION: Because of the line below, this is not going to cause infinite recursion.
+ // Think carefully before making changes to this code!
+ // Pre-populate versionHash with something because the loop over all modules below includes
+ // the startup module (this module).
+ // See ResourceLoaderModule::getVersionHash() for usage of this cache.
+ $this->versionHash[$context->getHash()] = null;
+
+ return $rl->getCombinedVersion( $context, $rl->getModuleNames() );
}
/**
diff --git a/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php b/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php
index 472ceb26..65d770e2 100644
--- a/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php
+++ b/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php
@@ -27,25 +27,13 @@
*/
class ResourceLoaderUserCSSPrefsModule extends ResourceLoaderModule {
- /* Protected Members */
-
- protected $modifiedTime = array();
-
protected $origin = self::ORIGIN_CORE_INDIVIDUAL;
- /* Methods */
-
/**
- * @param ResourceLoaderContext $context
- * @return array|int|mixed
+ * @return bool
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
- $hash = $context->getHash();
- if ( !isset( $this->modifiedTime[$hash] ) ) {
- $this->modifiedTime[$hash] = wfTimestamp( TS_UNIX, $context->getUserObj()->getTouched() );
- }
-
- return $this->modifiedTime[$hash];
+ public function enableModuleContentVersion() {
+ return true;
}
/**
diff --git a/includes/resourceloader/ResourceLoaderUserDefaultsModule.php b/includes/resourceloader/ResourceLoaderUserDefaultsModule.php
index 5f4bc16b..eba61edc 100644
--- a/includes/resourceloader/ResourceLoaderUserDefaultsModule.php
+++ b/includes/resourceloader/ResourceLoaderUserDefaultsModule.php
@@ -26,26 +26,13 @@
*/
class ResourceLoaderUserDefaultsModule extends ResourceLoaderModule {
- /* Protected Members */
-
protected $targets = array( 'desktop', 'mobile' );
- /* Methods */
-
- /**
- * @param ResourceLoaderContext $context
- * @return string Hash
- */
- public function getModifiedHash( ResourceLoaderContext $context ) {
- return md5( serialize( User::getDefaultOptions() ) );
- }
-
/**
- * @param ResourceLoaderContext $context
- * @return int
+ * @return bool
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
- return $this->getHashMtime( $context );
+ public function enableModuleContentVersion() {
+ return true;
}
/**
diff --git a/includes/resourceloader/ResourceLoaderUserOptionsModule.php b/includes/resourceloader/ResourceLoaderUserOptionsModule.php
index 84c1906d..0847109c 100644
--- a/includes/resourceloader/ResourceLoaderUserOptionsModule.php
+++ b/includes/resourceloader/ResourceLoaderUserOptionsModule.php
@@ -27,34 +27,23 @@
*/
class ResourceLoaderUserOptionsModule extends ResourceLoaderModule {
- /* Protected Members */
-
- protected $modifiedTime = array();
-
protected $origin = self::ORIGIN_CORE_INDIVIDUAL;
protected $targets = array( 'desktop', 'mobile' );
- /* Methods */
-
/**
+ * @param ResourceLoaderContext $context
* @return array List of module names as strings
*/
- public function getDependencies() {
+ public function getDependencies( ResourceLoaderContext $context = null ) {
return array( 'user.defaults' );
}
/**
- * @param ResourceLoaderContext $context
- * @return int
+ * @return bool
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
- $hash = $context->getHash();
- if ( !isset( $this->modifiedTime[$hash] ) ) {
- $this->modifiedTime[$hash] = wfTimestamp( TS_UNIX, $context->getUserObj()->getTouched() );
- }
-
- return $this->modifiedTime[$hash];
+ public function enableModuleContentVersion() {
+ return true;
}
/**
diff --git a/includes/resourceloader/ResourceLoaderWikiModule.php b/includes/resourceloader/ResourceLoaderWikiModule.php
index 7b44cc67..0023de27 100644
--- a/includes/resourceloader/ResourceLoaderWikiModule.php
+++ b/includes/resourceloader/ResourceLoaderWikiModule.php
@@ -26,15 +26,30 @@
* Abstraction for resource loader modules which pull from wiki pages
*
* This can only be used for wiki pages in the MediaWiki and User namespaces,
- * because of its dependence on the functionality of
- * Title::isCssJsSubpage.
+ * because of its dependence on the functionality of Title::isCssJsSubpage.
+ *
+ * This module supports being used as a placeholder for a module on a remote wiki.
+ * To do so, getDB() must be overloaded to return a foreign database object that
+ * allows local wikis to query page metadata.
+ *
+ * Safe for calls on local wikis are:
+ * - Option getters:
+ * - getGroup()
+ * - getPosition()
+ * - getPages()
+ * - Basic methods that strictly involve the foreign database
+ * - getDB()
+ * - isKnownEmpty()
+ * - getTitleInfo()
*/
class ResourceLoaderWikiModule extends ResourceLoaderModule {
+ /** @var string Position on the page to load this module at */
+ protected $position = 'bottom';
// Origin defaults to users with sitewide authority
protected $origin = self::ORIGIN_USER_SITEWIDE;
- // In-object cache for title info
+ // In-process cache for title info
protected $titleInfo = array();
// List of page names that contain CSS
@@ -50,14 +65,21 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
* @param array $options For back-compat, this can be omitted in favour of overwriting getPages.
*/
public function __construct( array $options = null ) {
- if ( isset( $options['styles'] ) ) {
- $this->styles = $options['styles'];
+ if ( is_null( $options ) ) {
+ return;
}
- if ( isset( $options['scripts'] ) ) {
- $this->scripts = $options['scripts'];
- }
- if ( isset( $options['group'] ) ) {
- $this->group = $options['group'];
+
+ foreach ( $options as $member => $option ) {
+ switch ( $member ) {
+ case 'position':
+ $this->isPositionDefined = true;
+ // Don't break since we need the member set as well
+ case 'styles':
+ case 'scripts':
+ case 'group':
+ $this->{$member} = $option;
+ break;
+ }
}
}
@@ -107,13 +129,13 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
}
/**
- * Get the Database object used in getTitleMTimes(). Defaults to the local slave DB
- * but subclasses may want to override this to return a remote DB object, or to return
- * null if getTitleMTimes() shouldn't access the DB at all.
+ * Get the Database object used in getTitleInfo().
+ *
+ * Defaults to the local slave DB. Subclasses may want to override this to return a foreign
+ * database object, or null if getTitleInfo() shouldn't access the database.
*
- * NOTE: This ONLY works for getTitleMTimes() and getModifiedTime(), NOT FOR ANYTHING ELSE.
- * In particular, it doesn't work for getting the content of JS and CSS pages. That functionality
- * will use the local DB irrespective of the return value of this method.
+ * NOTE: This ONLY works for getTitleInfo() and isKnownEmpty(), NOT FOR ANYTHING ELSE.
+ * In particular, it doesn't work for getContent() or getScript() etc.
*
* @return IDatabase|null
*/
@@ -122,10 +144,15 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
}
/**
- * @param Title $title
+ * @param string $title
* @return null|string
*/
- protected function getContent( $title ) {
+ protected function getContent( $titleText ) {
+ $title = Title::newFromText( $titleText );
+ if ( !$title ) {
+ return null;
+ }
+
$handler = ContentHandler::getForTitle( $title );
if ( $handler->isSupportedFormat( CONTENT_FORMAT_CSS ) ) {
$format = CONTENT_FORMAT_CSS;
@@ -160,11 +187,7 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
if ( $options['type'] !== 'script' ) {
continue;
}
- $title = Title::newFromText( $titleText );
- if ( !$title || $title->isRedirect() ) {
- continue;
- }
- $script = $this->getContent( $title );
+ $script = $this->getContent( $titleText );
if ( strval( $script ) !== '' ) {
$script = $this->validateScriptFile( $titleText, $script );
$scripts .= ResourceLoader::makeComment( $titleText ) . $script . "\n";
@@ -183,12 +206,8 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
if ( $options['type'] !== 'style' ) {
continue;
}
- $title = Title::newFromText( $titleText );
- if ( !$title || $title->isRedirect() ) {
- continue;
- }
$media = isset( $options['media'] ) ? $options['media'] : 'all';
- $style = $this->getContent( $title );
+ $style = $this->getContent( $titleText );
if ( strval( $style ) === '' ) {
continue;
}
@@ -206,37 +225,31 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
}
/**
- * @param ResourceLoaderContext $context
- * @return int
+ * Disable module content versioning.
+ *
+ * This class does not support generating content outside of a module
+ * request due to foreign database support.
+ *
+ * See getDefinitionSummary() for meta-data versioning.
+ *
+ * @return bool
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
- $modifiedTime = 1;
- $titleInfo = $this->getTitleInfo( $context );
- if ( count( $titleInfo ) ) {
- $mtimes = array_map( function ( $value ) {
- return $value['timestamp'];
- }, $titleInfo );
- $modifiedTime = max( $modifiedTime, max( $mtimes ) );
- }
- $modifiedTime = max(
- $modifiedTime,
- $this->getMsgBlobMtime( $context->getLanguage() ),
- $this->getDefinitionMtime( $context )
- );
- return $modifiedTime;
+ public function enableModuleContentVersion() {
+ return false;
}
/**
- * Get the definition summary for this module.
- *
* @param ResourceLoaderContext $context
* @return array
*/
public function getDefinitionSummary( ResourceLoaderContext $context ) {
- return array(
- 'class' => get_class( $this ),
+ $summary = parent::getDefinitionSummary( $context );
+ $summary[] = array(
'pages' => $this->getPages( $context ),
+ // Includes SHA1 of content
+ 'titleInfo' => $this->getTitleInfo( $context ),
);
+ return $summary;
}
/**
@@ -244,33 +257,29 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
* @return bool
*/
public function isKnownEmpty( ResourceLoaderContext $context ) {
- $titleInfo = $this->getTitleInfo( $context );
- // Bug 68488: For modules in the "user" group, we should actually
- // check that the pages are empty (page_len == 0), but for other
- // groups, just check the pages exist so that we don't end up
- // caching temporarily-blank pages without the appropriate
- // <script> or <link> tag.
- if ( $this->getGroup() !== 'user' ) {
- return count( $titleInfo ) === 0;
- }
+ $revisions = $this->getTitleInfo( $context );
- foreach ( $titleInfo as $info ) {
- if ( $info['length'] !== 0 ) {
- // At least one non-0-lenth page, not empty
- return false;
+ // For user modules, don't needlessly load if there are no non-empty pages
+ if ( $this->getGroup() === 'user' ) {
+ foreach ( $revisions as $revision ) {
+ if ( $revision['rev_len'] > 0 ) {
+ // At least one non-empty page, module should be loaded
+ return false;
+ }
}
+ return true;
}
- // All pages are 0-length, so it's empty
- return true;
+ // Bug 68488: For other modules (i.e. ones that are called in cached html output) only check
+ // page existance. This ensures that, if some pages in a module are temporarily blanked,
+ // we don't end omit the module's script or link tag on some pages.
+ return count( $revisions ) === 0;
}
/**
- * Get the modification times of all titles that would be loaded for
- * a given context.
- * @param ResourceLoaderContext $context Context object
- * @return array Keyed by page dbkey. Value is an array with 'length' and 'timestamp'
- * keys, where the timestamp is a UNIX timestamp
+ * Get the information about the wiki pages for a given context.
+ * @param ResourceLoaderContext $context
+ * @return array Keyed by page name. Contains arrays with 'rev_len' and 'rev_sha1' keys
*/
protected function getTitleInfo( ResourceLoaderContext $context ) {
$dbr = $this->getDB();
@@ -279,31 +288,38 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
return array();
}
- $hash = $context->getHash();
- if ( isset( $this->titleInfo[$hash] ) ) {
- return $this->titleInfo[$hash];
- }
-
- $this->titleInfo[$hash] = array();
- $batch = new LinkBatch;
- foreach ( $this->getPages( $context ) as $titleText => $options ) {
- $batch->addObj( Title::newFromText( $titleText ) );
- }
+ $pages = $this->getPages( $context );
+ $key = implode( '|', array_keys( $pages ) );
+ if ( !isset( $this->titleInfo[$key] ) ) {
+ $this->titleInfo[$key] = array();
+ $batch = new LinkBatch;
+ foreach ( $pages as $titleText => $options ) {
+ $batch->addObj( Title::newFromText( $titleText ) );
+ }
- if ( !$batch->isEmpty() ) {
- $res = $dbr->select( 'page',
- array( 'page_namespace', 'page_title', 'page_touched', 'page_len' ),
- $batch->constructSet( 'page', $dbr ),
- __METHOD__
- );
- foreach ( $res as $row ) {
- $title = Title::makeTitle( $row->page_namespace, $row->page_title );
- $this->titleInfo[$hash][$title->getPrefixedDBkey()] = array(
- 'timestamp' => wfTimestamp( TS_UNIX, $row->page_touched ),
- 'length' => $row->page_len,
+ if ( !$batch->isEmpty() ) {
+ $res = $dbr->select( array( 'page', 'revision' ),
+ array( 'page_namespace', 'page_title', 'rev_len', 'rev_sha1' ),
+ $batch->constructSet( 'page', $dbr ),
+ __METHOD__,
+ array(),
+ array( 'revision' => array( 'INNER JOIN', array( 'page_latest=rev_id' ) ) )
);
+ foreach ( $res as $row ) {
+ // Avoid including ids or timestamps of revision/page tables so
+ // that versions are not wasted
+ $title = Title::makeTitle( $row->page_namespace, $row->page_title );
+ $this->titleInfo[$key][$title->getPrefixedText()] = array(
+ 'rev_len' => $row->rev_len,
+ 'rev_sha1' => $row->rev_sha1,
+ );
+ }
}
}
- return $this->titleInfo[$hash];
+ return $this->titleInfo[$key];
+ }
+
+ public function getPosition() {
+ return $this->position;
}
}
diff --git a/includes/revisiondelete/RevDelItem.php b/includes/revisiondelete/RevDelItem.php
index ebdbf3a8..dba368d8 100644
--- a/includes/revisiondelete/RevDelItem.php
+++ b/includes/revisiondelete/RevDelItem.php
@@ -36,6 +36,8 @@ abstract class RevDelItem extends RevisionItemBase {
/**
* Get the current deletion bitfield value
+ *
+ * @return integer
*/
abstract public function getBits();
diff --git a/includes/revisiondelete/RevDelList.php b/includes/revisiondelete/RevDelList.php
index c31c42b3..7ffb4279 100644
--- a/includes/revisiondelete/RevDelList.php
+++ b/includes/revisiondelete/RevDelList.php
@@ -97,7 +97,7 @@ abstract class RevDelList extends RevisionListBase {
* transactions are done here.
*
* @param array $params Associative array of parameters. Members are:
- * value: The integer value to set the visibility to
+ * value: ExtractBitParams() bitfield array
* comment: The log comment.
* perItemStatus: Set if you want per-item status reports
* @return Status
@@ -108,10 +108,13 @@ abstract class RevDelList extends RevisionListBase {
$comment = $params['comment'];
$perItemStatus = isset( $params['perItemStatus'] ) ? $params['perItemStatus'] : false;
- $this->res = false;
+ // CAS-style checks are done on the _deleted fields so the select
+ // does not need to use FOR UPDATE nor be in the atomic section
$dbw = wfGetDB( DB_MASTER );
- $this->doQuery( $dbw );
- $dbw->begin( __METHOD__ );
+ $this->res = $this->doQuery( $dbw );
+
+ $dbw->startAtomic( __METHOD__ );
+
$status = Status::newGood();
$missing = array_flip( $this->ids );
$this->clearFileOps();
@@ -125,6 +128,7 @@ abstract class RevDelList extends RevisionListBase {
// @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
for ( $this->reset(); $this->current(); $this->next() ) {
// @codingStandardsIgnoreEnd
+ /** @var $item RevDelItem */
$item = $this->current();
unset( $missing[$item->getId()] );
@@ -216,6 +220,7 @@ abstract class RevDelList extends RevisionListBase {
}
// Log it
+ // @FIXME: $newBits/$oldBits set in for loop, makes IDE warnings too
$this->updateLog( array(
'title' => $this->title,
'count' => $successCount,
@@ -226,10 +231,15 @@ abstract class RevDelList extends RevisionListBase {
'authorIds' => $authorIds,
'authorIPs' => $authorIPs
) );
- $dbw->commit( __METHOD__ );
// Clear caches
- $status->merge( $this->doPostCommitUpdates() );
+ $that = $this;
+ $dbw->onTransactionIdle( function() use ( $that ) {
+ $that->doPostCommitUpdates();
+ } );
+
+ $dbw->endAtomic( __METHOD__ );
+
return $status;
}
@@ -260,7 +270,7 @@ abstract class RevDelList extends RevisionListBase {
if ( !$field ) {
throw new MWException( "Bad log URL param type!" );
}
- // Put things hidden from sysops in the oversight log
+ // Put things hidden from sysops in the suppression log
if ( ( $params['newBits'] | $params['oldBits'] ) & $this->getSuppressBit() ) {
$logType = 'suppress';
} else {
diff --git a/includes/revisiondelete/RevDelLogItem.php b/includes/revisiondelete/RevDelLogItem.php
index 49adf204..65b03097 100644
--- a/includes/revisiondelete/RevDelLogItem.php
+++ b/includes/revisiondelete/RevDelLogItem.php
@@ -48,11 +48,26 @@ class RevDelLogItem extends RevDelItem {
}
public function getBits() {
- return $this->row->log_deleted;
+ return (int)$this->row->log_deleted;
}
public function setBits( $bits ) {
$dbw = wfGetDB( DB_MASTER );
+
+ $dbw->update( 'logging',
+ array( 'log_deleted' => $bits ),
+ array(
+ 'log_id' => $this->row->log_id,
+ 'log_deleted' => $this->getBits() // cas
+ ),
+ __METHOD__
+ );
+
+ if ( !$dbw->affectedRows() ) {
+ // Concurrent fail!
+ return false;
+ }
+
$dbw->update( 'recentchanges',
array(
'rc_deleted' => $bits,
@@ -64,16 +79,8 @@ class RevDelLogItem extends RevDelItem {
),
__METHOD__
);
- $dbw->update( 'logging',
- array( 'log_deleted' => $bits ),
- array(
- 'log_id' => $this->row->log_id,
- 'log_deleted' => $this->getBits()
- ),
- __METHOD__
- );
- return (bool)$dbw->affectedRows();
+ return true;
}
public function getHTML() {
diff --git a/includes/revisiondelete/RevDelRevisionItem.php b/includes/revisiondelete/RevDelRevisionItem.php
index 300ce6ad..17e1fd18 100644
--- a/includes/revisiondelete/RevDelRevisionItem.php
+++ b/includes/revisiondelete/RevDelRevisionItem.php
@@ -67,7 +67,7 @@ class RevDelRevisionItem extends RevDelItem {
array(
'rev_id' => $this->revision->getId(),
'rev_page' => $this->revision->getPage(),
- 'rev_deleted' => $this->getBits()
+ 'rev_deleted' => $this->getBits() // cas
),
__METHOD__
);
diff --git a/includes/revisiondelete/RevisionDeleter.php b/includes/revisiondelete/RevisionDeleter.php
index ba1f0f69..db2bc6a4 100644
--- a/includes/revisiondelete/RevisionDeleter.php
+++ b/includes/revisiondelete/RevisionDeleter.php
@@ -233,9 +233,9 @@ class RevisionDeleter {
* @since 1.22
* @param array $bitPars ExtractBitParams() params
* @param int $oldfield Current bitfield
- * @return array
+ * @return integer
*/
- public static function extractBitfield( $bitPars, $oldfield ) {
+ public static function extractBitfield( array $bitPars, $oldfield ) {
// Build the actual new rev_deleted bitfield
$newBits = 0;
foreach ( $bitPars as $const => $val ) {
diff --git a/includes/search/SearchEngine.php b/includes/search/SearchEngine.php
index 5770276a..e5ed23f5 100644
--- a/includes/search/SearchEngine.php
+++ b/includes/search/SearchEngine.php
@@ -33,7 +33,7 @@ class SearchEngine {
/** @var string */
public $prefix = '';
- /** @var int[] */
+ /** @var int[]|null */
public $namespaces = array( NS_MAIN );
/** @var int */
@@ -293,7 +293,7 @@ class SearchEngine {
* Set which namespaces the search should include.
* Give an array of namespace index numbers.
*
- * @param array $namespaces
+ * @param int[]|null $namespaces
*/
function setNamespaces( $namespaces ) {
$this->namespaces = $namespaces;
diff --git a/includes/search/SearchHighlighter.php b/includes/search/SearchHighlighter.php
index 5087e8d5..7d5d38f2 100644
--- a/includes/search/SearchHighlighter.php
+++ b/includes/search/SearchHighlighter.php
@@ -218,7 +218,7 @@ class SearchHighlighter {
}
// calc by how much to extend existing snippets
- $targetchars = intval( ( $contextchars * $contextlines ) / count ( $snippets ) );
+ $targetchars = intval( ( $contextchars * $contextlines ) / count( $snippets ) );
}
foreach ( $snippets as $index => $line ) {
diff --git a/includes/search/SearchMySQL.php b/includes/search/SearchMySQL.php
index 485088cb..246f1155 100644
--- a/includes/search/SearchMySQL.php
+++ b/includes/search/SearchMySQL.php
@@ -54,9 +54,9 @@ class SearchMySQL extends SearchDatabase {
if ( preg_match_all( '/([-+<>~]?)(([' . $lc . ']+)(\*?)|"[^"]*")/',
$filteredText, $m, PREG_SET_ORDER ) ) {
foreach ( $m as $bits ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
list( /* all */, $modifier, $term, $nonQuoted, $wildcard ) = $bits;
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $nonQuoted != '' ) {
$term = $nonQuoted;
@@ -439,7 +439,7 @@ class SearchMySQL extends SearchDatabase {
$sql = "SHOW GLOBAL VARIABLES LIKE 'ft\\_min\\_word\\_len'";
$dbr = wfGetDB( DB_SLAVE );
- $result = $dbr->query( $sql );
+ $result = $dbr->query( $sql, __METHOD__ );
$row = $result->fetchObject();
$result->free();
diff --git a/includes/search/SearchPostgres.php b/includes/search/SearchPostgres.php
index bda10b0b..71e3b635 100644
--- a/includes/search/SearchPostgres.php
+++ b/includes/search/SearchPostgres.php
@@ -186,7 +186,7 @@ class SearchPostgres extends SearchDatabase {
function update( $pageid, $title, $text ) {
## We don't want to index older revisions
$sql = "UPDATE pagecontent SET textvector = NULL WHERE textvector IS NOT NULL and old_id IN " .
- "(SELECT rev_text_id FROM revision WHERE rev_page = " . intval( $pageid ) .
+ "(SELECT DISTINCT rev_text_id FROM revision WHERE rev_page = " . intval( $pageid ) .
" ORDER BY rev_text_id DESC OFFSET 1)";
$this->db->query( $sql );
return true;
diff --git a/includes/search/SearchResultSet.php b/includes/search/SearchResultSet.php
index 406d322d..8d18b0e6 100644
--- a/includes/search/SearchResultSet.php
+++ b/includes/search/SearchResultSet.php
@@ -25,6 +25,12 @@
* @ingroup Search
*/
class SearchResultSet {
+ protected $containedSyntax = false;
+
+ public function __construct( $containedSyntax = false ) {
+ $this->containedSyntax = $containedSyntax;
+ }
+
/**
* Fetch an array of regular expression fragments for matching
* the search terms as parsed by this engine in a text extract.
@@ -55,6 +61,33 @@ class SearchResultSet {
}
/**
+ * Some search modes will run an alternative query that it thinks gives
+ * a better result than the provided search. Returns true if this has
+ * occured.
+ *
+ * @return bool
+ */
+ function hasRewrittenQuery() {
+ return false;
+ }
+
+ /**
+ * @return string|null The search the query was internally rewritten to,
+ * or null when the result of the original query was returned.
+ */
+ function getQueryAfterRewrite() {
+ return null;
+ }
+
+ /**
+ * @return string|null Same as self::getQueryAfterRewrite(), but in HTML
+ * and with changes highlighted. Null when the query was not rewritten.
+ */
+ function getQueryAfterRewriteSnippet() {
+ return null;
+ }
+
+ /**
* Some search modes return a suggested alternate term if there are
* no exact hits. Returns true if there is one on this set.
*
@@ -120,7 +153,7 @@ class SearchResultSet {
* @return bool
*/
public function searchContainedSyntax() {
- return false;
+ return $this->containedSyntax;
}
}
diff --git a/includes/search/SearchSqlite.php b/includes/search/SearchSqlite.php
index eee69307..3a5ee0ef 100644
--- a/includes/search/SearchSqlite.php
+++ b/includes/search/SearchSqlite.php
@@ -52,9 +52,9 @@ class SearchSqlite extends SearchDatabase {
if ( preg_match_all( '/([-+<>~]?)(([' . $lc . ']+)(\*?)|"[^"]*")/',
$filteredText, $m, PREG_SET_ORDER ) ) {
foreach ( $m as $bits ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
list( /* all */, $modifier, $term, $nonQuoted, $wildcard ) = $bits;
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $nonQuoted != '' ) {
$term = $nonQuoted;
diff --git a/includes/site/CachingSiteStore.php b/includes/site/CachingSiteStore.php
index 9243f12b..077dbc0e 100644
--- a/includes/site/CachingSiteStore.php
+++ b/includes/site/CachingSiteStore.php
@@ -168,9 +168,11 @@ class CachingSiteStore implements SiteStore {
}
/**
- * Purges the internal and external cache of the site list, forcing the list
+ * Purges the internal and external cache of the site list, forcing the list.
* of sites to be reloaded.
*
+ * Only use this for testing, as APC is typically used and is per-server
+ *
* @since 1.25
*/
public function reset() {
@@ -182,6 +184,8 @@ class CachingSiteStore implements SiteStore {
/**
* Clears the list of sites stored.
*
+ * Only use this for testing, as APC is typically used and is per-server.
+ *
* @see SiteStore::clear()
*
* @return bool Success
diff --git a/includes/site/DBSiteStore.php b/includes/site/DBSiteStore.php
index f167584e..1193bd65 100644
--- a/includes/site/DBSiteStore.php
+++ b/includes/site/DBSiteStore.php
@@ -153,7 +153,11 @@ class DBSiteStore implements SiteStore {
protected function loadSites() {
$this->sites = new SiteList();
- foreach ( $this->sitesTable->select() as $siteRow ) {
+ $siteRows = $this->sitesTable->select( null, array(), array(
+ 'ORDER BY' => 'site_global_key'
+ ) );
+
+ foreach ( $siteRows as $siteRow ) {
$this->sites[] = $this->siteFromRow( $siteRow );
}
diff --git a/includes/site/SiteExporter.php b/includes/site/SiteExporter.php
index 62f6ca3c..169c0d87 100644
--- a/includes/site/SiteExporter.php
+++ b/includes/site/SiteExporter.php
@@ -57,13 +57,13 @@ class SiteExporter {
'xmlns' => 'http://www.mediawiki.org/xml/sitelist-1.0/',
);
- fwrite( $this->sink, XML::openElement( 'sites', $attributes ) . "\n" );
+ fwrite( $this->sink, Xml::openElement( 'sites', $attributes ) . "\n" );
foreach ( $sites as $site ) {
$this->exportSite( $site );
}
- fwrite( $this->sink, XML::closeElement( 'sites' ) . "\n" );
+ fwrite( $this->sink, Xml::closeElement( 'sites' ) . "\n" );
fflush( $this->sink );
}
@@ -79,36 +79,36 @@ class SiteExporter {
$siteAttr = null;
}
- fwrite( $this->sink, "\t" . XML::openElement( 'site', $siteAttr ) . "\n" );
+ fwrite( $this->sink, "\t" . Xml::openElement( 'site', $siteAttr ) . "\n" );
- fwrite( $this->sink, "\t\t" . XML::element( 'globalid', null, $site->getGlobalId() ) . "\n" );
+ fwrite( $this->sink, "\t\t" . Xml::element( 'globalid', null, $site->getGlobalId() ) . "\n" );
if ( $site->getGroup() !== Site::GROUP_NONE ) {
- fwrite( $this->sink, "\t\t" . XML::element( 'group', null, $site->getGroup() ) . "\n" );
+ fwrite( $this->sink, "\t\t" . Xml::element( 'group', null, $site->getGroup() ) . "\n" );
}
if ( $site->getSource() !== Site::SOURCE_LOCAL ) {
- fwrite( $this->sink, "\t\t" . XML::element( 'source', null, $site->getSource() ) . "\n" );
+ fwrite( $this->sink, "\t\t" . Xml::element( 'source', null, $site->getSource() ) . "\n" );
}
if ( $site->shouldForward() ) {
- fwrite( $this->sink, "\t\t" . XML::element( 'forward', null, '' ) . "\n" );
+ fwrite( $this->sink, "\t\t" . Xml::element( 'forward', null, '' ) . "\n" );
}
foreach ( $site->getAllPaths() as $type => $path ) {
- fwrite( $this->sink, "\t\t" . XML::element( 'path', array( 'type' => $type ), $path ) . "\n" );
+ fwrite( $this->sink, "\t\t" . Xml::element( 'path', array( 'type' => $type ), $path ) . "\n" );
}
foreach ( $site->getLocalIds() as $type => $ids ) {
foreach ( $ids as $id ) {
- fwrite( $this->sink, "\t\t" . XML::element( 'localid', array( 'type' => $type ), $id ) . "\n" );
+ fwrite( $this->sink, "\t\t" . Xml::element( 'localid', array( 'type' => $type ), $id ) . "\n" );
}
}
//@todo: export <data>
//@todo: export <config>
- fwrite( $this->sink, "\t" . XML::closeElement( 'site' ) . "\n" );
+ fwrite( $this->sink, "\t" . Xml::closeElement( 'site' ) . "\n" );
}
}
diff --git a/includes/site/SiteSQLStore.php b/includes/site/SiteSQLStore.php
index d77f07be..e3230fff 100644
--- a/includes/site/SiteSQLStore.php
+++ b/includes/site/SiteSQLStore.php
@@ -41,7 +41,7 @@ class SiteSQLStore extends CachingSiteStore {
*/
public static function newInstance( ORMTable $sitesTable = null, BagOStuff $cache = null ) {
if ( $cache === null ) {
- $cache = wfGetMainCache();
+ $cache = wfGetCache( wfIsHHVM() ? CACHE_ACCEL : CACHE_ANYTHING );
}
$siteStore = new DBSiteStore();
diff --git a/includes/skins/MediaWikiI18N.php b/includes/skins/MediaWikiI18N.php
index 6e48d04a..20cceda2 100644
--- a/includes/skins/MediaWikiI18N.php
+++ b/includes/skins/MediaWikiI18N.php
@@ -42,9 +42,9 @@ class MediaWikiI18N {
$m = array();
while ( preg_match( '/\$([0-9]*?)/sm', $value, $m ) ) {
list( $src, $var ) = $m;
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$varValue = $this->context[$var];
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
$value = str_replace( $src, $varValue, $value );
}
return $value;
diff --git a/includes/skins/Skin.php b/includes/skins/Skin.php
index ac7a85ba..4e6201cd 100644
--- a/includes/skins/Skin.php
+++ b/includes/skins/Skin.php
@@ -180,8 +180,7 @@ abstract class Skin extends ContextSource {
* @return array Array of modules with helper keys for easy overriding
*/
public function getDefaultModules() {
- global $wgIncludeLegacyJavaScript, $wgPreloadJavaScriptMwUtil, $wgUseAjax,
- $wgAjaxWatch, $wgEnableAPI, $wgEnableWriteAPI;
+ global $wgUseAjax, $wgAjaxWatch, $wgEnableAPI, $wgEnableWriteAPI;
$out = $this->getOutput();
$user = $out->getUser();
@@ -191,7 +190,7 @@ abstract class Skin extends ContextSource {
'mediawiki.page.ready',
),
// modules that exist for legacy reasons
- 'legacy' => array(),
+ 'legacy' => ResourceLoaderStartUpModule::getLegacyModules(),
// modules relating to search functionality
'search' => array(),
// modules relating to functionality relating to watching an article
@@ -199,27 +198,17 @@ abstract class Skin extends ContextSource {
// modules which relate to the current users preferences
'user' => array(),
);
- if ( $wgIncludeLegacyJavaScript ) {
- $modules['legacy'][] = 'mediawiki.legacy.wikibits';
- }
-
- if ( $wgPreloadJavaScriptMwUtil ) {
- $modules['legacy'][] = 'mediawiki.util';
- }
// Add various resources if required
- if ( $wgUseAjax ) {
- $modules['legacy'][] = 'mediawiki.legacy.ajax';
-
- if ( $wgEnableAPI ) {
- if ( $wgEnableWriteAPI && $wgAjaxWatch && $user->isLoggedIn()
- && $user->isAllowed( 'writeapi' )
- ) {
- $modules['watch'][] = 'mediawiki.page.watch.ajax';
- }
-
- $modules['search'][] = 'mediawiki.searchSuggest';
+ if ( $wgUseAjax && $wgEnableAPI ) {
+ if ( $wgEnableWriteAPI && $wgAjaxWatch && $user->isLoggedIn()
+ && $user->isAllowedAll( 'writeapi', 'viewmywatchlist', 'editmywatchlist' )
+ && $this->getRelevantTitle()->canExist()
+ ) {
+ $modules['watch'][] = 'mediawiki.page.watch.ajax';
}
+
+ $modules['search'][] = 'mediawiki.searchSuggest';
}
if ( $user->getBoolOption( 'editsectiononrightclick' ) ) {
@@ -248,8 +237,8 @@ abstract class Skin extends ContextSource {
$titles[] = $user->getTalkPage();
}
- // Other tab link
- if ( $title->isSpecialPage() ) {
+ // Check, if the page can hold some kind of content, otherwise do nothing
+ if ( !$title->canExist() ) {
// nothing
} elseif ( $title->isTalkPage() ) {
$titles[] = $title->getSubjectPage();
@@ -365,8 +354,8 @@ abstract class Skin extends ContextSource {
*/
static function makeVariablesScript( $data ) {
if ( $data ) {
- return Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript( ResourceLoader::makeConfigSetScript( $data ) )
+ return ResourceLoader::makeInlineScript(
+ ResourceLoader::makeConfigSetScript( $data )
);
} else {
return '';
@@ -650,7 +639,7 @@ abstract class Skin extends ContextSource {
}
return $this->msg( 'retrievedfrom' )
- ->rawParams( '<a dir="ltr" href="' . $url. '">' . $url . '</a>' )
+ ->rawParams( '<a dir="ltr" href="' . $url . '">' . $url . '</a>' )
->parse();
}
@@ -1234,12 +1223,13 @@ abstract class Skin extends ContextSource {
* @return array
*/
function buildSidebar() {
- global $wgMemc, $wgEnableSidebarCache, $wgSidebarCacheExpiry;
+ global $wgEnableSidebarCache, $wgSidebarCacheExpiry;
+ $cache = ObjectCache::getMainWANInstance();
$key = wfMemcKey( 'sidebar', $this->getLanguage()->getCode() );
if ( $wgEnableSidebarCache ) {
- $cachedsidebar = $wgMemc->get( $key );
+ $cachedsidebar = $cache->get( $key );
if ( $cachedsidebar ) {
Hooks::run( 'SidebarBeforeOutput', array( $this, &$cachedsidebar ) );
@@ -1252,7 +1242,7 @@ abstract class Skin extends ContextSource {
Hooks::run( 'SkinBuildSidebar', array( $this, &$bar ) );
if ( $wgEnableSidebarCache ) {
- $wgMemc->set( $key, $bar, $wgSidebarCacheExpiry );
+ $cache->set( $key, $bar, $wgSidebarCacheExpiry );
}
Hooks::run( 'SidebarBeforeOutput', array( $this, &$bar ) );
diff --git a/includes/skins/SkinFallbackTemplate.php b/includes/skins/SkinFallbackTemplate.php
index 1c5f3a6f..cd5e43c6 100644
--- a/includes/skins/SkinFallbackTemplate.php
+++ b/includes/skins/SkinFallbackTemplate.php
@@ -65,7 +65,9 @@ class SkinFallbackTemplate extends BaseTemplate {
return $this->getMsg( 'default-skin-not-found' )->params(
$defaultSkin,
implode( "\n", $skinsInstalledText ),
- implode( "\n", $skinsInstalledSnippet )
+ implode( "\n", $skinsInstalledSnippet ) )->numParams(
+ count( $skinsInstalledText ),
+ count( $skinsInstalledSnippet )
)->parseAsBlock();
} else {
return $this->getMsg( 'default-skin-not-found-no-skins' )->params(
@@ -85,7 +87,7 @@ class SkinFallbackTemplate extends BaseTemplate {
if ( file_exists( "$IP/skins/$skin/skin.json" ) ) {
return "wfLoadSkin( '$skin' );";
} else {
- return "require_once \"\$IP/skins/$skin/$skin.php\";";
+ return "require_once \"\$IP/skins/$skin/$skin.php\";";
}
}
diff --git a/includes/skins/SkinTemplate.php b/includes/skins/SkinTemplate.php
index 61aad921..baf9d954 100644
--- a/includes/skins/SkinTemplate.php
+++ b/includes/skins/SkinTemplate.php
@@ -51,12 +51,22 @@ class SkinTemplate extends Skin {
* @param OutputPage $out
*/
function setupSkinUserCss( OutputPage $out ) {
- $out->addModuleStyles( array(
+ $moduleStyles = array(
'mediawiki.legacy.shared',
'mediawiki.legacy.commonPrint',
- 'mediawiki.ui.button',
'mediawiki.sectionAnchor'
- ) );
+ );
+ if ( $out->isSyndicated() ) {
+ $moduleStyles[] = 'mediawiki.feedlink';
+ }
+
+ // Deprecated since 1.26: Unconditional loading of mediawiki.ui.button
+ // on every page is deprecated. Express a dependency instead.
+ if ( strpos( $out->getHTML(), 'mw-ui-button' ) !== false ) {
+ $moduleStyles[] = 'mediawiki.ui.button';
+ }
+
+ $out->addModuleStyles( $moduleStyles );
}
/**
@@ -422,11 +432,9 @@ class SkinTemplate extends Skin {
# Add a mw-content-ltr/rtl class to be able to style based on text direction
# when the content is different from the UI language, i.e.:
- # not for special pages or file pages AND only when viewing AND if the page exists
- # (or is in MW namespace, because that has default content)
+ # not for special pages or file pages AND only when viewing
if ( !in_array( $title->getNamespace(), array( NS_SPECIAL, NS_FILE ) ) &&
- Action::getActionName( $this ) === 'view' &&
- ( $title->exists() || $title->getNamespace() == NS_MEDIAWIKI ) ) {
+ Action::getActionName( $this ) === 'view' ) {
$pageLang = $title->getPageViewLanguage();
$realBodyAttribs['lang'] = $pageLang->getHtmlCode();
$realBodyAttribs['dir'] = $pageLang->getDir();
@@ -1078,6 +1086,7 @@ class SkinTemplate extends Skin {
$xmlID = 'ca-nstab-' . $xmlID;
} elseif ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
$xmlID = 'ca-talk';
+ $link['rel'] = 'discussion';
} elseif ( $section == 'variants' ) {
$xmlID = 'ca-varlang-' . $xmlID;
} else {
diff --git a/includes/specialpage/ChangesListSpecialPage.php b/includes/specialpage/ChangesListSpecialPage.php
index b9132358..23bd394c 100644
--- a/includes/specialpage/ChangesListSpecialPage.php
+++ b/includes/specialpage/ChangesListSpecialPage.php
@@ -434,7 +434,8 @@ abstract class ChangesListSpecialPage extends SpecialPage {
$legend .= Html::element( 'dt',
array( 'class' => $cssClass ), $context->msg( $letter )->text()
) . "\n" .
- Html::rawElement( 'dd', array(),
+ Html::rawElement( 'dd',
+ array( 'class' => Sanitizer::escapeClass( 'mw-changeslist-legend-' . $key ) ),
$context->msg( $label )->parse()
) . "\n";
}
diff --git a/includes/specialpage/FormSpecialPage.php b/includes/specialpage/FormSpecialPage.php
index 90567617..42c59806 100644
--- a/includes/specialpage/FormSpecialPage.php
+++ b/includes/specialpage/FormSpecialPage.php
@@ -96,7 +96,11 @@ abstract class FormSpecialPage extends SpecialPage {
$this->getMessagePrefix()
);
$form->setSubmitCallback( array( $this, 'onSubmit' ) );
- $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-legend' );
+ if ( $this->getDisplayFormat() !== 'ooui' ) {
+ // No legend and wrapper by default in OOUI forms, but can be set manually
+ // from alterForm()
+ $form->setWrapperLegendMsg( $this->getMessagePrefix() . '-legend' );
+ }
$headerMsg = $this->msg( $this->getMessagePrefix() . '-text' );
if ( !$headerMsg->isDisabled() ) {
diff --git a/includes/specialpage/QueryPage.php b/includes/specialpage/QueryPage.php
index 1ff7e3fb..3c8b7420 100644
--- a/includes/specialpage/QueryPage.php
+++ b/includes/specialpage/QueryPage.php
@@ -70,7 +70,7 @@ abstract class QueryPage extends SpecialPage {
array( 'DeadendPagesPage', 'Deadendpages' ),
array( 'DoubleRedirectsPage', 'DoubleRedirects' ),
array( 'FileDuplicateSearchPage', 'FileDuplicateSearch' ),
- array( 'ListDuplicatedFilesPage', 'ListDuplicatedFiles'),
+ array( 'ListDuplicatedFilesPage', 'ListDuplicatedFiles' ),
array( 'LinkSearchPage', 'LinkSearch' ),
array( 'ListredirectsPage', 'Listredirects' ),
array( 'LonelyPagesPage', 'Lonelypages' ),
@@ -141,7 +141,7 @@ abstract class QueryPage extends SpecialPage {
* @return array
* @since 1.18
*/
- function getQueryInfo() {
+ public function getQueryInfo() {
return null;
}
@@ -178,7 +178,7 @@ abstract class QueryPage extends SpecialPage {
* @return bool
* @since 1.18
*/
- function usesTimestamps() {
+ public function usesTimestamps() {
return false;
}
@@ -198,7 +198,7 @@ abstract class QueryPage extends SpecialPage {
*
* @return bool
*/
- function isExpensive() {
+ public function isExpensive() {
return $this->getConfig()->get( 'DisableQueryPages' );
}
@@ -219,7 +219,7 @@ abstract class QueryPage extends SpecialPage {
*
* @return bool
*/
- function isCached() {
+ public function isCached() {
return $this->isExpensive() && $this->getConfig()->get( 'MiserMode' );
}
@@ -253,6 +253,17 @@ abstract class QueryPage extends SpecialPage {
}
/**
+ * Outputs some kind of an informative message (via OutputPage) to let the
+ * user know that the query returned nothing and thus there's nothing to
+ * show.
+ *
+ * @since 1.26
+ */
+ protected function showEmptyText() {
+ $this->getOutput()->addWikiMsg( 'specialpage-empty' );
+ }
+
+ /**
* If using extra form wheely-dealies, return a set of parameters here
* as an associative array. They will be encoded and added to the paging
* links (prev/next/lengths).
@@ -283,7 +294,7 @@ abstract class QueryPage extends SpecialPage {
* @throws DBError|Exception
* @return bool|int
*/
- function recache( $limit, $ignoreErrors = true ) {
+ public function recache( $limit, $ignoreErrors = true ) {
if ( !$this->isCacheable() ) {
return 0;
}
@@ -359,7 +370,7 @@ abstract class QueryPage extends SpecialPage {
* @return ResultWrapper
* @since 1.18
*/
- function reallyDoQuery( $limit, $offset = false ) {
+ public function reallyDoQuery( $limit, $offset = false ) {
$fname = get_class( $this ) . "::reallyDoQuery";
$dbr = $this->getRecacheDB();
$query = $this->getQueryInfo();
@@ -410,7 +421,7 @@ abstract class QueryPage extends SpecialPage {
* @param int|bool $limit
* @return ResultWrapper
*/
- function doQuery( $offset = false, $limit = false ) {
+ public function doQuery( $offset = false, $limit = false ) {
if ( $this->isCached() && $this->isCacheable() ) {
return $this->fetchFromCache( $limit, $offset );
} else {
@@ -425,7 +436,7 @@ abstract class QueryPage extends SpecialPage {
* @return ResultWrapper
* @since 1.18
*/
- function fetchFromCache( $limit, $offset = false ) {
+ public function fetchFromCache( $limit, $offset = false ) {
$dbr = wfGetDB( DB_SLAVE );
$options = array();
if ( $limit !== false ) {
@@ -460,11 +471,23 @@ abstract class QueryPage extends SpecialPage {
}
/**
+ * Returns limit and offset, as returned by $this->getRequest()->getLimitOffset().
+ * Subclasses may override this to further restrict or modify limit and offset.
+ *
+ * @since 1.26
+ *
+ * @return int[] list( $limit, $offset )
+ */
+ protected function getLimitOffset() {
+ return $this->getRequest()->getLimitOffset();
+ }
+
+ /**
* This is the actual workhorse. It does everything needed to make a
* real, honest-to-gosh query page.
* @param string $par
*/
- function execute( $par ) {
+ public function execute( $par ) {
$user = $this->getUser();
if ( !$this->userCanExecute( $user ) ) {
$this->displayRestrictionError();
@@ -484,7 +507,7 @@ abstract class QueryPage extends SpecialPage {
$out->setSyndicated( $this->isSyndicated() );
if ( $this->limit == 0 && $this->offset == 0 ) {
- list( $this->limit, $this->offset ) = $this->getRequest()->getLimitOffset();
+ list( $this->limit, $this->offset ) = $this->getLimitOffset();
}
// @todo Use doQuery()
@@ -527,7 +550,7 @@ abstract class QueryPage extends SpecialPage {
$this->numRows = $res->numRows();
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = $this->getRecacheDB();
$this->preprocessResults( $dbr, $res );
$out->addHTML( Xml::openElement( 'div', array( 'class' => 'mw-spcontent' ) ) );
@@ -546,7 +569,7 @@ abstract class QueryPage extends SpecialPage {
} else {
# No results to show, so don't bother with "showing X of Y" etc.
# -- just let the user know and give up now
- $out->addWikiMsg( 'specialpage-empty' );
+ $this->showEmptyText();
$out->addHTML( Xml::closeElement( 'div' ) );
return;
}
diff --git a/includes/specialpage/RedirectSpecialPage.php b/includes/specialpage/RedirectSpecialPage.php
index 2e6e55a7..9129ee5d 100644
--- a/includes/specialpage/RedirectSpecialPage.php
+++ b/includes/specialpage/RedirectSpecialPage.php
@@ -33,8 +33,11 @@ abstract class RedirectSpecialPage extends UnlistedSpecialPage {
// Query parameters added by redirects
protected $mAddedRedirectParams = array();
- public function execute( $par ) {
- $redirect = $this->getRedirect( $par );
+ /**
+ * @param string|null $subpage
+ */
+ public function execute( $subpage ) {
+ $redirect = $this->getRedirect( $subpage );
$query = $this->getRedirectQuery();
// Redirect to a page title with possible query parameters
if ( $redirect instanceof Title ) {
@@ -58,22 +61,24 @@ abstract class RedirectSpecialPage extends UnlistedSpecialPage {
* If the special page is a redirect, then get the Title object it redirects to.
* False otherwise.
*
- * @param string $par Subpage string
+ * @param string|null $subpage
* @return Title|bool
*/
- abstract public function getRedirect( $par );
+ abstract public function getRedirect( $subpage );
/**
* Return part of the request string for a special redirect page
* This allows passing, e.g. action=history to Special:Mypage, etc.
*
- * @return string
+ * @return array|bool
*/
public function getRedirectQuery() {
$params = array();
$request = $this->getRequest();
- foreach ( $this->mAllowedRedirectParams as $arg ) {
+ foreach ( array_merge( $this->mAllowedRedirectParams,
+ array( 'uselang', 'useskin', 'debug' ) // parameters which can be passed to all pages
+ ) as $arg ) {
if ( $request->getVal( $arg, null ) !== null ) {
$params[$arg] = $request->getVal( $arg );
} elseif ( $request->getArray( $arg, null ) !== null ) {
@@ -112,12 +117,16 @@ abstract class SpecialRedirectToSpecial extends RedirectSpecialPage {
$this->mAddedRedirectParams = $addedRedirectParams;
}
+ /**
+ * @param string|null $subpage
+ * @return Title|bool
+ */
public function getRedirect( $subpage ) {
if ( $this->redirSubpage === false ) {
return SpecialPage::getTitleFor( $this->redirName, $subpage );
- } else {
- return SpecialPage::getTitleFor( $this->redirName, $this->redirSubpage );
}
+
+ return SpecialPage::getTitleFor( $this->redirName, $this->redirSubpage );
}
}
@@ -140,11 +149,11 @@ abstract class SpecialRedirectToSpecial extends RedirectSpecialPage {
* - limit, offset: Useful for linking to history of one's own user page or
* user talk page. For example, this would be a link to "the last edit to your
* user talk page in the year 2010":
- * http://en.wikipedia.org/wiki/Special:MyPage?offset=20110000000000&limit=1&action=history
+ * https://en.wikipedia.org/wiki/Special:MyPage?offset=20110000000000&limit=1&action=history
*
* - feed: would allow linking to the current user's RSS feed for their user
* talk page:
- * http://en.wikipedia.org/w/index.php?title=Special:MyTalk&action=history&feed=rss
+ * https://en.wikipedia.org/w/index.php?title=Special:MyTalk&action=history&feed=rss
*
* - preloadtitle: Can be used to provide a default section title for a
* preloaded new comment on one's own talk page.
@@ -159,7 +168,7 @@ abstract class SpecialRedirectToSpecial extends RedirectSpecialPage {
* - redlink: Affects the message the user sees if their talk page/user talk
* page does not currently exist. Avoids confusion for newbies with no user
* pages over why they got a "permission error" following this link:
- * http://en.wikipedia.org/w/index.php?title=Special:MyPage&redlink=1
+ * https://en.wikipedia.org/w/index.php?title=Special:MyPage&redlink=1
*
* - debug: determines whether the debug parameter is passed to load.php,
* which disables reformatting and allows scripts to be debugged. Useful
@@ -198,7 +207,7 @@ abstract class RedirectSpecialArticle extends RedirectSpecialPage {
'section', 'oldid', 'diff', 'dir',
'limit', 'offset', 'feed',
# Misc options
- 'redlink', 'debug',
+ 'redlink',
# Options for action=raw; missing ctype can break JS or CSS in some browsers
'ctype', 'maxage', 'smaxage',
);
diff --git a/includes/specialpage/SpecialPage.php b/includes/specialpage/SpecialPage.php
index a7a43b0e..65a4eb9a 100644
--- a/includes/specialpage/SpecialPage.php
+++ b/includes/specialpage/SpecialPage.php
@@ -662,7 +662,6 @@ class SpecialPage {
*/
public function getFinalGroupName() {
$name = $this->getName();
- $specialPageGroups = $this->getConfig()->get( 'SpecialPageGroups' );
// Allow overbidding the group from the wiki side
$msg = $this->msg( 'specialpages-specialpagegroup-' . strtolower( $name ) )->inContentLanguage();
@@ -671,18 +670,6 @@ class SpecialPage {
} else {
// Than use the group from this object
$group = $this->getGroupName();
-
- // Group '-' is used as default to have the chance to determine,
- // if the special pages overrides this method,
- // if not overridden, $wgSpecialPageGroups is checked for b/c
- if ( $group === '-' && isset( $specialPageGroups[$name] ) ) {
- $group = $specialPageGroups[$name];
- }
- }
-
- // never give '-' back, change to 'other'
- if ( $group === '-' ) {
- $group = 'other';
}
return $group;
@@ -697,8 +684,16 @@ class SpecialPage {
* @since 1.21
*/
protected function getGroupName() {
- // '-' used here to determine, if this group is overridden or has a hardcoded 'other'
- // Needed for b/c in getFinalGroupName
- return '-';
+ return 'other';
+ }
+
+ /**
+ * Call wfTransactionalTimeLimit() if this request was POSTed
+ * @since 1.26
+ */
+ protected function useTransactionalTimeLimit() {
+ if ( $this->getRequest()->wasPosted() ) {
+ wfTransactionalTimeLimit();
+ }
}
}
diff --git a/includes/specialpage/SpecialPageFactory.php b/includes/specialpage/SpecialPageFactory.php
index dedfcb6a..e794a5df 100644
--- a/includes/specialpage/SpecialPageFactory.php
+++ b/includes/specialpage/SpecialPageFactory.php
@@ -218,7 +218,7 @@ class SpecialPageFactory {
global $wgSpecialPages;
global $wgDisableInternalSearch, $wgEmailAuthentication;
global $wgEnableEmail, $wgEnableJavaScriptTest;
- global $wgPageLanguageUseDB;
+ global $wgPageLanguageUseDB, $wgContentHandlerUseDB;
if ( !is_array( self::$list ) ) {
@@ -244,6 +244,9 @@ class SpecialPageFactory {
if ( $wgPageLanguageUseDB ) {
self::$list['PageLanguage'] = 'SpecialPageLanguage';
}
+ if ( $wgContentHandlerUseDB ) {
+ self::$list['ChangeContentModel'] = 'SpecialChangeContentModel';
+ }
self::$list['Activeusers'] = 'SpecialActiveUsers';
@@ -260,14 +263,13 @@ class SpecialPageFactory {
}
/**
- * Initialise and return the list of special page aliases. Returns an object with
- * properties which can be accessed $obj->pagename - each property name is an
- * alias, with the value being the canonical name of the special page. All
- * registered special pages are guaranteed to map to themselves.
- * @return object
+ * Initialise and return the list of special page aliases. Returns an array where
+ * the key is an alias, and the value is the canonical name of the special page.
+ * All registered special pages are guaranteed to map to themselves.
+ * @return array
*/
- private static function getAliasListObject() {
- if ( !is_object( self::$aliases ) ) {
+ private static function getAliasList() {
+ if ( is_null( self::$aliases ) ) {
global $wgContLang;
$aliases = $wgContLang->getSpecialPageAliases();
$pageList = self::getPageList();
@@ -310,9 +312,6 @@ class SpecialPageFactory {
}
}
}
-
- // Cast to object: func()[$key] doesn't work, but func()->$key does
- self::$aliases = (object)self::$aliases;
}
return self::$aliases;
@@ -332,8 +331,9 @@ class SpecialPageFactory {
$caseFoldedAlias = $wgContLang->caseFold( $bits[0] );
$caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
- if ( isset( self::getAliasListObject()->$caseFoldedAlias ) ) {
- $name = self::getAliasListObject()->$caseFoldedAlias;
+ $aliases = self::getAliasList();
+ if ( isset( $aliases[$caseFoldedAlias] ) ) {
+ $name = $aliases[$caseFoldedAlias];
} else {
return array( null, null );
}
@@ -348,34 +348,6 @@ class SpecialPageFactory {
}
/**
- * Add a page to a certain display group for Special:SpecialPages
- *
- * @param SpecialPage|string $page
- * @param string $group
- * @deprecated since 1.21 Override SpecialPage::getGroupName
- */
- public static function setGroup( $page, $group ) {
- wfDeprecated( __METHOD__, '1.21' );
-
- global $wgSpecialPageGroups;
- $name = is_object( $page ) ? $page->getName() : $page;
- $wgSpecialPageGroups[$name] = $group;
- }
-
- /**
- * Get the group that the special page belongs in on Special:SpecialPage
- *
- * @param SpecialPage $page
- * @return string
- * @deprecated since 1.21 Use SpecialPage::getFinalGroupName
- */
- public static function getGroup( &$page ) {
- wfDeprecated( __METHOD__, '1.21' );
-
- return $page->getFinalGroupName();
- }
-
- /**
* Check if a given name exist as a special page or as a special page alias
*
* @param string $name Name of a special page
@@ -572,7 +544,6 @@ class SpecialPageFactory {
$context->setTitle( $page->getPageTitle( $par ) );
}
} elseif ( !$page->isIncludable() ) {
-
return false;
}
@@ -638,7 +609,7 @@ class SpecialPageFactory {
public static function getLocalNameFor( $name, $subpage = false ) {
global $wgContLang;
$aliases = $wgContLang->getSpecialPageAliases();
- $aliasList = self::getAliasListObject();
+ $aliasList = self::getAliasList();
// Find the first alias that maps back to $name
if ( isset( $aliases[$name] ) ) {
@@ -646,8 +617,8 @@ class SpecialPageFactory {
foreach ( $aliases[$name] as $alias ) {
$caseFoldedAlias = $wgContLang->caseFold( $alias );
$caseFoldedAlias = str_replace( ' ', '_', $caseFoldedAlias );
- if ( isset( $aliasList->$caseFoldedAlias ) &&
- $aliasList->$caseFoldedAlias === $name
+ if ( isset( $aliasList[$caseFoldedAlias] ) &&
+ $aliasList[$caseFoldedAlias] === $name
) {
$name = $alias;
$found = true;
diff --git a/includes/specials/SpecialActiveusers.php b/includes/specials/SpecialActiveusers.php
index 5e2ee1c2..047e9413 100644
--- a/includes/specials/SpecialActiveusers.php
+++ b/includes/specials/SpecialActiveusers.php
@@ -267,21 +267,24 @@ class SpecialActiveUsers extends SpecialPage {
$out->wrapWikiMsg( "<div class='mw-activeusers-intro'>\n$1\n</div>",
array( 'activeusers-intro', $this->getLanguage()->formatNum( $days ) ) );
- // Get the timestamp of the last cache update
+ // Mention the level of cache staleness...
$dbr = wfGetDB( DB_SLAVE, 'recentchanges' );
- $cTime = $dbr->selectField( 'querycache_info',
- 'qci_timestamp',
- array( 'qci_type' => 'activeusers' )
- );
-
- $secondsOld = $cTime
- ? time() - wfTimestamp( TS_UNIX, $cTime )
- : $days * 86400; // fully stale :)
-
- if ( $secondsOld > 0 ) {
- // Mention the level of staleness
- $out->addWikiMsg( 'cachedspecial-viewing-cached-ttl',
+ $rcMax = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)' );
+ if ( $rcMax ) {
+ $cTime = $dbr->selectField( 'querycache_info',
+ 'qci_timestamp',
+ array( 'qci_type' => 'activeusers' )
+ );
+ if ( $cTime ) {
+ $secondsOld = wfTimestamp( TS_UNIX, $rcMax ) - wfTimestamp( TS_UNIX, $cTime );
+ } else {
+ $rcMin = $dbr->selectField( 'recentchanges', 'MIN(rc_timestamp)' );
+ $secondsOld = time() - wfTimestamp( TS_UNIX, $rcMin );
+ }
+ if ( $secondsOld > 0 ) {
+ $out->addWikiMsg( 'cachedspecial-viewing-cached-ttl',
$this->getLanguage()->formatDuration( $secondsOld ) );
+ }
}
$up = new ActiveUsersPager( $this->getContext(), null, $par );
diff --git a/includes/specials/SpecialAllMessages.php b/includes/specials/SpecialAllMessages.php
index 7b596bb0..762658c5 100644
--- a/includes/specials/SpecialAllMessages.php
+++ b/includes/specials/SpecialAllMessages.php
@@ -29,7 +29,7 @@
*/
class SpecialAllMessages extends SpecialPage {
/**
- * @var AllmessagesTablePager
+ * @var AllMessagesTablePager
*/
protected $table;
@@ -61,7 +61,7 @@ class SpecialAllMessages extends SpecialPage {
$out->addModuleStyles( 'mediawiki.special' );
$this->addHelpLink( 'Help:System message' );
- $this->table = new AllmessagesTablePager(
+ $this->table = new AllMessagesTablePager(
$this,
array(),
wfGetLangObj( $request->getVal( 'lang', $par ) )
@@ -130,7 +130,7 @@ class AllMessagesTablePager extends TablePager {
if ( $prefix !== null ) {
$this->displayPrefix = $prefix->getDBkey();
- $this->prefix = '/^' . preg_quote( $this->displayPrefix ) . '/i';
+ $this->prefix = '/^' . preg_quote( $this->displayPrefix, '/' ) . '/i';
} else {
$this->displayPrefix = false;
$this->prefix = false;
@@ -206,7 +206,7 @@ class AllMessagesTablePager extends TablePager {
Xml::label( $this->msg( 'table_pager_limit_label' )->text(), 'mw-table_pager_limit_label' ) .
'</td>
<td class="mw-input">' .
- $this->getLimitSelect() .
+ $this->getLimitSelect( array( 'id' => 'mw-table_pager_limit_label' ) ) .
'</td>
<tr>
<td></td>
@@ -392,10 +392,10 @@ class AllMessagesTablePager extends TablePager {
);
}
- return $title . ' '
- . $this->msg( 'parentheses' )->rawParams( $talk )->escaped()
- . ' '
- . $this->msg( 'parentheses' )->rawParams( $translation )->escaped();
+ return $title . ' ' .
+ $this->msg( 'parentheses' )->rawParams( $talk )->escaped() .
+ ' ' .
+ $this->msg( 'parentheses' )->rawParams( $translation )->escaped();
case 'am_default' :
case 'am_actual' :
@@ -445,7 +445,7 @@ class AllMessagesTablePager extends TablePager {
} elseif ( $field === 'am_title' ) {
return array( 'class' => $field );
} else {
- return array( 'lang' => $this->langcode, 'dir' => $this->lang->getDir(), 'class' => $field );
+ return array( 'lang' => wfBCP47( $this->langcode ), 'dir' => $this->lang->getDir(), 'class' => $field );
}
}
diff --git a/includes/specials/SpecialAllPages.php b/includes/specials/SpecialAllPages.php
index 74b1f7bb..c4a67c0c 100644
--- a/includes/specials/SpecialAllPages.php
+++ b/includes/specials/SpecialAllPages.php
@@ -25,6 +25,7 @@
* Implements Special:Allpages
*
* @ingroup SpecialPage
+ * @todo Rewrite using IndexPager
*/
class SpecialAllPages extends IncludableSpecialPage {
@@ -179,6 +180,7 @@ class SpecialAllPages extends IncludableSpecialPage {
$toList = $this->getNamespaceKeyAndText( $namespace, $to );
$namespaces = $this->getContext()->getLanguage()->getNamespaces();
$n = 0;
+ $prevTitle = null;
if ( !$fromList || !$toList ) {
$out = $this->msg( 'allpagesbadtitle' )->parseAsBlock();
@@ -191,15 +193,13 @@ class SpecialAllPages extends IncludableSpecialPage {
list( , $toKey, $to ) = $toList;
$dbr = wfGetDB( DB_SLAVE );
- $conds = array(
- 'page_namespace' => $namespace,
- 'page_title >= ' . $dbr->addQuotes( $fromKey )
- );
-
+ $filterConds = array( 'page_namespace' => $namespace );
if ( $hideredirects ) {
- $conds['page_is_redirect'] = 0;
+ $filterConds['page_is_redirect'] = 0;
}
+ $conds = $filterConds;
+ $conds[] = 'page_title >= ' . $dbr->addQuotes( $fromKey );
if ( $toKey !== "" ) {
$conds[] = 'page_title <= ' . $dbr->addQuotes( $toKey );
}
@@ -234,6 +234,35 @@ class SpecialAllPages extends IncludableSpecialPage {
} else {
$out = '';
}
+
+ if ( $fromKey !== '' && !$this->including() ) {
+ # Get the first title from previous chunk
+ $prevConds = $filterConds;
+ $prevConds[] = 'page_title < ' . $dbr->addQuotes( $fromKey );
+ $prevKey = $dbr->selectField(
+ 'page',
+ 'page_title',
+ $prevConds,
+ __METHOD__,
+ array( 'ORDER BY' => 'page_title DESC', 'OFFSET' => $this->maxPerPage - 1 )
+ );
+
+ if ( $prevKey === false ) {
+ # The previous chunk is not complete, need to link to the very first title
+ # available in the database
+ $prevKey = $dbr->selectField(
+ 'page',
+ 'page_title',
+ $prevConds,
+ __METHOD__,
+ array( 'ORDER BY' => 'page_title' )
+ );
+ }
+
+ if ( $prevKey !== false ) {
+ $prevTitle = Title::makeTitle( $namespace, $prevKey );
+ }
+ }
}
if ( $this->including() ) {
@@ -241,44 +270,6 @@ class SpecialAllPages extends IncludableSpecialPage {
return;
}
- if ( $from == '' ) {
- // First chunk; no previous link.
- $prevTitle = null;
- } else {
- # Get the last title from previous chunk
- $dbr = wfGetDB( DB_SLAVE );
- $res_prev = $dbr->select(
- 'page',
- 'page_title',
- array( 'page_namespace' => $namespace, 'page_title < ' . $dbr->addQuotes( $from ) ),
- __METHOD__,
- array( 'ORDER BY' => 'page_title DESC',
- 'LIMIT' => $this->maxPerPage, 'OFFSET' => ( $this->maxPerPage - 1 )
- )
- );
-
- # Get first title of previous complete chunk
- if ( $dbr->numrows( $res_prev ) >= $this->maxPerPage ) {
- $pt = $dbr->fetchObject( $res_prev );
- $prevTitle = Title::makeTitle( $namespace, $pt->page_title );
- } else {
- # The previous chunk is not complete, need to link to the very first title
- # available in the database
- $options = array( 'LIMIT' => 1 );
- if ( !$dbr->implicitOrderby() ) {
- $options['ORDER BY'] = 'page_title';
- }
- $reallyFirstPage_title = $dbr->selectField( 'page', 'page_title',
- array( 'page_namespace' => $namespace ), __METHOD__, $options );
- # Show the previous link if it s not the current requested chunk
- if ( $from != $reallyFirstPage_title ) {
- $prevTitle = Title::makeTitle( $namespace, $reallyFirstPage_title );
- } else {
- $prevTitle = null;
- }
- }
- }
-
$self = $this->getPageTitle();
$topLinks = array(
@@ -287,7 +278,7 @@ class SpecialAllPages extends IncludableSpecialPage {
$bottomLinks = array();
# Do we put a previous link ?
- if ( $prevTitle && $pt = $prevTitle->getText() ) {
+ if ( $prevTitle ) {
$query = array( 'from' => $prevTitle->getText() );
if ( $namespace ) {
@@ -300,7 +291,7 @@ class SpecialAllPages extends IncludableSpecialPage {
$prevLink = Linker::linkKnown(
$self,
- $this->msg( 'prevpage', $pt )->escaped(),
+ $this->msg( 'prevpage', $prevTitle->getText() )->escaped(),
array(),
$query
);
diff --git a/includes/specials/SpecialAncientpages.php b/includes/specials/SpecialAncientpages.php
index b0830327..2da24a8e 100644
--- a/includes/specials/SpecialAncientpages.php
+++ b/includes/specials/SpecialAncientpages.php
@@ -32,7 +32,7 @@ class AncientPagesPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -40,7 +40,7 @@ class AncientPagesPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'page', 'revision' ),
'fields' => array(
@@ -56,7 +56,7 @@ class AncientPagesPage extends QueryPage {
);
}
- function usesTimestamps() {
+ public function usesTimestamps() {
return true;
}
diff --git a/includes/specials/SpecialBlock.php b/includes/specials/SpecialBlock.php
index b80d921d..cd6cc76e 100644
--- a/includes/specials/SpecialBlock.php
+++ b/includes/specials/SpecialBlock.php
@@ -97,7 +97,6 @@ class SpecialBlock extends FormSpecialPage {
protected function alterForm( HTMLForm $form ) {
$form->setWrapperLegendMsg( 'blockip-legend' );
$form->setHeaderText( '' );
- $form->setSubmitCallback( array( __CLASS__, 'processUIForm' ) );
$form->setSubmitDestructive();
$msg = $this->alreadyBlocked ? 'ipb-change-block' : 'ipbsubmit';
@@ -394,8 +393,8 @@ class SpecialBlock extends FormSpecialPage {
# Link to edit the block dropdown reasons, if applicable
if ( $user->isAllowed( 'editinterface' ) ) {
- $links[] = Linker::link(
- Title::makeTitle( NS_MEDIAWIKI, 'Ipbreason-dropdown' ),
+ $links[] = Linker::linkKnown(
+ $this->msg( 'ipbreason-dropdown' )->inContentLanguage()->getTitle(),
$this->msg( 'ipb-edit-dropdown' )->escaped(),
array(),
array( 'action' => 'edit' )
@@ -597,17 +596,8 @@ class SpecialBlock extends FormSpecialPage {
}
/**
- * Submit callback for an HTMLForm object, will simply pass
- * @param array $data
- * @param HTMLForm $form
- * @return bool|string
- */
- public static function processUIForm( array $data, HTMLForm $form ) {
- return self::processForm( $data, $form->getContext() );
- }
-
- /**
- * Given the form data, actually implement a block
+ * Given the form data, actually implement a block. This is also called from ApiBlock.
+ *
* @param array $data
* @param IContextSource $context
* @return bool|string
@@ -672,8 +662,8 @@ class SpecialBlock extends FormSpecialPage {
if ( $data['HideUser'] ) {
if ( !$performer->isAllowed( 'hideuser' ) ) {
# this codepath is unreachable except by a malicious user spoofing forms,
- # or by race conditions (user has oversight and sysop, loads block form,
- # and is de-oversighted before submission); so need to fail completely
+ # or by race conditions (user has hideuser and block rights, loads block form,
+ # and loses hideuser rights before submission); so need to fail completely
# rather than just silently disable hiding
return array( 'badaccess-group0' );
}
@@ -797,7 +787,7 @@ class SpecialBlock extends FormSpecialPage {
$logParams['5::duration'] = $data['Expiry'];
$logParams['6::flags'] = self::blockLogFlags( $data, $type );
- # Make log entry, if the name is hidden, put it in the oversight log
+ # Make log entry, if the name is hidden, put it in the suppression log
$log_type = $data['HideUser'] ? 'suppress' : 'block';
$logEntry = new ManualLogEntry( $log_type, $logaction );
$logEntry->setTarget( Title::makeTitle( NS_USER, $target ) );
@@ -848,16 +838,11 @@ class SpecialBlock extends FormSpecialPage {
* Convert a submitted expiry time, which may be relative ("2 weeks", etc) or absolute
* ("24 May 2034", etc), into an absolute timestamp we can put into the database.
* @param string $expiry Whatever was typed into the form
- * @return string Timestamp or "infinity" string for the DB implementation
+ * @return string Timestamp or 'infinity'
*/
public static function parseExpiryInput( $expiry ) {
- static $infinity;
- if ( $infinity == null ) {
- $infinity = wfGetDB( DB_SLAVE )->getInfinity();
- }
-
if ( wfIsInfinity( $expiry ) ) {
- $expiry = $infinity;
+ $expiry = 'infinity';
} else {
$expiry = strtotime( $expiry );
@@ -967,11 +952,11 @@ class SpecialBlock extends FormSpecialPage {
/**
* Process the form on POST submission.
* @param array $data
+ * @param HTMLForm $form
* @return bool|array True for success, false for didn't-try, array of errors on failure
*/
- public function onSubmit( array $data ) {
- // This isn't used since we need that HTMLForm that's passed in the
- // second parameter. See alterForm for the real function
+ public function onSubmit( array $data, HTMLForm $form = null ) {
+ return self::processForm( $data, $form->getContext() );
}
/**
diff --git a/includes/specials/SpecialBlockList.php b/includes/specials/SpecialBlockList.php
index 0ec144a2..9defaba7 100644
--- a/includes/specials/SpecialBlockList.php
+++ b/includes/specials/SpecialBlockList.php
@@ -65,6 +65,9 @@ class SpecialBlockList extends SpecialPage {
return;
}
+ # setup BlockListPager here to get the actual default Limit
+ $pager = $this->getBlockListPager();
+
# Just show the block list
$fields = array(
'Target' => array(
@@ -77,11 +80,11 @@ class SpecialBlockList extends SpecialPage {
),
'Options' => array(
'type' => 'multiselect',
- 'options' => array(
- $this->msg( 'blocklist-userblocks' )->text() => 'userblocks',
- $this->msg( 'blocklist-tempblocks' )->text() => 'tempblocks',
- $this->msg( 'blocklist-addressblocks' )->text() => 'addressblocks',
- $this->msg( 'blocklist-rangeblocks' )->text() => 'rangeblocks',
+ 'options-messages' => array(
+ 'blocklist-userblocks' => 'userblocks',
+ 'blocklist-tempblocks' => 'tempblocks',
+ 'blocklist-addressblocks' => 'addressblocks',
+ 'blocklist-rangeblocks' => 'rangeblocks',
),
'flatlist' => true,
),
@@ -96,7 +99,7 @@ class SpecialBlockList extends SpecialPage {
$lang->formatNum( 500 ) => 500,
),
'name' => 'limit',
- 'default' => 50,
+ 'default' => $pager->getLimit(),
),
);
$context = new DerivativeContext( $this->getContext() );
@@ -109,10 +112,14 @@ class SpecialBlockList extends SpecialPage {
$form->prepareForm();
$form->displayForm( '' );
- $this->showList();
+ $this->showList( $pager );
}
- function showList() {
+ /**
+ * Setup a new BlockListPager instance.
+ * @return BlockListPager
+ */
+ protected function getBlockListPager() {
$conds = array();
# Is the user allowed to see hidden blocks?
if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
@@ -163,12 +170,20 @@ class SpecialBlockList extends SpecialPage {
$conds[] = "ipb_range_end = ipb_range_start";
}
+ return new BlockListPager( $this, $conds );
+ }
+
+ /**
+ * Show the list of blocked accounts matching the actual filter.
+ * @param BlockListPager $pager The BlockListPager instance for this page
+ */
+ protected function showList( BlockListPager $pager ) {
+ $out = $this->getOutput();
+
# Check for other blocks, i.e. global/tor blocks
$otherBlockLink = array();
Hooks::run( 'OtherBlockLogLink', array( &$otherBlockLink, $this->target ) );
- $out = $this->getOutput();
-
# Show additional header for the local block only when other blocks exists.
# Not necessary in a standard installation without such extensions enabled
if ( count( $otherBlockLink ) ) {
@@ -177,7 +192,6 @@ class SpecialBlockList extends SpecialPage {
);
}
- $pager = new BlockListPager( $this, $conds );
if ( $pager->getNumRows() ) {
$out->addParserOutputContent( $pager->getFullOutput() );
} elseif ( $this->target ) {
@@ -249,7 +263,7 @@ class BlockListPager extends TablePager {
function formatValue( $name, $value ) {
static $msg = null;
if ( $msg === null ) {
- $msg = array(
+ $keys = array(
'anononlyblock',
'createaccountblock',
'noautoblockblock',
@@ -258,17 +272,22 @@ class BlockListPager extends TablePager {
'unblocklink',
'change-blocklink',
);
- $msg = array_combine( $msg, array_map( array( $this, 'msg' ), $msg ) );
+
+ foreach ( $keys as $key ) {
+ $msg[$key] = $this->msg( $key )->escaped();
+ }
}
/** @var $row object */
$row = $this->mCurrentRow;
+ $language = $this->getLanguage();
+
$formatted = '';
switch ( $name ) {
case 'ipb_timestamp':
- $formatted = $this->getLanguage()->userTimeAndDate( $value, $this->getUser() );
+ $formatted = htmlspecialchars( $language->userTimeAndDate( $value, $this->getUser() ) );
break;
case 'ipb_target':
@@ -294,7 +313,10 @@ class BlockListPager extends TablePager {
break;
case 'ipb_expiry':
- $formatted = $this->getLanguage()->formatExpiry( $value, /* User preference timezone */true );
+ $formatted = htmlspecialchars( $language->formatExpiry(
+ $value,
+ /* User preference timezone */true
+ ) );
if ( $this->getUser()->isAllowed( 'block' ) ) {
if ( $row->ipb_auto ) {
$links[] = Linker::linkKnown(
@@ -317,7 +339,7 @@ class BlockListPager extends TablePager {
'span',
array( 'class' => 'mw-blocklist-actions' ),
$this->msg( 'parentheses' )->rawParams(
- $this->getLanguage()->pipeList( $links ) )->escaped()
+ $language->pipeList( $links ) )->escaped()
);
}
break;
@@ -355,7 +377,7 @@ class BlockListPager extends TablePager {
$properties[] = $msg['blocklist-nousertalk'];
}
- $formatted = $this->getLanguage()->commaList( $properties );
+ $formatted = $language->commaList( $properties );
break;
default:
@@ -430,23 +452,14 @@ class BlockListPager extends TablePager {
$lb = new LinkBatch;
$lb->setCaller( __METHOD__ );
- $userids = array();
-
foreach ( $result as $row ) {
- $userids[] = $row->ipb_by;
-
- # Usernames and titles are in fact related by a simple substitution of space -> underscore
- # The last few lines of Title::secureAndSplit() tell the story.
- $name = str_replace( ' ', '_', $row->ipb_address );
- $lb->add( NS_USER, $name );
- $lb->add( NS_USER_TALK, $name );
- }
+ $lb->add( NS_USER, $row->ipb_address );
+ $lb->add( NS_USER_TALK, $row->ipb_address );
- $ua = UserArray::newFromIDs( $userids );
- foreach ( $ua as $user ) {
- $name = str_replace( ' ', '_', $user->getName() );
- $lb->add( NS_USER, $name );
- $lb->add( NS_USER_TALK, $name );
+ if ( isset( $row->by_user_name ) ) {
+ $lb->add( NS_USER, $row->by_user_name );
+ $lb->add( NS_USER_TALK, $row->by_user_name );
+ }
}
$lb->execute();
diff --git a/includes/specials/SpecialBrokenRedirects.php b/includes/specials/SpecialBrokenRedirects.php
index 1bbdbeab..701f75f0 100644
--- a/includes/specials/SpecialBrokenRedirects.php
+++ b/includes/specials/SpecialBrokenRedirects.php
@@ -32,7 +32,7 @@ class BrokenRedirectsPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -48,7 +48,7 @@ class BrokenRedirectsPage extends QueryPage {
return $this->msg( 'brokenredirectstext' )->parseAsBlock();
}
- function getQueryInfo() {
+ public function getQueryInfo() {
$dbr = wfGetDB( DB_SLAVE );
return array(
diff --git a/includes/specials/SpecialChangeContentModel.php b/includes/specials/SpecialChangeContentModel.php
new file mode 100644
index 00000000..cce5da5c
--- /dev/null
+++ b/includes/specials/SpecialChangeContentModel.php
@@ -0,0 +1,223 @@
+<?php
+
+class SpecialChangeContentModel extends FormSpecialPage {
+
+ public function __construct() {
+ parent::__construct( 'ChangeContentModel', 'editcontentmodel' );
+ }
+
+ /**
+ * @var Title|null
+ */
+ private $title;
+
+ /**
+ * @var Revision|bool|null
+ *
+ * A Revision object, false if no revision exists, null if not loaded yet
+ */
+ private $oldRevision;
+
+ protected function setParameter( $par ) {
+ $par = $this->getRequest()->getVal( 'pagetitle', $par );
+ $title = Title::newFromText( $par );
+ if ( $title ) {
+ $this->title = $title;
+ $this->par = $title->getPrefixedText();
+ } else {
+ $this->par = '';
+ }
+ }
+
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
+ protected function alterForm( HTMLForm $form ) {
+ if ( !$this->title ) {
+ $form->setMethod( 'GET' );
+ }
+ }
+
+ public function validateTitle( $title ) {
+ if ( !$title ) {
+ // No form input yet
+ return true;
+ }
+
+ // Already validated by HTMLForm, but if not, throw
+ // and exception instead of a fatal
+ $titleObj = Title::newFromTextThrow( $title );
+
+ $this->oldRevision = Revision::newFromTitle( $titleObj ) ?: false;
+
+ if ( $this->oldRevision ) {
+ $oldContent = $this->oldRevision->getContent();
+ if ( !$oldContent->getContentHandler()->supportsDirectEditing() ) {
+ return $this->msg( 'changecontentmodel-nodirectediting' )
+ ->params( ContentHandler::getLocalizedName( $oldContent->getModel() ) )
+ ->escaped();
+ }
+ }
+
+ return true;
+ }
+
+ protected function getFormFields() {
+ $that = $this;
+ $fields = array(
+ 'pagetitle' => array(
+ 'type' => 'title',
+ 'creatable' => true,
+ 'name' => 'pagetitle',
+ 'default' => $this->par,
+ 'label-message' => 'changecontentmodel-title-label',
+ 'validation-callback' => array( $this, 'validateTitle' ),
+ ),
+ );
+ if ( $this->title ) {
+ $fields['pagetitle']['readonly'] = true;
+ $fields += array(
+ 'model' => array(
+ 'type' => 'select',
+ 'name' => 'model',
+ 'options' => $this->getOptionsForTitle( $this->title ),
+ 'label-message' => 'changecontentmodel-model-label'
+ ),
+ 'reason' => array(
+ 'type' => 'text',
+ 'name' => 'reason',
+ 'validation-callback' => function( $reason ) use ( $that ) {
+ $match = EditPage::matchSummarySpamRegex( $reason );
+ if ( $match ) {
+ return $that->msg( 'spamprotectionmatch', $match )->parse();
+ }
+
+ return true;
+ },
+ 'label-message' => 'changecontentmodel-reason-label',
+ ),
+ );
+ }
+
+ return $fields;
+ }
+
+ private function getOptionsForTitle( Title $title = null ) {
+ $models = ContentHandler::getContentModels();
+ $options = array();
+ foreach ( $models as $model ) {
+ $handler = ContentHandler::getForModelID( $model );
+ if ( !$handler->supportsDirectEditing() ) {
+ continue;
+ }
+ if ( $title ) {
+ if ( $title->getContentModel() === $model ) {
+ continue;
+ }
+ if ( !$handler->canBeUsedOn( $title ) ) {
+ continue;
+ }
+ }
+ $options[ContentHandler::getLocalizedName( $model )] = $model;
+ }
+
+ return $options;
+ }
+
+ public function onSubmit( array $data ) {
+ global $wgContLang;
+
+ if ( $data['pagetitle'] === '' ) {
+ // Initial form view of special page, pass
+ return false;
+ }
+
+ // At this point, it has to be a POST request. This is enforced by HTMLForm,
+ // but lets be safe verify that.
+ if ( !$this->getRequest()->wasPosted() ) {
+ throw new RuntimeException( "Form submission was not POSTed" );
+ }
+
+ $this->title = Title::newFromText( $data['pagetitle' ] );
+ $user = $this->getUser();
+ // Check permissions and make sure the user has permission to edit the specific page
+ $errors = $this->title->getUserPermissionsErrors( 'editcontentmodel', $user );
+ $errors = wfMergeErrorArrays( $errors, $this->title->getUserPermissionsErrors( 'edit', $user ) );
+ if ( $errors ) {
+ $out = $this->getOutput();
+ $wikitext = $out->formatPermissionsErrorMessage( $errors );
+ // Hack to get our wikitext parsed
+ return Status::newFatal( new RawMessage( '$1', array( $wikitext ) ) );
+ }
+
+ $page = WikiPage::factory( $this->title );
+ if ( $this->oldRevision === null ) {
+ $this->oldRevision = $page->getRevision() ?: false;
+ }
+ $oldModel = $this->title->getContentModel();
+ if ( $this->oldRevision ) {
+ $oldContent = $this->oldRevision->getContent();
+ try {
+ $newContent = ContentHandler::makeContent(
+ $oldContent->getNativeData(), $this->title, $data['model']
+ );
+ } catch ( MWException $e ) {
+ return Status::newFatal(
+ $this->msg( 'changecontentmodel-cannot-convert' )
+ ->params(
+ $this->title->getPrefixedText(),
+ ContentHandler::getLocalizedName( $data['model'] )
+ )
+ );
+ }
+ } else {
+ // Page doesn't exist, create an empty content object
+ $newContent = ContentHandler::getForModelID( $data['model'] )->makeEmptyContent();
+ }
+ $flags = $this->oldRevision ? EDIT_UPDATE : EDIT_NEW;
+ if ( $user->isAllowed( 'bot' ) ) {
+ $flags |= EDIT_FORCE_BOT;
+ }
+
+ $log = new ManualLogEntry( 'contentmodel', 'change' );
+ $log->setPerformer( $user );
+ $log->setTarget( $this->title );
+ $log->setComment( $data['reason'] );
+ $log->setParameters( array(
+ '4::oldmodel' => $oldModel,
+ '5::newmodel' => $data['model']
+ ) );
+
+ $formatter = LogFormatter::newFromEntry( $log );
+ $formatter->setContext( RequestContext::newExtraneousContext( $this->title ) );
+ $reason = $formatter->getPlainActionText();
+ if ( $data['reason'] !== '' ) {
+ $reason .= $this->msg( 'colon-separator' )->inContentLanguage()->text() . $data['reason'];
+ }
+ # Truncate for whole multibyte characters.
+ $reason = $wgContLang->truncate( $reason, 255 );
+
+ $status = $page->doEditContent(
+ $newContent,
+ $reason,
+ $flags,
+ $this->oldRevision ? $this->oldRevision->getId() : false,
+ $user
+ );
+ if ( !$status->isOK() ) {
+ return $status;
+ }
+
+ $logid = $log->insert();
+ $log->publish( $logid );
+
+ return $status;
+ }
+
+ public function onSuccess() {
+ $out = $this->getOutput();
+ $out->setPageTitle( $this->msg( 'changecontentmodel-success-title' ) );
+ $out->addWikiMsg( 'changecontentmodel-success-text', $this->title );
+ }
+}
diff --git a/includes/specials/SpecialChangeEmail.php b/includes/specials/SpecialChangeEmail.php
index eca307d9..22df04e8 100644
--- a/includes/specials/SpecialChangeEmail.php
+++ b/includes/specials/SpecialChangeEmail.php
@@ -92,14 +92,14 @@ class SpecialChangeEmail extends FormSpecialPage {
'NewEmail' => array(
'type' => 'email',
'label-message' => 'changeemail-newemail',
+ 'autofocus' => true
),
);
if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
$fields['Password'] = array(
'type' => 'password',
- 'label-message' => 'changeemail-password',
- 'autofocus' => true,
+ 'label-message' => 'changeemail-password'
);
}
@@ -107,7 +107,7 @@ class SpecialChangeEmail extends FormSpecialPage {
}
protected function getDisplayFormat() {
- return 'vform';
+ return 'ooui';
}
protected function alterForm( HTMLForm $form ) {
@@ -129,7 +129,8 @@ class SpecialChangeEmail extends FormSpecialPage {
public function onSuccess() {
$request = $this->getRequest();
- $titleObj = Title::newFromText( $request->getVal( 'returnto' ) );
+ $returnto = $request->getVal( 'returnto' );
+ $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
if ( !$titleObj instanceof Title ) {
$titleObj = Title::newMainPage();
}
@@ -159,6 +160,10 @@ class SpecialChangeEmail extends FormSpecialPage {
return Status::newFatal( 'invalidemailaddress' );
}
+ if ( $newaddr === $user->getEmail() ) {
+ return Status::newFatal( 'changeemail-nochange' );
+ }
+
$throttleCount = LoginForm::incLoginThrottle( $user->getName() );
if ( $throttleCount === true ) {
$lang = $this->getLanguage();
diff --git a/includes/specials/SpecialChangePassword.php b/includes/specials/SpecialChangePassword.php
index 168095f8..6a4347df 100644
--- a/includes/specials/SpecialChangePassword.php
+++ b/includes/specials/SpecialChangePassword.php
@@ -179,7 +179,8 @@ class SpecialChangePassword extends FormSpecialPage {
}
if ( $request->getCheck( 'wpCancel' ) ) {
- $titleObj = Title::newFromText( $request->getVal( 'returnto' ) );
+ $returnto = $request->getVal( 'returnto' );
+ $titleObj = $returnto !== null ? Title::newFromText( $returnto ) : null;
if ( !$titleObj instanceof Title ) {
$titleObj = Title::newMainPage();
}
diff --git a/includes/specials/SpecialComparePages.php b/includes/specials/SpecialComparePages.php
index da1a54cd..0f8b7291 100644
--- a/includes/specials/SpecialComparePages.php
+++ b/includes/specials/SpecialComparePages.php
@@ -50,10 +50,12 @@ class SpecialComparePages extends SpecialPage {
$this->setHeaders();
$this->outputHeader();
+ # Form (.mw-searchInput enables suggestions)
$form = new HTMLForm( array(
'Page1' => array(
'type' => 'text',
'name' => 'page1',
+ 'cssclass' => 'mw-searchInput',
'label-message' => 'compare-page1',
'size' => '40',
'section' => 'page1',
@@ -70,6 +72,7 @@ class SpecialComparePages extends SpecialPage {
'Page2' => array(
'type' => 'text',
'name' => 'page2',
+ 'cssclass' => 'mw-searchInput',
'label-message' => 'compare-page2',
'size' => '40',
'section' => 'page2',
diff --git a/includes/specials/SpecialConfirmemail.php b/includes/specials/SpecialConfirmemail.php
index 63561552..147f67e8 100644
--- a/includes/specials/SpecialConfirmemail.php
+++ b/includes/specials/SpecialConfirmemail.php
@@ -43,6 +43,10 @@ class EmailConfirmation extends UnlistedSpecialPage {
* @throws UserNotLoggedIn
*/
function execute( $code ) {
+ // Ignore things like master queries/connections on GET requests.
+ // It's very convenient to just allow formless link usage.
+ Profiler::instance()->getTransactionProfiler()->resetExpectations();
+
$this->setHeaders();
$this->checkReadOnly();
@@ -151,6 +155,10 @@ class EmailInvalidation extends UnlistedSpecialPage {
}
function execute( $code ) {
+ // Ignore things like master queries/connections on GET requests.
+ // It's very convenient to just allow formless link usage.
+ Profiler::instance()->getTransactionProfiler()->resetExpectations();
+
$this->setHeaders();
$this->checkReadOnly();
$this->checkPermissions();
diff --git a/includes/specials/SpecialContributions.php b/includes/specials/SpecialContributions.php
index c2cd8122..9672580d 100644
--- a/includes/specials/SpecialContributions.php
+++ b/includes/specials/SpecialContributions.php
@@ -38,6 +38,7 @@ class SpecialContributions extends IncludableSpecialPage {
$this->outputHeader();
$out = $this->getOutput();
$out->addModuleStyles( 'mediawiki.special' );
+ $this->addHelpLink( 'Help:User contributions' );
$this->opts = array();
$request = $this->getRequest();
@@ -724,7 +725,6 @@ class ContribsPager extends ReverseChronologicalPager {
$limit,
$descending
);
- $pager = $this;
/*
* This hook will allow extensions to add in additional queries, so they can get their data
@@ -749,7 +749,7 @@ class ContribsPager extends ReverseChronologicalPager {
) );
Hooks::run(
'ContribsPager::reallyDoQuery',
- array( &$data, $pager, $offset, $limit, $descending )
+ array( &$data, $this, $offset, $limit, $descending )
);
$result = array();
@@ -965,14 +965,14 @@ class ContribsPager extends ReverseChronologicalPager {
* we're definitely dealing with revision data and we may proceed, if not, we'll leave it
* to extensions to subscribe to the hook to parse the row.
*/
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
try {
$rev = new Revision( $row );
$validRevision = (bool)$rev->getId();
} catch ( Exception $e ) {
$validRevision = false;
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $validRevision ) {
$classes = array();
diff --git a/includes/specials/SpecialDeletedContributions.php b/includes/specials/SpecialDeletedContributions.php
index fb85942d..44352a78 100644
--- a/includes/specials/SpecialDeletedContributions.php
+++ b/includes/specials/SpecialDeletedContributions.php
@@ -88,15 +88,13 @@ class DeletedContribsPager extends IndexPager {
* @return ResultWrapper
*/
function reallyDoQuery( $offset, $limit, $descending ) {
- $pager = $this;
-
$data = array( parent::reallyDoQuery( $offset, $limit, $descending ) );
// This hook will allow extensions to add in additional queries, nearly
// identical to ContribsPager::reallyDoQuery.
Hooks::run(
'DeletedContribsPager::reallyDoQuery',
- array( &$data, $pager, $offset, $limit, $descending )
+ array( &$data, $this, $offset, $limit, $descending )
);
$result = array();
@@ -203,14 +201,14 @@ class DeletedContribsPager extends IndexPager {
* we're definitely dealing with revision data and we may proceed, if not, we'll leave it
* to extensions to subscribe to the hook to parse the row.
*/
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
try {
$rev = Revision::newFromArchiveRow( $row );
$validRevision = (bool)$rev->getId();
} catch ( Exception $e ) {
$validRevision = false;
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $validRevision ) {
$ret = $this->formatRevisionRow( $row );
diff --git a/includes/specials/SpecialDiff.php b/includes/specials/SpecialDiff.php
index 89c1c021..8b5d31a8 100644
--- a/includes/specials/SpecialDiff.php
+++ b/includes/specials/SpecialDiff.php
@@ -37,12 +37,16 @@
* @since 1.23
*/
class SpecialDiff extends RedirectSpecialPage {
- function __construct() {
+ public function __construct() {
parent::__construct( 'Diff' );
$this->mAllowedRedirectParams = array();
}
- function getRedirect( $subpage ) {
+ /**
+ * @param string|null $subpage
+ * @return Title|bool
+ */
+ public function getRedirect( $subpage ) {
$parts = explode( '/', $subpage );
// Try to parse the values given, generating somewhat pretty URLs if possible
diff --git a/includes/specials/SpecialDoubleRedirects.php b/includes/specials/SpecialDoubleRedirects.php
index c364f70f..6d40985b 100644
--- a/includes/specials/SpecialDoubleRedirects.php
+++ b/includes/specials/SpecialDoubleRedirects.php
@@ -32,7 +32,7 @@ class DoubleRedirectsPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -99,7 +99,7 @@ class DoubleRedirectsPage extends QueryPage {
return $retval;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return $this->reallyGetQueryInfo();
}
@@ -156,7 +156,6 @@ class DoubleRedirectsPage extends QueryPage {
$this->msg( 'parentheses', $this->msg( 'editlink' )->text() )->escaped(),
array(),
array(
- 'redirect' => 'no',
'action' => 'edit'
)
);
diff --git a/includes/specials/SpecialEditTags.php b/includes/specials/SpecialEditTags.php
index f41a1f1d..d2b2e708 100644
--- a/includes/specials/SpecialEditTags.php
+++ b/includes/specials/SpecialEditTags.php
@@ -123,7 +123,7 @@ class SpecialEditTags extends UnlistedSpecialPage {
// Either submit or create our form
if ( $this->isAllowed && $this->submitClicked ) {
- $this->submit( $request );
+ $this->submit();
} else {
$this->showForm();
}
@@ -349,20 +349,18 @@ class SpecialEditTags extends UnlistedSpecialPage {
protected function getTagSelect( $selectedTags, $label ) {
$result = array();
$result[0] = Xml::label( $label, 'mw-edittags-tag-list' );
- $result[1] = Xml::openElement( 'select', array(
- 'name' => 'wpTagList[]',
- 'id' => 'mw-edittags-tag-list',
- 'multiple' => 'multiple',
- 'size' => '8',
- ) );
+
+ $select = new XmlSelect( 'wpTagList[]', 'mw-edittags-tag-list', $selectedTags );
+ $select->setAttribute( 'multiple', 'multiple' );
+ $select->setAttribute( 'size', '8' );
$tags = ChangeTags::listExplicitlyDefinedTags();
$tags = array_unique( array_merge( $tags, $selectedTags ) );
- foreach ( $tags as $tag ) {
- $result[1] .= Xml::option( $tag, $tag, in_array( $tag, $selectedTags ) );
- }
- $result[1] .= Xml::closeElement( 'select' );
+ // Values of $tags are also used as <option> labels
+ $select->addOptions( array_combine( $tags, $tags ) );
+
+ $result[1] = $select->getHTML();
return $result;
}
diff --git a/includes/specials/SpecialEditWatchlist.php b/includes/specials/SpecialEditWatchlist.php
index 910fe259..74662aec 100644
--- a/includes/specials/SpecialEditWatchlist.php
+++ b/includes/specials/SpecialEditWatchlist.php
@@ -102,7 +102,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
case self::EDIT_NORMAL:
default:
- $this->executeViewEditWatchlist();
+ $this->executeViewEditWatchlist();
break;
}
}
@@ -299,7 +299,9 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
*/
private function getWatchlist() {
$list = array();
- $dbr = wfGetDB( DB_MASTER );
+
+ $index = $this->getRequest()->wasPosted() ? DB_MASTER : DB_SLAVE;
+ $dbr = wfGetDB( $index );
$res = $dbr->select(
'watchlist',
@@ -312,6 +314,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
);
if ( $res->numRows() > 0 ) {
+ /** @var Title[] $titles */
$titles = array();
foreach ( $res as $row ) {
$title = Title::makeTitleSafe( $row->wl_namespace, $row->wl_title );
diff --git a/includes/specials/SpecialEmailuser.php b/includes/specials/SpecialEmailuser.php
index c55fa94c..92cb8bf6 100644
--- a/includes/specials/SpecialEmailuser.php
+++ b/includes/specials/SpecialEmailuser.php
@@ -356,7 +356,9 @@ class SpecialEmailUser extends UnlistedSpecialPage {
$replyTo = null;
}
- $status = UserMailer::send( $to, $mailFrom, $subject, $text, $replyTo );
+ $status = UserMailer::send( $to, $mailFrom, $subject, $text, array(
+ 'replyTo' => $replyTo,
+ ) );
if ( !$status->isGood() ) {
return $status;
@@ -367,7 +369,10 @@ class SpecialEmailUser extends UnlistedSpecialPage {
if ( $data['CCMe'] && $to != $from ) {
$cc_subject = $context->msg( 'emailccsubject' )->rawParams(
$target->getName(), $subject )->text();
+
+ // target and sender are equal, because this is the CC for the sender
Hooks::run( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) );
+
$ccStatus = UserMailer::send( $from, $from, $cc_subject, $text );
$status->merge( $ccStatus );
}
diff --git a/includes/specials/SpecialExport.php b/includes/specials/SpecialExport.php
index c30d962a..39c4d771 100644
--- a/includes/specials/SpecialExport.php
+++ b/includes/specials/SpecialExport.php
@@ -30,7 +30,6 @@
*/
class SpecialExport extends SpecialPage {
private $curonly, $doExport, $pageLinkDepth, $templates;
- private $images;
public function __construct() {
parent::__construct( 'Export' );
@@ -46,7 +45,6 @@ class SpecialExport extends SpecialPage {
$this->doExport = false;
$request = $this->getRequest();
$this->templates = $request->getCheck( 'templates' );
- $this->images = $request->getCheck( 'images' ); // Doesn't do anything yet
$this->pageLinkDepth = $this->validateLinkDepth(
$request->getIntOrNull( 'pagelink-depth' )
);
@@ -188,113 +186,122 @@ class SpecialExport extends SpecialPage {
$categoryName = '';
}
- $form = Xml::openElement( 'form', array( 'method' => 'post',
- 'action' => $this->getPageTitle()->getLocalURL( 'action=submit' ) ) );
- $form .= Xml::inputLabel(
- $this->msg( 'export-addcattext' )->text(),
- 'catname',
- 'catname',
- 40,
- $categoryName
- ) . '&#160;';
- $form .= Xml::submitButton(
- $this->msg( 'export-addcat' )->text(),
- array( 'name' => 'addcat' )
- ) . '<br />';
-
+ $formDescriptor = array(
+ 'catname' => array(
+ 'type' => 'textwithbutton',
+ 'name' => 'catname',
+ 'horizontal-label' => true,
+ 'label-message' => 'export-addcattext',
+ 'default' => $categoryName,
+ 'size' => 40,
+ 'buttontype' => 'submit',
+ 'buttonname' => 'addcat',
+ 'buttondefault' => $this->msg( 'export-addcat' )->text(),
+ ),
+ );
if ( $config->get( 'ExportFromNamespaces' ) ) {
- $form .= Html::namespaceSelector(
- array(
- 'selected' => $nsindex,
- 'label' => $this->msg( 'export-addnstext' )->text()
- ), array(
+ $formDescriptor += array(
+ 'nsindex' => array(
+ 'type' => 'namespaceselectwithbutton',
+ 'default' => $nsindex,
+ 'label-message' => 'export-addnstext',
+ 'horizontal-label' => true,
'name' => 'nsindex',
'id' => 'namespace',
- 'class' => 'namespaceselector',
- )
- ) . '&#160;';
- $form .= Xml::submitButton(
- $this->msg( 'export-addns' )->text(),
- array( 'name' => 'addns' )
- ) . '<br />';
+ 'cssclass' => 'namespaceselector',
+ 'buttontype' => 'submit',
+ 'buttonname' => 'addns',
+ 'buttondefault' => $this->msg( 'export-addns' )->text(),
+ ),
+ );
}
if ( $config->get( 'ExportAllowAll' ) ) {
- $form .= Xml::checkLabel(
- $this->msg( 'exportall' )->text(),
- 'exportall',
- 'exportall',
- $request->wasPosted() ? $request->getCheck( 'exportall' ) : false
- ) . '<br />';
+ $formDescriptor += array(
+ 'exportall' => array(
+ 'type' => 'check',
+ 'label-message' => 'exportall',
+ 'name' => 'exportall',
+ 'id' => 'exportall',
+ 'default' => $request->wasPosted() ? $request->getCheck( 'exportall' ) : false,
+ ),
+ );
}
- $form .= Xml::element(
- 'textarea',
- array( 'name' => 'pages', 'cols' => 40, 'rows' => 10 ),
- $page,
- false
+ $formDescriptor += array(
+ 'textarea' => array(
+ 'class' => 'HTMLTextAreaField',
+ 'name' => 'pages',
+ 'nodata' => true,
+ 'cols' => 40,
+ 'rows' => 10,
+ 'default' => $page,
+ ),
);
- $form .= '<br />';
if ( $config->get( 'ExportAllowHistory' ) ) {
- $form .= Xml::checkLabel(
- $this->msg( 'exportcuronly' )->text(),
- 'curonly',
- 'curonly',
- $request->wasPosted() ? $request->getCheck( 'curonly' ) : true
- ) . '<br />';
+ $formDescriptor += array(
+ 'curonly' => array(
+ 'type' => 'check',
+ 'label-message' => 'exportcuronly',
+ 'name' => 'curonly',
+ 'id' => 'curonly',
+ 'default' => $request->wasPosted() ? $request->getCheck( 'curonly' ) : true,
+ ),
+ );
} else {
$out->addWikiMsg( 'exportnohistory' );
}
- $form .= Xml::checkLabel(
- $this->msg( 'export-templates' )->text(),
- 'templates',
- 'wpExportTemplates',
- $request->wasPosted() ? $request->getCheck( 'templates' ) : false
- ) . '<br />';
+ $formDescriptor += array(
+ 'templates' => array(
+ 'type' => 'check',
+ 'label-message' => 'export-templates',
+ 'name' => 'templates',
+ 'id' => 'wpExportTemplates',
+ 'default' => $request->wasPosted() ? $request->getCheck( 'templates' ) : false,
+ ),
+ );
if ( $config->get( 'ExportMaxLinkDepth' ) || $this->userCanOverrideExportDepth() ) {
- $form .= Xml::inputLabel(
- $this->msg( 'export-pagelinks' )->text(),
- 'pagelink-depth',
- 'pagelink-depth',
- 20,
- 0
- ) . '<br />';
+ $formDescriptor += array(
+ 'pagelink-depth' => array(
+ 'type' => 'text',
+ 'name' => 'pagelink-depth',
+ 'id' => 'pagelink-depth',
+ 'label-message' => 'export-pagelinks',
+ 'default' => '0',
+ 'size' => 20,
+ ),
+ );
}
- /* Enable this when we can do something useful exporting/importing image information.
- $form .= Xml::checkLabel(
- $this->msg( 'export-images' )->text(),
- 'images',
- 'wpExportImages',
- false
- ) . '<br />';
- */
- $form .= Xml::checkLabel(
- $this->msg( 'export-download' )->text(),
- 'wpDownload',
- 'wpDownload',
- $request->wasPosted() ? $request->getCheck( 'wpDownload' ) : true
- ) . '<br />';
+ $formDescriptor += array(
+ 'wpDownload' => array(
+ 'type' => 'check',
+ 'name' =>'wpDownload',
+ 'id' => 'wpDownload',
+ 'default' => $request->wasPosted() ? $request->getCheck( 'wpDownload' ) : true,
+ 'label-message' => 'export-download',
+ ),
+ );
if ( $config->get( 'ExportAllowListContributors' ) ) {
- $form .= Xml::checkLabel(
- $this->msg( 'exportlistauthors' )->text(),
- 'listauthors',
- 'listauthors',
- $request->wasPosted() ? $request->getCheck( 'listauthors' ) : false
- ) . '<br />';
+ $formDescriptor += array(
+ 'listauthors' => array(
+ 'type' => 'check',
+ 'label-message' => 'exportlistauthors',
+ 'default' => $request->wasPosted() ? $request->getCheck( 'listauthors' ) : false,
+ 'name' => 'listauthors',
+ 'id' => 'listauthors',
+ ),
+ );
}
- $form .= Xml::submitButton(
- $this->msg( 'export-submit' )->text(),
- Linker::tooltipAndAccesskeyAttribs( 'export' )
- );
- $form .= Xml::closeElement( 'form' );
-
- $out->addHTML( $form );
+ $htmlForm = HTMLForm::factory( 'div', $formDescriptor, $this->getContext() );
+ $htmlForm->setSubmitTextMsg( 'export-submit' );
+ $htmlForm->prepareForm()->displayForm( false );
+ $this->addHelpLink( 'Help:Export' );
}
/**
@@ -319,7 +326,6 @@ class SpecialExport extends SpecialPage {
if ( $exportall ) {
$history = WikiExporter::FULL;
} else {
-
$pageSet = array(); // Inverted index of all pages to look up
// Split up and normalize input
@@ -344,11 +350,6 @@ class SpecialExport extends SpecialPage {
$pageSet = $this->getPageLinks( $inputPages, $pageSet, $linkDepth );
}
- // Enable this when we can do something useful exporting/importing image information.
- // if( $this->images ) ) {
- // $pageSet = $this->getImages( $inputPages, $pageSet );
- // }
-
$pages = array_keys( $pageSet );
// Normalize titles to the same format and remove dupes, see bug 17374
@@ -371,9 +372,9 @@ class SpecialExport extends SpecialPage {
$buffer = WikiExporter::STREAM;
// This might take a while... :D
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
set_time_limit( 0 );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
$exporter = new WikiExporter( $db, $history, $buffer );
@@ -535,24 +536,6 @@ class SpecialExport extends SpecialPage {
}
/**
- * Expand a list of pages to include images used in those pages.
- *
- * @param array $inputPages List of titles to look up
- * @param array $pageSet Associative array indexed by titles for output
- *
- * @return array Associative array index by titles
- */
- private function getImages( $inputPages, $pageSet ) {
- return $this->getLinks(
- $inputPages,
- $pageSet,
- 'imagelinks',
- array( 'namespace' => NS_FILE, 'title' => 'il_to' ),
- array( 'page_id=il_from' )
- );
- }
-
- /**
* Expand a list of pages to include items used in those pages.
* @param array $inputPages Array of page titles
* @param array $pageSet
diff --git a/includes/specials/SpecialFewestrevisions.php b/includes/specials/SpecialFewestrevisions.php
index dc9d57c2..406233b4 100644
--- a/includes/specials/SpecialFewestrevisions.php
+++ b/includes/specials/SpecialFewestrevisions.php
@@ -32,7 +32,7 @@ class FewestrevisionsPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -40,7 +40,7 @@ class FewestrevisionsPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'revision', 'page' ),
'fields' => array(
diff --git a/includes/specials/SpecialFileDuplicateSearch.php b/includes/specials/SpecialFileDuplicateSearch.php
index da79bb81..4c0c75fb 100644
--- a/includes/specials/SpecialFileDuplicateSearch.php
+++ b/includes/specials/SpecialFileDuplicateSearch.php
@@ -48,7 +48,7 @@ class FileDuplicateSearchPage extends QueryPage {
return false;
}
- function isCached() {
+ public function isCached() {
return false;
}
@@ -82,7 +82,7 @@ class FileDuplicateSearchPage extends QueryPage {
$this->getOutput()->addHtml( implode( "\n", $html ) );
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'image' ),
'fields' => array(
@@ -95,7 +95,7 @@ class FileDuplicateSearchPage extends QueryPage {
);
}
- function execute( $par ) {
+ public function execute( $par ) {
$this->setHeaders();
$this->outputHeader();
diff --git a/includes/specials/SpecialFilepath.php b/includes/specials/SpecialFilepath.php
index 93232117..542589f3 100644
--- a/includes/specials/SpecialFilepath.php
+++ b/includes/specials/SpecialFilepath.php
@@ -27,13 +27,18 @@
* @ingroup SpecialPage
*/
class SpecialFilepath extends RedirectSpecialPage {
- function __construct() {
+ public function __construct() {
parent::__construct( 'Filepath' );
$this->mAllowedRedirectParams = array( 'width', 'height' );
}
- // implement by redirecting through Special:Redirect/file
- function getRedirect( $par ) {
+ /**
+ * Implement by redirecting through Special:Redirect/file.
+ *
+ * @param string|null $subpage
+ * @return Title
+ */
+ public function getRedirect( $par ) {
$file = $par ?: $this->getRequest()->getText( 'file' );
if ( $file ) {
diff --git a/includes/specials/SpecialImport.php b/includes/specials/SpecialImport.php
index af869647..4cdf6ddf 100644
--- a/includes/specials/SpecialImport.php
+++ b/includes/specials/SpecialImport.php
@@ -34,6 +34,7 @@ class SpecialImport extends SpecialPage {
private $interwiki = false;
private $subproject;
private $fullInterwikiPrefix;
+ private $mapping = 'default';
private $namespace;
private $rootpage = '';
private $frompage = '';
@@ -56,6 +57,8 @@ class SpecialImport extends SpecialPage {
* @throws ReadOnlyError
*/
function execute( $par ) {
+ $this->useTransactionalTimeLimit();
+
$this->setHeaders();
$this->outputHeader();
@@ -101,26 +104,33 @@ class SpecialImport extends SpecialPage {
private function doImport() {
$isUpload = false;
$request = $this->getRequest();
- $this->namespace = $request->getIntOrNull( 'namespace' );
$this->sourceName = $request->getVal( "source" );
$this->logcomment = $request->getText( 'log-comment' );
$this->pageLinkDepth = $this->getConfig()->get( 'ExportMaxLinkDepth' ) == 0
? 0
: $request->getIntOrNull( 'pagelink-depth' );
- $this->rootpage = $request->getText( 'rootpage' );
+
+ $this->mapping = $request->getVal( 'mapping' );
+ if ( $this->mapping === 'namespace' ) {
+ $this->namespace = $request->getIntOrNull( 'namespace' );
+ } elseif ( $this->mapping === 'subpage' ) {
+ $this->rootpage = $request->getText( 'rootpage' );
+ } else {
+ $this->mapping = 'default';
+ }
$user = $this->getUser();
if ( !$user->matchEditToken( $request->getVal( 'editToken' ) ) ) {
$source = Status::newFatal( 'import-token-mismatch' );
- } elseif ( $this->sourceName == 'upload' ) {
+ } elseif ( $this->sourceName === 'upload' ) {
$isUpload = true;
if ( $user->isAllowed( 'importupload' ) ) {
$source = ImportStreamSource::newFromUpload( "xmlimport" );
} else {
throw new PermissionsError( 'importupload' );
}
- } elseif ( $this->sourceName == "interwiki" ) {
+ } elseif ( $this->sourceName === 'interwiki' ) {
if ( !$user->isAllowed( 'import' ) ) {
throw new PermissionsError( 'import' );
}
@@ -163,8 +173,7 @@ class SpecialImport extends SpecialPage {
$importer = new WikiImporter( $source->value, $this->getConfig() );
if ( !is_null( $this->namespace ) ) {
$importer->setTargetNamespace( $this->namespace );
- }
- if ( !is_null( $this->rootpage ) ) {
+ } elseif ( !is_null( $this->rootpage ) ) {
$statusRootPage = $importer->setTargetRootPage( $this->rootpage );
if ( !$statusRootPage->isGood() ) {
$out->wrapWikiMsg(
@@ -219,13 +228,88 @@ class SpecialImport extends SpecialPage {
}
}
+ private function getMappingFormPart( $sourceName ) {
+ $isSameSourceAsBefore = ( $this->sourceName === $sourceName );
+ $defaultNamespace = $this->getConfig()->get( 'ImportTargetNamespace' );
+ return "<tr>
+ <td>
+ </td>
+ <td class='mw-input'>" .
+ Xml::radioLabel(
+ $this->msg( 'import-mapping-default' )->text(),
+ 'mapping',
+ 'default',
+ // mw-import-mapping-interwiki-default, mw-import-mapping-upload-default
+ "mw-import-mapping-$sourceName-default",
+ ( $isSameSourceAsBefore ?
+ ( $this->mapping === 'default' ) :
+ is_null( $defaultNamespace ) )
+ ) .
+ "</td>
+ </tr>
+ <tr>
+ <td>
+ </td>
+ <td class='mw-input'>" .
+ Xml::radioLabel(
+ $this->msg( 'import-mapping-namespace' )->text(),
+ 'mapping',
+ 'namespace',
+ // mw-import-mapping-interwiki-namespace, mw-import-mapping-upload-namespace
+ "mw-import-mapping-$sourceName-namespace",
+ ( $isSameSourceAsBefore ?
+ ( $this->mapping === 'namespace' ) :
+ !is_null( $defaultNamespace ) )
+ ) . ' ' .
+ Html::namespaceSelector(
+ array(
+ 'selected' => ( $isSameSourceAsBefore ?
+ $this->namespace :
+ ( $defaultNamespace || '' ) ),
+ ), array(
+ 'name' => "namespace",
+ // mw-import-namespace-interwiki, mw-import-namespace-upload
+ 'id' => "mw-import-namespace-$sourceName",
+ 'class' => 'namespaceselector',
+ )
+ ) .
+ "</td>
+ </tr>
+ <tr>
+ <td>
+ </td>
+ <td class='mw-input'>" .
+ Xml::radioLabel(
+ $this->msg( 'import-mapping-subpage' )->text(),
+ 'mapping',
+ 'subpage',
+ // mw-import-mapping-interwiki-subpage, mw-import-mapping-upload-subpage
+ "mw-import-mapping-$sourceName-subpage",
+ ( $isSameSourceAsBefore ? ( $this->mapping === 'subpage' ) : '' )
+ ) . ' ' .
+ Xml::input( 'rootpage', 50,
+ ( $isSameSourceAsBefore ? $this->rootpage : '' ),
+ array(
+ // Should be "mw-import-rootpage-...", but we keep this inaccurate
+ // ID for legacy reasons
+ // mw-interwiki-rootpage-interwiki, mw-interwiki-rootpage-upload
+ 'id' => "mw-interwiki-rootpage-$sourceName",
+ 'type' => 'text'
+ )
+ ) . ' ' .
+ "</td>
+ </tr>";
+ }
+
private function showForm() {
$action = $this->getPageTitle()->getLocalURL( array( 'action' => 'submit' ) );
$user = $this->getUser();
$out = $this->getOutput();
+ $this->addHelpLink( '//meta.wikimedia.org/wiki/Special:MyLanguage/Help:Import', true );
$importSources = $this->getConfig()->get( 'ImportSources' );
if ( $user->isAllowed( 'importupload' ) ) {
+ $mappingSelection = $this->getMappingFormPart( 'upload' );
$out->addHTML(
Xml::fieldset( $this->msg( 'import-upload' )->text() ) .
Xml::openElement(
@@ -255,22 +339,11 @@ class SpecialImport extends SpecialPage {
"</td>
<td class='mw-input'>" .
Xml::input( 'log-comment', 50,
- ( $this->sourceName == 'upload' ? $this->logcomment : '' ),
+ ( $this->sourceName === 'upload' ? $this->logcomment : '' ),
array( 'id' => 'mw-import-comment', 'type' => 'text' ) ) . ' ' .
"</td>
</tr>
- <tr>
- <td class='mw-label'>" .
- Xml::label(
- $this->msg( 'import-interwiki-rootpage' )->text(),
- 'mw-interwiki-rootpage-upload'
- ) .
- "</td>
- <td class='mw-input'>" .
- Xml::input( 'rootpage', 50, $this->rootpage,
- array( 'id' => 'mw-interwiki-rootpage-upload', 'type' => 'text' ) ) . ' ' .
- "</td>
- </tr>
+ $mappingSelection
<tr>
<td></td>
<td class='mw-submit'>" .
@@ -301,6 +374,7 @@ class SpecialImport extends SpecialPage {
"</td>
</tr>";
}
+ $mappingSelection = $this->getMappingFormPart( 'interwiki' );
$out->addHTML(
Xml::fieldset( $this->msg( 'importinterwiki' )->text() ) .
@@ -415,43 +489,15 @@ class SpecialImport extends SpecialPage {
$importDepth
<tr>
<td class='mw-label'>" .
- Xml::label( $this->msg( 'import-interwiki-namespace' )->text(), 'namespace' ) .
- "</td>
- <td class='mw-input'>" .
- Html::namespaceSelector(
- array(
- 'selected' => $this->namespace,
- 'all' => '',
- ), array(
- 'name' => 'namespace',
- 'id' => 'namespace',
- 'class' => 'namespaceselector',
- )
- ) .
- "</td>
- </tr>
- <tr>
- <td class='mw-label'>" .
Xml::label( $this->msg( 'import-comment' )->text(), 'mw-interwiki-comment' ) .
"</td>
<td class='mw-input'>" .
Xml::input( 'log-comment', 50,
- ( $this->sourceName == 'interwiki' ? $this->logcomment : '' ),
+ ( $this->sourceName === 'interwiki' ? $this->logcomment : '' ),
array( 'id' => 'mw-interwiki-comment', 'type' => 'text' ) ) . ' ' .
"</td>
</tr>
- <tr>
- <td class='mw-label'>" .
- Xml::label(
- $this->msg( 'import-interwiki-rootpage' )->text(),
- 'mw-interwiki-rootpage-interwiki'
- ) .
- "</td>
- <td class='mw-input'>" .
- Xml::input( 'rootpage', 50, $this->rootpage,
- array( 'id' => 'mw-interwiki-rootpage-interwiki', 'type' => 'text' ) ) . ' ' .
- "</td>
- </tr>
+ $mappingSelection
<tr>
<td>
</td>
diff --git a/includes/specials/SpecialJavaScriptTest.php b/includes/specials/SpecialJavaScriptTest.php
index ecb166a4..fbdefea4 100644
--- a/includes/specials/SpecialJavaScriptTest.php
+++ b/includes/specials/SpecialJavaScriptTest.php
@@ -44,6 +44,11 @@ class SpecialJavaScriptTest extends SpecialPage {
if ( $par === null ) {
// No framework specified
+ // If only one framework is configured, redirect to it. Otherwise display a list.
+ if ( count( self::$frameworks ) === 1 ) {
+ $out->redirect( $this->getPageTitle( self::$frameworks[0] . '/plain' )->getLocalURL() );
+ return;
+ }
$out->setStatusCode( 404 );
$out->setPageTitle( $this->msg( 'javascripttest' ) );
$out->addHTML(
@@ -74,10 +79,14 @@ class SpecialJavaScriptTest extends SpecialPage {
// no sensitive data. In order to allow TestSwarm to embed it into a test client window,
// we need to allow iframing of this page.
$out->allowClickjacking();
- $out->setSubtitle(
- $this->msg( 'javascripttest-backlink' )
- ->rawParams( Linker::linkKnown( $this->getPageTitle() ) )
- );
+ if ( count( self::$frameworks ) !== 1 ) {
+ // If there's only one framework, don't set the subtitle since it
+ // is going to redirect back to this page
+ $out->setSubtitle(
+ $this->msg( 'javascripttest-backlink' )
+ ->rawParams( Linker::linkKnown( $this->getPageTitle() ) )
+ );
+ }
// Custom actions
if ( isset( $pars[1] ) ) {
@@ -134,13 +143,15 @@ class SpecialJavaScriptTest extends SpecialPage {
}
/**
- * Wrap HTML contents in a summary container.
+ * Get summary text wrapped in a container
*
- * @param string $html HTML contents to be wrapped
* @return string HTML
*/
- private function wrapSummaryHtml( $html ) {
- return "<div id=\"mw-javascripttest-summary\">$html</div>";
+ private function getSummaryHtml() {
+ $summary = $this->msg( 'javascripttest-qunit-intro' )
+ ->params( 'https://www.mediawiki.org/wiki/Manual:JavaScript_unit_testing' )
+ ->parseAsBlock();
+ return "<div id=\"mw-javascripttest-summary\">$summary</div>";
}
/**
@@ -153,30 +164,24 @@ class SpecialJavaScriptTest extends SpecialPage {
$modules = $out->getResourceLoader()->getTestModuleNames( 'qunit' );
- $summary = $this->msg( 'javascripttest-qunit-intro' )
- ->params( 'https://www.mediawiki.org/wiki/Manual:JavaScript_unit_testing' )
- ->parseAsBlock();
-
$baseHtml = <<<HTML
<div class="mw-content-ltr">
<div id="qunit"></div>
</div>
HTML;
- $out->addHtml( $this->wrapSummaryHtml( $summary ) . $baseHtml );
+ $out->addHtml( $this->getSummaryHtml() . $baseHtml );
// The testrunner configures QUnit and essentially depends on it. However, test suites
// are reusable in environments that preload QUnit (or a compatibility interface to
// another framework). Therefore we have to load it ourselves.
- $out->addHtml( Html::inlineScript(
- ResourceLoader::makeLoaderConditionalScript(
- Xml::encodeJsCall( 'mw.loader.using', array(
- array( 'jquery.qunit', 'jquery.qunit.completenessTest' ),
- new XmlJsCode(
- 'function () {' . Xml::encodeJsCall( 'mw.loader.load', array( $modules ) ) . '}'
- )
- ) )
- )
+ $out->addHtml( ResourceLoader::makeInlineScript(
+ Xml::encodeJsCall( 'mw.loader.using', array(
+ array( 'jquery.qunit', 'jquery.qunit.completenessTest' ),
+ new XmlJsCode(
+ 'function () {' . Xml::encodeJsCall( 'mw.loader.load', array( $modules ) ) . '}'
+ )
+ ) )
) );
}
@@ -200,13 +205,27 @@ HTML;
'lang' => $this->getLanguage()->getCode(),
'skin' => $this->getSkin()->getSkinName(),
'debug' => ResourceLoader::inDebugMode() ? 'true' : 'false',
+ 'target' => 'test',
);
$embedContext = new ResourceLoaderContext( $rl, new FauxRequest( $query ) );
$query['only'] = 'scripts';
$startupContext = new ResourceLoaderContext( $rl, new FauxRequest( $query ) );
+ $query['raw'] = true;
+
$modules = $rl->getTestModuleNames( 'qunit' );
+ // Disable autostart because we load modules asynchronously. By default, QUnit would start
+ // at domready when there are no tests loaded and also fire 'QUnit.done' which then instructs
+ // Karma to end the run before the tests even started.
+ $qunitConfig = 'QUnit.config.autostart = false;'
+ . 'if (window.__karma__) {'
+ // karma-qunit's use of autostart=false and QUnit.start conflicts with ours.
+ // Hack around this by replacing 'karma.loaded' with a no-op and call it ourselves later.
+ // See <https://github.com/karma-runner/karma-qunit/issues/27>.
+ . 'window.__karma__.loaded = function () {};'
+ . '}';
+
// The below is essentially a pure-javascript version of OutputPage::getHeadScripts.
$startup = $rl->makeModuleResponse( $startupContext, array(
'startup' => $rl->getModule( 'startup' ),
@@ -220,43 +239,54 @@ HTML;
'user.options' => $rl->getModule( 'user.options' ),
'user.tokens' => $rl->getModule( 'user.tokens' ),
) );
- $code .= Xml::encodeJsCall( 'mw.loader.load', array( $modules ) );
+ // Catch exceptions (such as "dependency missing" or "unknown module") so that we
+ // always start QUnit. Re-throw so that they are caught and reported as global exceptions
+ // by QUnit and Karma.
+ $code .= '(function () {'
+ . 'var start = window.__karma__ ? window.__karma__.start : QUnit.start;'
+ . 'try {'
+ . 'mw.loader.using( ' . Xml::encodeJsVar( $modules ) . ' ).always( start );'
+ . '} catch ( e ) { start(); throw e; }'
+ . '}());';
header( 'Content-Type: text/javascript; charset=utf-8' );
header( 'Cache-Control: private, no-cache, must-revalidate' );
header( 'Pragma: no-cache' );
+ echo $qunitConfig;
echo $startup;
- echo "\n";
- // Note: The following has to be wrapped in a script tag because the startup module also
- // writes a script tag (the one loading mediawiki.js). Script tags are synchronous, block
- // each other, and run in order. But they don't nest. The code appended after the startup
- // module runs before the added script tag is parsed and executed.
- echo Xml::encodeJsCall( 'document.write', array( Html::inlineScript( $code ) ) );
+ // The following has to be deferred via RLQ because the startup module is asynchronous.
+ echo ResourceLoader::makeLoaderConditionalScript( $code );
}
private function plainQUnit() {
$out = $this->getOutput();
$out->disable();
- $url = $this->getPageTitle( 'qunit/export' )->getFullURL( array(
- 'debug' => ResourceLoader::inDebugMode() ? 'true' : 'false',
- ) );
-
- $styles = $out->makeResourceLoaderLink(
- 'jquery.qunit', ResourceLoaderModule::TYPE_STYLES, false
+ $styles = $out->makeResourceLoaderLink( 'jquery.qunit',
+ ResourceLoaderModule::TYPE_STYLES
);
- // Use 'raw' since this is a plain HTML page without ResourceLoader
- $scripts = $out->makeResourceLoaderLink(
- 'jquery.qunit', ResourceLoaderModule::TYPE_SCRIPTS, false, array( 'raw' => 'true' )
+
+ // Use 'raw' because QUnit loads before ResourceLoader initialises (omit mw.loader.state call)
+ // Use 'test' to ensure OutputPage doesn't use the "async" attribute because QUnit must
+ // load before qunit/export.
+ $scripts = $out->makeResourceLoaderLink( 'jquery.qunit',
+ ResourceLoaderModule::TYPE_SCRIPTS,
+ array( 'raw' => true, 'sync' => true )
);
- $head = trim( $styles['html'] . $scripts['html'] );
+ $head = implode( "\n", array_merge( $styles['html'], $scripts['html'] ) );
+ $summary = $this->getSummaryHtml();
$html = <<<HTML
<!DOCTYPE html>
<title>QUnit</title>
$head
+$summary
<div id="qunit"></div>
HTML;
+
+ $url = $this->getPageTitle( 'qunit/export' )->getFullURL( array(
+ 'debug' => ResourceLoader::inDebugMode() ? 'true' : 'false',
+ ) );
$html .= "\n" . Html::linkedScript( $url );
header( 'Content-Type: text/html; charset=utf-8' );
diff --git a/includes/specials/SpecialLinkSearch.php b/includes/specials/SpecialLinkSearch.php
index 75ff8f30..f4748674 100644
--- a/includes/specials/SpecialLinkSearch.php
+++ b/includes/specials/SpecialLinkSearch.php
@@ -80,7 +80,7 @@ class LinkSearchPage extends QueryPage {
return false;
}
- function execute( $par ) {
+ public function execute( $par ) {
$this->initServices();
$this->setHeaders();
@@ -91,7 +91,7 @@ class LinkSearchPage extends QueryPage {
$request = $this->getRequest();
$target = $request->getVal( 'target', $par );
- $namespace = $request->getIntOrNull( 'namespace', null );
+ $namespace = $request->getIntOrNull( 'namespace' );
$protocols_list = array();
foreach ( $this->getConfig()->get( 'UrlProtocols' ) as $prot ) {
@@ -121,43 +121,41 @@ class LinkSearchPage extends QueryPage {
'<nowiki>' . $this->getLanguage()->commaList( $protocols_list ) . '</nowiki>',
count( $protocols_list )
);
- $s = Html::openElement(
- 'form',
- array( 'id' => 'mw-linksearch-form', 'method' => 'get', 'action' => wfScript() )
- ) . "\n" .
- Html::hidden( 'title', $this->getPageTitle()->getPrefixedDBkey() ) . "\n" .
- Html::openElement( 'fieldset' ) . "\n" .
- Html::element( 'legend', array(), $this->msg( 'linksearch' )->text() ) . "\n" .
- Xml::inputLabel(
- $this->msg( 'linksearch-pat' )->text(),
- 'target',
- 'target',
- 50,
- $target,
- array(
- // URLs are always ltr
- 'dir' => 'ltr',
- )
- ) . "\n";
-
+ $fields = array(
+ 'target' => array(
+ 'type' => 'text',
+ 'name' => 'target',
+ 'id' => 'target',
+ 'size' => 50,
+ 'label-message' => 'linksearch-pat',
+ 'default' => $target,
+ 'dir' => 'ltr',
+ )
+ );
if ( !$this->getConfig()->get( 'MiserMode' ) ) {
- $s .= Html::namespaceSelector(
- array(
- 'selected' => $namespace,
- 'all' => '',
- 'label' => $this->msg( 'linksearch-ns' )->text()
- ), array(
+ $fields += array(
+ 'namespace' => array(
+ 'type' => 'namespaceselect',
'name' => 'namespace',
+ 'label-message' => 'linksearch-ns',
+ 'default' => $namespace,
'id' => 'namespace',
- 'class' => 'namespaceselector',
- )
+ 'all' => '',
+ 'cssclass' => 'namespaceselector',
+ ),
);
}
-
- $s .= Xml::submitButton( $this->msg( 'linksearch-ok' )->text() ) . "\n" .
- Html::closeElement( 'fieldset' ) . "\n" .
- Html::closeElement( 'form' ) . "\n";
- $out->addHTML( $s );
+ $hiddenFields = array(
+ 'title' => $this->getPageTitle()->getPrefixedDBkey(),
+ );
+ $htmlForm = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
+ $htmlForm->addHiddenFields( $hiddenFields );
+ $htmlForm->setSubmitTextMsg( 'linksearch-ok' );
+ $htmlForm->setWrapperLegendMsg( 'linksearch' );
+ $htmlForm->setAction( wfScript() );
+ $htmlForm->setMethod( 'get' );
+ $htmlForm->prepareForm()->displayForm( false );
+ $this->addHelpLink( 'Help:Linksearch' );
if ( $target != '' ) {
$this->setParams( array(
@@ -220,7 +218,7 @@ class LinkSearchPage extends QueryPage {
return $params;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
$dbr = wfGetDB( DB_SLAVE );
// strip everything past first wildcard, so that
// index-based-only lookup would be done
diff --git a/includes/specials/SpecialListDuplicatedFiles.php b/includes/specials/SpecialListDuplicatedFiles.php
index 1e3dff6f..317b62fe 100644
--- a/includes/specials/SpecialListDuplicatedFiles.php
+++ b/includes/specials/SpecialListDuplicatedFiles.php
@@ -34,7 +34,7 @@ class ListDuplicatedFilesPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -53,7 +53,7 @@ class ListDuplicatedFilesPage extends QueryPage {
* with however we are doing cached special pages.
* @return array
*/
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'image' ),
'fields' => array(
diff --git a/includes/specials/SpecialListfiles.php b/includes/specials/SpecialListfiles.php
index d4b45fb3..2d79aaf8 100644
--- a/includes/specials/SpecialListfiles.php
+++ b/includes/specials/SpecialListfiles.php
@@ -84,14 +84,26 @@ class ImageListPager extends TablePager {
function __construct( IContextSource $context, $userName = null, $search = '',
$including = false, $showAll = false
) {
+ $this->setContext( $context );
$this->mIncluding = $including;
$this->mShowAll = $showAll;
if ( $userName !== null && $userName !== '' ) {
$nt = Title::newFromText( $userName, NS_USER );
+ $user = User::newFromName( $userName, false );
if ( !is_null( $nt ) ) {
$this->mUserName = $nt->getText();
}
+ if ( !$user || ( $user->isAnon() && !User::isIP( $user->getName() ) ) ) {
+ $this->getOutput()->wrapWikiMsg(
+ "<div class=\"mw-userpage-userdoesnotexist error\">\n$1\n</div>",
+ array(
+ 'listfiles-userdoesnotexist',
+ wfEscapeWikiText( $userName ),
+ )
+ );
+ }
+
}
if ( $search !== '' && !$this->getConfig()->get( 'MiserMode' ) ) {
@@ -107,7 +119,7 @@ class ImageListPager extends TablePager {
}
if ( !$including ) {
- if ( $context->getRequest()->getText( 'sort', 'img_date' ) == 'img_date' ) {
+ if ( $this->getRequest()->getText( 'sort', 'img_date' ) == 'img_date' ) {
$this->mDefaultDirection = IndexPager::DIR_DESCENDING;
} else {
$this->mDefaultDirection = IndexPager::DIR_ASCENDING;
diff --git a/includes/specials/SpecialListredirects.php b/includes/specials/SpecialListredirects.php
index 2df48347..fa94b4ab 100644
--- a/includes/specials/SpecialListredirects.php
+++ b/includes/specials/SpecialListredirects.php
@@ -33,7 +33,7 @@ class ListredirectsPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -45,7 +45,7 @@ class ListredirectsPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'p1' => 'page', 'redirect', 'p2' => 'page' ),
'fields' => array( 'namespace' => 'p1.page_namespace',
diff --git a/includes/specials/SpecialListusers.php b/includes/specials/SpecialListusers.php
index 56c4eb50..31200c84 100644
--- a/includes/specials/SpecialListusers.php
+++ b/includes/specials/SpecialListusers.php
@@ -263,6 +263,8 @@ class UsersPager extends AlphabeticPager {
function getPageHeader() {
list( $self ) = explode( '/', $this->getTitle()->getPrefixedDBkey() );
+ $this->getOutput()->addModules( 'mediawiki.userSuggest' );
+
# Form tag
$out = Xml::openElement(
'form',
@@ -271,13 +273,14 @@ class UsersPager extends AlphabeticPager {
Xml::fieldset( $this->msg( 'listusers' )->text() ) .
Html::hidden( 'title', $self );
- # Username field
+ # Username field (with autocompletion support)
$out .= Xml::label( $this->msg( 'listusersfrom' )->text(), 'offset' ) . ' ' .
Html::input(
'username',
$this->requestedUser,
'text',
array(
+ 'class' => 'mw-autocomplete-user',
'id' => 'offset',
'size' => 20,
'autofocus' => $this->requestedUser === ''
@@ -285,13 +288,14 @@ class UsersPager extends AlphabeticPager {
) . ' ';
# Group drop-down list
- $out .= Xml::label( $this->msg( 'group' )->text(), 'group' ) . ' ' .
- Xml::openElement( 'select', array( 'name' => 'group', 'id' => 'group' ) ) .
- Xml::option( $this->msg( 'group-all' )->text(), '' );
+ $sel = new XmlSelect( 'group', 'group', $this->requestedGroup );
+ $sel->addOption( $this->msg( 'group-all' )->text(), '' );
foreach ( $this->getAllGroups() as $group => $groupText ) {
- $out .= Xml::option( $groupText, $group, $group == $this->requestedGroup );
+ $sel->addOption( $groupText, $group );
}
- $out .= Xml::closeElement( 'select' ) . '<br />';
+
+ $out .= Xml::label( $this->msg( 'group' )->text(), 'group' ) . ' ';
+ $out .= $sel->getHTML() . '<br />';
$out .= Xml::checkLabel(
$this->msg( 'listusers-editsonly' )->text(),
'editsOnly',
diff --git a/includes/specials/SpecialLockdb.php b/includes/specials/SpecialLockdb.php
index 1c1f1250..a276197d 100644
--- a/includes/specials/SpecialLockdb.php
+++ b/includes/specials/SpecialLockdb.php
@@ -73,9 +73,9 @@ class SpecialLockdb extends FormSpecialPage {
return Status::newFatal( 'locknoconfirm' );
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$fp = fopen( $this->getConfig()->get( 'ReadOnlyFile' ), 'w' );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( false === $fp ) {
# This used to show a file not found error, but the likeliest reason for fopen()
diff --git a/includes/specials/SpecialMIMEsearch.php b/includes/specials/SpecialMIMEsearch.php
index 60225ea5..32344a84 100644
--- a/includes/specials/SpecialMIMEsearch.php
+++ b/includes/specials/SpecialMIMEsearch.php
@@ -34,8 +34,8 @@ class MIMEsearchPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
- return false;
+ public function isExpensive() {
+ return true;
}
function isSyndicated() {
@@ -109,7 +109,6 @@ class MIMEsearchPage extends QueryPage {
* Return HTML to put just before the results.
*/
function getPageHeader() {
-
return Xml::openElement(
'form',
array( 'id' => 'specialmimesearch', 'method' => 'get', 'action' => wfScript() )
@@ -124,7 +123,7 @@ class MIMEsearchPage extends QueryPage {
Xml::closeElement( 'form' );
}
- function execute( $par ) {
+ public function execute( $par ) {
$this->mime = $par ? $par : $this->getRequest()->getText( 'mime' );
$this->mime = trim( $this->mime );
list( $this->major, $this->minor ) = File::splitMime( $this->mime );
diff --git a/includes/specials/SpecialMediaStatistics.php b/includes/specials/SpecialMediaStatistics.php
index b62de5d2..e5ba8c60 100644
--- a/includes/specials/SpecialMediaStatistics.php
+++ b/includes/specials/SpecialMediaStatistics.php
@@ -36,7 +36,7 @@ class MediaStatisticsPage extends QueryPage {
$this->shownavigation = false;
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -111,7 +111,11 @@ class MediaStatisticsPage extends QueryPage {
protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) {
$prevMediaType = null;
foreach ( $res as $row ) {
- list( $mediaType, $mime, $totalCount, $totalBytes ) = $this->splitFakeTitle( $row->title );
+ $mediaStats = $this->splitFakeTitle( $row->title );
+ if ( count( $mediaStats ) < 4 ) {
+ continue;
+ }
+ list( $mediaType, $mime, $totalCount, $totalBytes ) = $mediaStats;
if ( $prevMediaType !== $mediaType ) {
if ( $prevMediaType !== null ) {
// We're not at beginning, so we have to
@@ -232,7 +236,7 @@ class MediaStatisticsPage extends QueryPage {
'mw-mediastats-table-' . strtolower( $mediaType ),
'sortable',
'wikitable'
- ))
+ ) )
)
);
$this->getOutput()->addHTML( $this->getTableHeaderRow() );
@@ -271,7 +275,7 @@ class MediaStatisticsPage extends QueryPage {
array( 'class' => array(
'mw-mediastats-mediatype',
'mw-mediastats-mediatype-' . strtolower( $mediaType )
- )),
+ ) ),
// for grep
// mediastatistics-header-unknown, mediastatistics-header-bitmap,
// mediastatistics-header-drawing, mediastatistics-header-audio,
diff --git a/includes/specials/SpecialMergeHistory.php b/includes/specials/SpecialMergeHistory.php
index 1f0b6d45..7edf961a 100644
--- a/includes/specials/SpecialMergeHistory.php
+++ b/includes/specials/SpecialMergeHistory.php
@@ -109,6 +109,8 @@ class SpecialMergeHistory extends SpecialPage {
}
public function execute( $par ) {
+ $this->useTransactionalTimeLimit();
+
$this->checkPermissions();
$this->checkReadOnly();
diff --git a/includes/specials/SpecialMostcategories.php b/includes/specials/SpecialMostcategories.php
index c70bbdba..18083f61 100644
--- a/includes/specials/SpecialMostcategories.php
+++ b/includes/specials/SpecialMostcategories.php
@@ -34,7 +34,7 @@ class MostcategoriesPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -42,7 +42,7 @@ class MostcategoriesPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'categorylinks', 'page' ),
'fields' => array(
diff --git a/includes/specials/SpecialMostinterwikis.php b/includes/specials/SpecialMostinterwikis.php
index ab3d9c91..b07b8331 100644
--- a/includes/specials/SpecialMostinterwikis.php
+++ b/includes/specials/SpecialMostinterwikis.php
@@ -34,7 +34,7 @@ class MostinterwikisPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -42,7 +42,7 @@ class MostinterwikisPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array(
'langlinks',
diff --git a/includes/specials/SpecialMostlinked.php b/includes/specials/SpecialMostlinked.php
index ae0b0708..019df493 100644
--- a/includes/specials/SpecialMostlinked.php
+++ b/includes/specials/SpecialMostlinked.php
@@ -35,7 +35,7 @@ class MostlinkedPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -43,7 +43,7 @@ class MostlinkedPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'pagelinks', 'page' ),
'fields' => array(
diff --git a/includes/specials/SpecialMostlinkedcategories.php b/includes/specials/SpecialMostlinkedcategories.php
index cc718e06..6eeab91b 100644
--- a/includes/specials/SpecialMostlinkedcategories.php
+++ b/includes/specials/SpecialMostlinkedcategories.php
@@ -38,7 +38,7 @@ class MostlinkedCategoriesPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'category' ),
'fields' => array( 'title' => 'cat_title',
diff --git a/includes/specials/SpecialMovepage.php b/includes/specials/SpecialMovepage.php
index ae1fefea..8091f1b0 100644
--- a/includes/specials/SpecialMovepage.php
+++ b/includes/specials/SpecialMovepage.php
@@ -28,7 +28,7 @@
*/
class MovePageForm extends UnlistedSpecialPage {
/** @var Title */
- protected $oldTitle;
+ protected $oldTitle = null;
/** @var Title */
protected $newTitle;
@@ -64,6 +64,8 @@ class MovePageForm extends UnlistedSpecialPage {
}
public function execute( $par ) {
+ $this->useTransactionalTimeLimit();
+
$this->checkReadOnly();
$this->setHeaders();
@@ -75,9 +77,12 @@ class MovePageForm extends UnlistedSpecialPage {
// Yes, the use of getVal() and getText() is wanted, see bug 20365
$oldTitleText = $request->getVal( 'wpOldTitle', $target );
- $this->oldTitle = Title::newFromText( $oldTitleText );
+ if ( is_string( $oldTitleText ) ) {
+ $this->oldTitle = Title::newFromText( $oldTitleText );
+ }
- if ( is_null( $this->oldTitle ) ) {
+ if ( $this->oldTitle === null ) {
+ // Either oldTitle wasn't passed, or newFromText returned null
throw new ErrorPageError( 'notargettitle', 'notargettext' );
}
if ( !$this->oldTitle->exists() ) {
@@ -99,7 +104,9 @@ class MovePageForm extends UnlistedSpecialPage {
$permErrors = $this->oldTitle->getUserPermissionsErrors( 'move', $user );
if ( count( $permErrors ) ) {
// Auto-block user's IP if the account was "hard" blocked
- $user->spreadAnyEditBlock();
+ DeferredUpdates::addCallableUpdate( function() use ( $user ) {
+ $user->spreadAnyEditBlock();
+ } );
throw new PermissionsError( 'move', $permErrors );
}
@@ -140,6 +147,7 @@ class MovePageForm extends UnlistedSpecialPage {
$out = $this->getOutput();
$out->setPageTitle( $this->msg( 'move-page', $this->oldTitle->getPrefixedText() ) );
$out->addModules( 'mediawiki.special.movePage' );
+ $out->addModuleStyles( 'mediawiki.special.movePage.styles' );
$this->addHelpLink( 'Help:Moving a page' );
$newTitle = $this->newTitle;
@@ -283,7 +291,6 @@ class MovePageForm extends UnlistedSpecialPage {
// is enforced in the mediawiki.special.movePage module
$immovableNamespaces = array();
-
foreach ( array_keys( $this->getLanguage()->getNamespaces() ) as $nsId ) {
if ( !MWNamespace::isMovable( $nsId ) ) {
$immovableNamespaces[] = $nsId;
@@ -292,202 +299,207 @@ class MovePageForm extends UnlistedSpecialPage {
$handler = ContentHandler::getForTitle( $this->oldTitle );
- $out->addHTML(
- Xml::openElement(
- 'form',
- array(
- 'method' => 'post',
- 'action' => $this->getPageTitle()->getLocalURL( 'action=submit' ),
- 'id' => 'movepage'
- )
- ) .
- Xml::openElement( 'fieldset' ) .
- Xml::element( 'legend', null, $this->msg( 'move-page-legend' )->text() ) .
- Xml::openElement( 'table', array( 'id' => 'mw-movepage-table' ) )
+ $out->enableOOUI();
+ $fields = array();
+
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\LabelWidget( array(
+ 'label' => new OOUI\HtmlSnippet( "<strong>$oldTitleLink</strong>" )
+ ) ),
+ array(
+ 'label' => $this->msg( 'movearticle' )->text(),
+ 'align' => 'top',
+ )
);
- $out->addHTML(
- "<tr>
- <td class='mw-label'>" .
- $this->msg( 'movearticle' )->escaped() .
- "</td>
- <td class='mw-input'>
- <strong>{$oldTitleLink}</strong>
- </td>
- </tr>
- <tr>
- <td class='mw-label'>" .
- Xml::label( $this->msg( 'newtitle' )->text(), 'wpNewTitleMain' ) .
- "</td>
- <td class='mw-input'>" .
- Html::namespaceSelector(
- array(
- 'selected' => $newTitle->getNamespace(),
- 'exclude' => $immovableNamespaces
- ),
- array( 'name' => 'wpNewTitleNs', 'id' => 'wpNewTitleNs' )
- ) .
- Xml::input(
- 'wpNewTitleMain',
- 60,
- $wgContLang->recodeForEdit( $newTitle->getText() ),
- array(
- 'type' => 'text',
- 'id' => 'wpNewTitleMain',
- 'maxlength' => 255
- )
- ) .
- Html::hidden( 'wpOldTitle', $this->oldTitle->getPrefixedText() ) .
- "</td>
- </tr>
- <tr>
- <td class='mw-label'>" .
- Xml::label( $this->msg( 'movereason' )->text(), 'wpReason' ) .
- "</td>
- <td class='mw-input'>" .
- Xml::input( 'wpReason', 60, $this->reason, array(
- 'type' => 'text',
- 'id' => 'wpReason',
- 'maxlength' => 200,
- ) ) .
- "</td>
- </tr>"
+ $fields[] = new OOUI\FieldLayout(
+ new MediaWiki\Widget\ComplexTitleInputWidget( array(
+ 'id' => 'wpNewTitle',
+ 'namespace' => array(
+ 'id' => 'wpNewTitleNs',
+ 'name' => 'wpNewTitleNs',
+ 'value' => $newTitle->getNamespace(),
+ 'exclude' => $immovableNamespaces,
+ ),
+ 'title' => array(
+ 'id' => 'wpNewTitleMain',
+ 'name' => 'wpNewTitleMain',
+ 'value' => $wgContLang->recodeForEdit( $newTitle->getText() ),
+ // Inappropriate, since we're expecting the user to input a non-existent page's title
+ 'suggestions' => false,
+ ),
+ 'infusable' => true,
+ ) ),
+ array(
+ 'label' => $this->msg( 'newtitle' )->text(),
+ 'align' => 'top',
+ )
+ );
+
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\TextInputWidget( array(
+ 'name' => 'wpReason',
+ 'id' => 'wpReason',
+ 'maxLength' => 200,
+ 'infusable' => true,
+ ) ),
+ array(
+ 'label' => $this->msg( 'movereason' )->text(),
+ 'align' => 'top',
+ )
);
if ( $considerTalk ) {
- $out->addHTML( "
- <tr>
- <td></td>
- <td class='mw-input'>" .
- Xml::checkLabel(
- $this->msg( 'movetalk' )->text(),
- 'wpMovetalk',
- 'wpMovetalk',
- $this->moveTalk
- ) .
- "</td>
- </tr>"
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\CheckboxInputWidget( array(
+ 'name' => 'wpMovetalk',
+ 'id' => 'wpMovetalk',
+ 'value' => '1',
+ 'selected' => $this->moveTalk,
+ ) ),
+ array(
+ 'label' => $this->msg( 'movetalk' )->text(),
+ 'align' => 'inline',
+ )
);
}
if ( $user->isAllowed( 'suppressredirect' ) ) {
if ( $handler->supportsRedirects() ) {
$isChecked = $this->leaveRedirect;
- $options = array();
+ $isDisabled = false;
} else {
$isChecked = false;
- $options = array(
- 'disabled' => 'disabled'
- );
+ $isDisabled = true;
}
- $out->addHTML( "
- <tr>
- <td></td>
- <td class='mw-input'>" .
- Xml::checkLabel(
- $this->msg( 'move-leave-redirect' )->text(),
- 'wpLeaveRedirect',
- 'wpLeaveRedirect',
- $isChecked,
- $options
- ) .
- "</td>
- </tr>"
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\CheckboxInputWidget( array(
+ 'name' => 'wpLeaveRedirect',
+ 'id' => 'wpLeaveRedirect',
+ 'value' => '1',
+ 'selected' => $isChecked,
+ 'disabled' => $isDisabled,
+ ) ),
+ array(
+ 'label' => $this->msg( 'move-leave-redirect' )->text(),
+ 'align' => 'inline',
+ )
);
}
if ( $hasRedirects ) {
- $out->addHTML( "
- <tr>
- <td></td>
- <td class='mw-input'>" .
- Xml::checkLabel(
- $this->msg( 'fix-double-redirects' )->text(),
- 'wpFixRedirects',
- 'wpFixRedirects',
- $this->fixRedirects
- ) .
- "</td>
- </tr>"
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\CheckboxInputWidget( array(
+ 'name' => 'wpFixRedirects',
+ 'id' => 'wpFixRedirects',
+ 'value' => '1',
+ 'selected' => $this->fixRedirects,
+ ) ),
+ array(
+ 'label' => $this->msg( 'fix-double-redirects' )->text(),
+ 'align' => 'inline',
+ )
);
}
if ( $canMoveSubpage ) {
$maximumMovedPages = $this->getConfig()->get( 'MaximumMovedPages' );
- $out->addHTML( "
- <tr>
- <td></td>
- <td class='mw-input'>" .
- Xml::check(
- 'wpMovesubpages',
- # Don't check the box if we only have talk subpages to
- # move and we aren't moving the talk page.
- $this->moveSubpages && ( $this->oldTitle->hasSubpages() || $this->moveTalk ),
- array( 'id' => 'wpMovesubpages' )
- ) . '&#160;' .
- Xml::tags(
- 'label',
- array( 'for' => 'wpMovesubpages' ),
- $this->msg(
- ( $this->oldTitle->hasSubpages()
- ? 'move-subpages'
- : 'move-talk-subpages' )
- )->numParams( $maximumMovedPages )->params( $maximumMovedPages )->parse()
- ) .
- "</td>
- </tr>"
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\CheckboxInputWidget( array(
+ 'name' => 'wpMovesubpages',
+ 'id' => 'wpMovesubpages',
+ 'value' => '1',
+ # Don't check the box if we only have talk subpages to
+ # move and we aren't moving the talk page.
+ 'selected' => $this->moveSubpages && ( $this->oldTitle->hasSubpages() || $this->moveTalk ),
+ ) ),
+ array(
+ 'label' => new OOUI\HtmlSnippet(
+ $this->msg(
+ ( $this->oldTitle->hasSubpages()
+ ? 'move-subpages'
+ : 'move-talk-subpages' )
+ )->numParams( $maximumMovedPages )->params( $maximumMovedPages )->parse()
+ ),
+ 'align' => 'inline',
+ )
);
}
- $watchChecked = $user->isLoggedIn() && ( $this->watch || $user->getBoolOption( 'watchmoves' )
- || $user->isWatched( $this->oldTitle ) );
# Don't allow watching if user is not logged in
if ( $user->isLoggedIn() ) {
- $out->addHTML( "
- <tr>
- <td></td>
- <td class='mw-input'>" .
- Xml::checkLabel(
- $this->msg( 'move-watch' )->text(),
- 'wpWatch',
- 'watch',
- $watchChecked
- ) .
- "</td>
- </tr>"
+ $watchChecked = $user->isLoggedIn() && ( $this->watch || $user->getBoolOption( 'watchmoves' )
+ || $user->isWatched( $this->oldTitle ) );
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\CheckboxInputWidget( array(
+ 'name' => 'wpWatch',
+ 'id' => 'watch', # ew
+ 'value' => '1',
+ 'selected' => $watchChecked,
+ ) ),
+ array(
+ 'label' => $this->msg( 'move-watch' )->text(),
+ 'align' => 'inline',
+ )
);
}
if ( $confirm ) {
- $out->addHTML( "
- <tr>
- <td></td>
- <td class='mw-input'>" .
- Xml::checkLabel(
- $this->msg( 'delete_and_move_confirm' )->text(),
- 'wpConfirm',
- 'wpConfirm'
- ) .
- "</td>
- </tr>"
+ $watchChecked = $user->isLoggedIn() && ( $this->watch || $user->getBoolOption( 'watchmoves' )
+ || $user->isWatched( $this->oldTitle ) );
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\CheckboxInputWidget( array(
+ 'name' => 'wpConfirm',
+ 'id' => 'wpConfirm',
+ 'value' => '1',
+ ) ),
+ array(
+ 'label' => $this->msg( 'delete_and_move_confirm' )->text(),
+ 'align' => 'inline',
+ )
);
}
- $out->addHTML( "
- <tr>
- <td></td>
- <td class='mw-submit'>" .
- Xml::submitButton( $movepagebtn, array( 'name' => $submitVar ) ) .
- "</td>
- </tr>"
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\ButtonInputWidget( array(
+ 'name' => $submitVar,
+ 'value' => $movepagebtn,
+ 'label' => $movepagebtn,
+ 'flags' => array( 'progressive', 'primary' ),
+ 'type' => 'submit',
+ ) ),
+ array(
+ 'align' => 'top',
+ )
+ );
+
+ $fieldset = new OOUI\FieldsetLayout( array(
+ 'label' => $this->msg( 'move-page-legend' )->text(),
+ 'id' => 'mw-movepage-table',
+ 'items' => $fields,
+ ) );
+
+ $form = new OOUI\FormLayout( array(
+ 'method' => 'post',
+ 'action' => $this->getPageTitle()->getLocalURL( 'action=submit' ),
+ 'id' => 'movepage',
+ ) );
+ $form->appendContent(
+ $fieldset,
+ new OOUI\HtmlSnippet(
+ Html::hidden( 'wpOldTitle', $this->oldTitle->getPrefixedText() ) .
+ Html::hidden( 'wpEditToken', $user->getEditToken() )
+ )
);
$out->addHTML(
- Xml::closeElement( 'table' ) .
- Html::hidden( 'wpEditToken', $user->getEditToken() ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' ) .
- "\n"
+ new OOUI\PanelLayout( array(
+ 'classes' => array( 'movepage-wrapper' ),
+ 'expanded' => false,
+ 'padded' => true,
+ 'framed' => true,
+ 'content' => $form,
+ ) )
);
$this->showLogFragment( $this->oldTitle );
diff --git a/includes/specials/SpecialMyLanguage.php b/includes/specials/SpecialMyLanguage.php
index 6cea1581..3d8ff97b 100644
--- a/includes/specials/SpecialMyLanguage.php
+++ b/includes/specials/SpecialMyLanguage.php
@@ -41,11 +41,11 @@ class SpecialMyLanguage extends RedirectSpecialArticle {
* If the special page is a redirect, then get the Title object it redirects to.
* False otherwise.
*
- * @param string $par Subpage string
- * @return Title|bool
+ * @param string|null $subpage
+ * @return Title
*/
- public function getRedirect( $par ) {
- $title = $this->findTitle( $par );
+ public function getRedirect( $subpage ) {
+ $title = $this->findTitle( $subpage );
// Go to the main page if given invalid title.
if ( !$title ) {
$title = Title::newMainPage();
@@ -59,18 +59,22 @@ class SpecialMyLanguage extends RedirectSpecialArticle {
* it returns Page/fi if it exists, otherwise Page/de if it exists,
* otherwise Page.
*
- * @param string $par
+ * @param string|null $subpage
* @return Title|null
*/
- public function findTitle( $par ) {
+ public function findTitle( $subpage ) {
// base = title without language code suffix
// provided = the title as it was given
- $base = $provided = Title::newFromText( $par );
+ $base = $provided = null;
+ if ( $subpage !== null ) {
+ $provided = Title::newFromText( $subpage );
+ $base = $provided;
+ }
- if ( $base && strpos( $par, '/' ) !== false ) {
- $pos = strrpos( $par, '/' );
- $basepage = substr( $par, 0, $pos );
- $code = substr( $par, $pos + 1 );
+ if ( $provided && strpos( $subpage, '/' ) !== false ) {
+ $pos = strrpos( $subpage, '/' );
+ $basepage = substr( $subpage, 0, $pos );
+ $code = substr( $subpage, $pos + 1 );
if ( strlen( $code ) && Language::isKnownLanguageTag( $code ) ) {
$base = Title::newFromText( $basepage );
}
diff --git a/includes/specials/SpecialMyRedirectPages.php b/includes/specials/SpecialMyRedirectPages.php
index 9b8d52bb..5ef03f13 100644
--- a/includes/specials/SpecialMyRedirectPages.php
+++ b/includes/specials/SpecialMyRedirectPages.php
@@ -30,16 +30,20 @@
* @ingroup SpecialPage
*/
class SpecialMypage extends RedirectSpecialArticle {
- function __construct() {
+ public function __construct() {
parent::__construct( 'Mypage' );
}
- function getRedirect( $subpage ) {
- if ( strval( $subpage ) !== '' ) {
- return Title::makeTitle( NS_USER, $this->getUser()->getName() . '/' . $subpage );
- } else {
+ /**
+ * @param string|null $subpage
+ * @return Title
+ */
+ public function getRedirect( $subpage ) {
+ if ( $subpage === null || $subpage === '' ) {
return Title::makeTitle( NS_USER, $this->getUser()->getName() );
}
+
+ return Title::makeTitle( NS_USER, $this->getUser()->getName() . '/' . $subpage );
}
}
@@ -49,16 +53,20 @@ class SpecialMypage extends RedirectSpecialArticle {
* @ingroup SpecialPage
*/
class SpecialMytalk extends RedirectSpecialArticle {
- function __construct() {
+ public function __construct() {
parent::__construct( 'Mytalk' );
}
- function getRedirect( $subpage ) {
- if ( strval( $subpage ) !== '' ) {
- return Title::makeTitle( NS_USER_TALK, $this->getUser()->getName() . '/' . $subpage );
- } else {
+ /**
+ * @param string|null $subpage
+ * @return Title
+ */
+ public function getRedirect( $subpage ) {
+ if ( $subpage === null || $subpage === '' ) {
return Title::makeTitle( NS_USER_TALK, $this->getUser()->getName() );
}
+
+ return Title::makeTitle( NS_USER_TALK, $this->getUser()->getName() . '/' . $subpage );
}
}
@@ -68,13 +76,18 @@ class SpecialMytalk extends RedirectSpecialArticle {
* @ingroup SpecialPage
*/
class SpecialMycontributions extends RedirectSpecialPage {
- function __construct() {
+ public function __construct() {
parent::__construct( 'Mycontributions' );
$this->mAllowedRedirectParams = array( 'limit', 'namespace', 'tagfilter',
- 'offset', 'dir', 'year', 'month', 'feed' );
+ 'offset', 'dir', 'year', 'month', 'feed', 'deletedOnly',
+ 'nsInvert', 'associated', 'newOnly', 'topOnly' );
}
- function getRedirect( $subpage ) {
+ /**
+ * @param string|null $subpage
+ * @return Title
+ */
+ public function getRedirect( $subpage ) {
return SpecialPage::getTitleFor( 'Contributions', $this->getUser()->getName() );
}
}
@@ -85,12 +98,16 @@ class SpecialMycontributions extends RedirectSpecialPage {
* @ingroup SpecialPage
*/
class SpecialMyuploads extends RedirectSpecialPage {
- function __construct() {
+ public function __construct() {
parent::__construct( 'Myuploads' );
$this->mAllowedRedirectParams = array( 'limit', 'ilshowall', 'ilsearch' );
}
- function getRedirect( $subpage ) {
+ /**
+ * @param string|null $subpage
+ * @return Title
+ */
+ public function getRedirect( $subpage ) {
return SpecialPage::getTitleFor( 'Listfiles', $this->getUser()->getName() );
}
}
@@ -101,12 +118,16 @@ class SpecialMyuploads extends RedirectSpecialPage {
* @ingroup SpecialPage
*/
class SpecialAllMyUploads extends RedirectSpecialPage {
- function __construct() {
+ public function __construct() {
parent::__construct( 'AllMyUploads' );
$this->mAllowedRedirectParams = array( 'limit', 'ilsearch' );
}
- function getRedirect( $subpage ) {
+ /**
+ * @param string|null $subpage
+ * @return Title
+ */
+ public function getRedirect( $subpage ) {
$this->mAddedRedirectParams['ilshowall'] = 1;
return SpecialPage::getTitleFor( 'Listfiles', $this->getUser()->getName() );
diff --git a/includes/specials/SpecialNewpages.php b/includes/specials/SpecialNewpages.php
index 899c7368..251a8e03 100644
--- a/includes/specials/SpecialNewpages.php
+++ b/includes/specials/SpecialNewpages.php
@@ -233,7 +233,7 @@ class SpecialNewpages extends IncludableSpecialPage {
'name' => 'invert',
'label-message' => 'invert',
'default' => $nsinvert,
- 'tooltip' => $this->msg( 'tooltip-invert' )->text(),
+ 'tooltip' => 'invert',
),
'tagFilter' => array(
'type' => 'tagfilter',
@@ -594,7 +594,7 @@ class NewPagesPager extends ReverseChronologicalPager {
foreach ( $this->mResult as $row ) {
$linkBatch->add( NS_USER, $row->rc_user_text );
$linkBatch->add( NS_USER_TALK, $row->rc_user_text );
- $linkBatch->add( $row->rc_namespace, $row->rc_title );
+ $linkBatch->add( $row->page_namespace, $row->page_title );
}
$linkBatch->execute();
diff --git a/includes/specials/SpecialPageLanguage.php b/includes/specials/SpecialPageLanguage.php
index 79b2444e..6756f274 100644
--- a/includes/specials/SpecialPageLanguage.php
+++ b/includes/specials/SpecialPageLanguage.php
@@ -87,11 +87,14 @@ class SpecialPageLanguage extends FormSpecialPage {
}
protected function postText() {
- return $this->showLogFragment( $this->par );
+ if ( $this->par ) {
+ return $this->showLogFragment( $this->par );
+ }
+ return '';
}
protected function getDisplayFormat() {
- return 'vform';
+ return 'ooui';
}
public function alterForm( HTMLForm $form ) {
diff --git a/includes/specials/SpecialPagesWithProp.php b/includes/specials/SpecialPagesWithProp.php
index 670a3973..f211ec9b 100644
--- a/includes/specials/SpecialPagesWithProp.php
+++ b/includes/specials/SpecialPagesWithProp.php
@@ -40,7 +40,7 @@ class SpecialPagesWithProp extends QueryPage {
return false;
}
- function execute( $par ) {
+ public function execute( $par ) {
$this->setHeaders();
$this->outputHeader();
$this->getOutput()->addModuleStyles( 'mediawiki.special.pagesWithProp' );
@@ -100,7 +100,7 @@ class SpecialPagesWithProp extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'page_props', 'page' ),
'fields' => array(
@@ -113,9 +113,11 @@ class SpecialPagesWithProp extends QueryPage {
'pp_value',
),
'conds' => array(
- 'page_id = pp_page',
'pp_propname' => $this->propName,
),
+ 'join_conds' => array(
+ 'page' => array( 'INNER JOIN', 'page_id = pp_page' )
+ ),
'options' => array()
);
}
diff --git a/includes/specials/SpecialPasswordReset.php b/includes/specials/SpecialPasswordReset.php
index a2dc2add..8cad6168 100644
--- a/includes/specials/SpecialPasswordReset.php
+++ b/includes/specials/SpecialPasswordReset.php
@@ -104,7 +104,7 @@ class SpecialPasswordReset extends FormSpecialPage {
}
protected function getDisplayFormat() {
- return 'vform';
+ return 'ooui';
}
public function alterForm( HTMLForm $form ) {
diff --git a/includes/specials/SpecialPermanentLink.php b/includes/specials/SpecialPermanentLink.php
index 17115e88..53789c0d 100644
--- a/includes/specials/SpecialPermanentLink.php
+++ b/includes/specials/SpecialPermanentLink.php
@@ -27,12 +27,16 @@
* @ingroup SpecialPage
*/
class SpecialPermanentLink extends RedirectSpecialPage {
- function __construct() {
+ public function __construct() {
parent::__construct( 'PermanentLink' );
$this->mAllowedRedirectParams = array();
}
- function getRedirect( $subpage ) {
+ /**
+ * @param string|null $subpage
+ * @return Title|bool
+ */
+ public function getRedirect( $subpage ) {
$subpage = intval( $subpage );
if ( $subpage === 0 ) {
# throw an error page when no subpage was given
diff --git a/includes/specials/SpecialPreferences.php b/includes/specials/SpecialPreferences.php
index 7371da74..4b75e5f6 100644
--- a/includes/specials/SpecialPreferences.php
+++ b/includes/specials/SpecialPreferences.php
@@ -50,7 +50,14 @@ class SpecialPreferences extends SpecialPage {
if ( $this->getRequest()->getCheck( 'success' ) ) {
$out->wrapWikiMsg(
- "<div class=\"successbox\">\n$1\n</div>",
+ Html::rawElement(
+ 'div',
+ array(
+ 'class' => 'mw-preferences-messagebox successbox',
+ 'id' => 'mw-preferences-success'
+ ),
+ Html::element( 'p', array(), '$1' )
+ ),
'savedprefs'
);
}
diff --git a/includes/specials/SpecialProtectedtitles.php b/includes/specials/SpecialProtectedtitles.php
index dd9198cb..85ce78ff 100644
--- a/includes/specials/SpecialProtectedtitles.php
+++ b/includes/specials/SpecialProtectedtitles.php
@@ -67,16 +67,8 @@ class SpecialProtectedtitles extends SpecialPage {
* @return string
*/
function formatRow( $row ) {
-
- static $infinity = null;
-
- if ( is_null( $infinity ) ) {
- $infinity = wfGetDB( DB_SLAVE )->getInfinity();
- }
-
$title = Title::makeTitleSafe( $row->pt_namespace, $row->pt_title );
if ( !$title ) {
-
return Html::rawElement(
'li',
array(),
@@ -100,9 +92,9 @@ class SpecialProtectedtitles extends SpecialPage {
$lang = $this->getLanguage();
$expiry = strlen( $row->pt_expiry ) ?
$lang->formatExpiry( $row->pt_expiry, TS_MW ) :
- $infinity;
+ 'infinity';
- if ( $expiry != $infinity ) {
+ if ( $expiry !== 'infinity' ) {
$user = $this->getUser();
$description_items[] = $this->msg(
'protect-expiring-local',
diff --git a/includes/specials/SpecialRandomInCategory.php b/includes/specials/SpecialRandomInCategory.php
index b5c9e19a..7cf6b0a1 100644
--- a/includes/specials/SpecialRandomInCategory.php
+++ b/includes/specials/SpecialRandomInCategory.php
@@ -70,15 +70,15 @@ class SpecialRandomInCategory extends FormSpecialPage {
protected function getFormFields() {
$this->addHelpLink( 'Help:RandomInCategory' );
- $form = array(
+ return array(
'category' => array(
- 'type' => 'text',
+ 'type' => 'title',
+ 'namespace' => NS_CATEGORY,
+ 'relative' => true,
'label-message' => 'randomincategory-category',
'required' => true,
)
);
-
- return $form;
}
public function requiresWrite() {
@@ -89,6 +89,14 @@ class SpecialRandomInCategory extends FormSpecialPage {
return false;
}
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
+ protected function alterForm( HTMLForm $form ) {
+ $form->setSubmitTextMsg( 'randomincategory-submit' );
+ }
+
protected function setParameter( $par ) {
// if subpage present, fake form submission
$this->onSubmit( array( 'category' => $par ) );
diff --git a/includes/specials/SpecialRandompage.php b/includes/specials/SpecialRandompage.php
index 73a88b9e..9f7ef669 100644
--- a/includes/specials/SpecialRandompage.php
+++ b/includes/specials/SpecialRandompage.php
@@ -135,20 +135,26 @@ class RandomPage extends SpecialPage {
protected function getQueryInfo( $randstr ) {
$redirect = $this->isRedirect() ? 1 : 0;
+ $tables = array( 'page' );
+ $conds = array_merge( array(
+ 'page_namespace' => $this->namespaces,
+ 'page_is_redirect' => $redirect,
+ 'page_random >= ' . $randstr
+ ), $this->extra );
+ $joinConds = array();
+
+ // Allow extensions to modify the query
+ Hooks::run( 'RandomPageQuery', array( &$tables, &$conds, &$joinConds ) );
return array(
- 'tables' => array( 'page' ),
+ 'tables' => $tables,
'fields' => array( 'page_title', 'page_namespace' ),
- 'conds' => array_merge( array(
- 'page_namespace' => $this->namespaces,
- 'page_is_redirect' => $redirect,
- 'page_random >= ' . $randstr
- ), $this->extra ),
+ 'conds' => $conds,
'options' => array(
'ORDER BY' => 'page_random',
'LIMIT' => 1,
),
- 'join_conds' => array()
+ 'join_conds' => $joinConds
);
}
diff --git a/includes/specials/SpecialRecentchanges.php b/includes/specials/SpecialRecentchanges.php
index 64b0ecae..0f201d52 100644
--- a/includes/specials/SpecialRecentchanges.php
+++ b/includes/specials/SpecialRecentchanges.php
@@ -57,6 +57,10 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
return;
}
+ $this->addHelpLink(
+ '//meta.wikimedia.org/wiki/Special:MyLanguage/Help:Recent_changes',
+ true
+ );
parent::execute( $subpage );
}
@@ -233,14 +237,21 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
return false;
}
- // rc_new is not an ENUM, but adding a redundant rc_new IN (0,1) gives mysql enough
- // knowledge to use an index merge if it wants (it may use some other index though).
+ // array_merge() is used intentionally here so that hooks can, should
+ // they so desire, override the ORDER BY / LIMIT condition(s); prior to
+ // MediaWiki 1.26 this used to use the plus operator instead, which meant
+ // that extensions weren't able to change these conditions
+ $query_options = array_merge( array(
+ 'ORDER BY' => 'rc_timestamp DESC',
+ 'LIMIT' => $opts['limit'] ), $query_options );
$rows = $dbr->select(
$tables,
$fields,
+ // rc_new is not an ENUM, but adding a redundant rc_new IN (0,1) gives mysql enough
+ // knowledge to use an index merge if it wants (it may use some other index though).
$conds + array( 'rc_new' => array( 0, 1 ) ),
__METHOD__,
- array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $opts['limit'] ) + $query_options,
+ $query_options,
$join_conds
);
@@ -263,6 +274,10 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
);
}
+ protected function getDB() {
+ return wfGetDB( DB_SLAVE, 'recentchanges' );
+ }
+
public function outputFeedLinks() {
$this->addFeedLinks( $this->getFeedQuery() );
}
@@ -272,7 +287,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
*
* @return array
*/
- private function getFeedQuery() {
+ protected function getFeedQuery() {
$query = array_filter( $this->getOptions()->getAllValues(), function ( $value ) {
// API handles empty parameters in a different way
return $value !== '';
diff --git a/includes/specials/SpecialRecentchangeslinked.php b/includes/specials/SpecialRecentchangeslinked.php
index 3ad9f0f4..3c403feb 100644
--- a/includes/specials/SpecialRecentchangeslinked.php
+++ b/includes/specials/SpecialRecentchangeslinked.php
@@ -244,6 +244,7 @@ class SpecialRecentChangesLinked extends SpecialRecentChanges {
Xml::check( 'showlinkedto', $opts['showlinkedto'], array( 'id' => 'showlinkedto' ) ) . ' ' .
Xml::label( $this->msg( 'recentchangeslinked-to' )->text(), 'showlinkedto' ) );
+ $this->addHelpLink( 'Help:Related changes' );
return $extraOpts;
}
diff --git a/includes/specials/SpecialResetTokens.php b/includes/specials/SpecialResetTokens.php
index ba2b9a5b..cba5a449 100644
--- a/includes/specials/SpecialResetTokens.php
+++ b/includes/specials/SpecialResetTokens.php
@@ -25,6 +25,7 @@
* Let users reset tokens like the watchlist token.
*
* @ingroup SpecialPage
+ * @deprecated 1.26
*/
class SpecialResetTokens extends FormSpecialPage {
private $tokensList;
@@ -123,6 +124,10 @@ class SpecialResetTokens extends FormSpecialPage {
}
}
+ protected function getDisplayFormat() {
+ return 'ooui';
+ }
+
public function onSubmit( array $formData ) {
if ( $formData['tokens'] ) {
$user = $this->getUser();
diff --git a/includes/specials/SpecialRevisiondelete.php b/includes/specials/SpecialRevisiondelete.php
index 3b5ef9d4..d1072b4e 100644
--- a/includes/specials/SpecialRevisiondelete.php
+++ b/includes/specials/SpecialRevisiondelete.php
@@ -110,6 +110,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
}
public function execute( $par ) {
+ $this->useTransactionalTimeLimit();
+
$this->checkPermissions();
$this->checkReadOnly();
@@ -158,6 +160,13 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
$this->ids
);
+ # We need a target page!
+ if ( $this->targetObj === null ) {
+ $output->addWikiMsg( 'undelete-header' );
+
+ return;
+ }
+
$this->typeLabels = self::$UILabels[$this->typeName];
$list = $this->getList();
$list->reset();
@@ -168,12 +177,6 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
$this->mIsAllowed = $this->mIsAllowed && !( $canViewSuppressedOnly && $pageIsSuppressed );
$this->otherReason = $request->getVal( 'wpReason' );
- # We need a target page!
- if ( is_null( $this->targetObj ) ) {
- $output->addWikiMsg( 'undelete-header' );
-
- return;
- }
# Give a link to the logs/hist for this page
$this->showConvenienceLinks();
@@ -449,9 +452,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
Xml::closeElement( 'form' ) . "\n";
// Show link to edit the dropdown reasons
if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
- $title = Title::makeTitle( NS_MEDIAWIKI, 'Revdelete-reason-dropdown' );
- $link = Linker::link(
- $title,
+ $link = Linker::linkKnown(
+ $this->msg( 'revdelete-reason-dropdown' )->inContentLanguage()->getTitle(),
$this->msg( 'revdelete-edit-reasonlist' )->escaped(),
array(),
array( 'action' => 'edit' )
@@ -585,7 +587,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
throw new PermissionsError( 'suppressrevision' );
}
# If the save went through, go to success message...
- $status = $this->save( $bitParams, $comment, $this->targetObj );
+ $status = $this->save( $bitParams, $comment );
if ( $status->isGood() ) {
$this->success();
@@ -605,7 +607,7 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
// Messages: revdelete-success, logdelete-success
$this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
$this->getOutput()->wrapWikiMsg(
- "<span class=\"success\">\n$1\n</span>",
+ "<div class=\"successbox\">\n$1\n</div>",
$this->typeLabels['success']
);
$this->wasSaved = true;
@@ -620,7 +622,10 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
protected function failure( $status ) {
// Messages: revdelete-failure, logdelete-failure
$this->getOutput()->setPageTitle( $this->msg( 'actionfailed' ) );
- $this->getOutput()->addWikiText( $status->getWikiText( $this->typeLabels['failure'] ) );
+ $this->getOutput()->addWikiText( '<div class="errorbox">' .
+ $status->getWikiText( $this->typeLabels['failure'] ) .
+ '</div>'
+ );
$this->showForm();
}
@@ -648,14 +653,13 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
/**
* Do the write operations. Simple wrapper for RevDel*List::setVisibility().
- * @param int $bitfield
+ * @param array $bitPars ExtractBitParams() bitfield array
* @param string $reason
- * @param Title $title
* @return Status
*/
- protected function save( $bitfield, $reason, $title ) {
+ protected function save( array $bitPars, $reason ) {
return $this->getList()->setVisibility(
- array( 'value' => $bitfield, 'comment' => $reason )
+ array( 'value' => $bitPars, 'comment' => $reason )
);
}
diff --git a/includes/specials/SpecialRunJobs.php b/includes/specials/SpecialRunJobs.php
index 8cf93670..286a7456 100644
--- a/includes/specials/SpecialRunJobs.php
+++ b/includes/specials/SpecialRunJobs.php
@@ -38,14 +38,14 @@ class SpecialRunJobs extends UnlistedSpecialPage {
$this->getOutput()->disable();
if ( wfReadOnly() ) {
- header( "HTTP/1.0 423 Locked" );
+ // HTTP 423 Locked
+ HttpStatus::header( 423 );
print 'Wiki is in read-only mode';
return;
} elseif ( !$this->getRequest()->wasPosted() ) {
- header( "HTTP/1.0 400 Bad Request" );
+ HttpStatus::header( 400 );
print 'Request must be POSTed';
-
return;
}
@@ -55,9 +55,8 @@ class SpecialRunJobs extends UnlistedSpecialPage {
$params = array_intersect_key( $this->getRequest()->getValues(), $required + $optional );
$missing = array_diff_key( $required, $params );
if ( count( $missing ) ) {
- header( "HTTP/1.0 400 Bad Request" );
+ HttpStatus::header( 400 );
print 'Missing parameters: ' . implode( ', ', array_keys( $missing ) );
-
return;
}
@@ -69,9 +68,8 @@ class SpecialRunJobs extends UnlistedSpecialPage {
$verified = is_string( $providedSignature )
&& hash_equals( $correctSignature, $providedSignature );
if ( !$verified || $params['sigexpiry'] < time() ) {
- header( "HTTP/1.0 400 Bad Request" );
+ HttpStatus::header( 400 );
print 'Invalid or stale signature provided';
-
return;
}
@@ -83,7 +81,8 @@ class SpecialRunJobs extends UnlistedSpecialPage {
// but it needs to know when it is safe to disconnect. Until this
// reaches ignore_user_abort(), it is not safe as the jobs won't run.
ignore_user_abort( true ); // jobs may take a bit of time
- header( "HTTP/1.0 202 Accepted" );
+ // HTTP 202 Accepted
+ HttpStatus::header( 202 );
ob_flush();
flush();
// Once the client receives this response, it can disconnect
diff --git a/includes/specials/SpecialSearch.php b/includes/specials/SpecialSearch.php
index 608d62e6..f50fb732 100644
--- a/includes/specials/SpecialSearch.php
+++ b/includes/specials/SpecialSearch.php
@@ -47,7 +47,10 @@ class SpecialSearch extends SpecialPage {
/** @var array For links */
protected $extraParams = array();
- /** @var string No idea, apparently used by some other classes */
+ /**
+ * @var string The prefix url parameter. Set on the searcher and the
+ * is expected to treat it as prefix filter on titles.
+ */
protected $mPrefix;
/**
@@ -65,6 +68,11 @@ class SpecialSearch extends SpecialPage {
*/
protected $fulltext;
+ /**
+ * @var bool
+ */
+ protected $runSuggestion = true;
+
const NAMESPACES_CURRENT = 'sense';
public function __construct() {
@@ -166,6 +174,7 @@ class SpecialSearch extends SpecialPage {
}
$this->fulltext = $request->getVal( 'fulltext' );
+ $this->runSuggestion = (bool)$request->getVal( 'runsuggestion', true );
$this->profile = $profile;
}
@@ -207,11 +216,11 @@ class SpecialSearch extends SpecialPage {
global $wgContLang;
$search = $this->getSearchEngine();
+ $search->setFeatureData( 'rewrite', $this->runSuggestion );
$search->setLimitOffset( $this->limit, $this->offset );
$search->setNamespaces( $this->namespaces );
$search->prefix = $this->mPrefix;
$term = $search->transformSearchTerm( $term );
- $didYouMeanHtml = '';
Hooks::run( 'SpecialSearchSetupEngine', array( $this, $this->profile, $search ) );
@@ -262,37 +271,13 @@ class SpecialSearch extends SpecialPage {
}
// did you mean... suggestions
- if ( $showSuggestion && $textMatches && !$textStatus && $textMatches->hasSuggestion() ) {
- # mirror Go/Search behavior of original request ..
- $didYouMeanParams = array( 'search' => $textMatches->getSuggestionQuery() );
-
- if ( $this->fulltext != null ) {
- $didYouMeanParams['fulltext'] = $this->fulltext;
- }
-
- $stParams = array_merge(
- $didYouMeanParams,
- $this->powerSearchOptions()
- );
-
- $suggestionSnippet = $textMatches->getSuggestionSnippet();
-
- if ( $suggestionSnippet == '' ) {
- $suggestionSnippet = null;
+ $didYouMeanHtml = '';
+ if ( $showSuggestion && $textMatches && !$textStatus ) {
+ if ( $textMatches->hasRewrittenQuery() ) {
+ $didYouMeanHtml = $this->getDidYouMeanRewrittenHtml( $term, $textMatches );
+ } elseif ( $textMatches->hasSuggestion() ) {
+ $didYouMeanHtml = $this->getDidYouMeanHtml( $textMatches );
}
-
- $suggestLink = Linker::linkKnown(
- $this->getPageTitle(),
- $suggestionSnippet,
- array(),
- $stParams
- );
-
- # html of did you mean... search suggestion link
- $didYouMeanHtml =
- Xml::openElement( 'div', array( 'class' => 'searchdidyoumean' ) ) .
- $this->msg( 'search-suggest' )->rawParams( $suggestLink )->text() .
- Xml::closeElement( 'div' );
}
if ( !Hooks::run( 'SpecialSearchResultsPrepend', array( $this, $out, $term ) ) ) {
@@ -381,14 +366,14 @@ class SpecialSearch extends SpecialPage {
$out->wrapWikiMsg( "==$1==\n", 'textmatches' );
}
- // show interwiki results if any
- if ( $textMatches->hasInterwikiResults() ) {
- $out->addHTML( $this->showInterwiki( $textMatches->getInterwikiResults(), $term ) );
- }
// show results
if ( $numTextMatches > 0 ) {
$out->addHTML( $this->showMatches( $textMatches ) );
}
+ // show interwiki results if any
+ if ( $textMatches->hasInterwikiResults() ) {
+ $out->addHTML( $this->showInterwiki( $textMatches->getInterwikiResults(), $term ) );
+ }
$textMatches->free();
}
@@ -402,11 +387,104 @@ class SpecialSearch extends SpecialPage {
$this->showCreateLink( $title, $num, $titleMatches, $textMatches );
}
}
- $out->addHtml( "</div>" );
+ $out->addHTML( '<div class="visualClear"></div>\n' );
if ( $prevnext ) {
$out->addHTML( "<p class='mw-search-pager-bottom'>{$prevnext}</p>\n" );
}
+
+ $out->addHtml( "</div>" );
+
+ Hooks::run( 'SpecialSearchResultsAppend', array( $this, $out ) );
+
+ }
+
+ /**
+ * Decide if the suggested query should be run, and it's results returned
+ * instead of the provided $textMatches
+ *
+ * @param SearchResultSet $textMatches The results of a users query
+ * @return bool
+ */
+ protected function shouldRunSuggestedQuery( SearchResultSet $textMatches ) {
+ if ( !$this->runSuggestion ||
+ !$textMatches->hasSuggestion() ||
+ $textMatches->numRows() > 0 ||
+ $textMatches->searchContainedSyntax()
+ ) {
+ return false;
+ }
+
+ return $this->getConfig()->get( 'SearchRunSuggestedQuery' );
+ }
+
+ /**
+ * Generates HTML shown to the user when we have a suggestion about a query
+ * that might give more results than their current query.
+ */
+ protected function getDidYouMeanHtml( SearchResultSet $textMatches ) {
+ # mirror Go/Search behavior of original request ..
+ $params = array( 'search' => $textMatches->getSuggestionQuery() );
+ if ( $this->fulltext != null ) {
+ $params['fulltext'] = $this->fulltext;
+ }
+ $stParams = array_merge( $params, $this->powerSearchOptions() );
+
+ $suggest = Linker::linkKnown(
+ $this->getPageTitle(),
+ $textMatches->getSuggestionSnippet() ?: null,
+ array(),
+ $stParams
+ );
+
+ # html of did you mean... search suggestion link
+ return Html::rawElement(
+ 'div',
+ array( 'class' => 'searchdidyoumean' ),
+ $this->msg( 'search-suggest' )->rawParams( $suggest )->parse()
+ );
+ }
+
+ /**
+ * Generates HTML shown to user when their query has been internally rewritten,
+ * and the results of the rewritten query are being returned.
+ *
+ * @param string $term The users search input
+ * @param SearchResultSet $textMatches The response to the users initial search request
+ * @return string HTML linking the user to their original $term query, and the one
+ * suggested by $textMatches.
+ */
+ protected function getDidYouMeanRewrittenHtml( $term, SearchResultSet $textMatches ) {
+ // Showing results for '$rewritten'
+ // Search instead for '$orig'
+
+ $params = array( 'search' => $textMatches->getQueryAfterRewrite() );
+ if ( $this->fulltext != null ) {
+ $params['fulltext'] = $this->fulltext;
+ }
+ $stParams = array_merge( $params, $this->powerSearchOptions() );
+
+ $rewritten = Linker::linkKnown(
+ $this->getPageTitle(),
+ $textMatches->getQueryAfterRewriteSnippet() ?: null,
+ array(),
+ $stParams
+ );
+
+ $stParams['search'] = $term;
+ $stParams['runsuggestion'] = 0;
+ $original = Linker::linkKnown(
+ $this->getPageTitle(),
+ htmlspecialchars( $term ),
+ array(),
+ $stParams
+ );
+
+ return Html::rawElement(
+ 'div',
+ array( 'class' => 'searchdidyoumean' ),
+ $this->msg( 'search-rewritten' )->rawParams( $rewritten, $original )->escaped()
+ );
}
/**
diff --git a/includes/specials/SpecialShortpages.php b/includes/specials/SpecialShortpages.php
index 7ec69e06..ba11862e 100644
--- a/includes/specials/SpecialShortpages.php
+++ b/includes/specials/SpecialShortpages.php
@@ -37,7 +37,7 @@ class ShortPagesPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'page' ),
'fields' => array(
diff --git a/includes/specials/SpecialSpecialpages.php b/includes/specials/SpecialSpecialpages.php
index eaa90072..cf3804e5 100644
--- a/includes/specials/SpecialSpecialpages.php
+++ b/includes/specials/SpecialSpecialpages.php
@@ -96,22 +96,14 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
$includesCachedPages = false;
foreach ( $groups as $group => $sortedPages ) {
- $total = count( $sortedPages );
- $middle = ceil( $total / 2 );
- $count = 0;
$out->wrapWikiMsg(
"<h2 class=\"mw-specialpagesgroup\" id=\"mw-specialpagesgroup-$group\">$1</h2>\n",
"specialpages-group-$group"
);
$out->addHTML(
- Html::openElement(
- 'table',
- array( 'style' => 'width:100%;', 'class' => 'mw-specialpages-table' )
- ) . "\n" .
- Html::openElement( 'tr' ) . "\n" .
- Html::openElement( 'td', array( 'style' => 'width:30%;vertical-align:top' ) ) . "\n" .
- Html::openElement( 'ul' ) . "\n"
+ Html::openElement( 'div', array( 'class' => 'mw-specialpages-list' ) )
+ . '<ul>'
);
foreach ( $sortedPages as $desc => $specialpage ) {
list( $title, $restricted, $cached ) = $specialpage;
@@ -132,21 +124,10 @@ class SpecialSpecialpages extends UnlistedSpecialPage {
array( 'class' => implode( ' ', $pageClasses ) ),
$link
) . "\n" );
-
- # Split up the larger groups
- $count++;
- if ( $total > 3 && $count == $middle ) {
- $out->addHTML(
- Html::closeElement( 'ul' ) . Html::closeElement( 'td' ) .
- Html::element( 'td', array( 'style' => 'width:10%' ), '' ) .
- Html::openElement( 'td', array( 'style' => 'width:30%' ) ) . Html::openElement( 'ul' ) . "\n"
- );
- }
}
$out->addHTML(
- Html::closeElement( 'ul' ) . Html::closeElement( 'td' ) .
- Html::element( 'td', array( 'style' => 'width:30%' ), '' ) .
- Html::closeElement( 'tr' ) . Html::closeElement( 'table' ) . "\n"
+ Html::closeElement( 'ul' ) .
+ Html::closeElement( 'div' )
);
}
diff --git a/includes/specials/SpecialStatistics.php b/includes/specials/SpecialStatistics.php
index c35de241..8de6f8b8 100644
--- a/includes/specials/SpecialStatistics.php
+++ b/includes/specials/SpecialStatistics.php
@@ -107,10 +107,11 @@ class SpecialStatistics extends SpecialPage {
) {
if ( $descMsg ) {
$msg = $this->msg( $descMsg, $descMsgParam );
- if ( $msg->exists() ) {
- $descriptionText = $this->msg( 'parentheses' )->rawParams( $msg->parse() )->escaped();
- $text .= "<br />" . Xml::element( 'small', array( 'class' => 'mw-statistic-desc' ),
- " $descriptionText" );
+ if ( !$msg->isDisabled() ) {
+ $descriptionHtml = $this->msg( 'parentheses' )->rawParams( $msg->parse() )
+ ->escaped();
+ $text .= "<br />" . Html::rawElement( 'small', array( 'class' => 'mw-statistic-desc' ),
+ " $descriptionHtml" );
}
}
@@ -126,26 +127,36 @@ class SpecialStatistics extends SpecialPage {
* @return string
*/
private function getPageStats() {
- return Xml::openElement( 'tr' ) .
- Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-pages' )->parse() ) .
+ $pageStatsHtml = Xml::openElement( 'tr' ) .
+ Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-pages' )
+ ->parse() ) .
Xml::closeElement( 'tr' ) .
$this->formatRow( Linker::linkKnown( SpecialPage::getTitleFor( 'Allpages' ),
$this->msg( 'statistics-articles' )->parse() ),
$this->getLanguage()->formatNum( $this->good ),
- array( 'class' => 'mw-statistics-articles' ) ) .
+ array( 'class' => 'mw-statistics-articles' ),
+ 'statistics-articles-desc' ) .
$this->formatRow( $this->msg( 'statistics-pages' )->parse(),
$this->getLanguage()->formatNum( $this->total ),
array( 'class' => 'mw-statistics-pages' ),
- 'statistics-pages-desc' ) .
- $this->formatRow( Linker::linkKnown( SpecialPage::getTitleFor( 'MediaStatistics' ),
- $this->msg( 'statistics-files' )->parse() ),
- $this->getLanguage()->formatNum( $this->images ),
- array( 'class' => 'mw-statistics-files' ) );
+ 'statistics-pages-desc' );
+
+ // Show the image row only, when there are files or upload is possible
+ if ( $this->images !== 0 || $this->getConfig()->get( 'EnableUploads' ) ) {
+ $pageStatsHtml .= $this->formatRow(
+ Linker::linkKnown( SpecialPage::getTitleFor( 'MediaStatistics' ),
+ $this->msg( 'statistics-files' )->parse() ),
+ $this->getLanguage()->formatNum( $this->images ),
+ array( 'class' => 'mw-statistics-files' ) );
+ }
+
+ return $pageStatsHtml;
}
private function getEditStats() {
return Xml::openElement( 'tr' ) .
- Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-edits' )->parse() ) .
+ Xml::tags( 'th', array( 'colspan' => '2' ),
+ $this->msg( 'statistics-header-edits' )->parse() ) .
Xml::closeElement( 'tr' ) .
$this->formatRow( $this->msg( 'statistics-edits' )->parse(),
$this->getLanguage()->formatNum( $this->edits ),
@@ -160,7 +171,8 @@ class SpecialStatistics extends SpecialPage {
private function getUserStats() {
return Xml::openElement( 'tr' ) .
- Xml::tags( 'th', array( 'colspan' => '2' ), $this->msg( 'statistics-header-users' )->parse() ) .
+ Xml::tags( 'th', array( 'colspan' => '2' ),
+ $this->msg( 'statistics-header-users' )->parse() ) .
Xml::closeElement( 'tr' ) .
$this->formatRow( $this->msg( 'statistics-users' )->parse(),
$this->getLanguage()->formatNum( $this->users ),
@@ -223,7 +235,8 @@ class SpecialStatistics extends SpecialPage {
}
$text .= $this->formatRow( $grouppage . ' ' . $grouplink,
$this->getLanguage()->formatNum( $countUsers ),
- array( 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) . $classZero ) );
+ array( 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) .
+ $classZero ) );
}
return $text;
diff --git a/includes/specials/SpecialTags.php b/includes/specials/SpecialTags.php
index 0b8147e1..70eee9f0 100644
--- a/includes/specials/SpecialTags.php
+++ b/includes/specials/SpecialTags.php
@@ -27,14 +27,21 @@
* @ingroup SpecialPage
*/
class SpecialTags extends SpecialPage {
+
/**
- * @var array List of defined tags
+ * @var array List of explicitly defined tags
*/
- public $definedTags;
+ protected $explicitlyDefinedTags;
+
/**
- * @var array List of active tags
+ * @var array List of extension defined tags
*/
- public $activeTags;
+ protected $extensionDefinedTags;
+
+ /**
+ * @var array List of extension activated tags
+ */
+ protected $extensionActivatedTags;
function __construct() {
parent::__construct( 'Tags' );
@@ -69,9 +76,11 @@ class SpecialTags extends SpecialPage {
$out->wrapWikiMsg( "<div class='mw-tags-intro'>\n$1\n</div>", 'tags-intro' );
$user = $this->getUser();
+ $userCanManage = $user->isAllowed( 'managechangetags' );
+ $userCanEditInterface = $user->isAllowed( 'editinterface' );
// Show form to create a tag
- if ( $user->isAllowed( 'managechangetags' ) ) {
+ if ( $userCanManage ) {
$fields = array(
'Tag' => array(
'type' => 'text',
@@ -108,40 +117,50 @@ class SpecialTags extends SpecialPage {
}
}
- // Whether to show the "Actions" column in the tag list
- // If any actions added in the future require other user rights, add those
- // rights here
- $showActions = $user->isAllowed( 'managechangetags' );
+ // Used to get hitcounts for #doTagRow()
+ $tagStats = ChangeTags::tagUsageStatistics();
- // Write the headers
- $tagUsageStatistics = ChangeTags::tagUsageStatistics();
+ // Used in #doTagRow()
+ $this->explicitlyDefinedTags = array_fill_keys(
+ ChangeTags::listExplicitlyDefinedTags(), true );
+ $this->extensionDefinedTags = array_fill_keys(
+ ChangeTags::listExtensionDefinedTags(), true );
+
+ // List all defined tags, even if they were never applied
+ $definedTags = array_keys( array_merge(
+ $this->explicitlyDefinedTags, $this->extensionDefinedTags ) );
// Show header only if there exists atleast one tag
- if ( !$tagUsageStatistics ) {
+ if ( !$tagStats && !$definedTags ) {
return;
}
+
+ // Write the headers
$html = Xml::tags( 'tr', null, Xml::tags( 'th', null, $this->msg( 'tags-tag' )->parse() ) .
Xml::tags( 'th', null, $this->msg( 'tags-display-header' )->parse() ) .
Xml::tags( 'th', null, $this->msg( 'tags-description-header' )->parse() ) .
Xml::tags( 'th', null, $this->msg( 'tags-source-header' )->parse() ) .
Xml::tags( 'th', null, $this->msg( 'tags-active-header' )->parse() ) .
Xml::tags( 'th', null, $this->msg( 'tags-hitcount-header' )->parse() ) .
- ( $showActions ?
+ ( $userCanManage ?
Xml::tags( 'th', array( 'class' => 'unsortable' ),
$this->msg( 'tags-actions-header' )->parse() ) :
'' )
);
// Used in #doTagRow()
- $this->explicitlyDefinedTags = array_fill_keys(
- ChangeTags::listExplicitlyDefinedTags(), true );
- $this->extensionDefinedTags = array_fill_keys(
- ChangeTags::listExtensionDefinedTags(), true );
$this->extensionActivatedTags = array_fill_keys(
ChangeTags::listExtensionActivatedTags(), true );
- foreach ( $tagUsageStatistics as $tag => $hitcount ) {
- $html .= $this->doTagRow( $tag, $hitcount, $showActions );
+ // Insert tags that have been applied at least once
+ foreach ( $tagStats as $tag => $hitcount ) {
+ $html .= $this->doTagRow( $tag, $hitcount, $userCanManage, $userCanEditInterface );
+ }
+ // Insert tags defined somewhere but never applied
+ foreach ( $definedTags as $tag ) {
+ if ( !isset( $tagStats[$tag] ) ) {
+ $html .= $this->doTagRow( $tag, 0, $userCanManage, $userCanEditInterface );
+ }
}
$out->addHTML( Xml::tags(
@@ -151,16 +170,15 @@ class SpecialTags extends SpecialPage {
) );
}
- function doTagRow( $tag, $hitcount, $showActions ) {
- $user = $this->getUser();
+ function doTagRow( $tag, $hitcount, $showActions, $showEditLinks ) {
$newRow = '';
$newRow .= Xml::tags( 'td', null, Xml::element( 'code', null, $tag ) );
$disp = ChangeTags::tagDescription( $tag );
- if ( $user->isAllowed( 'editinterface' ) ) {
+ if ( $showEditLinks ) {
$disp .= ' ';
$editLink = Linker::link(
- Title::makeTitle( NS_MEDIAWIKI, "Tag-$tag" ),
+ $this->msg( "tag-$tag" )->inContentLanguage()->getTitle(),
$this->msg( 'tags-edit' )->escaped()
);
$disp .= $this->msg( 'parentheses' )->rawParams( $editLink )->escaped();
@@ -169,10 +187,10 @@ class SpecialTags extends SpecialPage {
$msg = $this->msg( "tag-$tag-description" );
$desc = !$msg->exists() ? '' : $msg->parse();
- if ( $user->isAllowed( 'editinterface' ) ) {
+ if ( $showEditLinks ) {
$desc .= ' ';
$editDescLink = Linker::link(
- Title::makeTitle( NS_MEDIAWIKI, "Tag-$tag-description" ),
+ $this->msg( "tag-$tag-description" )->inContentLanguage()->getTitle(),
$this->msg( 'tags-edit' )->escaped()
);
$desc .= $this->msg( 'parentheses' )->rawParams( $editDescLink )->escaped();
@@ -198,21 +216,24 @@ class SpecialTags extends SpecialPage {
$newRow .= Xml::tags( 'td', null, $this->msg( $activeMsg )->escaped() );
$hitcountLabel = $this->msg( 'tags-hitcount' )->numParams( $hitcount )->escaped();
- $hitcountLink = Linker::link(
- SpecialPage::getTitleFor( 'Recentchanges' ),
- $hitcountLabel,
- array(),
- array( 'tagfilter' => $tag )
- );
+ if ( $this->getConfig()->get( 'UseTagFilter' ) ) {
+ $hitcountLabel = Linker::link(
+ SpecialPage::getTitleFor( 'Recentchanges' ),
+ $hitcountLabel,
+ array(),
+ array( 'tagfilter' => $tag )
+ );
+ }
// add raw $hitcount for sorting, because tags-hitcount contains numbers and letters
- $newRow .= Xml::tags( 'td', array( 'data-sort-value' => $hitcount ), $hitcountLink );
+ $newRow .= Xml::tags( 'td', array( 'data-sort-value' => $hitcount ), $hitcountLabel );
// actions
- $actionLinks = array();
- if ( $showActions ) {
+ if ( $showActions ) { // we've already checked that the user had the requisite userright
+ $actionLinks = array();
+
// delete
- if ( ChangeTags::canDeleteTag( $tag, $user )->isOK() ) {
+ if ( ChangeTags::canDeleteTag( $tag )->isOK() ) {
$actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'delete' ),
$this->msg( 'tags-delete' )->escaped(),
array(),
@@ -220,7 +241,7 @@ class SpecialTags extends SpecialPage {
}
// activate
- if ( ChangeTags::canActivateTag( $tag, $user )->isOK() ) {
+ if ( ChangeTags::canActivateTag( $tag )->isOK() ) {
$actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'activate' ),
$this->msg( 'tags-activate' )->escaped(),
array(),
@@ -228,7 +249,7 @@ class SpecialTags extends SpecialPage {
}
// deactivate
- if ( ChangeTags::canDeactivateTag( $tag, $user )->isOK() ) {
+ if ( ChangeTags::canDeactivateTag( $tag )->isOK() ) {
$actionLinks[] = Linker::linkKnown( $this->getPageTitle( 'deactivate' ),
$this->msg( 'tags-deactivate' )->escaped(),
array(),
@@ -318,7 +339,7 @@ class SpecialTags extends SpecialPage {
$preText = $this->msg( 'tags-delete-explanation-initial', $tag )->parseAsBlock();
$tagUsage = ChangeTags::tagUsageStatistics();
- if ( $tagUsage[$tag] > 0 ) {
+ if ( isset( $tagUsage[$tag] ) && $tagUsage[$tag] > 0 ) {
$preText .= $this->msg( 'tags-delete-explanation-in-use', $tag,
$tagUsage[$tag] )->parseAsBlock();
}
diff --git a/includes/specials/SpecialUndelete.php b/includes/specials/SpecialUndelete.php
index f2362a18..a66a3d10 100644
--- a/includes/specials/SpecialUndelete.php
+++ b/includes/specials/SpecialUndelete.php
@@ -149,7 +149,8 @@ class PageArchive {
$fields,
$conds,
$join_conds,
- $options
+ $options,
+ ''
);
return $dbr->select( $tables,
@@ -756,8 +757,8 @@ class SpecialUndelete extends SpecialPage {
* @param User $user
* @return bool
*/
- private function isAllowed( $permission, User $user = null ) {
- $user = $user ? : $this->getUser();
+ protected function isAllowed( $permission, User $user = null ) {
+ $user = $user ?: $this->getUser();
if ( $this->mTargetObj !== null ) {
return $this->mTargetObj->userCan( $permission, $user );
} else {
@@ -770,6 +771,8 @@ class SpecialUndelete extends SpecialPage {
}
function execute( $par ) {
+ $this->useTransactionalTimeLimit();
+
$user = $this->getUser();
$this->setHeaders();
@@ -998,7 +1001,7 @@ class SpecialUndelete extends SpecialPage {
return;
}
- if ( $this->mPreview || !$isText ) {
+ if ( ( $this->mPreview || !$isText ) && $content ) {
// NOTE: non-text content has no source view, so always use rendered preview
// Hide [edit]s
@@ -1206,7 +1209,7 @@ class SpecialUndelete extends SpecialPage {
$repo->streamFile( $path );
}
- private function showHistory() {
+ protected function showHistory() {
$out = $this->getOutput();
if ( $this->mAllowed ) {
$out->addModules( 'mediawiki.special.undelete' );
@@ -1377,7 +1380,7 @@ class SpecialUndelete extends SpecialPage {
return true;
}
- private function formatRevisionRow( $row, $earliestLiveTime, $remaining ) {
+ protected function formatRevisionRow( $row, $earliestLiveTime, $remaining ) {
$rev = Revision::newFromArchiveRow( $row,
array(
'title' => $this->mTargetObj
diff --git a/includes/specials/SpecialUnlockdb.php b/includes/specials/SpecialUnlockdb.php
index a8b97d78..dc03a4a7 100644
--- a/includes/specials/SpecialUnlockdb.php
+++ b/includes/specials/SpecialUnlockdb.php
@@ -65,9 +65,9 @@ class SpecialUnlockdb extends FormSpecialPage {
}
$readOnlyFile = $this->getConfig()->get( 'ReadOnlyFile' );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$res = unlink( $readOnlyFile );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $res ) {
return Status::newGood();
diff --git a/includes/specials/SpecialUnusedcategories.php b/includes/specials/SpecialUnusedcategories.php
index 713823bb..0d3216cd 100644
--- a/includes/specials/SpecialUnusedcategories.php
+++ b/includes/specials/SpecialUnusedcategories.php
@@ -29,7 +29,7 @@ class UnusedCategoriesPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -37,7 +37,7 @@ class UnusedCategoriesPage extends QueryPage {
return $this->msg( 'unusedcategoriestext' )->parseAsBlock();
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'page', 'categorylinks' ),
'fields' => array(
diff --git a/includes/specials/SpecialUnusedtemplates.php b/includes/specials/SpecialUnusedtemplates.php
index 0c2b8707..33444f63 100644
--- a/includes/specials/SpecialUnusedtemplates.php
+++ b/includes/specials/SpecialUnusedtemplates.php
@@ -34,7 +34,7 @@ class UnusedtemplatesPage extends QueryPage {
parent::__construct( $name );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -46,7 +46,7 @@ class UnusedtemplatesPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'page', 'templatelinks' ),
'fields' => array(
diff --git a/includes/specials/SpecialUnwatchedpages.php b/includes/specials/SpecialUnwatchedpages.php
index bb07c197..b3ca006c 100644
--- a/includes/specials/SpecialUnwatchedpages.php
+++ b/includes/specials/SpecialUnwatchedpages.php
@@ -35,7 +35,7 @@ class UnwatchedpagesPage extends QueryPage {
parent::__construct( $name, 'unwatchedpages' );
}
- function isExpensive() {
+ public function isExpensive() {
return true;
}
@@ -43,7 +43,7 @@ class UnwatchedpagesPage extends QueryPage {
return false;
}
- function getQueryInfo() {
+ public function getQueryInfo() {
return array(
'tables' => array( 'page', 'watchlist' ),
'fields' => array(
diff --git a/includes/specials/SpecialUpload.php b/includes/specials/SpecialUpload.php
index 2e0699af..16f4d161 100644
--- a/includes/specials/SpecialUpload.php
+++ b/includes/specials/SpecialUpload.php
@@ -152,6 +152,8 @@ class SpecialUpload extends SpecialPage {
* @throws UserBlockedError
*/
public function execute( $par ) {
+ $this->useTransactionalTimeLimit();
+
$this->setHeaders();
$this->outputHeader();
@@ -357,7 +359,7 @@ class SpecialUpload extends SpecialPage {
$sessionKey = $this->mUpload->stashSession();
$warningHtml = '<h2>' . $this->msg( 'uploadwarning' )->escaped() . "</h2>\n"
- . '<ul class="warning">';
+ . '<div class="warningbox"><ul>';
foreach ( $warnings as $warning => $args ) {
if ( $warning == 'badfilename' ) {
$this->mDesiredDestName = Title::makeTitle( NS_FILE, $args )->getText();
@@ -385,7 +387,7 @@ class SpecialUpload extends SpecialPage {
}
$warningHtml .= $msg;
}
- $warningHtml .= "</ul>\n";
+ $warningHtml .= "</ul></div>\n";
$warningHtml .= $this->msg( 'uploadwarning-text' )->parseAsBlock();
$form = $this->getUploadForm( $warningHtml, $sessionKey, /* $hideIgnoreWarning */ true );
@@ -795,6 +797,10 @@ class UploadForm extends HTMLForm {
protected $mMaxUploadSize = array();
public function __construct( array $options = array(), IContextSource $context = null ) {
+ if ( $context instanceof IContextSource ) {
+ $this->setContext( $context );
+ }
+
$this->mWatch = !empty( $options['watch'] );
$this->mForReUpload = !empty( $options['forreupload'] );
$this->mSessionKey = isset( $options['sessionkey'] ) ? $options['sessionkey'] : '';
@@ -821,8 +827,8 @@ class UploadForm extends HTMLForm {
# Add a link to edit MediaWik:Licenses
if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
- $licensesLink = Linker::link(
- Title::makeTitle( NS_MEDIAWIKI, 'Licenses' ),
+ $licensesLink = Linker::linkKnown(
+ $this->msg( 'licenses' )->inContentLanguage()->getTitle(),
$this->msg( 'licenses-edit' )->escaped(),
array(),
array( 'action' => 'edit' )
diff --git a/includes/specials/SpecialUploadStash.php b/includes/specials/SpecialUploadStash.php
index 12e103e7..dd905900 100644
--- a/includes/specials/SpecialUploadStash.php
+++ b/includes/specials/SpecialUploadStash.php
@@ -58,6 +58,8 @@ class SpecialUploadStash extends UnlistedSpecialPage {
* @return bool Success
*/
public function execute( $subPage ) {
+ $this->useTransactionalTimeLimit();
+
$this->stash = RepoGroup::singleton()->getLocalRepo()->getUploadStash( $this->getUser() );
$this->checkPermissions();
@@ -226,7 +228,7 @@ class SpecialUploadStash extends UnlistedSpecialPage {
*/
private function outputRemoteScaledThumb( $file, $params, $flags ) {
// This option probably looks something like
- // 'http://upload.wikimedia.org/wikipedia/test/thumb/temp'. Do not use
+ // '//upload.wikimedia.org/wikipedia/test/thumb/temp'. Do not use
// trailing slash.
$scalerBaseUrl = $this->getConfig()->get( 'UploadStashScalerBaseUrl' );
diff --git a/includes/specials/SpecialUserlogin.php b/includes/specials/SpecialUserlogin.php
index 10edbcfb..21f1194f 100644
--- a/includes/specials/SpecialUserlogin.php
+++ b/includes/specials/SpecialUserlogin.php
@@ -20,6 +20,7 @@
* @file
* @ingroup SpecialPage
*/
+use MediaWiki\Logger\LoggerFactory;
/**
* Implements Special:UserLogin
@@ -43,6 +44,24 @@ class LoginForm extends SpecialPage {
const WRONG_TOKEN = 13;
const USER_MIGRATED = 14;
+ public static $statusCodes = array(
+ self::SUCCESS => 'success',
+ self::NO_NAME => 'no_name',
+ self::ILLEGAL => 'illegal',
+ self::WRONG_PLUGIN_PASS => 'wrong_plugin_pass',
+ self::NOT_EXISTS => 'not_exists',
+ self::WRONG_PASS => 'wrong_pass',
+ self::EMPTY_PASS => 'empty_pass',
+ self::RESET_PASS => 'reset_pass',
+ self::ABORTED => 'aborted',
+ self::CREATE_BLOCKED => 'create_blocked',
+ self::THROTTLED => 'throttled',
+ self::USER_BLOCKED => 'user_blocked',
+ self::NEED_TOKEN => 'need_token',
+ self::WRONG_TOKEN => 'wrong_token',
+ self::USER_MIGRATED => 'user_migrated',
+ );
+
/**
* Valid error and warning messages
*
@@ -194,13 +213,13 @@ class LoginForm extends SpecialPage {
&& in_array( $entryError->getKey(), self::getValidErrorMessages() )
) {
$this->mEntryErrorType = 'error';
- $this->mEntryError = $entryError->rawParams( $loginreqlink )->escaped();
+ $this->mEntryError = $entryError->rawParams( $loginreqlink )->parse();
} elseif ( $entryWarning->exists()
&& in_array( $entryWarning->getKey(), self::getValidErrorMessages() )
) {
$this->mEntryErrorType = 'warning';
- $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->escaped();
+ $this->mEntryError = $entryWarning->rawParams( $loginreqlink )->parse();
}
if ( $wgEnableEmail ) {
@@ -338,6 +357,10 @@ class LoginForm extends SpecialPage {
}
$status = $this->addNewAccountInternal();
+ LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt with mailed password', array(
+ 'event' => 'accountcreation',
+ 'status' => $status,
+ ) );
if ( !$status->isGood() ) {
$error = $status->getMessage();
$this->mainLoginForm( $error->toString() );
@@ -375,6 +398,11 @@ class LoginForm extends SpecialPage {
# Create the account and abort if there's a problem doing so
$status = $this->addNewAccountInternal();
+ LoggerFactory::getInstance( 'authmanager' )->info( 'Account creation attempt', array(
+ 'event' => 'accountcreation',
+ 'status' => $status,
+ ) );
+
if ( !$status->isGood() ) {
$error = $status->getMessage();
$this->mainLoginForm( $error->toString() );
@@ -453,8 +481,7 @@ class LoginForm extends SpecialPage {
* @return Status
*/
public function addNewAccountInternal() {
- global $wgAuth, $wgMemc, $wgAccountCreationThrottle,
- $wgMinimalPasswordLength, $wgEmailConfirmToEdit;
+ global $wgAuth, $wgMemc, $wgAccountCreationThrottle, $wgEmailConfirmToEdit;
// If the user passes an invalid domain, something is fishy
if ( !$wgAuth->validDomain( $this->mDomain ) ) {
@@ -530,9 +557,15 @@ class LoginForm extends SpecialPage {
# Now create a dummy user ($u) and check if it is valid
$u = User::newFromName( $this->mUsername, 'creatable' );
- if ( !is_object( $u ) ) {
+ if ( !$u ) {
return Status::newFatal( 'noname' );
- } elseif ( 0 != $u->idForName() ) {
+ }
+
+ # Make sure the user does not exist already
+ $lock = $wgMemc->getScopedLock( wfGlobalCacheKey( 'account', md5( $this->mUsername ) ) );
+ if ( !$lock ) {
+ return Status::newFatal( 'usernameinprogress' );
+ } elseif ( $u->idForName( User::READ_LOCKING ) ) {
return Status::newFatal( 'userexists' );
}
@@ -546,7 +579,7 @@ class LoginForm extends SpecialPage {
}
# check for password validity, return a fatal Status if invalid
- $validity = $u->checkPasswordValidity( $this->mPassword );
+ $validity = $u->checkPasswordValidity( $this->mPassword, 'create' );
if ( !$validity->isGood() ) {
$validity->ok = false; // make sure this Status is fatal
return $validity;
@@ -641,7 +674,12 @@ class LoginForm extends SpecialPage {
$u->setRealName( $this->mRealName );
$u->setToken();
+ Hooks::run( 'LocalUserCreated', array( $u, $autocreate ) );
+ $oldUser = $u;
$wgAuth->initUser( $u, $autocreate );
+ if ( $oldUser !== $u ) {
+ wfWarn( get_class( $wgAuth ) . '::initUser() replaced the user object' );
+ }
$u->saveSettings();
@@ -710,7 +748,11 @@ class LoginForm extends SpecialPage {
}
$u = User::newFromName( $this->mUsername );
+ if ( $u === false ) {
+ return self::ILLEGAL;
+ }
+ $msg = null;
// Give extensions a way to indicate the username has been updated,
// rather than telling the user the account doesn't exist.
if ( !Hooks::run( 'LoginUserMigrated', array( $u, &$msg ) ) ) {
@@ -718,7 +760,7 @@ class LoginForm extends SpecialPage {
return self::USER_MIGRATED;
}
- if ( !( $u instanceof User ) || !User::isUsableName( $u->getName() ) ) {
+ if ( !User::isUsableName( $u->getName() ) ) {
return self::ILLEGAL;
}
@@ -736,7 +778,6 @@ class LoginForm extends SpecialPage {
// Give general extensions, such as a captcha, a chance to abort logins
$abort = self::ABORTED;
- $msg = null;
if ( !Hooks::run( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$msg ) ) ) {
$this->mAbortLoginErrorMsg = $msg;
@@ -784,7 +825,12 @@ class LoginForm extends SpecialPage {
$retval = self::RESET_PASS;
$this->mAbortLoginErrorMsg = 'resetpass-expired';
} else {
+ Hooks::run( 'UserLoggedIn', array( $u ) );
+ $oldUser = $u;
$wgAuth->updateUser( $u );
+ if ( $oldUser !== $u ) {
+ wfWarn( get_class( $wgAuth ) . '::updateUser() replaced the user object' );
+ }
$wgUser = $u;
// This should set it for OutputPage and the Skin
// which is needed or the personal links will be
@@ -909,7 +955,8 @@ class LoginForm extends SpecialPage {
global $wgMemc, $wgLang, $wgSecureLogin, $wgPasswordAttemptThrottle,
$wgInvalidPasswordReset;
- switch ( $this->authenticateUserData() ) {
+ $authRes = $this->authenticateUserData();
+ switch ( $authRes ) {
case self::SUCCESS:
# We've verified now, update the real record
$user = $this->getUser();
@@ -946,7 +993,10 @@ class LoginForm extends SpecialPage {
} elseif ( $wgInvalidPasswordReset
&& !$user->isValidPassword( $this->mPassword )
) {
- $status = $user->checkPasswordValidity( $this->mPassword );
+ $status = $user->checkPasswordValidity(
+ $this->mPassword,
+ 'login'
+ );
$this->resetLoginForm(
$status->getMessage( 'resetpass-validity-soft' )
);
@@ -1029,6 +1079,12 @@ class LoginForm extends SpecialPage {
default:
throw new MWException( 'Unhandled case value' );
}
+
+ LoggerFactory::getInstance( 'authmanager' )->info( 'Login attempt', array(
+ 'event' => 'login',
+ 'successful' => $authRes === self::SUCCESS,
+ 'status' => LoginForm::$statusCodes[$authRes],
+ ) );
}
/**
@@ -1280,8 +1336,9 @@ class LoginForm extends SpecialPage {
function mainLoginForm( $msg, $msgtype = 'error' ) {
global $wgEnableEmail, $wgEnableUserEmail;
global $wgHiddenPrefs, $wgLoginLanguageSelector;
- global $wgAuth, $wgEmailConfirmToEdit, $wgCookieExpiration;
+ global $wgAuth, $wgEmailConfirmToEdit;
global $wgSecureLogin, $wgPasswordResetRoutes;
+ global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
$titleObj = $this->getPageTitle();
$user = $this->getUser();
@@ -1320,9 +1377,6 @@ class LoginForm extends SpecialPage {
'mediawiki.ui.input',
'mediawiki.special.userlogin.common.styles'
) );
- $out->addModules( array(
- 'mediawiki.special.userlogin.common.js'
- ) );
if ( $this->mType == 'signup' ) {
// XXX hack pending RL or JS parse() support for complex content messages
@@ -1384,6 +1438,7 @@ class LoginForm extends SpecialPage {
: is_array( $wgPasswordResetRoutes ) && in_array( true, array_values( $wgPasswordResetRoutes ) );
$template->set( 'header', '' );
+ $template->set( 'formheader', '' );
$template->set( 'skin', $this->getSkin() );
$template->set( 'name', $this->mUsername );
$template->set( 'password', $this->mPassword );
@@ -1404,7 +1459,7 @@ class LoginForm extends SpecialPage {
$template->set( 'emailothers', $wgEnableUserEmail );
$template->set( 'canreset', $wgAuth->allowPasswordChange() );
$template->set( 'resetlink', $resetLink );
- $template->set( 'canremember', ( $wgCookieExpiration > 0 ) );
+ $template->set( 'canremember', $wgExtendedLoginCookieExpiration === null ? ( $wgCookieExpiration > 0 ) : ( $wgExtendedLoginCookieExpiration > 0 ) );
$template->set( 'usereason', $user->isLoggedIn() );
$template->set( 'remember', $this->mRemember );
$template->set( 'cansecurelogin', ( $wgSecureLogin === true ) );
@@ -1526,7 +1581,6 @@ class LoginForm extends SpecialPage {
*/
public static function getCreateaccountToken() {
global $wgRequest;
-
return $wgRequest->getSessionData( 'wsCreateaccountToken' );
}
@@ -1601,22 +1655,21 @@ class LoginForm extends SpecialPage {
*/
function makeLanguageSelector() {
$msg = $this->msg( 'loginlanguagelinks' )->inContentLanguage();
- if ( !$msg->isBlank() ) {
- $langs = explode( "\n", $msg->text() );
- $links = array();
- foreach ( $langs as $lang ) {
- $lang = trim( $lang, '* ' );
- $parts = explode( '|', $lang );
- if ( count( $parts ) >= 2 ) {
- $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
- }
- }
-
- return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams(
- $this->getLanguage()->pipeList( $links ) )->escaped() : '';
- } else {
+ if ( $msg->isBlank() ) {
return '';
}
+ $langs = explode( "\n", $msg->text() );
+ $links = array();
+ foreach ( $langs as $lang ) {
+ $lang = trim( $lang, '* ' );
+ $parts = explode( '|', $lang );
+ if ( count( $parts ) >= 2 ) {
+ $links[] = $this->makeLanguageSelectorLink( $parts[0], trim( $parts[1] ) );
+ }
+ }
+
+ return count( $links ) > 0 ? $this->msg( 'loginlanguagelabel' )->rawParams(
+ $this->getLanguage()->pipeList( $links ) )->escaped() : '';
}
/**
diff --git a/includes/specials/SpecialUserrights.php b/includes/specials/SpecialUserrights.php
index 758e3c05..e91c0bde 100644
--- a/includes/specials/SpecialUserrights.php
+++ b/includes/specials/SpecialUserrights.php
@@ -106,7 +106,7 @@ class UserrightsPage extends SpecialPage {
}
}
- if ( User::getCanonicalName( $this->mTarget ) === $user->getName() ) {
+ if ( $this->mTarget !== null && User::getCanonicalName( $this->mTarget ) === $user->getName() ) {
$this->isself = true;
}
@@ -145,6 +145,7 @@ class UserrightsPage extends SpecialPage {
if (
$request->wasPosted() &&
$request->getCheck( 'saveusergroups' ) &&
+ $this->mTarget !== null &&
$user->matchEditToken( $request->getVal( 'wpEditToken' ), $this->mTarget )
) {
// save settings
@@ -249,7 +250,7 @@ class UserrightsPage extends SpecialPage {
if ( $remove ) {
foreach ( $remove as $index => $group ) {
if ( !$user->removeGroup( $group ) ) {
- unset($remove[$index]);
+ unset( $remove[$index] );
}
}
$newGroups = array_diff( $newGroups, $remove );
@@ -257,7 +258,7 @@ class UserrightsPage extends SpecialPage {
if ( $add ) {
foreach ( $add as $index => $group ) {
if ( !$user->addGroup( $group ) ) {
- unset($add[$index]);
+ unset( $add[$index] );
}
}
$newGroups = array_merge( $newGroups, $add );
@@ -268,6 +269,7 @@ class UserrightsPage extends SpecialPage {
$user->invalidateCache();
// update groups in external authentication database
+ Hooks::run( 'UserGroupsChanged', array( $user, $add, $remove, $this->getUser() ) );
$wgAuth->updateExternalDBGroups( $user, $add, $remove );
wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) . "\n" );
diff --git a/includes/specials/SpecialVersion.php b/includes/specials/SpecialVersion.php
index 9a1c5e5d..38baf5b9 100644
--- a/includes/specials/SpecialVersion.php
+++ b/includes/specials/SpecialVersion.php
@@ -92,7 +92,14 @@ class SpecialVersion extends SpecialPage {
if ( $file ) {
$wikiText = file_get_contents( $file );
if ( substr( $file, -4 ) === '.txt' ) {
- $wikiText = Html::element( 'pre', array(), $wikiText );
+ $wikiText = Html::element(
+ 'pre',
+ array(
+ 'lang' => 'en',
+ 'dir' => 'ltr',
+ ),
+ $wikiText
+ );
}
}
}
@@ -109,7 +116,14 @@ class SpecialVersion extends SpecialPage {
$file = $this->getExtLicenseFileName( dirname( $extNode['path'] ) );
if ( $file ) {
$wikiText = file_get_contents( $file );
- $wikiText = "<pre>$wikiText</pre>";
+ $wikiText = Html::element(
+ 'pre',
+ array(
+ 'lang' => 'en',
+ 'dir' => 'ltr',
+ ),
+ $wikiText
+ );
}
}
@@ -215,6 +229,10 @@ class SpecialVersion extends SpecialPage {
}
$software[$dbr->getSoftwareLink()] = $dbr->getServerInfo();
+ if ( IcuCollation::getICUVersion() ) {
+ $software['[http://site.icu-project.org/ ICU]'] = IcuCollation::getICUVersion();
+ }
+
// Allow a hook to add/remove items.
Hooks::run( 'SoftwareInfo', array( &$software ) );
@@ -522,6 +540,9 @@ class SpecialVersion extends SpecialPage {
$out .= Html::openElement( 'tr' )
. Html::element( 'th', array(), $this->msg( 'version-libraries-library' )->text() )
. Html::element( 'th', array(), $this->msg( 'version-libraries-version' )->text() )
+ . Html::element( 'th', array(), $this->msg( 'version-libraries-license' )->text() )
+ . Html::element( 'th', array(), $this->msg( 'version-libraries-description' )->text() )
+ . Html::element( 'th', array(), $this->msg( 'version-libraries-authors' )->text() )
. Html::closeElement( 'tr' );
foreach ( $lock->getInstalledDependencies() as $name => $info ) {
@@ -530,13 +551,32 @@ class SpecialVersion extends SpecialPage {
// in their proper section
continue;
}
+ $authors = array_map( function( $arr ) {
+ // If a homepage is set, link to it
+ if ( isset( $arr['homepage'] ) ) {
+ return "[{$arr['homepage']} {$arr['name']}]";
+ }
+ return $arr['name'];
+ }, $info['authors'] );
+ $authors = $this->listAuthors( $authors, false, "$IP/vendor/$name" );
+
+ // We can safely assume that the libraries' names and descriptions
+ // are written in English and aren't going to be translated,
+ // so set appropriate lang and dir attributes
$out .= Html::openElement( 'tr' )
. Html::rawElement(
'td',
array(),
- Linker::makeExternalLink( "https://packagist.org/packages/$name", $name )
+ Linker::makeExternalLink(
+ "https://packagist.org/packages/$name", $name,
+ true, '',
+ array( 'class' => 'mw-version-library-name' )
+ )
)
- . Html::element( 'td', array(), $info['version'] )
+ . Html::element( 'td', array( 'dir' => 'auto' ), $info['version'] )
+ . Html::element( 'td', array( 'dir' => 'auto' ), $this->listToText( $info['licenses'] ) )
+ . Html::element( 'td', array( 'lang' => 'en', 'dir' => 'ltr' ), $info['description'] )
+ . Html::rawElement( 'td', array(), $authors )
. Html::closeElement( 'tr' );
}
$out .= Html::closeElement( 'table' );
@@ -557,7 +597,10 @@ class SpecialVersion extends SpecialPage {
if ( count( $tags ) ) {
$out = Html::rawElement(
'h2',
- array( 'class' => 'mw-headline plainlinks' ),
+ array(
+ 'class' => 'mw-headline plainlinks',
+ 'id' => 'mw-version-parser-extensiontags',
+ ),
Linker::makeExternalLink(
'//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Tag_extensions',
$this->msg( 'version-parser-extensiontags' )->parse(),
@@ -597,7 +640,10 @@ class SpecialVersion extends SpecialPage {
if ( count( $fhooks ) ) {
$out = Html::rawElement(
'h2',
- array( 'class' => 'mw-headline plainlinks' ),
+ array(
+ 'class' => 'mw-headline plainlinks',
+ 'id' => 'mw-version-parser-function-hooks',
+ ),
Linker::makeExternalLink(
'//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Parser_functions',
$this->msg( 'version-parser-function-hooks' )->parse(),
@@ -842,7 +888,7 @@ class SpecialVersion extends SpecialPage {
// Finally! Create the table
$html = Html::openElement( 'tr', array(
'class' => 'mw-version-ext',
- 'id' => "mw-version-ext-{$extension['name']}"
+ 'id' => Sanitizer::escapeId( 'mw-version-ext-' . $extension['name'] )
)
);
@@ -959,7 +1005,8 @@ class SpecialVersion extends SpecialPage {
* 'and others' will be added to the end of the credits.
*
* @param string|array $authors
- * @param string $extName Name of the extension for link creation
+ * @param string|bool $extName Name of the extension for link creation,
+ * false if no links should be created
* @param string $extDir Path to the extension root directory
*
* @return string HTML fragment
@@ -972,7 +1019,7 @@ class SpecialVersion extends SpecialPage {
if ( $item == '...' ) {
$hasOthers = true;
- if ( $this->getExtAuthorsFileName( $extDir ) ) {
+ if ( $extName && $this->getExtAuthorsFileName( $extDir ) ) {
$text = Linker::link(
$this->getPageTitle( "Credits/$extName" ),
$this->msg( 'version-poweredby-others' )->escaped()
@@ -991,7 +1038,7 @@ class SpecialVersion extends SpecialPage {
}
}
- if ( !$hasOthers && $this->getExtAuthorsFileName( $extDir ) ) {
+ if ( $extName && !$hasOthers && $this->getExtAuthorsFileName( $extDir ) ) {
$list[] = $text = Linker::link(
$this->getPageTitle( "Credits/$extName" ),
$this->msg( 'version-poweredby-others' )->escaped()
@@ -1091,7 +1138,10 @@ class SpecialVersion extends SpecialPage {
if ( is_array( $list ) && count( $list ) == 1 ) {
$list = $list[0];
}
- if ( is_object( $list ) ) {
+ if ( $list instanceof Closure ) {
+ // Don't output stuff like "Closure$;1028376090#8$48499d94fe0147f7c633b365be39952b$"
+ return 'Closure';
+ } elseif ( is_object( $list ) ) {
$class = wfMessage( 'parentheses' )->params( get_class( $list ) )->escaped();
return $class;
@@ -1146,9 +1196,9 @@ class SpecialVersion extends SpecialPage {
}
// SimpleXml whines about the xmlns...
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$xml = simplexml_load_file( $entries );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $xml ) {
foreach ( $xml->entry as $entry ) {
diff --git a/includes/specials/SpecialWantedfiles.php b/includes/specials/SpecialWantedfiles.php
index 8a1a6c6c..a718aa81 100644
--- a/includes/specials/SpecialWantedfiles.php
+++ b/includes/specials/SpecialWantedfiles.php
@@ -52,7 +52,7 @@ class WantedFilesPage extends WantedQueryPage {
$noForeign = '';
if ( !$this->likelyToHaveFalsePositives() ) {
// Additional messages for grep:
- // wantedfiletext-cat-noforeign, wantedfiletext-nocat
+ // wantedfiletext-cat-noforeign, wantedfiletext-nocat-noforeign
$noForeign = '-noforeign';
}
diff --git a/includes/specials/SpecialWantedtemplates.php b/includes/specials/SpecialWantedtemplates.php
index a4b9dd84..9e26f0fa 100644
--- a/includes/specials/SpecialWantedtemplates.php
+++ b/includes/specials/SpecialWantedtemplates.php
@@ -44,10 +44,7 @@ class WantedTemplatesPage extends WantedQueryPage {
'title' => 'tl_title',
'value' => 'COUNT(*)'
),
- 'conds' => array(
- 'page_title IS NULL',
- 'tl_namespace' => NS_TEMPLATE
- ),
+ 'conds' => array( 'page_title IS NULL' ),
'options' => array( 'GROUP BY' => array( 'tl_namespace', 'tl_title' ) ),
'join_conds' => array( 'page' => array( 'LEFT JOIN',
array( 'page_namespace = tl_namespace',
diff --git a/includes/specials/SpecialWatchlist.php b/includes/specials/SpecialWatchlist.php
index df9d3639..20f57760 100644
--- a/includes/specials/SpecialWatchlist.php
+++ b/includes/specials/SpecialWatchlist.php
@@ -43,6 +43,7 @@ class SpecialWatchlist extends ChangesListSpecialPage {
$output = $this->getOutput();
$request = $this->getRequest();
+ $this->addHelpLink( 'Help:Watching pages' );
$mode = SpecialEditWatchlist::getMode( $request, $subpage );
if ( $mode !== false ) {
diff --git a/includes/specials/SpecialWhatlinkshere.php b/includes/specials/SpecialWhatlinkshere.php
index 0b3175a6..39980d29 100644
--- a/includes/specials/SpecialWhatlinkshere.php
+++ b/includes/specials/SpecialWhatlinkshere.php
@@ -46,6 +46,7 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
$this->setHeaders();
$this->outputHeader();
+ $this->addHelpLink( 'Help:What links here' );
$opts = new FormOptions();
@@ -154,7 +155,7 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
$conds['pagelinks'][] = 'rd_from is NOT NULL';
}
- $queryFunc = function ( $dbr, $table, $fromCol ) use (
+ $queryFunc = function ( IDatabase $dbr, $table, $fromCol ) use (
$conds, $target, $limit, $useLinkNamespaceDBFields
) {
// Read an extra row as an at-end check
@@ -169,11 +170,12 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
}
// Inner LIMIT is 2X in case of stale backlinks with wrong namespaces
$subQuery = $dbr->selectSqlText(
- array( $table, 'page', 'redirect' ),
+ array( $table, 'redirect', 'page' ),
array( $fromCol, 'rd_from' ),
$conds[$table],
__CLASS__ . '::showIndirectLinks',
- array( 'ORDER BY' => $fromCol, 'LIMIT' => 2 * $queryLimit ),
+ // Force JOIN order per T106682 to avoid large filesorts
+ array( 'ORDER BY' => $fromCol, 'LIMIT' => 2 * $queryLimit, 'STRAIGHT_JOIN' ),
array(
'page' => array( 'INNER JOIN', "$fromCol = page_id" ),
'redirect' => array( 'LEFT JOIN', $on )
@@ -266,6 +268,14 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
}
$prevId = $from;
+ // use LinkBatch to make sure, that all required data (associated with Titles)
+ // is loaded in one query
+ $lb = new LinkBatch();
+ foreach ( $rows as $row ) {
+ $lb->add( $row->page_namespace, $row->page_title );
+ }
+ $lb->execute();
+
if ( $level == 0 ) {
if ( !$this->including() ) {
$out->addHTML( $this->whatlinkshereForm() );
@@ -313,7 +323,7 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
static $msgcache = null;
if ( $msgcache === null ) {
static $msgs = array( 'isredirect', 'istemplate', 'semicolon-separator',
- 'whatlinkshere-links', 'isimage' );
+ 'whatlinkshere-links', 'isimage', 'editlink' );
$msgcache = array();
foreach ( $msgs as $msg ) {
$msgcache[$msg] = $this->msg( $msg )->escaped();
@@ -354,7 +364,7 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
}
# Space for utilities links, with a what-links-here link provided
- $wlhLink = $this->wlhLink( $nt, $msgcache['whatlinkshere-links'] );
+ $wlhLink = $this->wlhLink( $nt, $msgcache['whatlinkshere-links'], $msgcache['editlink'] );
$wlh = Xml::wrapClass(
$this->msg( 'parentheses' )->rawParams( $wlhLink )->escaped(),
'mw-whatlinkshere-tools'
@@ -369,18 +379,39 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
return Xml::closeElement( 'ul' );
}
- protected function wlhLink( Title $target, $text ) {
+ protected function wlhLink( Title $target, $text, $editText ) {
static $title = null;
if ( $title === null ) {
$title = $this->getPageTitle();
}
- return Linker::linkKnown(
- $title,
- $text,
- array(),
- array( 'target' => $target->getPrefixedText() )
+ // always show a "<- Links" link
+ $links = array(
+ 'links' => Linker::linkKnown(
+ $title,
+ $text,
+ array(),
+ array( 'target' => $target->getPrefixedText() )
+ ),
);
+
+ // if the page is editable, add an edit link
+ if (
+ // check user permissions
+ $this->getUser()->isAllowed( 'edit' ) &&
+ // check, if the content model is editable through action=edit
+ ContentHandler::getForTitle( $target )->supportsDirectEditing()
+ ) {
+ $links['edit'] = Linker::linkKnown(
+ $target,
+ $editText,
+ array(),
+ array( 'action' => 'edit' )
+ );
+ }
+
+ // build the links html
+ return $this->getLanguage()->pipeList( $links );
}
function makeSelfLink( $text, $query ) {
diff --git a/includes/templates/Usercreate.php b/includes/templates/Usercreate.php
index f09b6bba..a39690a7 100644
--- a/includes/templates/Usercreate.php
+++ b/includes/templates/Usercreate.php
@@ -38,8 +38,6 @@ class UsercreateTemplate extends BaseTemplate {
}
function execute() {
- global $wgCookieExpiration;
- $expirationDays = ceil( $wgCookieExpiration / ( 3600 * 24 ) );
?>
<div class="mw-ui-container">
<?php if ( $this->haveData( 'languages' ) ) { ?>
@@ -73,6 +71,12 @@ class UsercreateTemplate extends BaseTemplate {
<?php } ?>
</div>
+ <?php if ( $this->data['formheader'] ) { ?>
+ <div class="mw-form-formheader">
+ <?php $this->html( 'formheader' ); /* extensions such as MobileFrontend add html here */ ?>
+ </div>
+ <?php } ?>
+
<div class="mw-ui-vform-field">
<label for='wpName2'>
<?php $this->msg( 'userlogin-yourname' ); ?>
diff --git a/includes/templates/Userlogin.php b/includes/templates/Userlogin.php
index 345bb71b..4a0b413f 100644
--- a/includes/templates/Userlogin.php
+++ b/includes/templates/Userlogin.php
@@ -56,6 +56,11 @@ class UserloginTemplate extends BaseTemplate {
</div>
<?php } ?>
+ <?php if ( $this->data['formheader'] ) { ?>
+ <div class="mw-form-formheader">
+ <?php $this->html( 'formheader' ); /* extensions such as MobileFrontend add html here */ ?>
+ </div>
+ <?php } ?>
<div class="mw-ui-vform-field">
<label for='wpName1'>
<?php
diff --git a/includes/tidy/Html5Depurate.php b/includes/tidy/Html5Depurate.php
new file mode 100644
index 00000000..23e445fa
--- /dev/null
+++ b/includes/tidy/Html5Depurate.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace MediaWiki\Tidy;
+use MWHttpRequest;
+use Exception;
+
+class Html5Depurate extends TidyDriverBase {
+ public function __construct( array $config ) {
+ parent::__construct( $config + array(
+ 'url' => 'http://localhost:4339/document',
+ 'timeout' => 10,
+ 'connectTimeout' => 0.5,
+ ) );
+ }
+
+ public function tidy( $text ) {
+ $wrappedtext = '<!DOCTYPE html><html>' .
+ '<body>' . $text . '</body></html>';
+
+ $req = MWHttpRequest::factory( $this->config['url'],
+ array(
+ 'method' => 'POST',
+ 'timeout' => $this->config['timeout'],
+ 'connectTimeout' => $this->config['connectTimeout'],
+ 'postData' => array(
+ 'text' => $wrappedtext
+ )
+ ) );
+ $status = $req->execute();
+ if ( !$status->isOK() ) {
+ throw new Exception( "Error contacting depurate service: " . $status->getWikiText() );
+ } elseif ( $req->getStatus() !== 200 ) {
+ throw new Exception( "Depurate returned error: " . $status->getWikiText() );
+ }
+ $result = $req->getContent();
+ $startBody = strpos( $result, "<body>" );
+ $endBody = strrpos( $result, "</body>" );
+ if ( $startBody !== false && $endBody !== false && $endBody > $startBody ) {
+ $startBody += strlen( "<body>" );
+ return substr( $result, $startBody, $endBody - $startBody );
+ } else {
+ return $text . "\n<!-- Html5Depurate returned an invalid result -->";
+ }
+ }
+}
diff --git a/includes/tidy/RaggettBase.php b/includes/tidy/RaggettBase.php
new file mode 100644
index 00000000..a3717b2b
--- /dev/null
+++ b/includes/tidy/RaggettBase.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace MediaWiki\Tidy;
+
+abstract class RaggettBase extends TidyDriverBase {
+ /**
+ * Generic interface for wrapping and unwrapping HTML for Dave Raggett's tidy.
+ *
+ * @param string $text Hideous HTML input
+ * @return string Corrected HTML output
+ */
+ public function tidy( $text ) {
+ $wrapper = new RaggettWrapper;
+ $wrappedtext = $wrapper->getWrapped( $text );
+
+ $retVal = null;
+ $correctedtext = $this->cleanWrapped( $wrappedtext, false, $retVal );
+
+ if ( $retVal < 0 ) {
+ wfDebug( "Possible tidy configuration error!\n" );
+ return $text . "\n<!-- Tidy was unable to run -->\n";
+ } elseif ( is_null( $correctedtext ) ) {
+ wfDebug( "Tidy error detected!\n" );
+ return $text . "\n<!-- Tidy found serious XHTML errors -->\n";
+ }
+
+ $correctedtext = $wrapper->postprocess( $correctedtext ); // restore any hidden tokens
+
+ return $correctedtext;
+ }
+
+ public function validate( $text, &$errorStr ) {
+ $retval = 0;
+ $errorStr = $this->cleanWrapped( $text, true, $retval );
+ return ( $retval < 0 && $errorStr == '' ) || $retval == 0;
+ }
+
+ /**
+ * Perform a clean/repair operation
+ * @param string $text HTML to check
+ * @param bool $stderr Whether to read result from STDERR rather than STDOUT
+ * @param int &$retval Exit code (-1 on internal error)
+ * @return null|string
+ * @throws MWException
+ */
+ abstract protected function cleanWrapped( $text, $stderr = false, &$retval = null );
+}
diff --git a/includes/tidy/RaggettExternal.php b/includes/tidy/RaggettExternal.php
new file mode 100644
index 00000000..11933188
--- /dev/null
+++ b/includes/tidy/RaggettExternal.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace MediaWiki\Tidy;
+
+class RaggettExternal extends RaggettBase {
+ /**
+ * Spawn an external HTML tidy process and get corrected markup back from it.
+ * Also called in OutputHandler.php for full page validation
+ *
+ * @param string $text HTML to check
+ * @param bool $stderr Whether to read result from STDERR rather than STDOUT
+ * @param int &$retval Exit code (-1 on internal error)
+ * @return string|null
+ */
+ protected function cleanWrapped( $text, $stderr = false, &$retval = null ) {
+ $cleansource = '';
+ $opts = ' -utf8';
+
+ if ( $stderr ) {
+ $descriptorspec = array(
+ 0 => array( 'pipe', 'r' ),
+ 1 => array( 'file', wfGetNull(), 'a' ),
+ 2 => array( 'pipe', 'w' )
+ );
+ } else {
+ $descriptorspec = array(
+ 0 => array( 'pipe', 'r' ),
+ 1 => array( 'pipe', 'w' ),
+ 2 => array( 'file', wfGetNull(), 'a' )
+ );
+ }
+
+ $readpipe = $stderr ? 2 : 1;
+ $pipes = array();
+
+ $process = proc_open(
+ "{$this->config['tidyBin']} -config {$this->config['tidyConfigFile']} " .
+ $this->config['tidyCommandLine'] . $opts, $descriptorspec, $pipes );
+
+ //NOTE: At least on linux, the process will be created even if tidy is not installed.
+ // This means that missing tidy will be treated as a validation failure.
+
+ if ( is_resource( $process ) ) {
+ // Theoretically, this style of communication could cause a deadlock
+ // here. If the stdout buffer fills up, then writes to stdin could
+ // block. This doesn't appear to happen with tidy, because tidy only
+ // writes to stdout after it's finished reading from stdin. Search
+ // for tidyParseStdin and tidySaveStdout in console/tidy.c
+ fwrite( $pipes[0], $text );
+ fclose( $pipes[0] );
+ while ( !feof( $pipes[$readpipe] ) ) {
+ $cleansource .= fgets( $pipes[$readpipe], 1024 );
+ }
+ fclose( $pipes[$readpipe] );
+ $retval = proc_close( $process );
+ } else {
+ wfWarn( "Unable to start external tidy process" );
+ $retval = -1;
+ }
+
+ if ( !$stderr && $cleansource == '' && $text != '' ) {
+ // Some kind of error happened, so we couldn't get the corrected text.
+ // Just give up; we'll use the source text and append a warning.
+ $cleansource = null;
+ }
+
+ return $cleansource;
+ }
+
+ public function supportsValidate() {
+ return true;
+ }
+}
diff --git a/includes/tidy/RaggettInternalHHVM.php b/includes/tidy/RaggettInternalHHVM.php
new file mode 100644
index 00000000..2a3986df
--- /dev/null
+++ b/includes/tidy/RaggettInternalHHVM.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace MediaWiki\Tidy;
+
+class RaggettInternalHHVM extends RaggettBase {
+ /**
+ * Use the HTML tidy extension to use the tidy library in-process,
+ * saving the overhead of spawning a new process.
+ *
+ * @param string $text HTML to check
+ * @param bool $stderr Whether to read result from error status instead of output
+ * @param int &$retval Exit code (-1 on internal error)
+ * @return string|null
+ */
+ protected function cleanWrapped( $text, $stderr = false, &$retval = null ) {
+ if ( $stderr ) {
+ throw new Exception( "\$stderr cannot be used with RaggettInternalHHVM" );
+ }
+ $cleansource = tidy_repair_string( $text, $this->config['tidyConfigFile'], 'utf8' );
+ if ( $cleansource === false ) {
+ $cleansource = null;
+ $retval = -1;
+ } else {
+ $retval = 0;
+ }
+
+ return $cleansource;
+ }
+}
diff --git a/includes/tidy/RaggettInternalPHP.php b/includes/tidy/RaggettInternalPHP.php
new file mode 100644
index 00000000..1ce14b60
--- /dev/null
+++ b/includes/tidy/RaggettInternalPHP.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace MediaWiki\Tidy;
+
+class RaggettInternalPHP extends RaggettBase {
+ /**
+ * Use the HTML tidy extension to use the tidy library in-process,
+ * saving the overhead of spawning a new process.
+ *
+ * @param string $text HTML to check
+ * @param bool $stderr Whether to read result from error status instead of output
+ * @param int &$retval Exit code (-1 on internal error)
+ * @return string|null
+ */
+ protected function cleanWrapped( $text, $stderr = false, &$retval = null ) {
+ if ( !class_exists( 'tidy' ) ) {
+ wfWarn( "Unable to load internal tidy class." );
+ $retval = -1;
+
+ return null;
+ }
+
+ $tidy = new \tidy;
+ $tidy->parseString( $text, $this->config['tidyConfigFile'], 'utf8' );
+
+ if ( $stderr ) {
+ $retval = $tidy->getStatus();
+ return $tidy->errorBuffer;
+ }
+
+ $tidy->cleanRepair();
+ $retval = $tidy->getStatus();
+ if ( $retval == 2 ) {
+ // 2 is magic number for fatal error
+ // http://www.php.net/manual/en/function.tidy-get-status.php
+ $cleansource = null;
+ } else {
+ $cleansource = tidy_get_output( $tidy );
+ if ( !empty( $this->config['debugComment'] ) && $retval > 0 ) {
+ $cleansource .= "<!--\nTidy reports:\n" .
+ str_replace( '-->', '--&gt;', $tidy->errorBuffer ) .
+ "\n-->";
+ }
+ }
+
+ return $cleansource;
+ }
+
+ public function supportsValidate() {
+ return true;
+ }
+}
diff --git a/includes/tidy/RaggettWrapper.php b/includes/tidy/RaggettWrapper.php
new file mode 100644
index 00000000..083f4020
--- /dev/null
+++ b/includes/tidy/RaggettWrapper.php
@@ -0,0 +1,89 @@
+<?php
+namespace MediaWiki\Tidy;
+
+use ReplacementArray;
+use ParserOutput;
+use Parser;
+
+/**
+ * Class used to hide mw:editsection tokens from Tidy so that it doesn't break them
+ * or break on them. This is a bit of a hack for now, but hopefully in the future
+ * we may create a real postprocessor or something that will replace this.
+ * It's called wrapper because for now it basically takes over MWTidy::tidy's task
+ * of wrapping the text in a xhtml block
+ *
+ * This re-uses some of the parser's UNIQ tricks, though some of it is private so it's
+ * duplicated. Perhaps we should create an abstract marker hiding class.
+ *
+ * @ingroup Parser
+ */
+class RaggettWrapper {
+
+ /**
+ * @var ReplacementArray
+ */
+ protected $mTokens;
+
+ protected $mMarkerIndex;
+
+ public function __construct() {
+ $this->mTokens = null;
+ }
+
+ /**
+ * @param string $text
+ * @return string
+ */
+ public function getWrapped( $text ) {
+ $this->mTokens = new ReplacementArray;
+ $this->mMarkerIndex = 0;
+
+ // Replace <mw:editsection> elements with placeholders
+ $wrappedtext = preg_replace_callback( ParserOutput::EDITSECTION_REGEX,
+ array( &$this, 'replaceCallback' ), $text );
+ // ...and <mw:toc> markers
+ $wrappedtext = preg_replace_callback( '/\<\\/?mw:toc\>/',
+ array( &$this, 'replaceCallback' ), $wrappedtext );
+ // ... and <math> tags
+ $wrappedtext = preg_replace_callback( '/\<math(.*?)\<\\/math\>/s',
+ array( &$this, 'replaceCallback' ), $wrappedtext );
+ // Modify inline Microdata <link> and <meta> elements so they say <html-link> and <html-meta> so
+ // we can trick Tidy into not stripping them out by including them in tidy's new-empty-tags config
+ $wrappedtext = preg_replace( '!<(link|meta)([^>]*?)(/{0,1}>)!', '<html-$1$2$3', $wrappedtext );
+
+ // Wrap the whole thing in a doctype and body for Tidy.
+ $wrappedtext = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' .
+ ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>' .
+ '<head><title>test</title></head><body>' . $wrappedtext . '</body></html>';
+
+ return $wrappedtext;
+ }
+
+ /**
+ * @param array $m
+ *
+ * @return string
+ */
+ public function replaceCallback( $m ) {
+ $marker = Parser::MARKER_PREFIX . "-item-{$this->mMarkerIndex}" . Parser::MARKER_SUFFIX;
+ $this->mMarkerIndex++;
+ $this->mTokens->setPair( $marker, $m[0] );
+ return $marker;
+ }
+
+ /**
+ * @param string $text
+ * @return string
+ */
+ public function postprocess( $text ) {
+ // Revert <html-{link,meta}> back to <{link,meta}>
+ $text = preg_replace( '!<html-(link|meta)([^>]*?)(/{0,1}>)!', '<$1$2$3', $text );
+
+ // Restore the contents of placeholder tokens
+ $text = $this->mTokens->replace( $text );
+
+ return $text;
+ }
+
+}
+?>
diff --git a/includes/tidy/TidyDriverBase.php b/includes/tidy/TidyDriverBase.php
new file mode 100644
index 00000000..1d994aa1
--- /dev/null
+++ b/includes/tidy/TidyDriverBase.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace MediaWiki\Tidy;
+
+/**
+ * Base class for HTML cleanup utilities
+ */
+abstract class TidyDriverBase {
+ protected $config;
+
+ function __construct( $config ) {
+ $this->config = $config;
+ }
+
+ /**
+ * Return true if validate() can be used
+ */
+ public function supportsValidate() {
+ return false;
+ }
+
+ /**
+ * Check HTML for errors, used if $wgValidateAllHtml = true.
+ *
+ * @param string $text
+ * @param string &$errorStr Return the error string
+ * @return bool Whether the HTML is valid
+ */
+ public function validate( $text, &$errorStr ) {
+ throw new MWException( get_class( $this ) . " does not support validate()" );
+ }
+
+ /**
+ * Clean up HTML
+ *
+ * @param string HTML document fragment to clean up
+ * @param string The corrected HTML output
+ */
+ public abstract function tidy( $text );
+}
diff --git a/includes/tidy.conf b/includes/tidy/tidy.conf
index 4c4daed5..4c4daed5 100644
--- a/includes/tidy.conf
+++ b/includes/tidy/tidy.conf
diff --git a/includes/title/MalformedTitleException.php b/includes/title/MalformedTitleException.php
index a9e58b3e..0892ce4e 100644
--- a/includes/title/MalformedTitleException.php
+++ b/includes/title/MalformedTitleException.php
@@ -1,7 +1,5 @@
<?php
/**
- * Representation of a page title within %MediaWiki.
- *
* 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
@@ -18,16 +16,58 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
- * @license GPL 2+
- * @author Daniel Kinzler
*/
/**
* MalformedTitleException is thrown when a TitleParser is unable to parse a title string.
- *
- * @license GPL 2+
- * @author Daniel Kinzler
* @since 1.23
*/
class MalformedTitleException extends Exception {
+ private $titleText = null;
+ private $errorMessage = null;
+ private $errorMessageParameters = array();
+
+ /**
+ * @param string $errorMessage Localisation message describing the error (since MW 1.26)
+ * @param string $titleText The invalid title text (since MW 1.26)
+ * @param string[] $errorMessageParameters Additional parameters for the error message.
+ * $titleText will be appended if it's not null. (since MW 1.26)
+ */
+ public function __construct( $errorMessage = null, $titleText = null, $errorMessageParameters = array() ) {
+ $this->errorMessage = $errorMessage;
+ $this->titleText = $titleText;
+ if ( $titleText !== null ) {
+ $errorMessageParameters[] = $titleText;
+ }
+ $this->errorMessageParameters = $errorMessageParameters;
+
+ // Supply something useful for Exception::getMessage() to return.
+ $enMsg = wfMessage( $errorMessage, $errorMessageParameters );
+ $enMsg->inLanguage( 'en' )->useDatabase( false );
+ parent::__construct( $enMsg->text() );
+ }
+
+ /**
+ * @since 1.26
+ * @return string|null
+ */
+ public function getTitleText() {
+ return $this->titleText;
+ }
+
+ /**
+ * @since 1.26
+ * @return string|null
+ */
+ public function getErrorMessage() {
+ return $this->errorMessage;
+ }
+
+ /**
+ * @since 1.26
+ * @return string[]
+ */
+ public function getErrorMessageParameters() {
+ return $this->errorMessageParameters;
+ }
}
diff --git a/includes/title/MediaWikiTitleCodec.php b/includes/title/MediaWikiTitleCodec.php
index 20034b74..01575ac0 100644
--- a/includes/title/MediaWikiTitleCodec.php
+++ b/includes/title/MediaWikiTitleCodec.php
@@ -137,12 +137,12 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
// Interwiki links are not supported by TitleValue
if ( $parts['interwiki'] !== '' ) {
- throw new MalformedTitleException( 'Title must not contain an interwiki prefix: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-interwiki', $text );
}
// Relative fragment links are not supported by TitleValue
if ( $parts['dbkey'] === '' ) {
- throw new MalformedTitleException( 'Title must not be empty: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-empty', $text );
}
return new TitleValue( $parts['namespace'], $parts['dbkey'], $parts['fragment'] );
@@ -232,7 +232,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
if ( strpos( $dbkey, UtfNormal\Constants::UTF8_REPLACEMENT ) !== false ) {
# Contained illegal UTF-8 sequences or forbidden Unicode chars.
- throw new MalformedTitleException( 'Bad UTF-8 sequences found in title: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-utf8', $text );
}
$parts['dbkey'] = $dbkey;
@@ -246,7 +246,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
}
if ( $dbkey == '' ) {
- throw new MalformedTitleException( 'Empty title: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-empty', $text );
}
# Namespace or interwiki prefix
@@ -263,11 +263,11 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
if ( $ns == NS_TALK && preg_match( $prefixRegexp, $dbkey, $x ) ) {
if ( $this->language->getNsIndex( $x[1] ) ) {
# Disallow Talk:File:x type titles...
- throw new MalformedTitleException( 'Bad namespace prefix: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-talk-namespace', $text );
} elseif ( Interwiki::isValidInterwiki( $x[1] ) ) {
//TODO: get rid of global state!
# Disallow Talk:Interwiki:x type titles...
- throw new MalformedTitleException( 'Interwiki prefix found in title: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-talk-namespace', $text );
}
}
} elseif ( Interwiki::isValidInterwiki( $p ) ) {
@@ -324,8 +324,9 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
# Reject illegal characters.
$rxTc = self::getTitleInvalidRegex();
- if ( preg_match( $rxTc, $dbkey ) ) {
- throw new MalformedTitleException( 'Illegal characters found in title: ' . $text );
+ $matches = array();
+ if ( preg_match( $rxTc, $dbkey, $matches ) ) {
+ throw new MalformedTitleException( 'title-invalid-characters', $text, array( $matches[0] ) );
}
# Pages with "/./" or "/../" appearing in the URLs will often be un-
@@ -343,23 +344,22 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
substr( $dbkey, -3 ) == '/..'
)
) {
- throw new MalformedTitleException( 'Bad title: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-relative', $text );
}
# Magic tilde sequences? Nu-uh!
if ( strpos( $dbkey, '~~~' ) !== false ) {
- throw new MalformedTitleException( 'Bad title: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-magic-tilde', $text );
}
# Limit the size of titles to 255 bytes. This is typically the size of the
# underlying database field. We make an exception for special pages, which
# don't need to be stored in the database, and may edge over 255 bytes due
# to subpage syntax for long titles, e.g. [[Special:Block/Long name]]
- if (
- ( $parts['namespace'] != NS_SPECIAL && strlen( $dbkey ) > 255 )
- || strlen( $dbkey ) > 512
- ) {
- throw new MalformedTitleException( 'Title too long: ' . substr( $dbkey, 0, 255 ) . '...' );
+ $maxLength = ( $parts['namespace'] != NS_SPECIAL ) ? 255 : 512;
+ if ( strlen( $dbkey ) > $maxLength ) {
+ throw new MalformedTitleException( 'title-invalid-too-long', $text,
+ array( Message::numParam( $maxLength ) ) );
}
# Normally, all wiki links are forced to have an initial capital letter so [[foo]]
@@ -374,7 +374,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
# self-links with a fragment identifier.
if ( $dbkey == '' && $parts['interwiki'] === '' ) {
if ( $parts['namespace'] != NS_MAIN ) {
- throw new MalformedTitleException( 'Empty title: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-empty', $text );
}
}
@@ -390,7 +390,7 @@ class MediaWikiTitleCodec implements TitleFormatter, TitleParser {
// Any remaining initial :s are illegal.
if ( $dbkey !== '' && ':' == $dbkey[0] ) {
- throw new MalformedTitleException( 'Title must not start with a colon: ' . $text );
+ throw new MalformedTitleException( 'title-invalid-leading-colon', $text );
}
# Fill fields
diff --git a/includes/title/TitleValue.php b/includes/title/TitleValue.php
index 5cac3470..a0f3b6f9 100644
--- a/includes/title/TitleValue.php
+++ b/includes/title/TitleValue.php
@@ -21,6 +21,7 @@
* @license GPL 2+
* @author Daniel Kinzler
*/
+use Wikimedia\Assert\Assert;
/**
* Represents a page (or page fragment) title within %MediaWiki.
@@ -67,26 +68,13 @@ class TitleValue {
* @throws InvalidArgumentException
*/
public function __construct( $namespace, $dbkey, $fragment = '' ) {
- if ( !is_int( $namespace ) ) {
- throw new InvalidArgumentException( '$namespace must be an integer' );
- }
-
- if ( !is_string( $dbkey ) ) {
- throw new InvalidArgumentException( '$dbkey must be a string' );
- }
+ Assert::parameterType( 'integer', $namespace, '$namespace' );
+ Assert::parameterType( 'string', $dbkey, '$dbkey' );
+ Assert::parameterType( 'string', $fragment, '$fragment' );
// Sanity check, no full validation or normalization applied here!
- if ( preg_match( '/^_|[ \r\n\t]|_$/', $dbkey ) ) {
- throw new InvalidArgumentException( '$dbkey must be a valid DB key: ' . $dbkey );
- }
-
- if ( !is_string( $fragment ) ) {
- throw new InvalidArgumentException( '$fragment must be a string' );
- }
-
- if ( $dbkey === '' ) {
- throw new InvalidArgumentException( '$dbkey must not be empty' );
- }
+ Assert::parameter( !preg_match( '/^_|[ \r\n\t]|_$/', $dbkey ), '$dbkey', 'invalid DB key' );
+ Assert::parameter( $dbkey !== '', '$dbkey', 'should not be empty' );
$this->namespace = $namespace;
$this->dbkey = $dbkey;
diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php
index 9e113749..e9e1f658 100644
--- a/includes/upload/UploadBase.php
+++ b/includes/upload/UploadBase.php
@@ -298,7 +298,6 @@ abstract class UploadBase {
* If there was no filename or a zero size given, give up quick.
*/
if ( $this->isEmptyFile() ) {
-
return array( 'status' => self::EMPTY_FILE );
}
@@ -307,7 +306,6 @@ abstract class UploadBase {
*/
$maxSize = self::getMaxUploadSize( $this->getSourceType() );
if ( $this->mFileSize > $maxSize ) {
-
return array(
'status' => self::FILE_TOO_LARGE,
'max' => $maxSize,
@@ -321,7 +319,6 @@ abstract class UploadBase {
*/
$verification = $this->verifyFile();
if ( $verification !== true ) {
-
return array(
'status' => self::VERIFICATION_ERROR,
'details' => $verification
@@ -333,7 +330,6 @@ abstract class UploadBase {
*/
$result = $this->validateName();
if ( $result !== true ) {
-
return $result;
}
@@ -341,7 +337,6 @@ abstract class UploadBase {
if ( !Hooks::run( 'UploadVerification',
array( $this->mDestName, $this->mTempPath, &$error ) )
) {
-
return array( 'status' => self::HOOK_ABORTED, 'error' => $error );
}
@@ -390,7 +385,6 @@ abstract class UploadBase {
wfDebug( "mime: <$mime> extension: <{$this->mFinalExtension}>\n" );
global $wgMimeTypeBlacklist;
if ( $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
-
return array( 'filetype-badmime', $mime );
}
@@ -404,7 +398,6 @@ abstract class UploadBase {
$ieTypes = $magic->getIEMimeTypes( $this->mTempPath, $chunk, $extMime );
foreach ( $ieTypes as $ieType ) {
if ( $this->checkFileExtension( $ieType, $wgMimeTypeBlacklist ) ) {
-
return array( 'filetype-bad-ie-mime', $ieType );
}
}
@@ -423,7 +416,6 @@ abstract class UploadBase {
$status = $this->verifyPartialFile();
if ( $status !== true ) {
-
return $status;
}
@@ -433,7 +425,6 @@ abstract class UploadBase {
if ( $wgVerifyMimeType ) {
# XXX: Missing extension will be caught by validateName() via getTitle()
if ( $this->mFinalExtension != '' && !$this->verifyExtension( $mime, $this->mFinalExtension ) ) {
-
return array( 'filetype-mime-mismatch', $this->mFinalExtension, $mime );
}
}
@@ -443,7 +434,6 @@ abstract class UploadBase {
if ( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) {
$svgStatus = $this->detectScriptInSvg( $this->mTempPath, false );
if ( $svgStatus !== false ) {
-
return $svgStatus;
}
}
@@ -461,7 +451,6 @@ abstract class UploadBase {
Hooks::run( 'UploadVerifyFile', array( $this, $mime, &$status ) );
if ( $status !== true ) {
-
return $status;
}
@@ -490,20 +479,17 @@ abstract class UploadBase {
$mime = $this->mFileProps['file-mime'];
$status = $this->verifyMimeType( $mime );
if ( $status !== true ) {
-
return $status;
}
# check for htmlish code and javascript
if ( !$wgDisableUploadScriptChecks ) {
if ( self::detectScript( $this->mTempPath, $mime, $this->mFinalExtension ) ) {
-
return array( 'uploadscripted' );
}
if ( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) {
$svgStatus = $this->detectScriptInSvg( $this->mTempPath, true );
if ( $svgStatus !== false ) {
-
return $svgStatus;
}
}
@@ -519,12 +505,10 @@ abstract class UploadBase {
$errors = $zipStatus->getErrorsArray();
$error = reset( $errors );
if ( $error[0] !== 'zip-wrong-format' ) {
-
return $error;
}
}
if ( $this->mJavaDetected ) {
-
return array( 'uploadjava' );
}
}
@@ -532,7 +516,6 @@ abstract class UploadBase {
# Scan the uploaded file for viruses
$virus = $this->detectVirus( $this->mTempPath );
if ( $virus ) {
-
return array( 'uploadvirus', $virus );
}
@@ -756,11 +739,11 @@ abstract class UploadBase {
$file = $this->getLocalFile();
foreach ( $sizes as $size ) {
- if ( $file->isVectorized()
- || $file->getWidth() > $size ) {
- $jobs[] = new ThumbnailRenderJob( $file->getTitle(), array(
- 'transformParams' => array( 'width' => $size ),
- ) );
+ if ( $file->isVectorized() || $file->getWidth() > $size ) {
+ $jobs[] = new ThumbnailRenderJob(
+ $file->getTitle(),
+ array( 'transformParams' => array( 'width' => $size ) )
+ );
}
}
@@ -779,6 +762,12 @@ abstract class UploadBase {
if ( $this->mTitle !== false ) {
return $this->mTitle;
}
+ if ( !is_string( $this->mDesiredDestName ) ) {
+ $this->mTitleError = self::ILLEGAL_FILENAME;
+ $this->mTitle = null;
+
+ return $this->mTitle;
+ }
/* Assume that if a user specified File:Something.jpg, this is an error
* and that the namespace prefix needs to be stripped of.
*/
@@ -1086,7 +1075,6 @@ abstract class UploadBase {
$chunk = strtolower( $chunk );
if ( !$chunk ) {
-
return false;
}
@@ -1110,7 +1098,6 @@ abstract class UploadBase {
# check for HTML doctype
if ( preg_match( "/<!DOCTYPE *X?HTML/i", $chunk ) ) {
-
return true;
}
@@ -1118,7 +1105,6 @@ abstract class UploadBase {
// PHP/expat will interpret the given encoding in the xml declaration (bug 47304)
if ( $extension == 'svg' || strpos( $mime, 'image/svg' ) === 0 ) {
if ( self::checkXMLEncodingMissmatch( $file ) ) {
-
return true;
}
}
@@ -1231,9 +1217,9 @@ abstract class UploadBase {
// detect the encoding in case is specifies an encoding not whitelisted in self::$safeXmlEncodings
$attemptEncodings = array( 'UTF-16', 'UTF-16BE', 'UTF-32', 'UTF-32BE' );
foreach ( $attemptEncodings as $encoding ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$str = iconv( $encoding, 'UTF-8', $contents );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $str != '' && preg_match( "!<\?xml\b(.*?)\?>!si", $str, $matches ) ) {
if ( preg_match( $encodingRegex, $matches[1], $encMatch )
&& !in_array( strtoupper( $encMatch[1] ), self::$safeXmlEncodings )
@@ -1276,7 +1262,7 @@ abstract class UploadBase {
return array( 'uploadscriptednamespace', $this->mSVGNSError );
}
- return array( 'uploadscripted' );
+ return $check->filterMatchType;
}
return false;
@@ -1291,7 +1277,7 @@ abstract class UploadBase {
public static function checkSvgPICallback( $target, $data ) {
// Don't allow external stylesheets (bug 57550)
if ( preg_match( '/xml-stylesheet/i', $target ) ) {
- return true;
+ return array( 'upload-scripted-pi-callback' );
}
return false;
@@ -1363,7 +1349,7 @@ abstract class UploadBase {
if ( $strippedElement == 'script' ) {
wfDebug( __METHOD__ . ": Found script element '$element' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-script-svg', $strippedElement );
}
# e.g., <svg xmlns="http://www.w3.org/2000/svg">
@@ -1371,21 +1357,21 @@ abstract class UploadBase {
if ( $strippedElement == 'handler' ) {
wfDebug( __METHOD__ . ": Found scriptable element '$element' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-script-svg', $strippedElement );
}
# SVG reported in Feb '12 that used xml:stylesheet to generate javascript block
if ( $strippedElement == 'stylesheet' ) {
wfDebug( __METHOD__ . ": Found scriptable element '$element' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-script-svg', $strippedElement );
}
# Block iframes, in case they pass the namespace check
if ( $strippedElement == 'iframe' ) {
wfDebug( __METHOD__ . ": iframe in uploaded file.\n" );
- return true;
+ return array( 'uploaded-script-svg', $strippedElement );
}
# Check <style> css
@@ -1393,7 +1379,7 @@ abstract class UploadBase {
&& self::checkCssFragment( Sanitizer::normalizeCss( $data ) )
) {
wfDebug( __METHOD__ . ": hostile css in style element.\n" );
- return true;
+ return array( 'uploaded-hostile-svg' );
}
foreach ( $attribs as $attrib => $value ) {
@@ -1404,7 +1390,7 @@ abstract class UploadBase {
wfDebug( __METHOD__
. ": Found event-handler attribute '$attrib'='$value' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-event-handler-on-svg', $attrib, $value );
}
# href with non-local target (don't allow http://, javascript:, etc)
@@ -1418,7 +1404,7 @@ abstract class UploadBase {
wfDebug( __METHOD__ . ": Found href attribute <$strippedElement "
. "'$attrib'='$value' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-href-attribute-svg', $strippedElement, $attrib, $value );
}
}
@@ -1430,7 +1416,7 @@ abstract class UploadBase {
if ( !preg_match( "!^data:\s*image/(gif|jpeg|jpg|png)$parameters,!i", $value ) ) {
wfDebug( __METHOD__ . ": Found href to unwhitelisted data: uri "
. "\"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
- return true;
+ return array( 'uploaded-href-unsafe-target-svg', $strippedElement, $attrib, $value );
}
}
@@ -1442,7 +1428,7 @@ abstract class UploadBase {
wfDebug( __METHOD__ . ": Found animate that might be changing href using from "
. "\"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
- return true;
+ return array( 'uploaded-animate-svg', $strippedElement, $attrib, $value );
}
# use set/animate to add event-handler attribute to parent
@@ -1453,7 +1439,7 @@ abstract class UploadBase {
wfDebug( __METHOD__ . ": Found svg setting event-handler attribute with "
. "\"<$strippedElement $stripped='$value'...\" in uploaded file.\n" );
- return true;
+ return array( 'uploaded-setting-event-handler-svg', $strippedElement, $stripped, $value );
}
# use set to add href attribute to parent element
@@ -1463,7 +1449,7 @@ abstract class UploadBase {
) {
wfDebug( __METHOD__ . ": Found svg setting href attribute '$value' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-setting-href-svg' );
}
# use set to add a remote / data / script target to an element
@@ -1473,7 +1459,7 @@ abstract class UploadBase {
) {
wfDebug( __METHOD__ . ": Found svg setting attribute to '$value' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-wrong-setting-svg', $value );
}
# use handler attribute with remote / data / script
@@ -1481,7 +1467,7 @@ abstract class UploadBase {
wfDebug( __METHOD__ . ": Found svg setting handler with remote/data/script "
. "'$attrib'='$value' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-setting-handler-svg', $attrib, $value );
}
# use CSS styles to bring in remote code
@@ -1490,7 +1476,7 @@ abstract class UploadBase {
) {
wfDebug( __METHOD__ . ": Found svg setting a style with "
. "remote url '$attrib'='$value' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-remote-url-svg', $attrib, $value );
}
# Several attributes can include css, css character escaping isn't allowed
@@ -1501,7 +1487,7 @@ abstract class UploadBase {
) {
wfDebug( __METHOD__ . ": Found svg setting a style with "
. "remote url '$attrib'='$value' in uploaded file.\n" );
- return true;
+ return array( 'uploaded-remote-url-svg', $attrib, $value );
}
# image filters can pull in url, which could be svg that executes scripts
@@ -1512,7 +1498,7 @@ abstract class UploadBase {
wfDebug( __METHOD__ . ": Found image filter with url: "
. "\"<$strippedElement $stripped='$value'...\" in uploaded file.\n" );
- return true;
+ return array( 'uploaded-image-filter-svg', $strippedElement, $stripped, $value );
}
}
@@ -1730,24 +1716,21 @@ abstract class UploadBase {
* Check if a user is the last uploader
*
* @param User $user
- * @param string $img Image name
+ * @param File $img
* @return bool
*/
- public static function userCanReUpload( User $user, $img ) {
+ public static function userCanReUpload( User $user, File $img ) {
if ( $user->isAllowed( 'reupload' ) ) {
return true; // non-conditional
- }
- if ( !$user->isAllowed( 'reupload-own' ) ) {
+ } elseif ( !$user->isAllowed( 'reupload-own' ) ) {
return false;
}
- if ( is_string( $img ) ) {
- $img = wfLocalFile( $img );
- }
+
if ( !( $img instanceof LocalFile ) ) {
return false;
}
- $img->load( File::READ_LATEST );
+ $img->load();
return $user->getId() == $img->getUser( 'id' );
}
@@ -1965,7 +1948,7 @@ abstract class UploadBase {
public static function getSessionStatus( User $user, $statusKey ) {
$key = wfMemcKey( 'uploadstatus', $user->getId() ?: md5( $user->getName() ), $statusKey );
- return wfGetCache( CACHE_ANYTHING )->get( $key );
+ return ObjectCache::getMainStashInstance()->get( $key );
}
/**
@@ -1981,7 +1964,7 @@ abstract class UploadBase {
public static function setSessionStatus( User $user, $statusKey, $value ) {
$key = wfMemcKey( 'uploadstatus', $user->getId() ?: md5( $user->getName() ), $statusKey );
- $cache = wfGetCache( CACHE_ANYTHING );
+ $cache = ObjectCache::getMainStashInstance();
if ( $value === false ) {
$cache->delete( $key );
} else {
diff --git a/includes/upload/UploadFromUrl.php b/includes/upload/UploadFromUrl.php
index fc59ace5..f5787451 100644
--- a/includes/upload/UploadFromUrl.php
+++ b/includes/upload/UploadFromUrl.php
@@ -195,7 +195,7 @@ class UploadFromUrl extends UploadBase {
*/
public function fetchFile( $httpOptions = array() ) {
if ( !Http::isValidURI( $this->mUrl ) ) {
- return Status::newFatal( 'http-invalid-url' );
+ return Status::newFatal( 'http-invalid-url', $this->mUrl );
}
if ( !self::isAllowedHost( $this->mUrl ) ) {
@@ -241,7 +241,7 @@ class UploadFromUrl extends UploadBase {
wfDebugLog(
'fileupload',
'Short write ' . $this->nbytes . '/' . strlen( $buffer ) .
- ' bytes, aborting with ' . $this->mFileSize . ' uploaded so far'
+ ' bytes, aborting with ' . $this->mFileSize . ' uploaded so far'
);
fclose( $this->mTmpHandle );
$this->mTmpHandle = false;
diff --git a/includes/utils/AutoloadGenerator.php b/includes/utils/AutoloadGenerator.php
index 9cf8cab5..7d631563 100644
--- a/includes/utils/AutoloadGenerator.php
+++ b/includes/utils/AutoloadGenerator.php
@@ -119,13 +119,49 @@ class AutoloadGenerator {
}
/**
- * Write out all known classes to autoload.php in
- * the provided basedir
+ * Updates the AutoloadClasses field at the given
+ * filename.
*
- * @param string $commandName Value used in file comment to direct
- * developers towards the appropriate way to update the autoload.
+ * @param {string} $filename Filename of JSON
+ * extension/skin registration file
*/
- public function generateAutoload( $commandName = 'AutoloadGenerator' ) {
+ protected function generateJsonAutoload( $filename ) {
+ require_once __DIR__ . '/../../includes/json/FormatJson.php';
+ $key = 'AutoloadClasses';
+ $json = FormatJson::decode( file_get_contents( $filename ), true );
+ unset( $json[$key] );
+ // Inverting the key-value pairs so that they become of the
+ // format class-name : path when they get converted into json.
+ foreach ( $this->classes as $path => $contained ) {
+ foreach ( $contained as $fqcn ) {
+
+ // Using substr to remove the leading '/'
+ $json[$key][$fqcn] = substr( $path, 1 );
+ }
+ }
+ foreach ( $this->overrides as $path => $fqcn ) {
+
+ // Using substr to remove the leading '/'
+ $json[$key][$fqcn] = substr( $path, 1 );
+ }
+
+ // Sorting the list of autoload classes.
+ ksort( $json[$key] );
+
+ // Update file, using constants for the required
+ // formatting.
+ file_put_contents( $filename,
+ FormatJson::encode( $json, true ) . "\n" );
+ }
+
+ /**
+ * Generates a PHP file setting up autoload information.
+ *
+ * @param {string} $commandName Command name to include in comment
+ * @param {string} $filename of PHP file to put autoload information in.
+ */
+ protected function generatePHPAutoload( $commandName, $filename ) {
+ // No existing JSON file found; update/generate PHP file
$content = array();
// We need to generate a line each rather than exporting the
@@ -163,7 +199,7 @@ class AutoloadGenerator {
$output = implode( "\n\t", $content );
file_put_contents(
- $this->basepath . '/autoload.php',
+ $filename,
<<<EOD
<?php
// This file is generated by $commandName, do not adjust manually
@@ -176,9 +212,35 @@ global \${$this->variableName};
EOD
);
+
}
/**
+ * Write out all known classes to autoload.php, extension.json, or skin.json in
+ * the provided basedir
+ *
+ * @param string $commandName Value used in file comment to direct
+ * developers towards the appropriate way to update the autoload.
+ */
+ public function generateAutoload( $commandName = 'AutoloadGenerator' ) {
+
+ // We need to check whether an extenson.json or skin.json exists or not, and
+ // incase it doesn't, update the autoload.php file.
+
+ $jsonFilename = null;
+ if ( file_exists( $this->basepath . "/extension.json" ) ) {
+ $jsonFilename = $this->basepath . "/extension.json";
+ } elseif ( file_exists( $this->basepath . "/skin.json" ) ) {
+ $jsonFilename = $this->basepath . "/skin.json";
+ }
+
+ if ( $jsonFilename !== null ) {
+ $this->generateJsonAutoload( $jsonFilename );
+ } else {
+ $this->generatePHPAutoload( $commandName, $this->basepath . '/autoload.php' );
+ }
+ }
+ /**
* Ensure that Unix-style path separators ("/") are used in the path.
*
* @param string $path
diff --git a/includes/utils/AvroValidator.php b/includes/utils/AvroValidator.php
new file mode 100644
index 00000000..4f8e0b17
--- /dev/null
+++ b/includes/utils/AvroValidator.php
@@ -0,0 +1,184 @@
+<?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
+ */
+
+/**
+ * Generate error strings for data that doesn't match the specified
+ * Avro schema. This is very similar to AvroSchema::is_valid_datum(),
+ * but returns error messages instead of a boolean.
+ *
+ * @since 1.26
+ * @author Erik Bernhardson <ebernhardson@wikimedia.org>
+ * @copyright © 2015 Erik Bernhardson and Wikimedia Foundation.
+ */
+class AvroValidator {
+ /**
+ * @param AvroSchema $schema The rules to conform to.
+ * @param mixed $datum The value to validate against $schema.
+ * @return string|string[] An error or list of errors in the
+ * provided $datum. When no errors exist the empty array is
+ * returned.
+ */
+ public static function getErrors( AvroSchema $schema, $datum ) {
+ switch ( $schema->type) {
+ case AvroSchema::NULL_TYPE:
+ if ( !is_null($datum) ) {
+ return self::wrongType( 'null', $datum );
+ }
+ return array();
+ case AvroSchema::BOOLEAN_TYPE:
+ if ( !is_bool($datum) ) {
+ return self::wrongType( 'boolean', $datum );
+ }
+ return array();
+ case AvroSchema::STRING_TYPE:
+ case AvroSchema::BYTES_TYPE:
+ if ( !is_string($datum) ) {
+ return self::wrongType( 'string', $datum );
+ }
+ return array();
+ case AvroSchema::INT_TYPE:
+ if ( !is_int($datum) ) {
+ return self::wrongType( 'integer', $datum );
+ }
+ if ( AvroSchema::INT_MIN_VALUE > $datum
+ || $datum > AvroSchema::INT_MAX_VALUE
+ ) {
+ return self::outOfRange(
+ AvroSchema::INT_MIN_VALUE,
+ AvroSchema::INT_MAX_VALUE,
+ $datum
+ );
+ }
+ return array();
+ case AvroSchema::LONG_TYPE:
+ if ( !is_int($datum) ) {
+ return self::wrongType( 'integer', $datum );
+ }
+ if ( AvroSchema::LONG_MIN_VALUE > $datum
+ || $datum > AvroSchema::LONG_MAX_VALUE
+ ) {
+ return self::outOfRange(
+ AvroSchema::LONG_MIN_VALUE,
+ AvroSchema::LONG_MAX_VALUE,
+ $datum
+ );
+ }
+ return array();
+ case AvroSchema::FLOAT_TYPE:
+ case AvroSchema::DOUBLE_TYPE:
+ if ( !is_float($datum) && !is_int($datum) ) {
+ return self::wrongType( 'float or integer', $datum );
+ }
+ return array();
+ case AvroSchema::ARRAY_SCHEMA:
+ if (!is_array($datum)) {
+ return self::wrongType( 'array', $datum );
+ }
+ $errors = array();
+ foreach ($datum as $d) {
+ $result = $this->validate( $schema->items(), $d );
+ if ( $result ) {
+ $errors[] = $result;
+ }
+ }
+ if ( $errors ) {
+ return $errors;
+ }
+ return array();
+ case AvroSchema::MAP_SCHEMA:
+ if (!is_array($datum)) {
+ return self::wrongType( 'array', $datum );
+ }
+ $errors = array();
+ foreach ($datum as $k => $v) {
+ if ( !is_string($k) ) {
+ $errors[] = self::wrongType( 'string key', $k );
+ }
+ $result = self::getErrors( $schema->values(), $v );
+ if ( $result ) {
+ $errors[$k] = $result;
+ }
+ }
+ return $errors;
+ case AvroSchema::UNION_SCHEMA:
+ $errors = array();
+ foreach ($schema->schemas() as $schema) {
+ $result = self::getErrors( $schema, $datum );
+ if ( !$result ) {
+ return array();
+ }
+ $errors[] = $result;
+ }
+ if ( $errors ) {
+ return array( "Expected any one of these to be true", $errors );
+ }
+ return "No schemas provided to union";
+ case AvroSchema::ENUM_SCHEMA:
+ if ( !in_array( $datum, $schema->symbols() ) ) {
+ $symbols = implode( ', ', $schema->symbols );
+ return "Expected one of $symbols but recieved $datum";
+ }
+ return array();
+ case AvroSchema::FIXED_SCHEMA:
+ if ( !is_string( $datum ) ) {
+ return self::wrongType( 'string', $datum );
+ }
+ $len = strlen( $datum );
+ if ( $len !== $schema->size() ) {
+ return "Expected string of length {$schema->size()}, "
+ . "but recieved one of length $len";
+ }
+ return array();
+ case AvroSchema::RECORD_SCHEMA:
+ case AvroSchema::ERROR_SCHEMA:
+ case AvroSchema::REQUEST_SCHEMA:
+ if ( !is_array( $datum ) ) {
+ return self::wrongType( 'array', $datum );
+ }
+ $errors = array();
+ foreach ( $schema->fields() as $field ) {
+ $name = $field->name();
+ if ( !array_key_exists( $name, $datum ) ) {
+ $errors[$name] = 'Missing expected field';
+ continue;
+ }
+ $result = self::getErrors( $field->type(), $datum[$name] );
+ if ( $result ) {
+ $errors[$name] = $result;
+ }
+ }
+ return $errors;
+ default:
+ return "Unknown avro schema type: {$schema->type}";
+ }
+ }
+
+ public static function typeOf( $datum ) {
+ return is_object( $datum ) ? get_class( $datum ) : gettype( $datum );
+ }
+
+ public static function wrongType( $expected, $datum ) {
+ return "Expected $expected, but recieved " . self::typeOf( $datum );
+ }
+
+ public static function outOfRange( $min, $max, $datum ) {
+ return "Expected value between $min and $max, but recieved $datum";
+ }
+}
diff --git a/includes/utils/BatchRowIterator.php b/includes/utils/BatchRowIterator.php
new file mode 100644
index 00000000..9441608a
--- /dev/null
+++ b/includes/utils/BatchRowIterator.php
@@ -0,0 +1,278 @@
+<?php
+/**
+ * Allows iterating a large number of rows in batches transparently.
+ * By default when iterated over returns the full query result as an
+ * array of rows. Can be wrapped in RecursiveIteratorIterator to
+ * collapse those arrays into a single stream of rows queried in batches.
+ *
+ * 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 Maintenance
+ */
+class BatchRowIterator implements RecursiveIterator {
+
+ /**
+ * @var DatabaseBase $db The database to read from
+ */
+ protected $db;
+
+ /**
+ * @var string $table The name of the table to read from
+ */
+ protected $table;
+
+ /**
+ * @var array $primaryKey The name of the primary key(s)
+ */
+ protected $primaryKey;
+
+ /**
+ * @var integer $batchSize The number of rows to fetch per iteration
+ */
+ protected $batchSize;
+
+ /**
+ * @var array $conditions Array of strings containing SQL conditions
+ * to add to the query
+ */
+ protected $conditions = array();
+
+ /**
+ * @var array $joinConditions
+ */
+ protected $joinConditions = array();
+
+ /**
+ * @var array $fetchColumns List of column names to select from the
+ * table suitable for use with DatabaseBase::select()
+ */
+ protected $fetchColumns;
+
+ /**
+ * @var string $orderBy SQL Order by condition generated from $this->primaryKey
+ */
+ protected $orderBy;
+
+ /**
+ * @var array $current The current iterator value
+ */
+ private $current = array();
+
+ /**
+ * @var integer key 0-indexed number of pages fetched since self::reset()
+ */
+ private $key;
+
+ /**
+ * @param DatabaseBase $db The database to read from
+ * @param string $table The name of the table to read from
+ * @param string|array $primaryKey The name or names of the primary key columns
+ * @param integer $batchSize The number of rows to fetch per iteration
+ * @throws MWException
+ */
+ public function __construct( DatabaseBase $db, $table, $primaryKey, $batchSize ) {
+ if ( $batchSize < 1 ) {
+ throw new MWException( 'Batch size must be at least 1 row.' );
+ }
+ $this->db = $db;
+ $this->table = $table;
+ $this->primaryKey = (array) $primaryKey;
+ $this->fetchColumns = $this->primaryKey;
+ $this->orderBy = implode( ' ASC,', $this->primaryKey ) . ' ASC';
+ $this->batchSize = $batchSize;
+ }
+
+ /**
+ * @param array $condition Query conditions suitable for use with
+ * DatabaseBase::select
+ */
+ public function addConditions( array $conditions ) {
+ $this->conditions = array_merge( $this->conditions, $conditions );
+ }
+
+ /**
+ * @param array $condition Query join conditions suitable for use
+ * with DatabaseBase::select
+ */
+ public function addJoinConditions( array $conditions ) {
+ $this->joinConditions = array_merge( $this->joinConditions, $conditions );
+ }
+
+ /**
+ * @param array $columns List of column names to select from the
+ * table suitable for use with DatabaseBase::select()
+ */
+ public function setFetchColumns( array $columns ) {
+ // If it's not the all column selector merge in the primary keys we need
+ if ( count( $columns ) === 1 && reset( $columns ) === '*' ) {
+ $this->fetchColumns = $columns;
+ } else {
+ $this->fetchColumns = array_unique( array_merge(
+ $this->primaryKey,
+ $columns
+ ) );
+ }
+ }
+
+ /**
+ * Extracts the primary key(s) from a database row.
+ *
+ * @param stdClass $row An individual database row from this iterator
+ * @return array Map of primary key column to value within the row
+ */
+ public function extractPrimaryKeys( $row ) {
+ $pk = array();
+ foreach ( $this->primaryKey as $column ) {
+ $pk[$column] = $row->$column;
+ }
+ return $pk;
+ }
+
+ /**
+ * @return array The most recently fetched set of rows from the database
+ */
+ public function current() {
+ return $this->current;
+ }
+
+ /**
+ * @return integer 0-indexed count of the page number fetched
+ */
+ public function key() {
+ return $this->key;
+ }
+
+ /**
+ * Reset the iterator to the begining of the table.
+ */
+ public function rewind() {
+ $this->key = -1; // self::next() will turn this into 0
+ $this->current = array();
+ $this->next();
+ }
+
+ /**
+ * @return boolean True when the iterator is in a valid state
+ */
+ public function valid() {
+ return (bool) $this->current;
+ }
+
+ /**
+ * @return boolean True when this result set has rows
+ */
+ public function hasChildren() {
+ return $this->current && count( $this->current );
+ }
+
+ /**
+ * @return RecursiveIterator
+ */
+ public function getChildren() {
+ return new NotRecursiveIterator( new ArrayIterator( $this->current ) );
+ }
+
+ /**
+ * Fetch the next set of rows from the database.
+ */
+ public function next() {
+ $res = $this->db->select(
+ $this->table,
+ $this->fetchColumns,
+ $this->buildConditions(),
+ __METHOD__,
+ array(
+ 'LIMIT' => $this->batchSize,
+ 'ORDER BY' => $this->orderBy,
+ ),
+ $this->joinConditions
+ );
+
+ // The iterator is converted to an array because in addition to
+ // returning it in self::current() we need to use the end value
+ // in self::buildConditions()
+ $this->current = iterator_to_array( $res );
+ $this->key++;
+ }
+
+ /**
+ * Uses the primary key list and the maximal result row from the
+ * previous iteration to build an SQL condition sufficient for
+ * selecting the next page of results. All except the final key use
+ * `=` conditions while the final key uses a `>` condition
+ *
+ * Example output:
+ * array( '( foo = 42 AND bar > 7 ) OR ( foo > 42 )' )
+ *
+ * @return array The SQL conditions necessary to select the next set
+ * of rows in the batched query
+ */
+ protected function buildConditions() {
+ if ( !$this->current ) {
+ return $this->conditions;
+ }
+
+ $maxRow = end( $this->current );
+ $maximumValues = array();
+ foreach ( $this->primaryKey as $column ) {
+ $maximumValues[$column] = $this->db->addQuotes( $maxRow->$column );
+ }
+
+ $pkConditions = array();
+ // For example: If we have 3 primary keys
+ // first run through will generate
+ // col1 = 4 AND col2 = 7 AND col3 > 1
+ // second run through will generate
+ // col1 = 4 AND col2 > 7
+ // and the final run through will generate
+ // col1 > 4
+ while ( $maximumValues ) {
+ $pkConditions[] = $this->buildGreaterThanCondition( $maximumValues );
+ array_pop( $maximumValues );
+ }
+
+ $conditions = $this->conditions;
+ $conditions[] = sprintf( '( %s )', implode( ' ) OR ( ', $pkConditions ) );
+
+ return $conditions;
+ }
+
+ /**
+ * Given an array of column names and their maximum value generate
+ * an SQL condition where all keys except the last match $quotedMaximumValues
+ * exactly and the last column is greater than the matching value in
+ * $quotedMaximumValues
+ *
+ * @param array $quotedMaximumValues The maximum values quoted with
+ * $this->db->addQuotes()
+ * @return string An SQL condition that will select rows where all
+ * columns match the maximum value exactly except the last column
+ * which must be greater than the provided maximum value
+ */
+ protected function buildGreaterThanCondition( array $quotedMaximumValues ) {
+ $keys = array_keys( $quotedMaximumValues );
+ $lastColumn = end( $keys );
+ $lastValue = array_pop( $quotedMaximumValues );
+ $conditions = array();
+ foreach ( $quotedMaximumValues as $column => $value ) {
+ $conditions[] = "$column = $value";
+ }
+ $conditions[] = "$lastColumn > $lastValue";
+
+ return implode( ' AND ', $conditions );
+ }
+}
diff --git a/includes/utils/BatchRowUpdate.php b/includes/utils/BatchRowUpdate.php
new file mode 100644
index 00000000..a4257a53
--- /dev/null
+++ b/includes/utils/BatchRowUpdate.php
@@ -0,0 +1,133 @@
+<?php
+/*
+ * Ties together the batch update components to provide a composable
+ * method of batch updating rows in a database. To use create a class
+ * implementing the RowUpdateGenerator interface and configure the
+ * BatchRowIterator and BatchRowWriter for access to the correct table.
+ * The components will handle reading, writing, and waiting for slaves
+ * while the generator implementation handles generating update arrays
+ * for singular rows.
+ *
+ * Instantiate:
+ * $updater = new BatchRowUpdate(
+ * new BatchRowIterator( $dbr, 'some_table', 'primary_key_column', 500 ),
+ * new BatchRowWriter( $dbw, 'some_table', 'clusterName' ),
+ * new MyImplementationOfRowUpdateGenerator
+ * );
+ *
+ * Run:
+ * $updater->execute();
+ *
+ * An example maintenance script utilizing the BatchRowUpdate can be
+ * located in the Echo extension file maintenance/updateSchema.php
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+class BatchRowUpdate {
+ /**
+ * @var BatchRowIterator $reader Iterator that returns an array of
+ * database rows
+ */
+ protected $reader;
+
+ /**
+ * @var BatchRowWriter $writer Writer capable of pushing row updates
+ * to the database
+ */
+ protected $writer;
+
+ /**
+ * @var RowUpdateGenerator $generator Generates single row updates
+ * based on the rows content
+ */
+ protected $generator;
+
+ /**
+ * @var callable $output Output callback
+ */
+ protected $output;
+
+ /**
+ * @param BatchRowIterator $reader Iterator that returns an
+ * array of database rows
+ * @param BatchRowWriter $writer Writer capable of pushing
+ * row updates to the database
+ * @param RowUpdateGenerator $generator Generates single row updates
+ * based on the rows content
+ */
+ public function __construct( BatchRowIterator $reader, BatchRowWriter $writer, RowUpdateGenerator $generator ) {
+ $this->reader = $reader;
+ $this->writer = $writer;
+ $this->generator = $generator;
+ $this->output = function() {
+ }; // nop
+ }
+
+ /**
+ * Runs the batch update process
+ */
+ public function execute() {
+ foreach ( $this->reader as $rows ) {
+ $updates = array();
+ foreach ( $rows as $row ) {
+ $update = $this->generator->update( $row );
+ if ( $update ) {
+ $updates[] = array(
+ 'primaryKey' => $this->reader->extractPrimaryKeys( $row ),
+ 'changes' => $update,
+ );
+ }
+ }
+
+ if ( $updates ) {
+ $this->output( "Processing " . count( $updates ) . " rows\n" );
+ $this->writer->write( $updates );
+ }
+ }
+
+ $this->output( "Completed\n" );
+ }
+
+ /**
+ * Accepts a callable which will receive a single parameter
+ * containing string status updates
+ *
+ * @param callable $output A callback taking a single string
+ * parameter to output
+ *
+ * @throws MWException
+ */
+ public function setOutput( $output ) {
+ if ( !is_callable( $output ) ) {
+ throw new MWException(
+ 'Provided $output param is required to be callable.'
+ );
+ }
+ $this->output = $output;
+ }
+
+ /**
+ * Write out a status update
+ *
+ * @param string $text The value to print
+ */
+ protected function output( $text ) {
+ call_user_func( $this->output, $text );
+ }
+}
diff --git a/includes/utils/BatchRowWriter.php b/includes/utils/BatchRowWriter.php
new file mode 100644
index 00000000..04c00a3d
--- /dev/null
+++ b/includes/utils/BatchRowWriter.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Updates database rows by primary key in batches.
+ *
+ * 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 Maintenance
+ */
+class BatchRowWriter {
+ /**
+ * @var DatabaseBase $db The database to write to
+ */
+ protected $db;
+
+ /**
+ * @var string $table The name of the table to update
+ */
+ protected $table;
+
+ /**
+ * @var string $clusterName A cluster name valid for use with LBFactory
+ */
+ protected $clusterName;
+
+ /**
+ * @param DatabaseBase $db The database to write to
+ * @param string $table The name of the table to update
+ * @param string|bool $clusterName A cluster name valid for use with LBFactory
+ */
+ public function __construct( DatabaseBase $db, $table, $clusterName = false ) {
+ $this->db = $db;
+ $this->table = $table;
+ $this->clusterName = $clusterName;
+ }
+
+ /**
+ * @param array $updates Array of arrays each containing two keys, 'primaryKey'
+ * and 'changes'. primaryKey must contain a map of column names to values
+ * sufficient to uniquely identify the row changes must contain a map of column
+ * names to update values to apply to the row.
+ */
+ public function write( array $updates ) {
+ $this->db->begin();
+
+ foreach ( $updates as $update ) {
+ $this->db->update(
+ $this->table,
+ $update['changes'],
+ $update['primaryKey'],
+ __METHOD__
+ );
+ }
+
+ $this->db->commit();
+ wfWaitForSlaves( false, false, $this->clusterName );
+ }
+}
diff --git a/includes/utils/IP.php b/includes/utils/IP.php
index 4441236d..666660aa 100644
--- a/includes/utils/IP.php
+++ b/includes/utils/IP.php
@@ -21,6 +21,8 @@
* @author Antoine Musso "<hashar at free dot fr>", Aaron Schulz
*/
+use IPSet\IPSet;
+
// Some regex definition to "play" with IP address and IP address blocks
// An IPv4 address is made of 4 bytes from x00 to xFF which is d0 to d255
@@ -240,7 +242,7 @@ class IP {
* A bare IPv6 address is accepted despite the lack of square brackets.
*
* @param string $both The string with the host and port
- * @return array
+ * @return array|false Array normally, false on certain failures
*/
public static function splitHostAndPort( $both ) {
if ( substr( $both, 0, 1 ) === '[' ) {
@@ -375,6 +377,8 @@ class IP {
'127.0.0.0/8', # loopback
'fc00::/7', # RFC 4193 (local)
'0:0:0:0:0:0:0:1', # loopback
+ '169.254.0.0/16', # link-local
+ 'fe80::/10', # link-local
) );
}
return !$privateSet->match( $ip );
diff --git a/includes/utils/MWCryptHKDF.php b/includes/utils/MWCryptHKDF.php
index 950dd846..740df922 100644
--- a/includes/utils/MWCryptHKDF.php
+++ b/includes/utils/MWCryptHKDF.php
@@ -161,7 +161,7 @@ class MWCryptHKDF {
* @throws MWException
*/
protected static function singleton() {
- global $wgHKDFAlgorithm, $wgHKDFSecret, $wgSecretKey;
+ global $wgHKDFAlgorithm, $wgHKDFSecret, $wgSecretKey, $wgMainCacheType;
$secret = $wgHKDFSecret ?: $wgSecretKey;
if ( !$secret ) {
@@ -176,11 +176,7 @@ class MWCryptHKDF {
$context[] = gethostname();
// Setup salt cache. Use APC, or fallback to the main cache if it isn't setup
- try {
- $cache = ObjectCache::newAccelerator( array() );
- } catch ( Exception $e ) {
- $cache = wfGetMainCache();
- }
+ $cache = ObjectCache::newAccelerator( $wgMainCacheType );
if ( is_null( self::$singleton ) ) {
self::$singleton = new self( $secret, $wgHKDFAlgorithm, $cache, $context );
diff --git a/includes/utils/MWCryptRand.php b/includes/utils/MWCryptRand.php
index e6c0e784..f2237909 100644
--- a/includes/utils/MWCryptRand.php
+++ b/includes/utils/MWCryptRand.php
@@ -96,9 +96,9 @@ class MWCryptRand {
}
foreach ( $files as $file ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$stat = stat( $file );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $stat ) {
// stat() duplicates data into numeric and string keys so kill off all the numeric ones
foreach ( $stat as $k => $v ) {
@@ -363,9 +363,9 @@ class MWCryptRand {
}
// /dev/urandom is generally considered the best possible commonly
// available random source, and is available on most *nix systems.
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$urandom = fopen( "/dev/urandom", "rb" );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
// Attempt to read all our random data from urandom
// php's fread always does buffered reads based on the stream's chunk_size
diff --git a/includes/utils/RowUpdateGenerator.php b/includes/utils/RowUpdateGenerator.php
new file mode 100644
index 00000000..6a4792cb
--- /dev/null
+++ b/includes/utils/RowUpdateGenerator.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Interface for generating updates to single rows in the database.
+ *
+ * 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 Maintenance
+ */
+interface RowUpdateGenerator {
+ /**
+ * Given a database row, generates an array mapping column names to
+ * updated value within the database row.
+ *
+ * Sample Response:
+ * return array(
+ * 'some_col' => 'new value',
+ * 'other_col' => 99,
+ * );
+ *
+ * @param stdClass $row A row from the database
+ * @return array Map of column names to updated value within the
+ * database row. When no update is required returns an empty array.
+ */
+ public function update( $row );
+}
diff --git a/includes/utils/UIDGenerator.php b/includes/utils/UIDGenerator.php
index 92415877..04c8e194 100644
--- a/includes/utils/UIDGenerator.php
+++ b/includes/utils/UIDGenerator.php
@@ -20,6 +20,7 @@
* @file
* @author Aaron Schulz
*/
+use Wikimedia\Assert\Assert;
/**
* Class for getting statistically unique IDs
@@ -51,7 +52,7 @@ class UIDGenerator {
}
// Try to get some ID that uniquely identifies this machine (RFC 4122)...
if ( !preg_match( '/^[0-9a-f]{12}$/i', $nodeId ) ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
if ( wfIsWindows() ) {
// http://technet.microsoft.com/en-us/library/bb490913.aspx
$csv = trim( wfShellExec( 'getmac /NH /FO CSV' ) );
@@ -65,7 +66,7 @@ class UIDGenerator {
wfShellExec( '/sbin/ifconfig -a' ), $m );
$nodeId = isset( $m[1] ) ? str_replace( ':', '', $m[1] ) : '';
}
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !preg_match( '/^[0-9a-f]{12}$/i', $nodeId ) ) {
$nodeId = MWCryptRand::generateHex( 12, true );
$nodeId[1] = dechex( hexdec( $nodeId[1] ) | 0x1 ); // set multicast bit
@@ -107,9 +108,10 @@ class UIDGenerator {
* @throws MWException
*/
public static function newTimestampedUID88( $base = 10 ) {
- if ( !is_integer( $base ) || $base > 36 || $base < 2 ) {
- throw new MWException( "Base must an integer be between 2 and 36" );
- }
+ Assert::parameterType( 'integer', $base, '$base' );
+ Assert::parameter( $base <= 36, '$base', 'must be <= 36' );
+ Assert::parameter( $base >= 2, '$base', 'must be >= 2' );
+
$gen = self::singleton();
$time = $gen->getTimestampAndDelay( 'lockFile88', 1, 1024 );
@@ -152,9 +154,10 @@ class UIDGenerator {
* @throws MWException
*/
public static function newTimestampedUID128( $base = 10 ) {
- if ( !is_integer( $base ) || $base > 36 || $base < 2 ) {
- throw new MWException( "Base must be an integer between 2 and 36" );
- }
+ Assert::parameterType( 'integer', $base, '$base' );
+ Assert::parameter( $base <= 36, '$base', 'must be <= 36' );
+ Assert::parameter( $base >= 2, '$base', 'must be >= 2' );
+
$gen = self::singleton();
$time = $gen->getTimestampAndDelay( 'lockFile128', 16384, 1048576 );
@@ -280,7 +283,7 @@ class UIDGenerator {
$cache = null;
if ( ( $flags & self::QUICK_VOLATILE ) && PHP_SAPI !== 'cli' ) {
try {
- $cache = ObjectCache::newAccelerator( array() );
+ $cache = ObjectCache::newAccelerator();
} catch ( Exception $e ) {
// not supported
}
diff --git a/includes/utils/iterators/IteratorDecorator.php b/includes/utils/iterators/IteratorDecorator.php
new file mode 100644
index 00000000..c1b50207
--- /dev/null
+++ b/includes/utils/iterators/IteratorDecorator.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Allows extending classes to decorate an Iterator with
+ * reduced boilerplate.
+ *
+ * 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 Maintenance
+ */
+abstract class IteratorDecorator implements Iterator {
+ protected $iterator;
+
+ public function __construct( Iterator $iterator ) {
+ $this->iterator = $iterator;
+ }
+
+ public function current() {
+ return $this->iterator->current();
+ }
+
+ public function key() {
+ return $this->iterator->key();
+ }
+
+ public function next() {
+ $this->iterator->next();
+ }
+
+ public function rewind() {
+ $this->iterator->rewind();
+ }
+
+ public function valid() {
+ return $this->iterator->valid();
+ }
+}
diff --git a/includes/utils/MWFunction.php b/includes/utils/iterators/NotRecursiveIterator.php
index fa7eebe8..52ca61b4 100644
--- a/includes/utils/MWFunction.php
+++ b/includes/utils/iterators/NotRecursiveIterator.php
@@ -1,6 +1,10 @@
<?php
/**
- * Helper methods to call functions and instance objects.
+ * Wraps a non-recursive iterator with methods to be recursive
+ * without children.
+ *
+ * Alternatively wraps a recursive iterator to prevent recursing deeper
+ * than the wrapped iterator.
*
* 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
@@ -18,23 +22,14 @@
* http://www.gnu.org/copyleft/gpl.html
*
* @file
+ * @ingroup Maintenance
*/
+class NotRecursiveIterator extends IteratorDecorator implements RecursiveIterator {
+ public function hasChildren() {
+ return false;
+ }
-class MWFunction {
-
- /**
- * @param string $class
- * @param array $args
- * @return object
- * @deprecated 1.25 Use ObjectFactory::getObjectFromSpec() instead
- */
- public static function newObj( $class, $args = array() ) {
- wfDeprecated( __METHOD__, '1.25' );
-
- return ObjectFactory::getObjectFromSpec( array(
- 'class' => $class,
- 'args' => $args,
- 'closure_expansion' => false,
- ) );
+ public function getChildren() {
+ return null;
}
}
diff --git a/includes/widget/AUTHORS.txt b/includes/widget/AUTHORS.txt
new file mode 100644
index 00000000..a0d77030
--- /dev/null
+++ b/includes/widget/AUTHORS.txt
@@ -0,0 +1,11 @@
+Authors (alphabetically)
+
+Alex Monk <krenair@wikimedia.org>
+Bartosz Dziewoński <bdziewonski@wikimedia.org>
+Ed Sanders <esanders@wikimedia.org>
+Florian Schmidt <florian.schmidt.welzow@t-online.de>
+James D. Forrester <jforrester@wikimedia.org>
+Roan Kattouw <roan@wikimedia.org>
+Sucheta Ghoshal <sghoshal@wikimedia.org>
+Timo Tijhof <timo@wikimedia.org>
+Trevor Parscal <trevor@wikimedia.org>
diff --git a/includes/widget/ComplexNamespaceInputWidget.php b/includes/widget/ComplexNamespaceInputWidget.php
new file mode 100644
index 00000000..21c57099
--- /dev/null
+++ b/includes/widget/ComplexNamespaceInputWidget.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * MediaWiki Widgets – ComplexNamespaceInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+namespace MediaWiki\Widget;
+
+/**
+ * Namespace input widget. Displays a dropdown box with the choice of available namespaces, plus two
+ * checkboxes to include associated namespace or to invert selection.
+ */
+class ComplexNamespaceInputWidget extends \OOUI\Widget {
+
+ protected $config;
+ protected $namespace;
+ protected $associated = null;
+ protected $associatedLabel = null;
+ protected $invert = null;
+ protected $invertLabel = null;
+
+ /**
+ * @param array $config Configuration options
+ * @param array $config['namespace'] Configuration for the NamespaceInputWidget dropdown with list
+ * of namespaces
+ * @param string $config['namespace']['includeAllValue'] If specified, add a "all namespaces"
+ * option to the dropdown, and use this as the input value for it
+ * @param array|null $config['invert'] Configuration for the "invert selection" CheckboxInputWidget. If
+ * null, the checkbox will not be generated.
+ * @param array|null $config['associated'] Configuration for the "include associated namespace"
+ * CheckboxInputWidget. If null, the checkbox will not be generated.
+ * @param array $config['invertLabel'] Configuration for the FieldLayout with label wrapping the
+ * "invert selection" checkbox
+ * @param string $config['invertLabel']['label'] Label text for the label
+ * @param array $config['associatedLabel'] Configuration for the FieldLayout with label wrapping
+ * the "include associated namespace" checkbox
+ * @param string $config['associatedLabel']['label'] Label text for the label
+ */
+ public function __construct( array $config = array() ) {
+ // Configuration initialization
+ $config = array_merge(
+ array(
+ // Config options for nested widgets
+ 'namespace' => array(),
+ 'invert' => array(),
+ 'invertLabel' => array(),
+ 'associated' => array(),
+ 'associatedLabel' => array(),
+ ),
+ $config
+ );
+
+ // Parent constructor
+ parent::__construct( $config );
+
+ // Properties
+ $this->config = $config;
+
+ $this->namespace = new NamespaceInputWidget( $config['namespace'] );
+ if ( $config['associated'] !== null ) {
+ $this->associated = new \OOUI\CheckboxInputWidget( array_merge(
+ array( 'value' => '1' ),
+ $config['associated']
+ ) );
+ // TODO Should use a LabelWidget? But they don't work like HTML <label>s yet
+ $this->associatedLabel = new \OOUI\FieldLayout(
+ $this->associated,
+ array_merge(
+ array( 'align' => 'inline' ),
+ $config['associatedLabel']
+ )
+ );
+ }
+ if ( $config['invert'] !== null ) {
+ $this->invert = new \OOUI\CheckboxInputWidget( array_merge(
+ array( 'value' => '1' ),
+ $config['invert']
+ ) );
+ // TODO Should use a LabelWidget? But they don't work like HTML <label>s yet
+ $this->invertLabel = new \OOUI\FieldLayout(
+ $this->invert,
+ array_merge(
+ array( 'align' => 'inline' ),
+ $config['invertLabel']
+ )
+ );
+ }
+
+ // Initialization
+ $this
+ ->addClasses( array( 'mw-widget-complexNamespaceInputWidget' ) )
+ ->appendContent( $this->namespace, $this->associatedLabel, $this->invertLabel );
+ }
+
+ protected function getJavaScriptClassName() {
+ return 'mw.widgets.ComplexNamespaceInputWidget';
+ }
+
+ public function getConfig( &$config ) {
+ $config = array_merge(
+ $config,
+ array_intersect_key(
+ $this->config,
+ array_fill_keys( array( 'namespace', 'invert', 'invertLabel', 'associated', 'associatedLabel' ), true )
+ )
+ );
+ return parent::getConfig( $config );
+ }
+}
diff --git a/includes/widget/ComplexTitleInputWidget.php b/includes/widget/ComplexTitleInputWidget.php
new file mode 100644
index 00000000..73ef54c8
--- /dev/null
+++ b/includes/widget/ComplexTitleInputWidget.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * MediaWiki Widgets – ComplexTitleInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+namespace MediaWiki\Widget;
+
+/**
+ * Complex title input widget.
+ */
+class ComplexTitleInputWidget extends \OOUI\Widget {
+
+ protected $namespace = null;
+ protected $title = null;
+
+ /**
+ * Like TitleInputWidget, but the namespace has to be input through a separate dropdown field.
+ *
+ * @param array $config Configuration options
+ * @param array $config['namespace'] Configuration for the NamespaceInputWidget dropdown with list
+ * of namespaces
+ * @param array $config['title'] Configuration for the TitleInputWidget text field
+ */
+ public function __construct( array $config = array() ) {
+ // Configuration initialization
+ $config = array_merge(
+ array(
+ 'namespace' => array(),
+ 'title' => array(),
+ ),
+ $config
+ );
+
+ // Parent constructor
+ parent::__construct( $config );
+
+ // Properties
+ $this->config = $config;
+ $this->namespace = new NamespaceInputWidget( $config['namespace'] );
+ $this->title = new TitleInputWidget( array_merge(
+ $config['title'],
+ array(
+ // The inner TitleInputWidget shouldn't be infusable, only the ComplexTitleInputWidget itself can be.
+ 'infusable' => false,
+ 'relative' => true,
+ 'namespace' => isset( $config['namespace']['value'] ) ? $config['namespace']['value'] : null,
+ )
+ ) );
+
+ // Initialization
+ $this
+ ->addClasses( array( 'mw-widget-complexTitleInputWidget' ) )
+ ->appendContent( $this->namespace, $this->title );
+ }
+
+ protected function getJavaScriptClassName() {
+ return 'mw.widgets.ComplexTitleInputWidget';
+ }
+
+ public function getConfig( &$config ) {
+ $config['namespace'] = $this->config['namespace'];
+ $config['title'] = $this->config['title'];
+ return parent::getConfig( $config );
+ }
+}
diff --git a/includes/widget/LICENSE.txt b/includes/widget/LICENSE.txt
new file mode 100644
index 00000000..b03ca801
--- /dev/null
+++ b/includes/widget/LICENSE.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2011-2015 MediaWiki Widgets Team and others under the
+terms of The MIT License (MIT), as follows:
+
+This software consists of voluntary contributions made by many
+individuals (AUTHORS.txt) For exact contribution history, see the
+revision history and logs, available at https://gerrit.wikimedia.org
+
+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 to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/includes/widget/NamespaceInputWidget.php b/includes/widget/NamespaceInputWidget.php
new file mode 100644
index 00000000..696c8adf
--- /dev/null
+++ b/includes/widget/NamespaceInputWidget.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * MediaWiki Widgets – NamespaceInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+namespace MediaWiki\Widget;
+
+/**
+ * Namespace input widget. Displays a dropdown box with the choice of available namespaces.
+ */
+class NamespaceInputWidget extends \OOUI\DropdownInputWidget {
+
+ protected $includeAllValue = null;
+
+ /**
+ * @param array $config Configuration options
+ * @param string $config['includeAllValue'] If specified, add a "all namespaces" option to the
+ * namespace dropdown, and use this as the input value for it
+ * @param number[] $config['exclude'] List of namespace numbers to exclude from the selector
+ */
+ public function __construct( array $config = array() ) {
+ // Configuration initialization
+ $config['options'] = $this->getNamespaceDropdownOptions( $config );
+
+ // Parent constructor
+ parent::__construct( $config );
+
+ // Properties
+ $this->includeAllValue = isset( $config['includeAllValue'] ) ? $config['includeAllValue'] : null;
+ $this->exclude = isset( $config['exclude'] ) ? $config['exclude'] : array();
+
+ // Initialization
+ $this->addClasses( array( 'mw-widget-namespaceInputWidget' ) );
+ }
+
+ protected function getNamespaceDropdownOptions( array $config ) {
+ $namespaceOptionsParams = array(
+ 'all' => isset( $config['includeAllValue'] ) ? $config['includeAllValue'] : null,
+ 'exclude' => isset( $config['exclude'] ) ? $config['exclude'] : null
+ );
+ $namespaceOptions = \Html::namespaceSelectorOptions( $namespaceOptionsParams );
+
+ $options = array();
+ foreach ( $namespaceOptions as $id => $name ) {
+ $options[] = array(
+ 'data' => (string)$id,
+ 'label' => $name,
+ );
+ }
+
+ return $options;
+ }
+
+ protected function getJavaScriptClassName() {
+ return 'mw.widgets.NamespaceInputWidget';
+ }
+
+ public function getConfig( &$config ) {
+ $config['includeAllValue'] = $this->includeAllValue;
+ $config['exclude'] = $this->exclude;
+ // Skip DropdownInputWidget's getConfig(), we don't need 'options' config
+ return \OOUI\InputWidget::getConfig( $config );
+ }
+}
diff --git a/includes/widget/TitleInputWidget.php b/includes/widget/TitleInputWidget.php
new file mode 100644
index 00000000..8ac7014e
--- /dev/null
+++ b/includes/widget/TitleInputWidget.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * MediaWiki Widgets – TitleInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+namespace MediaWiki\Widget;
+
+/**
+ * Title input widget.
+ */
+class TitleInputWidget extends \OOUI\TextInputWidget {
+
+ protected $namespace = null;
+ protected $relative = null;
+ protected $suggestions = null;
+
+ /**
+ * @param array $config Configuration options
+ * @param int|null $config['namespace'] Namespace to prepend to queries
+ * @param bool|null $config['relative'] If a namespace is set, return a title relative to it (default: true)
+ * @param bool|null $config['suggestions'] Display search suggestions (default: true)
+ */
+ public function __construct( array $config = array() ) {
+ // Parent constructor
+ parent::__construct( array_merge( array( 'infusable' => true, 'maxLength' => 255 ), $config ) );
+
+ // Properties, which are ignored in PHP and just shipped back to JS
+ if ( isset( $config['namespace'] ) ) {
+ $this->namespace = $config['namespace'];
+ }
+ if ( isset( $config['relative'] ) ) {
+ $this->relative = $config['relative'];
+ }
+ if ( isset( $config['suggestions'] ) ) {
+ $this->suggestions = $config['suggestions'];
+ }
+
+ // Initialization
+ $this->addClasses( array( 'mw-widget-titleInputWidget' ) );
+ }
+
+ protected function getJavaScriptClassName() {
+ return 'mw.widgets.TitleInputWidget';
+ }
+
+ public function getConfig( &$config ) {
+ if ( $this->namespace !== null ) {
+ $config['namespace'] = $this->namespace;
+ }
+ if ( $this->relative !== null ) {
+ $config['relative'] = $this->relative;
+ }
+ if ( $this->suggestions !== null ) {
+ $config['suggestions'] = $this->suggestions;
+ }
+ return parent::getConfig( $config );
+ }
+}
diff --git a/includes/widget/UserInputWidget.php b/includes/widget/UserInputWidget.php
new file mode 100644
index 00000000..1e2d3d61
--- /dev/null
+++ b/includes/widget/UserInputWidget.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * MediaWiki Widgets – UserInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+namespace MediaWiki\Widget;
+
+/**
+ * User input widget.
+ */
+class UserInputWidget extends \OOUI\TextInputWidget {
+
+ /**
+ * @param array $config Configuration options
+ */
+ public function __construct( array $config = array() ) {
+ // Parent constructor
+ parent::__construct( array_merge( array( 'infusable' => true ), $config ) );
+
+ // Initialization
+ $this->addClasses( array( 'mw-widget-userInputWidget' ) );
+ }
+
+ protected function getJavaScriptClassName() {
+ return 'mw.widgets.UserInputWidget';
+ }
+}