Merge "Get to the point about howto download Vector :p"
authorBartosz Dziewoński <matma.rex@gmail.com>
Sat, 13 Dec 2014 18:14:39 +0000 (18:14 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Sat, 13 Dec 2014 18:14:39 +0000 (18:14 +0000)
362 files changed:
HISTORY
README
RELEASE-NOTES-1.25
api.php
autoload.php
composer.json
docs/export-demo.xml
docs/hooks.txt
docs/memcached.txt
images/.htaccess
includes/Autopromote.php
includes/Block.php
includes/CdbCompat.php
includes/ChangeTags.php
includes/Collation.php
includes/Defines.php
includes/EditPage.php
includes/Export.php
includes/FileDeleteForm.php
includes/GitInfo.php
includes/GlobalFunctions.php
includes/Import.php
includes/Linker.php
includes/MWNamespace.php
includes/MWTimestamp.php
includes/MagicWord.php
includes/MediaWiki.php
includes/MimeMagic.php
includes/MovePage.php
includes/OutputHandler.php
includes/OutputPage.php
includes/Preferences.php
includes/PrefixSearch.php
includes/ProtectionForm.php
includes/Revision.php
includes/Sanitizer.php
includes/Setup.php
includes/Status.php
includes/Title.php
includes/TitleArray.php
includes/User.php
includes/UserArray.php
includes/WebRequest.php
includes/WebResponse.php
includes/Xml.php
includes/actions/EditAction.php
includes/actions/FormAction.php
includes/actions/HistoryAction.php
includes/actions/InfoAction.php
includes/actions/RawAction.php
includes/actions/RevertAction.php
includes/actions/WatchAction.php
includes/api/ApiBase.php
includes/api/ApiCreateAccount.php
includes/api/ApiEditPage.php
includes/api/ApiFormatBase.php
includes/api/ApiHelp.php
includes/api/ApiLogin.php
includes/api/ApiLogout.php
includes/api/ApiMain.php
includes/api/ApiOpenSearch.php
includes/api/ApiPageSet.php
includes/api/ApiParse.php
includes/api/ApiPatrol.php
includes/api/ApiQuery.php
includes/api/ApiQueryInfo.php
includes/api/ApiQueryRecentChanges.php
includes/api/ApiQueryRevisions.php
includes/api/ApiQueryRevisionsBase.php
includes/api/ApiQuerySearch.php
includes/api/ApiQuerySiteinfo.php
includes/api/ApiQueryTokens.php
includes/api/ApiQueryUsers.php
includes/api/ApiRsd.php
includes/api/ApiStashEdit.php
includes/api/ApiTokens.php
includes/api/ApiUndelete.php
includes/api/i18n/ar.json
includes/api/i18n/be-tarask.json
includes/api/i18n/bs.json [new file with mode: 0644]
includes/api/i18n/en.json
includes/api/i18n/es.json
includes/api/i18n/fa.json
includes/api/i18n/fr.json
includes/api/i18n/gl.json [new file with mode: 0644]
includes/api/i18n/ksh.json
includes/api/i18n/mg.json [new file with mode: 0644]
includes/api/i18n/mk.json
includes/api/i18n/ms.json
includes/api/i18n/nl.json
includes/api/i18n/te.json [new file with mode: 0644]
includes/api/i18n/zh-hans.json
includes/api/i18n/zh-hant.json
includes/cache/BacklinkCache.php
includes/cache/HTMLFileCache.php
includes/cache/LocalisationCache.php
includes/cache/MessageCache.php
includes/cache/ResourceFileCache.php
includes/changes/ChangesList.php
includes/changes/OldChangesList.php
includes/changes/RecentChange.php
includes/content/AbstractContent.php
includes/content/ContentHandler.php
includes/content/WikitextContent.php
includes/context/RequestContext.php
includes/db/Database.php
includes/db/DatabaseMysqlBase.php
includes/db/DatabaseOracle.php
includes/db/DatabaseUtility.php
includes/db/LBFactory.php
includes/db/LoadBalancer.php
includes/debug/logger/monolog/Spi.php
includes/deferred/LinksUpdate.php
includes/deferred/SearchUpdate.php
includes/diff/DifferenceEngine.php
includes/exception/MWExceptionHandler.php
includes/filebackend/FSFileBackend.php
includes/filebackend/FileBackendMultiWrite.php
includes/filebackend/lockmanager/DBLockManager.php
includes/filebackend/lockmanager/LockManager.php
includes/filebackend/lockmanager/MemcLockManager.php
includes/filerepo/file/File.php
includes/filerepo/file/LocalFile.php
includes/gallery/ImageGalleryBase.php
includes/gallery/TraditionalImageGallery.php
includes/installer/DatabaseUpdater.php
includes/installer/WebInstallerOutput.php
includes/installer/i18n/bg.json
includes/installer/i18n/bn.json
includes/installer/i18n/ca.json
includes/installer/i18n/de.json
includes/installer/i18n/fi.json
includes/installer/i18n/te.json
includes/installer/i18n/vi.json
includes/installer/i18n/zh-hant.json
includes/interwiki/Interwiki.php
includes/jobqueue/JobQueueFederated.php
includes/libs/GenericArrayObject.php
includes/libs/IPSet.php
includes/libs/ObjectFactory.php
includes/libs/ScopedCallback.php
includes/libs/Xhprof.php
includes/libs/XmlTypeCheck.php
includes/logging/LogEventsList.php
includes/logging/LogFormatter.php
includes/mail/EmailNotification.php
includes/mail/UserMailer.php
includes/media/Bitmap.php
includes/media/FormatMetadata.php
includes/media/MediaHandler.php
includes/media/MediaTransformOutput.php
includes/media/TransformationalImageHandler.php
includes/media/XMP.php
includes/media/XMPInfo.php
includes/page/Article.php
includes/page/CategoryPage.php
includes/page/ImagePage.php
includes/page/WikiPage.php
includes/parser/LinkHolderArray.php
includes/parser/MWTidy.php
includes/parser/Parser.php
includes/parser/ParserOptions.php
includes/profiler/Profiler.php
includes/profiler/ProfilerStandard.php
includes/profiler/ProfilerStub.php
includes/profiler/ProfilerXhprof.php
includes/profiler/SectionProfiler.php
includes/profiler/output/ProfilerOutputDb.php
includes/profiler/output/ProfilerOutputText.php
includes/profiler/output/ProfilerOutputUdp.php
includes/rcfeed/IRCColourfulRCFeedFormatter.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderContext.php
includes/resourceloader/ResourceLoaderImage.php [new file with mode: 0644]
includes/resourceloader/ResourceLoaderImageModule.php [new file with mode: 0644]
includes/resourceloader/ResourceLoaderModule.php
includes/resourceloader/ResourceLoaderSkinModule.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php
includes/resourceloader/ResourceLoaderUserDefaultsModule.php [new file with mode: 0644]
includes/resourceloader/ResourceLoaderUserOptionsModule.php
includes/resourceloader/ResourceLoaderWikiModule.php
includes/revisiondelete/RevDelArchiveList.php
includes/revisiondelete/RevDelArchivedFileList.php
includes/revisiondelete/RevDelFileList.php
includes/revisiondelete/RevDelList.php
includes/revisiondelete/RevDelLogList.php
includes/revisiondelete/RevDelRevisionList.php
includes/revisiondelete/RevisionDeleteUser.php
includes/search/SearchEngine.php
includes/search/SearchResult.php
includes/site/SiteListFileCache.php
includes/site/SiteListFileCacheBuilder.php
includes/skins/BaseTemplate.php
includes/skins/Skin.php
includes/skins/SkinTemplate.php
includes/specialpage/ChangesListSpecialPage.php
includes/specialpage/FormSpecialPage.php
includes/specialpage/ImageQueryPage.php
includes/specialpage/PageQueryPage.php
includes/specialpage/QueryPage.php
includes/specialpage/RedirectSpecialPage.php
includes/specialpage/SpecialPage.php
includes/specialpage/SpecialPageFactory.php
includes/specialpage/WantedQueryPage.php
includes/specials/SpecialBlock.php
includes/specials/SpecialBlockList.php
includes/specials/SpecialBooksources.php
includes/specials/SpecialChangeEmail.php
includes/specials/SpecialChangePassword.php
includes/specials/SpecialContributions.php
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialEditWatchlist.php
includes/specials/SpecialEmailuser.php
includes/specials/SpecialImport.php
includes/specials/SpecialListusers.php
includes/specials/SpecialLog.php
includes/specials/SpecialLonelypages.php
includes/specials/SpecialMergeHistory.php
includes/specials/SpecialMovepage.php
includes/specials/SpecialNewpages.php
includes/specials/SpecialPageLanguage.php
includes/specials/SpecialPasswordReset.php
includes/specials/SpecialRandompage.php
includes/specials/SpecialRecentchanges.php
includes/specials/SpecialResetTokens.php
includes/specials/SpecialSearch.php
includes/specials/SpecialStatistics.php
includes/specials/SpecialUndelete.php
includes/specials/SpecialUpload.php
includes/specials/SpecialUserlogin.php
includes/specials/SpecialUserlogout.php
includes/specials/SpecialUserrights.php
includes/specials/SpecialVersion.php
includes/specials/SpecialWantedfiles.php
includes/specials/SpecialWantedpages.php
includes/specials/SpecialWatchlist.php
includes/specials/SpecialWhatlinkshere.php
includes/upload/UploadBase.php
includes/upload/UploadFromUrl.php
includes/utils/AutoloadGenerator.php
includes/utils/IP.php
languages/Language.php
languages/classes/LanguageQqx.php
languages/i18n/ar.json
languages/i18n/be-tarask.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/ca.json
languages/i18n/cdo.json
languages/i18n/ce.json
languages/i18n/cs.json
languages/i18n/de.json
languages/i18n/egl.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/es.json
languages/i18n/et.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/gd.json
languages/i18n/gl.json
languages/i18n/he.json
languages/i18n/hr.json
languages/i18n/hu.json
languages/i18n/ilo.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/ka.json
languages/i18n/ko.json
languages/i18n/lb.json
languages/i18n/mk.json
languages/i18n/ml.json
languages/i18n/nap.json
languages/i18n/nds-nl.json
languages/i18n/nl.json
languages/i18n/pl.json
languages/i18n/pms.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ro.json
languages/i18n/ru.json
languages/i18n/sco.json
languages/i18n/sl.json
languages/i18n/sv.json
languages/i18n/te.json
languages/i18n/th.json
languages/i18n/uk.json
languages/i18n/uz.json
languages/i18n/yi.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
languages/messages/MessagesHe.php
maintenance/Maintenance.php
maintenance/backupTextPass.inc
maintenance/checkLess.php
maintenance/dictionary/mediawiki.dic
maintenance/findHooks.php
maintenance/language/StatOutputs.php
maintenance/parse.php
maintenance/storage/recompressTracked.php
maintenance/updateArticleCount.php
resources/Resources.php
resources/lib/oojs-ui/i18n/ca.json
resources/lib/oojs-ui/i18n/uk.json
resources/lib/oojs-ui/images/grab.cur [new file with mode: 0644]
resources/lib/oojs-ui/images/grabbing.cur [new file with mode: 0644]
resources/lib/oojs-ui/oojs-ui-apex.css
resources/lib/oojs-ui/oojs-ui-apex.js
resources/lib/oojs-ui/oojs-ui-apex.svg.css
resources/lib/oojs-ui/oojs-ui-mediawiki.css
resources/lib/oojs-ui/oojs-ui-mediawiki.js
resources/lib/oojs-ui/oojs-ui-mediawiki.svg.css
resources/lib/oojs-ui/oojs-ui.js
resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg [new file with mode: 0644]
resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.png [new file with mode: 0644]
resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg [new file with mode: 0644]
resources/src/jquery/jquery.accessKeyLabel.js
resources/src/jquery/jquery.client.js
resources/src/jquery/jquery.makeCollapsible.js
resources/src/jquery/jquery.textSelection.js
resources/src/mediawiki.action/mediawiki.action.edit.preview.js
resources/src/mediawiki.action/mediawiki.action.edit.stash.js
resources/src/mediawiki.language/mediawiki.language.js
resources/src/mediawiki.legacy/images/magnify-clip-ltr.png [new file with mode: 0644]
resources/src/mediawiki.legacy/images/magnify-clip-ltr.svg [new file with mode: 0644]
resources/src/mediawiki.legacy/images/magnify-clip-rtl.png [new file with mode: 0644]
resources/src/mediawiki.legacy/images/magnify-clip-rtl.svg [new file with mode: 0644]
resources/src/mediawiki.legacy/oldshared.css
resources/src/mediawiki/mediawiki.Title.js
resources/src/mediawiki/mediawiki.Uri.js
resources/src/mediawiki/mediawiki.feedback.js
resources/src/mediawiki/mediawiki.js
resources/src/mediawiki/mediawiki.util.js
skins/.gitignore
tests/TestsAutoLoader.php
tests/parser/parserTest.inc
tests/parser/parserTests.txt
tests/phpunit/Makefile
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/HtmlTest.php
tests/phpunit/includes/PrefixSearchTest.php
tests/phpunit/includes/UserTest.php
tests/phpunit/includes/XmlSelectTest.php
tests/phpunit/includes/api/ApiMainTest.php
tests/phpunit/includes/api/format/ApiFormatWddxTest.php
tests/phpunit/includes/api/query/ApiQueryTest.php
tests/phpunit/includes/cache/LocalisationCacheTest.php
tests/phpunit/includes/db/DatabaseSqliteTest.php
tests/phpunit/includes/media/FormatMetadataTest.php
tests/phpunit/includes/parser/NewParserTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderStartupModuleTest.php
tests/phpunit/maintenance/backupTextPassTest.php
tests/phpunit/suites/ExtensionsTestSuite.php
tests/qunit/suites/resources/jquery/jquery.client.test.js
tests/qunit/suites/resources/jquery/jquery.mwExtension.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.Uri.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.test.js

diff --git a/HISTORY b/HISTORY
index 78ece33..4343c5d 100644 (file)
--- a/HISTORY
+++ b/HISTORY
@@ -462,9 +462,9 @@ changes to languages because of Bugzilla reports.
   meaning that JavaScript is no longer executed in these browser versions.
 * Browser support for Opera 11 lowered from Grade A to Grade C.
 * Removed IEFixes module which existed purely to provide support for MSIE versions
+  below 7 (conditionally loaded only for those browsers).
 * Deprecated SpecialPageFactory::getList() in favor of
   SpecialPageFactory::getNames()
-  below 7 (conditionally loaded only for those browsers).
 * Action::checkCanExecute() no longer has a return value.
 * Removed cleanupForIRC(), loadFromCurRow(), newFromCurRow(), notifyRC2UDP()
   and sendToUDP() from RecentChange.php. (deprecated since 1.22)
@@ -799,7 +799,7 @@ of files that are no longer available follows.
 * Added jquery.throttle-debounce ResourceLoader module to limit the number of
   callbacks for frequently occurring events.
 * Special:ProtectedPages shows now a table. The timestamp, the reason and
-  the protecting user is also shown.
+  the protecting user are also shown.
 * Added experimental support for using Microsoft SQL Server as the database
   backend.
 ** Added new Microsoft SQL Server-specific configuration variable
@@ -994,7 +994,7 @@ changes to languages because of Bugzilla reports.
 * (bug 52810) Preference "Justify paragraphs" was removed.
 * OutputPage::showErrorPage raises a notice if arguments are incoherent.
 * Thumbnails that keep failing to render in thumb.php will be rate-limited
-  againt further render attempts for 1 hour. $wgAttemptFailureEpoch can be
+  against further render attempts for 1 hour. $wgAttemptFailureEpoch can be
   altered to reset all rate-limited thumbnails at once.
 * (bug 56572) Builds of the OOjs and OOjs UI libraries are now available.
 * mw.loader.go and mw.loader.version have been removed.
@@ -1289,7 +1289,7 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
   HTML output is now exclusively HTML5.
 * $wgDBOracleDRCP added. True enables persistent connection with DRCP on Oracle.
 * $wgLogAutopatrol added to allow disabling logging of autopatrol edits in the logging table.
-  default for $wgLogAutopatrol is true.
+  Default for $wgLogAutopatrol is true.
 * The 'edit' right no longer allows for editing a user's own CSS and JS.
 * New rights 'editmyusercss', 'editmyuserjs', 'viewmywatchlist',
   'editmywatchlist', 'viewmyprivateinfo', 'editmyprivateinfo', and
@@ -1389,7 +1389,7 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 * $wgCascadingRestrictionLevels was added, allowing one to specify restriction levels
   which can be cascading (previously 'sysop' was hard-coded as the only one).
 * XHTML5 support has been improved. If you set $wgMimeType = 'application/xhtml+xml'
-  MediaWiki will try outputting markup acording to XHTML5 rules.
+  MediaWiki will try outputting markup according to XHTML5 rules.
 * Altered hook 'ProtectionForm::save', adding the reason page protection is
   changed as third parameter.
 * New hook 'TitleSquidURLs' for manipulating the list of URLs to be purged from
@@ -1484,7 +1484,7 @@ This is a security and maintenance release of the MediaWiki 1.22 branch.
 * Make thumb.php give HTTP redirects for file redirects
 * (bug 30607) Special:ListFiles can now show old versions of files. Additionally
   Special:AllMyUploads was introduced so the user can get a list of all things
-  they have ever uploaded, even if it was subsequently overriden.
+  they have ever uploaded, even if it was subsequently overridden.
 * Introduced Special:MyFiles and Special:AllMyFiles as an alias for Special:MyUploads
   and Special:AllMyUploads respectively.
 * IPv6 addresses in X-Forwarded-For headers are now normalised before checking
@@ -1779,7 +1779,7 @@ changes to languages because of Bugzilla reports.
   The skins/common/wikiprintable.css file no longer exists. Return value of
   Skin#commonPrintStylesheet is ignored. Please use the 'mediawiki.legacy.commonPrint'
   module instead or base your skin on SkinTemplate.
-* (bug 49629) The hook ExtractThumbParamaters has been deprecated in favour
+* (bug 49629) The hook ExtractThumbParameters has been deprecated in favour
   of media handler overriding MediaHandler::parseParamString.
 * (bug 46512) The collapsibleNav feature from the Vector extension has been moved
   to the Vector skin in core.
@@ -2440,7 +2440,7 @@ upgrade PHP if you have not done so prior to upgrading MediaWiki.
 * Added $wgCopyUploadProxy global to define which proxy to use for copy
   uploads.
 * (bug 40448) mediawiki.legacy.mwsuggest has been replaced with a new module,
-  mediawiki.searchSuggest, based on SimpleSeach from Extension:Vector.
+  mediawiki.searchSuggest, based on SimpleSearch from Extension:Vector.
 
 === Known issues in 1.20.0 ===
 These are issues that we're targeting to be fixed in a later release
@@ -2492,7 +2492,7 @@ milestone in Bugzilla.
 * (bug 34735) Updated compressOld.php documentation to mention the different
   usages of -s and -n parameters depending on compression type.
 * (bug 13896) Rendering of devanagari numbers in automatic '#' number lists.
-* (bug 33689) Upgrade to 1.19 on Postgres fails due to incomplete query when.
+* (bug 33689) Upgrade to 1.19 on Postgres fails due to incomplete query when
   trying to defer foreign key for externallinks.
 * (bug 32748) Printer friendly version of article decode Unicode chars as a
   pretty IRI in footer.
@@ -2510,7 +2510,7 @@ milestone in Bugzilla.
 * (bug 30410) Removed deprecated $wgFilterCallback and the 'filtered' API error.
 * (bug 32604) Some messages needs escaping of wikitext inside username.
 * (bug 36537) Rename wfArrayToCGI to wfArrayToCgi for consistency with wfCgiToArray.
-* (bug 25946) The message on the top of Special:RecentChanges is now displayed.
+* (bug 25946) The message on the top of Special:RecentChanges is now displayed
   in user language instead of content language.
 * (bug 35264) Wrong type used for <ns> in export.xsd
 * (bug 24985) Use $wgTmpDirectory as the default temp directory so that people
@@ -3010,8 +3010,8 @@ release and submitting bug reports.
   until the second was introduced in 1.17.
 * BREAKING CHANGE:  Style rules for wikitable are now more specific and prevent
   inheritance to nested tables which caused various issues (bug 30485 and bug
-  33434). If your wiki has overriden rules for ".wikitable", please revise them and
-  adjust where neccecary. For comparison, use the "table.wikitable" section in
+  33434). If your wiki has overridden rules for ".wikitable", please revise them and
+  adjust where necessary. For comparison, use the "table.wikitable" section in
   skins/common/shared.css as base.
 * $wgUploadNavigationUrl is now used for file redlinks if
   $wgUploadMissingFileUrl is not set. The former was used for this until the
@@ -3051,7 +3051,7 @@ release and submitting bug reports.
   "create account" when the user cannot create an account.
 * (bug 31818) 'usercreated' message now supports GENDER.
 * (bug 32022) Our phpunit.php script can now be executed from another directory.
-* (bug 26020) Setting $wgEmailConfirmToEdit to true no longer removes diffs.
+* (bug 26020) Setting $wgEmailConfirmToEdit to true no longer removes diffs
   from recent changes feeds.
 * (bug 30232) add current time to message wlnote on Special:Watchlist.
 * (bug 29110) $wgFeedDiffCutoff did not affect new pages.
@@ -3061,7 +3061,7 @@ release and submitting bug reports.
 * (bug 32168) Add wfAssembleUrl for use in wfExpandUrl.
 * (bug 32168) fixed - wfExpandUrl expands dot segments now.
 * (bug 31535) Upload comments now truncated properly, and don't have brackets.
-* (bug 32086) Special:PermanentLink now show an error message when no subpage
+* (bug 32086) Special:PermanentLink now shows an error message when no subpage
   was specified.
 * (bug 30368) Special:Newpages now shows the new page name for moved pages.
 * (bug 1697) The way to search blocked usernames in block log should be clearer.
@@ -3135,7 +3135,8 @@ release and submitting bug reports.
 * (bug 28936, bug 5280) Broken or invalid titles can't be removed from watchlist.
 * (bug 34600) Older skins using useHeadElement=false were broken in 1.18.
 * (bug 34604) [mw.config] wgActionPaths should be an object instead of a numeral
-  array.* (bug 12262) Indents and lists are now aligned
+  array.
+* (bug 12262) Indents and lists are now aligned
 * (bug 29753) mw.util.tooltipAccessKeyPrefix should be alt-shift for Chrome
    on Windows
 * (bug 25095) Special:Categories should also include the first relevant item
@@ -3159,7 +3160,7 @@ release and submitting bug reports.
   address blocks for list=blocks.
 * (bug 30591) Add support to only return keys in ApiAllMessages.
 * The API now respects $wgShowHostnames and won't share the hostname in
-  severedby if it's set to false.
+  servedby if it's set to false.
 * wlexcludeuser parameter added to ApiFeedWatchlist.
 * (bug 7304) Links on redirect pages no longer cause the redirect page to show
   up as a redirect to the linked page on Special:Whatlinkshere.
@@ -3277,8 +3278,8 @@ This is a maintenance release of the MediaWiki 1.18 branch.
 This is a maintenance and security release of the MediaWiki 1.18 branch.
 
 === Changes since 1.18.1 ===
-* (bug 33686) could not get a list of contributor for an article when using
- a SQLite database.
+* (bug 33686) could not get a list of contributors for an article when using
 a SQLite database.
 * (Bug 33865) Exception thrown in action=parse when attempting to use the title
   parameter without setting the text parameter.
 * UserMailer could potentially throw a fatal error when a MailAddress object had
@@ -3466,9 +3467,9 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 
 === New features in 1.18 ===
 * BREAKING CHANGE: action=watch / action=unwatch now requires a token.
-* BREAKING CHANGE: Article class hierarchy split into WikiPage (backend).
+* BREAKING CHANGE: Article class hierarchy split into WikiPage (backend)
   and Article (frontend) hierarchies. Several hooks now pass a WikiPage object instead
-  of an Article object. These hooks all use an $article paramater as documented in hooks.txt.
+  of an Article object. These hooks all use an $article parameter as documented in hooks.txt.
   Extensions should be updated to account for this, though most won't require any changes.
 * (bug 27860) Minor edit after clicking 'new section' tab
   Now the "This is a minor edit" checkbox is not available when you
@@ -3598,7 +3599,7 @@ Selected changes since MediaWiki 1.17 that may be of interest:
   unicode code point is (aka pre-1.17 behavior).
 * (bug 30940) Add a hook in User:getDefaultOptions.
   To give extensions a better and more flexible way of providing default
-  values for preferences a hook has been introdiced in User:getDefaultOptions().
+  values for preferences a hook has been introduced in User:getDefaultOptions().
   Setting preferences in $wgDefaultUserOptions still work fine, but when reading
   them (i.e. with array_keys) to get a list of all preferences, then
   $wgDefaultUserOptions should no longer be used as it will contain those set via
@@ -3744,7 +3745,7 @@ Selected changes since MediaWiki 1.17 that may be of interest:
   file description page for multi-paged documents.
 * (bug 28883) Message names for different compression types commonly
   used in Tiff files.
-* When translcuding a special page, do not let it interpret url parameters.
+* When transcluding a special page, do not let it interpret url parameters.
 * (bug 28887) Special page classes are no longer re-used during 1 request.
 * (bug 28888) Searching for something starting with a # sign no longer tells
   the user a page named [[:]] already exists.
@@ -3821,7 +3822,7 @@ Selected changes since MediaWiki 1.17 that may be of interest:
   RefreshLinks::deleteLinksFromNonexistent.
 * (bug 29797) Error: "Tried to load block with invalid type" when subpages
   are disabled for user pages.
-* (bug 12205) Bidirectional names in action=credits are split and displayed.
+* (bug 12205) Bidirectional names in action=credits are split and displayed
   incorrectly when wrapped to the next line.
 * (bug 20781) Move 'mainpagetext' messages to installer's .i18n file.
 * (bug 29737) "MediaWiki:Qbsettings-directionality" should refer to script,
@@ -3831,7 +3832,7 @@ Selected changes since MediaWiki 1.17 that may be of interest:
   to the FCKEditor extension.
 * (bug 28762) Resizing to specified height broken for very thin images.
 * (bug 29959) Installer fatal when cURL and allow_url_fopen is disabled and user
-  tries to subsribe to mediawiki-announce.
+  tries to subscribe to mediawiki-announce.
 * (bug 27427) mw.util.getParamValue shouldn't return value from hash even if
   param is only present in hash.
 * Installer checked for magic_quotes_runtime instead of register_globals.
@@ -3846,7 +3847,7 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 * (bug 30335) Fix for HTMLForms using GET breaking when non-friendly URLs
   are used.
 * (bug 30264) Changed installer-generated LocalSettings.php to use require_once()
instead require() for included extensions.
 instead of require() for included extensions.
 * Tracking categories are no longer shown in footer for special pages.
 * (bug 30684) Fix bad escaping in mw.message for inexistent messages (i.e. <key>).
 * $wgOverrideSiteFeed no longer double escapes urls.
@@ -3918,7 +3919,7 @@ Selected changes since MediaWiki 1.17 that may be of interest:
 * (bug 27897) list=allusers and list=users list hidden users.
 * (bug 27717) API's exturlusage module does not respect $wgMiserMode.
 * (bug 27588) list=filearchive&faprop=sha1 returns empty attribute.
-* (bug 28010) Passing a non existant user to list=users gives internal error.
+* (bug 28010) Passing a non existent user to list=users gives internal error.
 * (bug 27549) action=query&list=users&usprop=groups doesn't show implicit
   groups if a user doesn't have explicit groups.
 * (bug 27670) Ordering by timestamp (and usage of start and end) isn't as clear
@@ -4135,7 +4136,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * $wgSVGMaxSize is now applied to the smaller of width or height, making very
   wide pano/timeline/diagram SVGs renderable at saner sizes.
 * (bug 29959) Installer fatal when cURL and allow_url_fopen is disabled and user
-  tries to subsribe to mediawiki-announce.
+  tries to subscribe to mediawiki-announce.
 * Installer checked for magic_quotes_runtime instead of register_globals
 * (bug 30131) XCache with variable caching disabled no longer used for variable
   caching (CACHE_ACCEL)
@@ -4150,7 +4151,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * Fixed recentchanges FK violation on page delete and cache purge error in updater
   for Oracle DB.
 * (bug 32276) Skins were generating output using the internal page title which
-  would allow anonymous users to determine wheter a page exists, potentially
+  would allow anonymous users to determine whether a page exists, potentially
   leaking private data. In fact, the curid and oldid request parameters would
   allow page titles to be enumerated even when they are not guessable.
 * (bug 32616) action=ajax requests were dispatched to the relevant internal
@@ -4423,7 +4424,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
   with $wgPasswordSender configurable.
 * (bug 22463) $wgFooterIcons added to allow configuration of the icons shown in
   the footers of skins.
-* $wgFileCacheDepth can be used to set the depth of the subdirectory hierarchy.
+* $wgFileCacheDepth can be used to set the depth of the subdirectory hierarchy
   used for the file cache. Default value is 2, which matches former behavior.
 
 === Bug fixes in 1.17 ===
@@ -4467,14 +4468,14 @@ Selected changes since MediaWiki 1.16 that may be of interest:
   language.
 * (bug 22852) "Served in" comment is now the time used to cache a single page
   when using rebuildFileCache.php
-* (bug 22496) Viewing diff of a redirect page without specifying "oldid".
+* (bug 22496) Viewing diff of a redirect page without specifying "oldid"
   parameter no longer makes the page displayed as being the redirect target.
 * (bug 22918) Feed cache keys now use $wgRenderHashAppend.
 * (bug 21916) Last-Modified header is now correct when outputting cached feed.
 * (bug 20049) Fixed PHP notice in search highlighter that occurs in some cases.
 * (bug 23017) Special:Disambiguations now list pages in content namespaces
   rather than only main namespace.
-* (bug 23063) $wgMaxAnimatedGifArea is checked against the total size of all.
+* (bug 23063) $wgMaxAnimatedGifArea is checked against the total size of all
   frames, and $wgMaxImageArea against the size of the first frame, rather than
   the other way around.  Both now default to 12.5 megapixels.  Also, images
   exceeding $wgMaxImageArea can still be embedded at original size.
@@ -4504,7 +4505,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
   correct link.
 * (bug 23284) Times are now rounded correctly.
 * (bug 23375) Added ogv, oga, spx as extensions for ogg files.
-* (bug 18408) All required permissions for uploading (upload, edit, create).
+* (bug 18408) All required permissions for uploading (upload, edit, create)
   are now checked when loading Special:Upload. Toolbar link for Special:Upload
   is no longer shown if the user does not have the required permissions.
 * (bug 23397) texvc in html mode renders \sim as &tilde; not &sim;
@@ -4551,7 +4552,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * (bug 19910) Headings of the form ===+\s+ are now displayed as valid headings.
 * (bug 24022) Only check file extensions on the uploadpage when needed.
 * (bug 24076) Recognize Office 2003 files with OpenXML trailers.
-* (bug 24244) Updated comments in DefaultSettings.php to reflect.
+* (bug 24244) Updated comments in DefaultSettings.php to reflect
   Image: --> File: namespace rename.
 * Make wfTimestamp recognize negative unix timestamp values.
 * (bug 24401) SimpleSearch: No button/text indicating 'Search' if image is
@@ -4591,7 +4592,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * (bug 20744) Wiki forgets about an uploaded file.
 * (bug 17913) Don't show "older edit" when no older edit available.
 * (bug 6204) TOC not properly rendered when using $wgMaxTocLevel.
-* (bug 24977) The accesskey in history page now lead directly to the diff.
+* (bug 24977) The accesskey in history page now lead directly to the diff
   instead of alternating focus between the two buttons.
 * (bug 24987) Special:ListUsers does not take external groups into account.
 * (bug 20633) update.php has mixed language output.
@@ -4631,7 +4632,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * (bug 25175) HTML file cache now honor $wgCacheDirectory if
   $wgFileCacheDirectory is not set.
 * (bug 13353) Diff3 version checks were too strict, did not detect working diff3.
-* (bug 25843) Links to special pages using link= attribute on images are now.
+* (bug 25843) Links to special pages using link= attribute on images are now
   normalised like normal links to special pages.
 * (bug 21364) External links using link= attribute on images now respect
   $wgExternalLinkTarget.
@@ -4718,7 +4719,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * (bug 27508) SVGMetadataExtractor takes too much resources on huge svgs.
 * (bug 27465) SVG thumbnail generation.
 * (bug 27467) preload can leave UNIQ.
-* (bug 27539) Allow attributes beginning with a digit in wiktext tag parameters.
+* (bug 27539) Allow attributes beginning with a digit in wikitext tag parameters.
 * (bug 27328) using relative paths in CSS imports in MediaWiki:Common.css broken
   in 1.17.
 * (bug 27333) Fix repetitive last-seen time queries on page history.
@@ -4767,7 +4768,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * (bug 22764) uselang parameter for action=parse.
 * (bug 22944) API: watchlist options are inconsistent.
 * (bug 22868) don't list infinite block expiry date as "now" in API logevents.
-* (bug 22290) prop=revisions now outputs "comment" field even when comment.
+* (bug 22290) prop=revisions now outputs "comment" field even when comment
   is empty, for consistency with list=recentchanges.
 * (bug 19721) API action=help should have a way to just list for a specific
   module.
@@ -4780,7 +4781,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
 * (bug 23524) Api Modules as followup to bug 14473 (Add iwlinks table to
   track inline interwiki link usage).
 * Add pltitles and tltemplates to prop=links and prop=templates respectively,
-  similar to prop=categories's clcategorie.
+  similar to prop=categories's clcategories.
 * (bug 23834) Invalid "thumbwidth" and "thumbheight" in "imageinfo" query when
   thumbnailing larger than original image.
 * (bug 23835) Need "thumbmime" result in "imageinfo" query.
@@ -4838,7 +4839,7 @@ Selected changes since MediaWiki 1.16 that may be of interest:
   current revision id, try the parser cache, and save it to it if necessary.
 * (bug 25463) Export header should not be shown if no pages were requested, to
   reduce confusion.
-* (bug 25648) API discovery information has been added as RSD link in page.
+* (bug 25648) API discovery information has been added as RSD link in page
   <head> and by providing an API module action=rsd. Added hook
   ApiRsdServiceApis for extensions to add their own service to the services
   list.
@@ -4867,7 +4868,7 @@ The following languages were added:
 
 * Moroccan Spoken Arabic (ary)
 * Banjar (bjn)
-* Kabardian (kdb)
+* Kabardian (kbd)
 * Kabardian (Cyrillic) (kbd-cyrl)
 * Latgalian (ltg)
 * Minangkabau (min)
@@ -4974,7 +4975,7 @@ Other significant changes to MediaWiki's language support:
   similarly to the category namespace.
 * $wgEnableSorbs renamed to $wgDnsBlacklistUrls ($wgEnableSorbs kept for
   backward compatibility)
-* $wgUploadNavigationUrl now also affects images inline images that do not
+* $wgUploadNavigationUrl now also affects inline images that do not
   exist. In that case the URL will get (?|&)wpDestFile=<filename> appended to
   it as appropriate.
 * If $wgLocaltimezone is null, use the server's timezone as the default for
@@ -5054,7 +5055,7 @@ Other significant changes to MediaWiki's language support:
 * Added a feature to allow per-article process pool size control for the parsing
   task, to limit resource usage when the cache for a heavily-viewed article is
   invalidated. Requires an external daemon.
-* (bug 19576) Moved the id attribues from the anchors accompanying section
+* (bug 19576) Moved the id attributes from the anchors accompanying section
   headers to the <span class="mw-headline"> elements within the section headers,
   removing the redundant anchor elements.
 * Parser::setFunctionTagHook now can be used to add a new tag which is parsed at
@@ -5304,7 +5305,7 @@ comment from another wiki.
 * (bug 18943) Handle invalid titles gracefully at Special:Mostlinked
 * (bug 8873) Enable variant conversion in text on 'alt' and 'title' attributes
 * (bug 10837) Introducing the StubUserVariant class to determine the variant
-  variable instead of using this to overrules the user language preference.
+  variable instead of using this to overrule the user language preference.
 * (bug 19014) If user had deletedhistory right, but not undeleted right, then
   show "view" instead of "view/restore" on logs.
 * (bug 19017) TOC level calculation error in an odd case
@@ -5358,7 +5359,7 @@ comment from another wiki.
   are no longer recorded in the pagelinks table
 * (bug 19784) date option "ISO 8601" produced illegal id
 * (bug 19761) Removed autogenerated <meta keywords> tag with link data.
-  Keyword set was not useful, and is ignored by modern search engines anway.
+  Keyword set was not useful, and is ignored by modern search engines anyway.
 * (bug 19827) Special:SpecialPages title is "Upload file
 * (bug 19355) Added .xhtml, .xht to upload file extension blacklist
 * (bug 19287) Workaround for lag on history page in Firefox 3.5
@@ -5381,7 +5382,7 @@ comment from another wiki.
 * The display of the language list on the preferences is more comply with the
   BCP 47 standards.
 * (bug 19849) Custom X-Vary-Options header now disabled unless $wgUseXVO is set
-* (bug 19301) Duplicates entries in $wgAddGroups, $wgRemoveGroups,
+* (bug 19301) Duplicate entries in $wgAddGroups, $wgRemoveGroups,
   $wgGroupsAddToSelf and $wgGroupsRemoveFromSelf are no more displayed on
   Special:ListGroupRights
 * (bug 18799) Special:Userlogin now handles correctly the returnto parameter
@@ -5398,7 +5399,7 @@ comment from another wiki.
 * (bug 15680) Split the edit tip message of user CSS/JS subpage into
   "usercssyoucanpreview" and "userjsyoucanpreview" respectively.
 * (bug 12110) Split the rights for editing users' CSS/JS subpage from
-  "editusercssjs" into "editusercss" and edituserjs" respectively.
+  "editusercssjs" into "editusercss" and "edituserjs" respectively.
 * (bug 19394) RecentChanges feed URLs for log items with no revisions
   (eg Newuser, Userrights) are no longer broken
 * (bug 17395) Remote file descriptions use user language ($wgLang), not wiki
@@ -5584,7 +5585,7 @@ comment from another wiki.
   "unknown error"
 * (bug 18762) both redirects and links get fixed one after another if
   redirects-only switch is not present
-* (bug 20159) thumbnails rerendered if older that $wgThumbnailEpoch
+* (bug 20159) thumbnails rerendered if older than $wgThumbnailEpoch
 * Fixed a bug which in some situations causes the job queue to grow forever,
   due to an infinite loop of job requeues.
 * (bug 21523) File that can have multiple pages (djvu, pdf, ...) no longer have
@@ -5595,7 +5596,7 @@ comment from another wiki.
 * (bug 21776) Interwiki urls like http://en.wikibooks.org/wiki/cs: should give
   a redirect instead of a baderror.
 * (bug 21803) Special:MyContributions now keeps the query string parameters
-* Redirecting special pages now keep query string paramters set to "0" (e.g.
+* Redirecting special pages now keep query string parameters set to "0" (e.g.
   for namespace)
 * (bug 20765) Special:ListGroupRights no longer misses addables and removables
   groups if there are duplicate entries
@@ -5608,8 +5609,8 @@ comment from another wiki.
 * refreshLinks.php now purges orphaned redirect table rows
 * (bug 2971) Swap links of hist & diff location on Special:Contributions for
   consistency with RC/WL
-* (bug 21986) Special page names were are now capitalized by content language
-* If two log type have the same description, they're now both displayed in the
+* (bug 21986) Special page names are now capitalized by content language
+* If two log types have the same description, they're now both displayed in the
   type selector on Special:Log
 * (bug 20115) Special:Userlogin title says "Log in / create account" even if the
   user can't create an account
@@ -5795,7 +5796,7 @@ changes to languages because of Bugzilla reports.
 * Added $wgNoFollowDomainExceptions to allow exempting particular domain names
   from rel="nofollow" on external links
 * (bug 12970) Brought back $wgUseImageResize.
-* Added $wgRedirectOnLogin to allow specifying a specifc page to redirect users
+* Added $wgRedirectOnLogin to allow specifying a specific page to redirect users
   to upon logging in (ex: "Main Page")
 * Add $wgExportFromNamespaces for enabling/disabling the "export all from
   namespace" option (disabled by default)
@@ -5898,7 +5899,7 @@ changes to languages because of Bugzilla reports.
   $wgRedirectOnLogin
 * Added a link to Special:UserRights on Special:Contributions for privileged users
 * (bug 10336) Added new magic word {{REVISIONUSER}}, which displays the editor
-  of the displayed revision's author user name
+  of the displayed revision
 * LinkerMakeExternalLink now has an $attribs parameter for link attributes and
   a $linkType parameter for the type of external link being made
 * (bug 17785) Dynamic dates surrounded with a <span> tag, fixing sortable tables with
@@ -6044,7 +6045,7 @@ changes to languages because of Bugzilla reports.
 * (bug 17778) MediaWiki:Catseparator can now have HTML entities
 * (bug 17676) Error on Special:ListFiles when using Postgres
 * Special:Export doesn't use raw SQL queries anymore
-* (bug 14771) Thumbnail links to individual DjVu pages have two no longer have
+* (bug 14771) Thumbnail links to individual DjVu pages no longer have
   two "page" parameters
 * (bug 17972) Special:FileDuplicateSearch form now works correctly on wikis that
   don't use PathInfo or short urls
@@ -6348,7 +6349,7 @@ The following extensions are migrated into MediaWiki 1.14:
 * Dropped old Paser_OldPP class. Only new parser with preprocessor is used.
 * Moved password reset form from Special:Preferences to Special:ResetPass
 * Added Special:ChangePassword as a special page alias for Special:ResetPass
-* Added complimentary function for addHandler() called removeHandler() for removing events
+* Added complementary function for addHandler() called removeHandler() for removing events
 * Improved security of file uploads for IE clients, using a reverse-engineered
   algorithm very similar to IE's content detection algorithm.
 * Cascading protection no longer requires that both edit and move are restricted
@@ -7124,7 +7125,7 @@ Other changes in this release:
 * (bug 13705) Don't show rollback link in page history on incorrect revisions
 * (bug 13708) Don't set "Search results" title when loading Special:Search
   without query
-* (bug 13736) Don't show MediaWiki:Anontalkpagetext on non-existant IP addresses
+* (bug 13736) Don't show MediaWiki:Anontalkpagetext on non-existent IP addresses
 * (bug 13728) Don't trim initial whitespace during section edits
 * (bug 13727) Don't delete log entries from recentchanges on page deletion
 * (bug 13752) Redirects to sections now work again
@@ -7262,7 +7263,7 @@ Other changes in this release:
 * (bug 14764) Fix regression in from Article::lastModified(), failed to work
   on non-mySQL schemas.
 * (bug 14763) Child classes of Database (DatabasePostgres and DatabaseOracle)
-  had stict standards issues with setFakeSlaveLag() and setFakeMaster().
+  had strict standards issues with setFakeSlaveLag() and setFakeMaster().
 * (bug 451) Improve the phrase mappings of the Chinese converter arrays.
 * (bug 12487) Rights log is not fully internationalized
 * (bug 10837) Language variants no longer override other languages than base
@@ -7284,7 +7285,7 @@ Other changes in this release:
 * (bug 13128) Added patrolled flag to list=recentchanges
 * Implemented {bl,ei,iu}redirect (lists links through redirects as well)
 * (bug 13154) Introduced subpages flag to meta=siteinfo&siprop=namespaces
-* (bug 13157) Added ucuserprefix parameter to list=usercontibs
+* (bug 13157) Added ucuserprefix parameter to list=usercontribs
 * (bug 12394) Added rctitles parameter to list=recentchanges, making rcid
   retrieval easier
 * (bug 13218) Fix inclusion of " character in hyperlinks
@@ -8790,7 +8791,7 @@ it from source control: https://www.mediawiki.org/wiki/Download_from_SVN
 * (bug 3953) Work around poor display of parenthesis in the in other
   languages section of MonoBook skin
 * (bug 8539) Enable PLURAL option for another message of recentchanges.
-* (bug 8728) MediaWiki:Badfiletype splitted into 3 messages
+* (bug 8728) MediaWiki:Badfiletype split into 3 messages
 * (bug 9131) Allow SpecialContributions to work with Postgres
 * (bug 9155) Allow footer info to wrap in Monobook
 * (bug 8847) Strip spurious #fragments from request URI to fix redirect
@@ -10442,7 +10443,7 @@ they will be run along with the main tests by maintenance/parserTests.php
 * (bug 6304) Show timestamp for current revision in diff pages
 * Vertically align current version with old version header in diff display
 * (bug 6174) Remove redundant "emailforlost" message
-* (bug 6189) Show an error to an unprivilleged user trying to create account
+* (bug 6189) Show an error to an unprivileged user trying to create account
 * (bug 6365) Show user information in the "old revision" navigation links
 * Introduce 'FetchChangesList' hook; see docs/hooks.txt for more information
 * (bug 6345) Update to Indonesian localisation (id) #22
@@ -10911,7 +10912,7 @@ Special Pages:
 * (bug 1956) Hide bot uploads from Special:Newimages
 * (bug 3220) Fix escaping of block URLs in Recentchanges
 * (bug 3284) Ipblocklist paging, substring search
-* Allow filtering of robot edits in Special:Watchlist by stting
+* Allow filtering of robot edits in Special:Watchlist by setting
   $wgFilterRobotsWL = true.
 * Fix interlanguage links on special pages when extra namespaces configured
 * (bug 3475) anon contrib links on Special:Newpages
@@ -11818,8 +11819,8 @@ Various bugfixes, small features, and a few experimental things:
 * Supplying a reason for a block is no longer mandatory
 * Language conversion support for category pages
 * $wgStyleSheetDirectory is no longer an alias for $wgStyleDirectory;
-* Special:Movepage can now take paramaters like Special:Movepage/Page_to_move
-  (used to just be able to take paramaters via a GET request like index.php?title=Special:Movepage&target=Page_to_move)
+* Special:Movepage can now take parameters like Special:Movepage/Page_to_move
+  (used to just be able to take parameters via a GET request like index.php?title=Special:Movepage&target=Page_to_move)
 * (bug 2151) The delete summary now includes editor name, if only one has edited the article.
 * (bug 2105) Fixed from argument to the PHP mail() function. A missing space could prevent sending mail with some versions of sendmail.
 * (bug 2228) Updated the Slovak translation
@@ -12004,7 +12005,7 @@ Various bugfixes, small features, and a few experimental things:
 * Skip sidebar entries where link text is '-'
 * Convert non-UTF-8 URL parameters even if referer is local
 * (bug 2460) <img> width & height properly filled when resizing image
-* (bug 2273) deletion log comment used user interface langage
+* (bug 2273) deletion log comment used user interface language
 * Try reading revision _text_ from master if no result on slave
 * Use content-language message cache for raw view of message pages
 * (bug 2530) Not displaying talk pages on Special:Watchlist/edit
diff --git a/README b/README
index 282ee6c..29577bc 100644 (file)
--- a/README
+++ b/README
@@ -1,17 +1,17 @@
 == MediaWiki ==
 
-MediaWiki is a popular and free, open-source wiki software package written in
-PHP. It serves as the platform for Wikipedia and the other projects of the Wikimedia
-Foundation, which deliver content in over 280 languages to more than half a billion
-people each month. MediaWiki's reliability and robust feature set have earned it a
-large and vibrant community of third-party users and developers.
+MediaWiki is a free and open-source wiki software package written in PHP. It
+serves as the platform for Wikipedia and the other projects of the Wikimedia
+Foundation, which deliver content in over 280 languages to more than half a
+billion people each month. MediaWiki's reliability and robust feature set have
+earned it a large and vibrant community of third-party users and developers.
 
 MediaWiki is:
 
-* feature-rich and extensible, both on-wiki and with over 2,000 extensions;
+* feature-rich and extensible, both on-wiki and with hundreds of extensions;
 * scalable and suitable for both small and large sites;
-* available in your language; and
-* simple to install, working on most hardware/software combinations.
+* simple to install, working on most hardware/software combinations; and
+* available in your language.
 
 For system requirements, installation, and upgrade details, see the files
 RELEASE-NOTES, INSTALL, and UPGRADE.
@@ -23,7 +23,7 @@ RELEASE-NOTES, INSTALL, and UPGRADE.
 * Seeking help from a person?
 ** https://www.mediawiki.org/wiki/Communication
 * Looking to file a bug report or a feature request?
-** https://bugzilla.wikimedia.org/
+** https://bugs.mediawiki.org/
 * Interested in helping out?
 ** https://www.mediawiki.org/wiki/How_to_contribute
 
index 36d698f..d98d7bb 100644 (file)
@@ -29,7 +29,7 @@ production.
 * $wgOpenSearchTemplate is deprecated in favor of $wgOpenSearchTemplates.
 * Edits are now prepared via AJAX as users type edit summaries. This behavior
   can be disabled via $wgAjaxEditStash.
-* (bug 44740) The temporary option $wgIncludejQueryMigrate was removed, along
+* (T46740) The temporary option $wgIncludejQueryMigrate was removed, along
   with the jQuery Migrate library, as indicated when this option was provided in
   MediaWiki 1.24.
 
@@ -102,7 +102,7 @@ production.
 * Page moving was refactored into a MovePage class. As part of that:
 ** The AbortMove hook was removed.
 ** MovePageIsValidMove is for extensions to specify whether a page
-   cannot be moved for technical reasons, and should not be overriden.
+   cannot be moved for technical reasons, and should not be overridden.
 ** MovePageCheckPermissions is for checking whether the given user is
    allowed to make the move.
 ** Title::moveNoAuth() was deprecated. Use the MovePage class instead.
@@ -271,6 +271,8 @@ changes to languages because of Bugzilla reports.
 ** In source text of the form '{$A}'{$B}' or `{$A}`{$B}`, where variable A
    does not exist yet variable B does, the latter may not be replaced.
    However, this difference is unlikely to arise in practice.
+* (T67278) RFC, PMID, and ISBN "magic links" must be surrounded by non-word
+  characters on both sides.
 
 == Compatibility ==
 
diff --git a/api.php b/api.php
index 74ee775..cc589b0 100644 (file)
--- a/api.php
+++ b/api.php
@@ -72,7 +72,7 @@ try {
        // Last chance hook before executing the API
        wfRunHooks( 'ApiBeforeMain', array( &$processor ) );
        if ( !$processor instanceof ApiMain ) {
-               throw new MWException( 'ApiBeforMain hook set $processor to a non-ApiMain class' );
+               throw new MWException( 'ApiBeforeMain hook set $processor to a non-ApiMain class' );
        }
 } catch ( Exception $e ) {
        // Crap. Try to report the exception in API format to be friendly to clients.
index dbc28ed..175ab42 100644 (file)
@@ -951,6 +951,8 @@ $wgAutoloadLocalClasses = array(
        'ResourceLoaderFileModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderFileModule.php',
        'ResourceLoaderFilePageModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderFilePageModule.php',
        'ResourceLoaderFilePath' => __DIR__ . '/includes/resourceloader/ResourceLoaderFilePath.php',
+       'ResourceLoaderImage' => __DIR__ . '/includes/resourceloader/ResourceLoaderImage.php',
+       'ResourceLoaderImageModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderImageModule.php',
        'ResourceLoaderLanguageDataModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderLanguageDataModule.php',
        'ResourceLoaderLanguageNamesModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderLanguageNamesModule.php',
        'ResourceLoaderModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderModule.php',
@@ -959,6 +961,7 @@ $wgAutoloadLocalClasses = array(
        'ResourceLoaderSkinModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSkinModule.php',
        'ResourceLoaderStartUpModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderStartUpModule.php',
        'ResourceLoaderUserCSSPrefsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php',
+       'ResourceLoaderUserDefaultsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserDefaultsModule.php',
        'ResourceLoaderUserGroupsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserGroupsModule.php',
        'ResourceLoaderUserModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserModule.php',
        'ResourceLoaderUserOptionsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserOptionsModule.php',
index bcd196f..d7a7f04 100644 (file)
@@ -11,7 +11,7 @@
        ],
        "license": "GPL-2.0",
        "support": {
-               "issues": "https://bugzilla.wikimedia.org/",
+               "issues": "https://bugs.mediawiki.org/",
                "irc": "irc://irc.freenode.net/mediawiki",
                "wiki": "https://www.mediawiki.org/"
        },
@@ -20,7 +20,8 @@
                "php": ">=5.3.3",
                "psr/log": "1.0.0",
                "cssjanus/cssjanus": "1.1.1",
-               "cdb/cdb": "1.0.0"
+               "wikimedia/cdb": "1.0.1",
+               "oojs/oojs-ui": "0.5.0"
        },
        "require-dev": {
                "phpunit/phpunit": "*"
index e96bd6c..93b237f 100644 (file)
@@ -55,7 +55,7 @@
     <!-- if a page is deleted and recreated.                          -->
     <id>1</id>
     
-    <!-- Tag wether this article is a redirect and its target -->
+    <!-- Tag whether this article is a redirect and its target -->
     <!-- This corresponds to the page_is_redirect in the page table -->
     <redirect title="Target" />
     
index 062a0c8..0644536 100644 (file)
@@ -66,7 +66,7 @@ email notification when an article is shown may add:
                # code to actually show the article goes here
 
                if ($wgNotifyArticle) {
-                       wfNotifyArticleShow($article));
+                       wfNotifyArticleShow($article);
                }
        }
 
@@ -776,12 +776,10 @@ $out: OutputPage object
 'BeforeParserFetchFileAndTitle': Before an image is rendered by Parser.
 $parser: Parser object
 $nt: the image title
-&$options: array of options to RepoGroup::findFile
+&$options: array of options to RepoGroup::findFile. If it contains 'broken'
+  as a key then the file will appear as a broken thumbnail.
 &$descQuery: query string to add to thumbnail URL
 
-FIXME: Where does the below sentence fit in?
-If 'broken' is a key in $options then the file will appear as a broken thumbnail.
-
 'BeforeParserFetchTemplateAndtitle': Before a template is fetched by Parser.
 $parser: Parser object
 $title: title of the template
@@ -1048,7 +1046,8 @@ This may be triggered by the EditPage or any other facility that modifies page c
 Use the $status object to indicate whether the edit should be allowed, and to provide
 a reason for disallowing it. Return false to abort the edit, and true to continue.
 Returning true if $status->isOK() returns false means "don't save but continue user
-interaction", e.g. show the edit form.
+interaction", e.g. show the edit form. $status->apiHookResult can be set to an array
+to be returned by api.php action=edit. This is used to deliver captchas.
 $context: object implementing the IContextSource interface.
 $content: content of the edit box, as a Content object.
 $status: Status object to represent errors, etc.
@@ -2424,7 +2423,7 @@ after variants have been added.
 'SkinTemplateOutputPageBeforeExec': Before SkinTemplate::outputPage() starts
 page output.
 &$sktemplate: SkinTemplate object
-&$tpl: Template engine object
+&$tpl: QuickTemplate engine object
 
 'SkinTemplatePreventOtherActiveTabs': Use this to prevent showing active tabs.
 $sktemplate: SkinTemplate object
index 16c5760..d18b199 100644 (file)
@@ -1,5 +1,5 @@
-MediaWiki has optional support for memcached, a "high-performance, 
-distributed memory object caching system". For general information 
+MediaWiki has optional support for memcached, a "high-performance,
+distributed memory object caching system". For general information
 on it, see: http://www.danga.com/memcached/
 
 Memcached is likely more trouble than a small site will need, but
@@ -10,7 +10,7 @@ in memory.
 == Installation ==
 
 Packages are available for Fedora, Debian, Ubuntu and probably other
-Linux distributions. If you there's no package available for your 
+Linux distributions. If there's no package available for your
 distribution, you can compile it from source.
 
 == Compilation ==
@@ -25,7 +25,7 @@ distribution, you can compile it from source.
 
 * memcached: http://www.danga.com/memcached/download.bml
   (as of this writing, 1.1.9 is current)
-  
+
 Memcached and libevent are under BSD-style licenses.
 
 The server should run on Linux and other Unix-like systems... you
@@ -40,9 +40,9 @@ memcached servers are not publicly accessible. Otherwise, anyone on
 the internet can put data into and read data from your cache.
 
 An attacker familiar with MediaWiki internals could use this to steal
-passwords and email addresses, or to make themselves a sysop and 
-install malicious javascript on the site. There may be other types 
-of vulnerability, no audit has been done -- so be safe and keep it 
+passwords and email addresses, or to make themselves a sysop and
+install malicious javascript on the site. There may be other types
+of vulnerability, no audit has been done -- so be safe and keep it
 behind a firewall.
 ********************* W A R N I N G ! ! ! ! ! ***********************
 
@@ -247,5 +247,5 @@ User:
        stores: instance of class User
        set in: User::saveToCache()
        cleared by: User::saveSettings(), User::clearSharedCache()
-       
+
 ... more to come ...
index 1cc74f4..8c46bbb 100644 (file)
@@ -3,4 +3,6 @@
        RewriteEngine On
        RewriteCond %{QUERY_STRING} \.[^\\/:*?\x22<>|%]+(#|\?|$) [nocase]
        RewriteRule . - [forbidden]
+       # Fix for bug T64289
+       Options +FollowSymLinks
 </IfModule>
index 81f3b7a..d492d19 100644 (file)
@@ -43,7 +43,7 @@ class Autopromote {
                        }
                }
 
-               wfRunHooks( 'GetAutoPromoteGroups', array( $user, &$promote ) );
+               Hooks::run( 'GetAutoPromoteGroups', array( $user, &$promote ) );
 
                return $promote;
        }
@@ -197,7 +197,7 @@ class Autopromote {
                                return in_array( 'bot', User::getGroupPermissions( $user->getGroups() ) );
                        default:
                                $result = null;
-                               wfRunHooks( 'AutopromoteCondition', array( $cond[0],
+                               Hooks::run( 'AutopromoteCondition', array( $cond[0],
                                        array_slice( $cond, 1 ), $user, &$result ) );
                                if ( $result === null ) {
                                        throw new MWException( "Unrecognized condition {$cond[0]} for autopromotion!" );
index 3c80035..9079fb0 100644 (file)
@@ -113,7 +113,7 @@ class Block {
                        $this->forcedTargetID = $user; // needed for foreign users
                }
                if ( $by ) { // local user
-                       $this->setBlocker( User::newFromID( $by ) );
+                       $this->setBlocker( User::newFromId( $by ) );
                } else { // foreign user
                        $this->setBlocker( $byText );
                }
@@ -366,7 +366,7 @@ class Block {
        protected function initFromRow( $row ) {
                $this->setTarget( $row->ipb_address );
                if ( $row->ipb_by ) { // local user
-                       $this->setBlocker( User::newFromID( $row->ipb_by ) );
+                       $this->setBlocker( User::newFromId( $row->ipb_by ) );
                } else { // foreign user
                        $this->setBlocker( $row->ipb_by_text );
                }
@@ -580,7 +580,7 @@ class Block {
                if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
                        wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
 
-                       $continue = wfRunHooks(
+                       $continue = Hooks::run(
                                'PerformRetroactiveAutoblock', array( $this, &$blockIds ) );
 
                        if ( $continue ) {
@@ -693,7 +693,7 @@ class Block {
                }
 
                # Allow hooks to cancel the autoblock.
-               if ( !wfRunHooks( 'AbortAutoblock', array( $autoblockIP, &$this ) ) ) {
+               if ( !Hooks::run( 'AbortAutoblock', array( $autoblockIP, &$this ) ) ) {
                        wfDebug( "Autoblock aborted by hook.\n" );
                        return false;
                }
index 0c00b39..0074cc9 100644 (file)
 /**
  * @deprecated since 1.25
  */
-abstract class CdbReader extends \Cdb\Reader {}
+abstract class CdbReader extends \Cdb\Reader {
+}
 
 /**
  * @deprecated since 1.25
  */
-abstract class CdbWriter extends \Cdb\Writer {}
+abstract class CdbWriter extends \Cdb\Writer {
+}
 
 /**
  * @deprecated since 1.25
  */
-class CdbException extends \Cdb\Exception {}
+class CdbException extends \Cdb\Exception {
+}
index 87c6ce5..9ee2460 100644 (file)
@@ -320,7 +320,7 @@ class ChangeTags {
                        $emptyTags[] = $row->vt_tag;
                }
 
-               wfRunHooks( 'ListDefinedTags', array( &$emptyTags ) );
+               Hooks::run( 'ListDefinedTags', array( &$emptyTags ) );
 
                $emptyTags = array_filter( array_unique( $emptyTags ) );
 
index 1c2c2db..dac3e93 100644 (file)
@@ -59,7 +59,7 @@ abstract class Collation {
 
                                # Provide a mechanism for extensions to hook in.
                                $collationObject = null;
-                               wfRunHooks( 'Collation::factory', array( $collationName, &$collationObject ) );
+                               Hooks::run( 'Collation::factory', array( $collationName, &$collationObject ) );
 
                                if ( $collationObject instanceof Collation ) {
                                        return $collationObject;
index d0c2226..d63d5ca 100644 (file)
@@ -2,10 +2,6 @@
 /**
  * A few constants that might be needed during LocalSettings.php.
  *
- * Note: these constants must all be resolvable at compile time by HipHop,
- * since this file will not be executed during request startup for a compiled
- * 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
@@ -216,6 +212,7 @@ define( 'MW_SUPPORTS_EDITFILTERMERGED', 1 );
 define( 'MW_SUPPORTS_PARSERFIRSTCALLINIT', 1 );
 define( 'MW_SUPPORTS_LOCALISATIONCACHE', 1 );
 define( 'MW_SUPPORTS_CONTENTHANDLER', 1 );
+define( 'MW_EDITFILTERMERGED_SUPPORTS_API', 1 );
 /**@}*/
 
 /** Support for $wgResourceModules */
index 4a013ef..2155c1b 100644 (file)
@@ -150,6 +150,12 @@ class EditPage {
         */
        const AS_NO_CHANGE_CONTENT_MODEL = 235;
 
+       /**
+        * Status: user tried to create self-redirect (redirect to the same article) and
+        * wpIgnoreSelfRedirect == false
+        */
+       const AS_SELF_REDIRECT = 236;
+
        /**
         * Status: can't parse content
         */
@@ -256,6 +262,12 @@ class EditPage {
        /** @var bool */
        protected $allowBlankArticle = false;
 
+       /** @var bool */
+       protected $selfRedirect = false;
+
+       /** @var bool */
+       protected $allowSelfRedirect = false;
+
        /** @var string */
        public $autoSumm = '';
 
@@ -451,7 +463,7 @@ class EditPage {
        function edit() {
                global $wgOut, $wgRequest, $wgUser;
                // Allow extensions to modify/prevent this form or submission
-               if ( !wfRunHooks( 'AlternateEdit', array( $this ) ) ) {
+               if ( !Hooks::run( 'AlternateEdit', array( $this ) ) ) {
                        return;
                }
 
@@ -546,9 +558,9 @@ class EditPage {
                        }
 
                        if ( !$this->mTitle->getArticleID() ) {
-                               wfRunHooks( 'EditFormPreloadText', array( &$this->textbox1, &$this->mTitle ) );
+                               Hooks::run( 'EditFormPreloadText', array( &$this->textbox1, &$this->mTitle ) );
                        } else {
-                               wfRunHooks( 'EditFormInitialText', array( $this ) );
+                               Hooks::run( 'EditFormInitialText', array( $this ) );
                        }
 
                }
@@ -615,7 +627,7 @@ class EditPage {
                        throw new PermissionsError( $action, $permErrors );
                }
 
-               wfRunHooks( 'EditPage::showReadOnlyForm:initial', array( $this, &$wgOut ) );
+               Hooks::run( 'EditPage::showReadOnlyForm:initial', array( $this, &$wgOut ) );
 
                $wgOut->setRobotPolicy( 'noindex,nofollow' );
                $wgOut->setPageTitle( wfMessage(
@@ -848,6 +860,7 @@ class EditPage {
                        $this->autoSumm = $request->getText( 'wpAutoSummary' );
 
                        $this->allowBlankArticle = $request->getBool( 'wpIgnoreBlankArticle' );
+                       $this->allowSelfRedirect = $request->getBool( 'wpIgnoreSelfRedirect' );
                } else {
                        # Not a posted form? Start with nothing.
                        wfDebug( __METHOD__ . ": Not a posted form.\n" );
@@ -916,7 +929,7 @@ class EditPage {
                        $this->section === 'new' ? 'MediaWiki:addsection-editintro' : '' );
 
                // Allow extensions to modify form data
-               wfRunHooks( 'EditPage::importFormData', array( $this, $request ) );
+               Hooks::run( 'EditPage::importFormData', array( $this, $request ) );
 
                wfProfileOut( __METHOD__ );
        }
@@ -1334,6 +1347,7 @@ class EditPage {
                        case self::AS_MAX_ARTICLE_SIZE_EXCEEDED:
                        case self::AS_END:
                        case self::AS_BLANK_ARTICLE:
+                       case self::AS_SELF_REDIRECT:
                                return true;
 
                        case self::AS_HOOK_ERROR:
@@ -1354,7 +1368,7 @@ class EditPage {
                                $sectionanchor = $resultDetails['sectionanchor'];
 
                                // Give extensions a chance to modify URL query on update
-                               wfRunHooks(
+                               Hooks::run(
                                        'ArticleUpdateBeforeRedirect',
                                        array( $this->mArticle, &$sectionanchor, &$extraQuery )
                                );
@@ -1420,8 +1434,8 @@ class EditPage {
        protected function runPostMergeFilters( Content $content, Status $status, User $user ) {
                // Run old style post-section-merge edit filter
                if ( !ContentHandler::runLegacyHooks( 'EditFilterMerged',
-                       array( $this, $content, &$this->hookError, $this->summary ) ) ) {
-
+                       array( $this, $content, &$this->hookError, $this->summary ) )
+               ) {
                        # Error messages etc. could be handled within the hook...
                        $status->fatal( 'hookaborted' );
                        $status->value = self::AS_HOOK_ERROR;
@@ -1434,15 +1448,24 @@ class EditPage {
                }
 
                // Run new style post-section-merge edit filter
-               if ( !wfRunHooks( 'EditFilterMergedContent',
-                       array( $this->mArticle->getContext(), $content, $status, $this->summary,
-                               $user, $this->minoredit ) ) ) {
-
+               if ( !Hooks::run( 'EditFilterMergedContent',
+                               array( $this->mArticle->getContext(), $content, $status, $this->summary,
+                               $user, $this->minoredit ) )
+               ) {
                        # Error messages etc. could be handled within the hook...
-                       // XXX: $status->value may already be something informative...
-                       $this->hookError = $status->getWikiText();
-                       $status->fatal( 'hookaborted' );
-                       $status->value = self::AS_HOOK_ERROR;
+                       if ( $status->isGood() ) {
+                               $status->fatal( 'hookaborted' );
+                               // Not setting $this->hookError here is a hack to allow the hook
+                               // to cause a return to the edit page without $this->hookError
+                               // being set. This is used by ConfirmEdit to display a captcha
+                               // without any error message cruft.
+                       } else {
+                               $this->hookError = $status->getWikiText();
+                       }
+                       // Use the existing $status->value if the hook set it
+                       if ( !$status->value ) {
+                               $status->value = self::AS_HOOK_ERROR;
+                       }
                        return false;
                } elseif ( !$status->isOK() ) {
                        # ...or the hook could be expecting us to produce an error
@@ -1518,7 +1541,7 @@ class EditPage {
                wfProfileIn( __METHOD__ );
                wfProfileIn( __METHOD__ . '-checks' );
 
-               if ( !wfRunHooks( 'EditPage::attemptSave', array( $this ) ) ) {
+               if ( !Hooks::run( 'EditPage::attemptSave', array( $this ) ) ) {
                        wfDebug( "Hook 'EditPage::attemptSave' aborted article saving\n" );
                        $status->fatal( 'hookaborted' );
                        $status->value = self::AS_HOOK_ERROR;
@@ -1604,7 +1627,7 @@ class EditPage {
                        wfProfileOut( __METHOD__ );
                        return $status;
                }
-               if ( !wfRunHooks(
+               if ( !Hooks::run(
                        'EditFilter',
                        array( $this, $this->textbox1, $this->section, &$this->hookError, $this->summary ) )
                ) {
@@ -1901,6 +1924,17 @@ class EditPage {
                        $status->value = self::AS_SUCCESS_UPDATE;
                }
 
+               if ( !$this->allowSelfRedirect
+                       && $content->isRedirect()
+                       && $content->getRedirectTarget()->equals( $this->getTitle() )
+               ) {
+                       $this->selfRedirect = true;
+                       $status->fatal( 'selfredirect' );
+                       $status->value = self::AS_SELF_REDIRECT;
+                       wfProfileOut( __METHOD__ );
+                       return $status;
+               }
+
                // Check for length errors again now that the section is merged in
                $this->kblength = (int)( strlen( $this->toEditText( $content ) ) / 1024 );
                if ( $this->kblength > $wgMaxArticleSize ) {
@@ -2320,6 +2354,9 @@ class EditPage {
         * Send the edit form and related headers to $wgOut
         * @param callable|null $formCallback That takes an OutputPage parameter; will be called
         *     during form output near the top, for captchas and the like.
+        *
+        * The $formCallback parameter is deprecated since MediaWiki 1.25. Please
+        * use the EditPage::showEditForm:fields hook instead.
         */
        function showEditForm( $formCallback = null ) {
                global $wgOut, $wgUser;
@@ -2335,7 +2372,7 @@ class EditPage {
                        $previewOutput = $this->getPreviewText();
                }
 
-               wfRunHooks( 'EditPage::showEditForm:initial', array( &$this, &$wgOut ) );
+               Hooks::run( 'EditPage::showEditForm:initial', array( &$this, &$wgOut ) );
 
                $this->setHeaders();
 
@@ -2378,6 +2415,7 @@ class EditPage {
                ) );
 
                if ( is_callable( $formCallback ) ) {
+                       wfWarn( 'The $formCallback parameter to ' . __METHOD__ . 'is deprecated' );
                        call_user_func_array( $formCallback, array( &$wgOut ) );
                }
 
@@ -2401,7 +2439,7 @@ class EditPage {
                        . Xml::closeElement( 'div' )
                );
 
-               wfRunHooks( 'EditPage::showEditForm:fields', array( &$this, &$wgOut ) );
+               Hooks::run( 'EditPage::showEditForm:fields', array( &$this, &$wgOut ) );
 
                // Put these up at the top to ensure they aren't lost on early form submission
                $this->showFormBeforeText();
@@ -2445,6 +2483,10 @@ class EditPage {
                        $wgOut->addHTML( Html::hidden( 'wpUndidRevision', $this->undidRev ) );
                }
 
+               if ( $this->selfRedirect ) {
+                       $wgOut->addHTML( Html::hidden( 'wpIgnoreSelfRedirect', true ) );
+               }
+
                if ( $this->hasPresetSummary ) {
                        // If a summary has been preset using &summary= we don't want to prompt for
                        // a different summary. Only prompt for a summary if the summary is blanked.
@@ -2609,6 +2651,10 @@ class EditPage {
                                $wgOut->wrapWikiMsg( "<div id='mw-blankarticle'>\n$1\n</div>", 'blankarticle' );
                        }
 
+                       if ( $this->selfRedirect ) {
+                               $wgOut->wrapWikiMsg( "<div id='mw-selfredirect'>\n$1\n</div>", 'selfredirect' );
+                       }
+
                        if ( $this->hookError !== '' ) {
                                $wgOut->addWikiText( $this->hookError );
                        }
@@ -3039,7 +3085,7 @@ HTML
                }
                # This hook seems slightly odd here, but makes things more
                # consistent for extensions.
-               wfRunHooks( 'OutputPageBeforeHTML', array( &$wgOut, &$text ) );
+               Hooks::run( 'OutputPageBeforeHTML', array( &$wgOut, &$text ) );
                $wgOut->addHTML( $text );
                if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
                        $this->mArticle->closeShowCategory();
@@ -3078,7 +3124,7 @@ HTML
 
                if ( $newContent ) {
                        ContentHandler::runLegacyHooks( 'EditPageGetDiffText', array( $this, &$newContent ) );
-                       wfRunHooks( 'EditPageGetDiffContent', array( $this, &$newContent ) );
+                       Hooks::run( 'EditPageGetDiffContent', array( $this, &$newContent ) );
 
                        $popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
                        $newContent = $newContent->preSaveTransform( $this->mTitle, $wgUser, $popts );
@@ -3130,7 +3176,7 @@ HTML
         */
        protected function showTosSummary() {
                $msg = 'editpage-tos-summary';
-               wfRunHooks( 'EditPageTosSummary', array( $this->mTitle, &$msg ) );
+               Hooks::run( 'EditPageTosSummary', array( $this->mTitle, &$msg ) );
                if ( !wfMessage( $msg )->isDisabled() ) {
                        global $wgOut;
                        $wgOut->addHTML( '<div class="mw-tos-summary">' );
@@ -3174,7 +3220,7 @@ HTML
                                '[[' . wfMessage( 'copyrightpage' )->inContentLanguage()->text() . ']]' );
                }
                // Allow for site and per-namespace customization of contribution/copyright notice.
-               wfRunHooks( 'EditPageCopyrightWarning', array( $title, &$copywarnMsg ) );
+               Hooks::run( 'EditPageCopyrightWarning', array( $title, &$copywarnMsg ) );
 
                return "<div id=\"editpage-copywarn\">\n" .
                        call_user_func_array( 'wfMessage', $copywarnMsg )->$format() . "\n</div>";
@@ -3207,7 +3253,7 @@ HTML
                        Html::openElement( 'tbody' );
 
                foreach ( $output->getLimitReportData() as $key => $value ) {
-                       if ( wfRunHooks( 'ParserLimitReportFormat',
+                       if ( Hooks::run( 'ParserLimitReportFormat',
                                array( $key, &$value, &$limitReport, true, true )
                        ) ) {
                                $keyMsg = wfMessage( $key );
@@ -3275,7 +3321,7 @@ HTML
                $wgOut->addHTML( "      <span class='editHelp'>{$edithelp}</span>\n" );
                $wgOut->addHTML( "</div><!-- editButtons -->\n" );
 
-               wfRunHooks( 'EditPage::showStandardInputs:options', array( $this, $wgOut, &$tabindex ) );
+               Hooks::run( 'EditPage::showStandardInputs:options', array( $this, $wgOut, &$tabindex ) );
 
                $wgOut->addHTML( "</div><!-- editOptions -->\n" );
        }
@@ -3287,7 +3333,7 @@ HTML
        protected function showConflict() {
                global $wgOut;
 
-               if ( wfRunHooks( 'EditPageBeforeConflictDiff', array( &$this, &$wgOut ) ) ) {
+               if ( Hooks::run( 'EditPageBeforeConflictDiff', array( &$this, &$wgOut ) ) ) {
                        $wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
 
                        $content1 = $this->toEditContent( $this->textbox1 );
@@ -3438,7 +3484,7 @@ HTML
                        $content = $this->toEditContent( $this->textbox1 );
 
                        $previewHTML = '';
-                       if ( !wfRunHooks(
+                       if ( !Hooks::run(
                                'AlternateEditPreview',
                                array( $this, &$content, &$previewHTML, &$this->mParserOutput ) )
                        ) {
@@ -3463,7 +3509,6 @@ HTML
                        }
 
                        $parserOptions = $this->mArticle->makeParserOptions( $this->mArticle->getContext() );
-                       $parserOptions->setEditSection( false );
                        $parserOptions->setIsPreview( true );
                        $parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
 
@@ -3508,20 +3553,24 @@ HTML
 
                        $hook_args = array( $this, &$content );
                        ContentHandler::runLegacyHooks( 'EditPageGetPreviewText', $hook_args );
-                       wfRunHooks( 'EditPageGetPreviewContent', $hook_args );
+                       Hooks::run( 'EditPageGetPreviewContent', $hook_args );
 
                        $parserOptions->enableLimitReport();
 
                        # For CSS/JS pages, we should have called the ShowRawCssJs hook here.
                        # But it's now deprecated, so never mind
 
-                       $content = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
-                       $parserOutput = $content->getParserOutput(
-                               $this->getArticle()->getTitle(),
-                               null,
-                               $parserOptions
+                       $pstContent = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
+                       $parserOutput = $pstContent->getParserOutput( $this->mTitle, null, $parserOptions );
+
+                       # Try to stash the edit for the final submission step
+                       # @todo: different date format preferences cause cache misses
+                       ApiStashEdit::stashEditFromPreview(
+                               $this->getArticle(), $content, $pstContent,
+                               $parserOutput, $parserOptions, $parserOptions, wfTimestampNow()
                        );
 
+                       $parserOutput->setEditSectionTokens( false ); // no section edit links
                        $previewHTML = $parserOutput->getText();
                        $this->mParserOutput = $parserOutput;
                        $wgOut->addParserOutputMetadata( $parserOutput );
@@ -3702,7 +3751,7 @@ HTML
 
                $toolbar = '<div id="toolbar"></div>';
 
-               wfRunHooks( 'EditPageBeforeEditToolbar', array( &$toolbar ) );
+               Hooks::run( 'EditPageBeforeEditToolbar', array( &$toolbar ) );
 
                return $toolbar;
        }
@@ -3769,7 +3818,7 @@ HTML
                                $checkboxes['watch'] = $watchThisHtml;
                        }
                }
-               wfRunHooks( 'EditPageBeforeEditChecks', array( &$this, &$checkboxes, &$tabindex ) );
+               Hooks::run( 'EditPageBeforeEditChecks', array( &$this, &$checkboxes, &$tabindex ) );
                return $checkboxes;
        }
 
@@ -3810,7 +3859,7 @@ HTML
                $buttons['diff'] = Html::submitButton( wfMessage( 'showdiff' )->text(),
                        $attribs );
 
-               wfRunHooks( 'EditPageBeforeEditButtons', array( &$this, &$buttons, &$tabindex ) );
+               Hooks::run( 'EditPageBeforeEditButtons', array( &$this, &$buttons, &$tabindex ) );
                return $buttons;
        }
 
@@ -3854,7 +3903,7 @@ HTML
                $wgOut->prepareErrorPage( wfMessage( 'nosuchsectiontitle' ) );
 
                $res = wfMessage( 'nosuchsectiontext', $this->section )->parseAsBlock();
-               wfRunHooks( 'EditPageNoSuchSection', array( &$this, &$res ) );
+               Hooks::run( 'EditPageNoSuchSection', array( &$this, &$res ) );
                $wgOut->addHTML( $res );
 
                $wgOut->returnToMain( false, $this->mTitle );
index 840e723..dd5cb0c 100644 (file)
@@ -348,7 +348,7 @@ class WikiExporter {
                                # Default JOIN, to be overridden...
                                $join['revision'] = array( 'INNER JOIN', 'page_id=rev_page AND page_latest=rev_id' );
                                # One, and only one hook should set this, and return false
-                               if ( wfRunHooks( 'WikiExporter::dumpStableQuery', array( &$tables, &$opts, &$join ) ) ) {
+                               if ( Hooks::run( 'WikiExporter::dumpStableQuery', array( &$tables, &$opts, &$join ) ) ) {
                                        wfProfileOut( __METHOD__ );
                                        throw new MWException( __METHOD__ . " given invalid history dump type." );
                                }
@@ -378,7 +378,7 @@ class WikiExporter {
 
                        $result = null; // Assuring $result is not undefined, if exception occurs early
                        try {
-                               wfRunHooks( 'ModifyExportQuery',
+                               Hooks::run( 'ModifyExportQuery',
                                                array( $this->db, &$tables, &$cond, &$opts, &$join ) );
 
                                # Do the query!
@@ -627,7 +627,7 @@ class XmlDumpWriter {
                                strval( $row->page_restrictions ) ) . "\n";
                }
 
-               wfRunHooks( 'XmlDumpWriterOpenPage', array( $this, &$out, $row, $title ) );
+               Hooks::run( 'XmlDumpWriterOpenPage', array( $this, &$out, $row, $title ) );
 
                return $out;
        }
@@ -722,7 +722,7 @@ class XmlDumpWriter {
                        $out .= "      <sha1/>\n";
                }
 
-               wfRunHooks( 'XmlDumpWriterWriteRevision', array( &$this, &$out, $row, $text ) );
+               Hooks::run( 'XmlDumpWriterWriteRevision', array( &$this, &$out, $row, $text ) );
 
                $out .= "    </revision>\n";
 
index b4e2458..1c709e6 100644 (file)
@@ -210,7 +210,7 @@ class FileDeleteForm {
                }
 
                if ( $status->isOK() ) {
-                       wfRunHooks( 'FileDeleteComplete', array( &$file, &$oldimage, &$page, &$user, &$reason ) );
+                       Hooks::run( 'FileDeleteComplete', array( &$file, &$oldimage, &$page, &$user, &$reason ) );
                }
 
                return $status;
index 7052820..fb298cf 100644 (file)
@@ -392,7 +392,7 @@ class GitInfo {
 
                if ( self::$viewers === false ) {
                        self::$viewers = $wgGitRepositoryViewers;
-                       wfRunHooks( 'GitViewers', array( &self::$viewers ) );
+                       Hooks::run( 'GitViewers', array( &self::$viewers ) );
                }
 
                return self::$viewers;
index 14326ec..859b421 100644 (file)
@@ -1081,7 +1081,7 @@ function wfDebugMem( $exact = false ) {
  * @param string|bool $dest Destination of the message:
  *     - 'all': both to the log and HTML (debug toolbar or HTML comments)
  *     - 'log': only to the log and not in HTML
- *     - 'private': only to the specifc log if set in $wgDebugLogGroups and
+ *     - 'private': only to the specific log if set in $wgDebugLogGroups and
  *       discarded otherwise
  *   For backward compatibility, it can also take a boolean:
  *     - true: same as 'all'
@@ -1531,7 +1531,7 @@ function wfMsgReal( $key, $args, $useDB = true, $forContent = false, $transform
 function wfMsgGetKey( $key, $useDB = true, $langCode = false, $transform = true ) {
        wfDeprecated( __METHOD__, '1.21' );
 
-       wfRunHooks( 'NormalizeMessageKey', array( &$key, &$useDB, &$langCode, &$transform ) );
+       Hooks::run( 'NormalizeMessageKey', array( &$key, &$useDB, &$langCode, &$transform ) );
 
        $cache = MessageCache::singleton();
        $message = $cache->get( $key, $useDB, $langCode );
@@ -1837,7 +1837,7 @@ function wfBacktrace( $raw = null ) {
 
        $frames = array_map( function ( $frame ) use ( $frameFormat ) {
                $file = !empty( $frame['file'] ) ? basename( $frame['file'] ) : '-';
-               $line = $frame['line'] ?: '-';
+               $line = isset( $frame['line'] ) ? $frame['line'] : '-';
                $call = $frame['function'];
                if ( !empty( $frame['class'] ) ) {
                        $call = $frame['class'] . $frame['type'] . $call;
@@ -2964,7 +2964,7 @@ function wfShellWikiCmd( $script, array $parameters = array(), array $options =
        global $wgPhpCli;
        // Give site config file a chance to run the script in a wrapper.
        // The caller may likely want to call wfBasename() on $script.
-       wfRunHooks( 'wfShellWikiCmd', array( &$script, &$parameters, &$options ) );
+       Hooks::run( 'wfShellWikiCmd', array( &$script, &$parameters, &$options ) );
        $cmd = isset( $options['php'] ) ? array( $options['php'] ) : array( $wgPhpCli );
        if ( isset( $options['wrapper'] ) ) {
                $cmd[] = $options['wrapper'];
@@ -3416,7 +3416,7 @@ function wfResetSessionID() {
                $_SESSION = $tmp;
        }
        $newSessionId = session_id();
-       wfRunHooks( 'ResetSessionID', array( $oldSessionId, $newSessionId ) );
+       Hooks::run( 'ResetSessionID', array( $oldSessionId, $newSessionId ) );
 }
 
 /**
@@ -3551,7 +3551,7 @@ function wfSplitWikiID( $wiki ) {
  *
  * @return DatabaseBase
  */
-function &wfGetDB( $db, $groups = array(), $wiki = false ) {
+function wfGetDB( $db, $groups = array(), $wiki = false ) {
        return wfGetLB( $wiki )->getConnection( $db, $groups, $wiki );
 }
 
@@ -3570,7 +3570,7 @@ function wfGetLB( $wiki = false ) {
  *
  * @return LBFactory
  */
-function &wfGetLBFactory() {
+function wfGetLBFactory() {
        return LBFactory::singleton();
 }
 
@@ -3946,6 +3946,7 @@ function wfGetLangConverterCacheStorage() {
  * @param string|null $deprecatedVersion Optionally mark hook as deprecated with version number
  *
  * @return bool True if no handler aborted the hook
+ * @deprecated 1.25
  */
 function wfRunHooks( $event, array $args = array(), $deprecatedVersion = null ) {
        return Hooks::run( $event, $args, $deprecatedVersion );
@@ -4013,7 +4014,7 @@ function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
 
        # Run the extension hook
        $bad = false;
-       if ( !wfRunHooks( 'BadImage', array( $name, &$bad ) ) ) {
+       if ( !Hooks::run( 'BadImage', array( $name, &$bad ) ) ) {
                wfProfileOut( __METHOD__ );
                return $bad;
        }
@@ -4077,7 +4078,7 @@ function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
  */
 function wfCanIPUseHTTPS( $ip ) {
        $canDo = true;
-       wfRunHooks( 'CanIPUseHTTPS', array( $ip, &$canDo ) );
+       Hooks::run( 'CanIPUseHTTPS', array( $ip, &$canDo ) );
        return !!$canDo;
 }
 
index 4eb8e97..6f93351 100644 (file)
@@ -328,7 +328,7 @@ class WikiImporter {
         */
        public function finishImportPage( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) {
                $args = func_get_args();
-               return wfRunHooks( 'AfterImportPage', $args );
+               return Hooks::run( 'AfterImportPage', $args );
        }
 
        /**
@@ -464,7 +464,7 @@ class WikiImporter {
                        $tag = $this->reader->name;
                        $type = $this->reader->nodeType;
 
-                       if ( !wfRunHooks( 'ImportHandleToplevelXMLTag', array( $this ) ) ) {
+                       if ( !Hooks::run( 'ImportHandleToplevelXMLTag', array( $this ) ) ) {
                                // Do nothing
                        } elseif ( $tag == 'mediawiki' && $type == XmlReader::END_ELEMENT ) {
                                break;
@@ -523,7 +523,7 @@ class WikiImporter {
 
                        $tag = $this->reader->name;
 
-                       if ( !wfRunHooks( 'ImportHandleLogItemXMLTag', array(
+                       if ( !Hooks::run( 'ImportHandleLogItemXMLTag', array(
                                $this, $logInfo
                        ) ) ) {
                                // Do nothing
@@ -590,7 +590,7 @@ class WikiImporter {
                        if ( $badTitle ) {
                                // The title is invalid, bail out of this page
                                $skip = true;
-                       } elseif ( !wfRunHooks( 'ImportHandlePageXMLTag', array( $this,
+                       } elseif ( !Hooks::run( 'ImportHandlePageXMLTag', array( $this,
                                                &$pageInfo ) ) ) {
                                // Do nothing
                        } elseif ( in_array( $tag, $normalFields ) ) {
@@ -652,7 +652,7 @@ class WikiImporter {
 
                        $tag = $this->reader->name;
 
-                       if ( !wfRunHooks( 'ImportHandleRevisionXMLTag', array(
+                       if ( !Hooks::run( 'ImportHandleRevisionXMLTag', array(
                                $this, $pageInfo, $revisionInfo
                        ) ) ) {
                                // Do nothing
@@ -744,7 +744,7 @@ class WikiImporter {
 
                        $tag = $this->reader->name;
 
-                       if ( !wfRunHooks( 'ImportHandleUploadXMLTag', array(
+                       if ( !Hooks::run( 'ImportHandleUploadXMLTag', array(
                                $this, $pageInfo
                        ) ) ) {
                                // Do nothing
index d84e5d0..a55eee9 100644 (file)
@@ -209,7 +209,7 @@ class Linker {
                $dummy = new DummyLinker; // dummy linker instance for bc on the hooks
 
                $ret = null;
-               if ( !wfRunHooks( 'LinkBegin',
+               if ( !Hooks::run( 'LinkBegin',
                        array( $dummy, $target, &$html, &$customAttribs, &$query, &$options, &$ret ) )
                ) {
                        wfProfileOut( __METHOD__ );
@@ -251,7 +251,7 @@ class Linker {
                }
 
                $ret = null;
-               if ( wfRunHooks( 'LinkEnd', array( $dummy, $target, $options, &$html, &$attribs, &$ret ) ) ) {
+               if ( Hooks::run( 'LinkEnd', array( $dummy, $target, $options, &$html, &$attribs, &$ret ) ) ) {
                        $ret = Html::rawElement( 'a', $attribs, $html );
                }
 
@@ -411,7 +411,7 @@ class Linker {
         */
        public static function makeSelfLinkObj( $nt, $html = '', $query = '', $trail = '', $prefix = '' ) {
                $ret = "<strong class=\"selflink\">{$prefix}{$html}</strong>{$trail}";
-               if ( !wfRunHooks( 'SelfLinkBegin', array( $nt, &$html, &$trail, &$prefix, &$ret ) ) ) {
+               if ( !Hooks::run( 'SelfLinkBegin', array( $nt, &$html, &$trail, &$prefix, &$ret ) ) ) {
                        return $ret;
                }
 
@@ -497,7 +497,7 @@ class Linker {
                        $alt = self::fnamePart( $url );
                }
                $img = '';
-               $success = wfRunHooks( 'LinkerMakeExternalImage', array( &$url, &$alt, &$img ) );
+               $success = Hooks::run( 'LinkerMakeExternalImage', array( &$url, &$alt, &$img ) );
                if ( !$success ) {
                        wfDebug( "Hook LinkerMakeExternalImage changed the output of external image "
                                . "with url {$url} and alt text {$alt} to {$img}\n", true );
@@ -551,7 +551,7 @@ class Linker {
        ) {
                $res = null;
                $dummy = new DummyLinker;
-               if ( !wfRunHooks( 'ImageBeforeProduceHTML', array( &$dummy, &$title,
+               if ( !Hooks::run( 'ImageBeforeProduceHTML', array( &$dummy, &$title,
                        &$file, &$frameParams, &$handlerParams, &$time, &$res ) ) ) {
                        return $res;
                }
@@ -1031,7 +1031,7 @@ class Linker {
                        'title' => $alt
                );
 
-               if ( !wfRunHooks( 'LinkerMakeMediaLinkFile',
+               if ( !Hooks::run( 'LinkerMakeMediaLinkFile',
                        array( $title, $file, &$html, &$attribs, &$ret ) ) ) {
                        wfDebug( "Hook LinkerMakeMediaLinkFile changed the output of link "
                                . "with url {$url} and text {$html} to {$ret}\n", true );
@@ -1090,7 +1090,7 @@ class Linker {
                }
                $attribs['rel'] = Parser::getExternalLinkRel( $url, $title );
                $link = '';
-               $success = wfRunHooks( 'LinkerMakeExternalLink',
+               $success = Hooks::run( 'LinkerMakeExternalLink',
                        array( &$url, &$text, &$link, &$attribs, $linktype ) );
                if ( !$success ) {
                        wfDebug( "Hook LinkerMakeExternalLink changed the output of link "
@@ -1176,7 +1176,7 @@ class Linker {
                        $items[] = self::emailLink( $userId, $userText );
                }
 
-               wfRunHooks( 'UserToolLinksEdit', array( $userId, $userText, &$items ) );
+               Hooks::run( 'UserToolLinksEdit', array( $userId, $userText, &$items ) );
 
                if ( $items ) {
                        return wfMessage( 'word-separator' )->plain()
@@ -1333,7 +1333,7 @@ class Linker {
                                $auto = $match[2];
                                $post = $match[3];
                                $comment = null;
-                               wfRunHooks( 'FormatAutocomments', array( &$comment, $pre, $auto, $post, $title, $local ) );
+                               Hooks::run( 'FormatAutocomments', array( &$comment, $pre, $auto, $post, $title, $local ) );
                                if ( $comment === null ) {
                                        $link = '';
                                        if ( $title ) {
@@ -1897,7 +1897,7 @@ class Linker {
        ) {
                global $wgShowRollbackEditCount, $wgMiserMode;
 
-               // To config which pages are effected by miser mode
+               // To config which pages are affected by miser mode
                $disableRollbackEditCountSpecialPage = array( 'Recentchanges', 'Watchlist' );
 
                if ( $context === null ) {
index 392f558..bd68551 100644 (file)
@@ -72,7 +72,7 @@ class MWNamespace {
                /**
                 * @since 1.20
                 */
-               wfRunHooks( 'NamespaceIsMovable', array( $index, &$result ) );
+               Hooks::run( 'NamespaceIsMovable', array( $index, &$result ) );
 
                return $result;
        }
@@ -213,7 +213,7 @@ class MWNamespace {
                        if ( is_array( $wgExtraNamespaces ) ) {
                                $namespaces += $wgExtraNamespaces;
                        }
-                       wfRunHooks( 'CanonicalNamespaces', array( &$namespaces ) );
+                       Hooks::run( 'CanonicalNamespaces', array( &$namespaces ) );
                }
                return $namespaces;
        }
index 26f5e54..4b3d36a 100644 (file)
@@ -221,7 +221,7 @@ class MWTimestamp {
                $offsetRel = $relativeTo->offsetForUser( $user );
 
                $ts = '';
-               if ( wfRunHooks( 'GetHumanTimestamp', array( &$ts, $this, $relativeTo, $user, $lang ) ) ) {
+               if ( Hooks::run( 'GetHumanTimestamp', array( &$ts, $this, $relativeTo, $user, $lang ) ) ) {
                        $ts = $lang->getHumanTimestamp( $this, $relativeTo, $user );
                }
 
@@ -326,7 +326,7 @@ class MWTimestamp {
 
                $ts = '';
                $diff = $this->diff( $relativeTo );
-               if ( wfRunHooks(
+               if ( Hooks::run(
                        'GetRelativeTimestamp',
                        array( &$ts, &$diff, $this, $relativeTo, $user, $lang )
                ) ) {
index d281555..4b24a00 100644 (file)
@@ -273,7 +273,7 @@ class MagicWord {
        static function getVariableIDs() {
                if ( !self::$mVariableIDsInitialised ) {
                        # Get variable IDs
-                       wfRunHooks( 'MagicWordwgVariableIDs', array( &self::$mVariableIDs ) );
+                       Hooks::run( 'MagicWordwgVariableIDs', array( &self::$mVariableIDs ) );
                        self::$mVariableIDsInitialised = true;
                }
                return self::$mVariableIDs;
@@ -308,7 +308,7 @@ class MagicWord {
         */
        static function getDoubleUnderscoreArray() {
                if ( is_null( self::$mDoubleUnderscoreArray ) ) {
-                       wfRunHooks( 'GetDoubleUnderscoreIDs', array( &self::$mDoubleUnderscoreIDs ) );
+                       Hooks::run( 'GetDoubleUnderscoreIDs', array( &self::$mDoubleUnderscoreIDs ) );
                        self::$mDoubleUnderscoreArray = new MagicWordArray( self::$mDoubleUnderscoreIDs );
                }
                return self::$mDoubleUnderscoreArray;
index 7ce6d1b..6e2a0c9 100644 (file)
@@ -169,7 +169,7 @@ class MediaWiki {
                }
 
                $unused = null; // To pass it by reference
-               wfRunHooks( 'BeforeInitialize', array( &$title, &$unused, &$output, &$user, $request, $this ) );
+               Hooks::run( 'BeforeInitialize', array( &$title, &$unused, &$output, &$user, $request, $this ) );
 
                // Invalid titles. Bug 21776: The interwikis must redirect even if the page name is empty.
                if ( is_null( $title ) || ( $title->getDBkey() == '' && !$title->isExternal() )
@@ -233,7 +233,7 @@ class MediaWiki {
                        && ( $request->getVal( 'title' ) === null
                                || $title->getPrefixedDBkey() != $request->getVal( 'title' ) )
                        && !count( $request->getValueNames( array( 'action', 'title' ) ) )
-                       && wfRunHooks( 'TestCanonicalRedirect', array( $request, $title, $output ) )
+                       && Hooks::run( 'TestCanonicalRedirect', array( $request, $title, $output ) )
                ) {
                        if ( $title->isSpecialPage() ) {
                                list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
@@ -342,7 +342,7 @@ class MediaWiki {
                        // Give extensions a change to ignore/handle redirects as needed
                        $ignoreRedirect = $target = false;
 
-                       wfRunHooks( 'InitializeArticleMaybeRedirect',
+                       Hooks::run( 'InitializeArticleMaybeRedirect',
                                array( &$title, &$request, &$ignoreRedirect, &$target, &$article ) );
 
                        // Follow redirects only for... redirects.
@@ -392,7 +392,7 @@ class MediaWiki {
                $title = $this->context->getTitle();
                $user = $this->context->getUser();
 
-               if ( !wfRunHooks( 'MediaWikiPerformAction',
+               if ( !Hooks::run( 'MediaWikiPerformAction',
                                array( $output, $page, $title, $user, $request, $this ) )
                ) {
                        wfProfileOut( __METHOD__ );
@@ -416,7 +416,7 @@ class MediaWiki {
                        return;
                }
 
-               if ( wfRunHooks( 'UnknownAction', array( $request->getVal( 'action', 'view' ), $page ) ) ) {
+               if ( Hooks::run( 'UnknownAction', array( $request->getVal( 'action', 'view' ), $page ) ) ) {
                        $output->setStatusCode( 404 );
                        $output->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
                }
@@ -530,7 +530,7 @@ class MediaWiki {
                        $redirUrl = preg_replace( '#^http://#', 'https://', $oldUrl );
 
                        // ATTENTION: This hook is likely to be removed soon due to overall design of the system.
-                       if ( wfRunHooks( 'BeforeHttpsRedirect', array( $this->context, &$redirUrl ) ) ) {
+                       if ( Hooks::run( 'BeforeHttpsRedirect', array( $this->context, &$redirUrl ) ) ) {
 
                                if ( $request->wasPosted() ) {
                                        // This is weird and we'd hope it almost never happens. This
index 3406831..ebe98a3 100644 (file)
@@ -200,7 +200,7 @@ class MimeMagic {
                global $IP;
 
                # Allow media handling extensions adding MIME-types and MIME-info
-               wfRunHooks( 'MimeMagicInit', array( $this ) );
+               Hooks::run( 'MimeMagicInit', array( $this ) );
 
                $types = MM_WELL_KNOWN_MIME_TYPES;
 
@@ -218,7 +218,7 @@ class MimeMagic {
                                wfDebug( __METHOD__ . ": can't load mime types from $mimeTypeFile\n" );
                        }
                } else {
-                       wfDebug( __METHOD__ . ": no mime types file defined, using build-ins only.\n" );
+                       wfDebug( __METHOD__ . ": no mime types file defined, using built-ins only.\n" );
                }
 
                $types .= "\n" . $this->mExtraTypes;
@@ -295,7 +295,7 @@ class MimeMagic {
                                wfDebug( __METHOD__ . ": can't load mime info from $mimeInfoFile\n" );
                        }
                } else {
-                       wfDebug( __METHOD__ . ": no mime info file defined, using build-ins only.\n" );
+                       wfDebug( __METHOD__ . ": no mime info file defined, using built-ins only.\n" );
                }
 
                $info .= "\n" . $this->mExtraInfo;
@@ -569,7 +569,7 @@ class MimeMagic {
                }
 
                # Media handling extensions can improve the MIME detected
-               wfRunHooks( 'MimeMagicImproveFromExtension', array( $this, $ext, &$mime ) );
+               Hooks::run( 'MimeMagicImproveFromExtension', array( $this, $ext, &$mime ) );
 
                if ( isset( $this->mMimeTypeAliases[$mime] ) ) {
                        $mime = $this->mMimeTypeAliases[$mime];
@@ -802,7 +802,7 @@ class MimeMagic {
                # people will hopefully nag and submit patches :)
                $mime = false;
                # Some strings by reference for performance - assuming well-behaved hooks
-               wfRunHooks(
+               Hooks::run(
                        'MimeMagicGuessFromContent',
                        array( $this, &$head, &$tail, $file, &$mime )
                );
index 994be91..065e189 100644 (file)
@@ -81,7 +81,7 @@ class MovePage {
                        }
                }
 
-               wfRunHooks( 'MovePageCheckPermissions',
+               Hooks::run( 'MovePageCheckPermissions',
                        array( $this->oldTitle, $this->newTitle, $user, $reason, $status )
                );
 
@@ -146,7 +146,7 @@ class MovePage {
                }
 
                // Hook for extensions to say a title can't be moved for technical reasons
-               wfRunHooks( 'MovePageIsValidMove', array( $this->oldTitle, $this->newTitle, $status ) );
+               Hooks::run( 'MovePageIsValidMove', array( $this->oldTitle, $this->newTitle, $status ) );
 
                return $status;
        }
@@ -231,7 +231,7 @@ class MovePage {
        public function move( User $user, $reason, $createRedirect ) {
                global $wgCategoryCollation;
 
-               wfRunHooks( 'TitleMove', array( $this->oldTitle, $this->newTitle, $user ) );
+               Hooks::run( 'TitleMove', array( $this->oldTitle, $this->newTitle, $user ) );
 
                // If it is a file, move it first.
                // It is done before all other moving stuff is done because it's hard to revert.
@@ -370,7 +370,7 @@ class MovePage {
 
                $dbw->commit( __METHOD__ );
 
-               wfRunHooks( 'TitleMoveComplete', array( &$this->oldTitle, &$this->newTitle, &$user, $pageid, $redirid, $reason ) );
+               Hooks::run( 'TitleMoveComplete', array( &$this->oldTitle, &$this->newTitle, &$user, $pageid, $redirid, $reason ) );
                return Status::newGood();
        }
 
@@ -486,7 +486,7 @@ class MovePage {
 
                $newpage->updateRevisionOn( $dbw, $nullRevision );
 
-               wfRunHooks( 'NewRevisionFromEditComplete',
+               Hooks::run( 'NewRevisionFromEditComplete',
                        array( $newpage, $nullRevision, $nullRevision->getParentId(), $user ) );
 
                $newpage->doEditUpdates( $nullRevision, $user,
@@ -513,7 +513,7 @@ class MovePage {
                                $redirectRevision->insertOn( $dbw );
                                $redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 );
 
-                               wfRunHooks( 'NewRevisionFromEditComplete',
+                               Hooks::run( 'NewRevisionFromEditComplete',
                                        array( $redirectArticle, $redirectRevision, false, $user ) );
 
                                $redirectArticle->doEditUpdates( $redirectRevision, $user, array( 'created' => true ) );
index b0bbcdd..c6209ee 100644 (file)
@@ -129,7 +129,8 @@ function wfGzipHandler( $s ) {
        $headers = headers_list();
        $foundVary = false;
        foreach ( $headers as $header ) {
-               if ( substr( $header, 0, 5 ) == 'Vary:' ) {
+               $headerName = strtolower( substr( $header, 0, 5 ) );
+               if ( $headerName == 'vary:' ) {
                        $foundVary = true;
                        break;
                }
index fb2d6f4..24b9e46 100644 (file)
@@ -786,7 +786,7 @@ class OutputPage extends ContextSource {
                        // bug 44570: the core page itself may not change, but resources might
                        $modifiedTimes['sepoch'] = wfTimestamp( TS_MW, time() - $config->get( 'SquidMaxage' ) );
                }
-               wfRunHooks( 'OutputPageCheckLastModified', array( &$modifiedTimes ) );
+               Hooks::run( 'OutputPageCheckLastModified', array( &$modifiedTimes ) );
 
                $maxModified = max( $modifiedTimes );
                $this->mLastModified = wfTimestamp( TS_RFC2822, $maxModified );
@@ -1033,17 +1033,29 @@ class OutputPage extends ContextSource {
        }
 
        /**
-        * Add a subtitle containing a backlink to a page
+        * Build message object for a subtitle containing a backlink to a page
         *
         * @param Title $title Title to link to
         * @param array $query Array of additional parameters to include in the link
+        * @return Message
+        * @since 1.25
         */
-       public function addBacklinkSubtitle( Title $title, $query = array() ) {
+       public static function buildBacklinkSubtitle( Title $title, $query = array() ) {
                if ( $title->isRedirect() ) {
                        $query['redirect'] = 'no';
                }
-               $this->addSubtitle( $this->msg( 'backlinksubtitle' )
-                       ->rawParams( Linker::link( $title, null, array(), $query ) ) );
+               return wfMessage( 'backlinksubtitle' )
+                       ->rawParams( Linker::link( $title, null, array(), $query ) );
+       }
+
+       /**
+        * Add a subtitle containing a backlink to a page
+        *
+        * @param Title $title Title to link to
+        * @param array $query Array of additional parameters to include in the link
+        */
+       public function addBacklinkSubtitle( Title $title, $query = array() ) {
+               $this->addSubtitle( self::buildBacklinkSubtitle( $title, $query ) );
        }
 
        /**
@@ -1313,7 +1325,7 @@ class OutputPage extends ContextSource {
                }
 
                # Add the remaining categories to the skin
-               if ( wfRunHooks(
+               if ( Hooks::run(
                        'OutputPageMakeCategoryLinks',
                        array( &$this, $categories, &$this->mCategoryLinks ) )
                ) {
@@ -1753,8 +1765,8 @@ class OutputPage extends ContextSource {
                // Link flags are ignored for now, but may in the future be
                // used to mark individual language links.
                $linkFlags = array();
-               wfRunHooks( 'LanguageLinks', array( $this->getTitle(), &$this->mLanguageLinks, &$linkFlags ) );
-               wfRunHooks( 'OutputPageParserOutput', array( &$this, $parserOutput ) );
+               Hooks::run( 'LanguageLinks', array( $this->getTitle(), &$this->mLanguageLinks, &$linkFlags ) );
+               Hooks::run( 'OutputPageParserOutput', array( &$this, $parserOutput ) );
        }
 
        /**
@@ -1783,7 +1795,7 @@ class OutputPage extends ContextSource {
         */
        public function addParserOutputText( $parserOutput ) {
                $text = $parserOutput->getText();
-               wfRunHooks( 'OutputPageBeforeHTML', array( &$this, &$text ) );
+               Hooks::run( 'OutputPageBeforeHTML', array( &$this, &$text ) );
                $this->addHTML( $text );
        }
 
@@ -1908,7 +1920,7 @@ class OutputPage extends ContextSource {
                                ),
                                $config->get( 'CacheVaryCookies' )
                        );
-                       wfRunHooks( 'GetCacheVaryCookies', array( $this, &$cookies ) );
+                       Hooks::run( 'GetCacheVaryCookies', array( $this, &$cookies ) );
                }
                return $cookies;
        }
@@ -2171,7 +2183,7 @@ class OutputPage extends ContextSource {
                        $redirect = $this->mRedirect;
                        $code = $this->mRedirectCode;
 
-                       if ( wfRunHooks( "BeforePageRedirect", array( $this, &$redirect, &$code ) ) ) {
+                       if ( Hooks::run( "BeforePageRedirect", array( $this, &$redirect, &$code ) ) ) {
                                if ( $code == '301' || $code == '303' ) {
                                        if ( !$config->get( 'DebugRedirects' ) ) {
                                                $message = HttpStatus::getMessage( $code );
@@ -2248,7 +2260,7 @@ class OutputPage extends ContextSource {
 
                        // Hook that allows last minute changes to the output page, e.g.
                        // adding of CSS or Javascript by extensions.
-                       wfRunHooks( 'BeforePageDisplay', array( &$this, &$sk ) );
+                       Hooks::run( 'BeforePageDisplay', array( &$this, &$sk ) );
 
                        wfProfileIn( 'Output-skin' );
                        $sk->outputPage();
@@ -2256,7 +2268,7 @@ class OutputPage extends ContextSource {
                }
 
                // This hook allows last minute changes to final overall output by modifying output buffer
-               wfRunHooks( 'AfterFinalPageOutput', array( $this ) );
+               Hooks::run( 'AfterFinalPageOutput', array( $this ) );
 
                $this->sendCacheControl();
 
@@ -2685,7 +2697,7 @@ class OutputPage extends ContextSource {
 
                // Allow skins and extensions to add body attributes they need
                $sk->addToBodyAttributes( $this, $bodyAttrs );
-               wfRunHooks( 'OutputPageBodyAttributes', array( $this, $sk, &$bodyAttrs ) );
+               Hooks::run( 'OutputPageBodyAttributes', array( $this, $sk, &$bodyAttrs ) );
 
                $ret .= Html::openElement( 'body', $bodyAttrs ) . "\n";
 
@@ -3235,7 +3247,7 @@ class OutputPage extends ContextSource {
                // Use the 'ResourceLoaderGetConfigVars' hook if the variable is not
                // page-dependant but site-wide (without state).
                // Alternatively, you may want to use OutputPage->addJsConfigVars() instead.
-               wfRunHooks( 'MakeGlobalVariablesScript', array( &$vars, $this ) );
+               Hooks::run( 'MakeGlobalVariablesScript', array( &$vars, $this ) );
 
                // Merge in variables from addJsConfigVars last
                return array_merge( $vars, $this->getJsConfigVars() );
index 93844f6..44995ac 100644 (file)
@@ -96,7 +96,7 @@ class Preferences {
                self::searchPreferences( $user, $context, $defaultPreferences );
                self::miscPreferences( $user, $context, $defaultPreferences );
 
-               wfRunHooks( 'GetPreferences', array( $user, &$defaultPreferences ) );
+               Hooks::run( 'GetPreferences', array( $user, &$defaultPreferences ) );
 
                self::loadPreferenceValues( $user, $context, $defaultPreferences );
                self::$defaultPreferences = $defaultPreferences;
@@ -1433,7 +1433,7 @@ class Preferences {
                                $user->setOption( $key, $value );
                        }
 
-                       wfRunHooks( 'PreferencesFormPreSave', array( $formData, $form, $user, &$result ) );
+                       Hooks::run( 'PreferencesFormPreSave', array( $formData, $form, $user, &$result ) );
                        $user->saveSettings();
                }
 
@@ -1575,7 +1575,7 @@ class PreferencesForm extends HTMLForm {
         */
        function getLegend( $key ) {
                $legend = parent::getLegend( $key );
-               wfRunHooks( 'PreferencesGetLegend', array( $this, $key, &$legend ) );
+               Hooks::run( 'PreferencesGetLegend', array( $this, $key, &$legend ) );
                return $legend;
        }
 }
index a4e64ee..caa3ef5 100644 (file)
@@ -65,7 +65,7 @@ abstract class PrefixSearch {
                        $search = $title->getText();
                        if ( $ns[0] == NS_MAIN ) {
                                $ns = $namespaces; // no explicit prefix, use default namespaces
-                               wfRunHooks( 'PrefixSearchExtractNamespace', array( &$ns, &$search ) );
+                               Hooks::run( 'PrefixSearchExtractNamespace', array( &$ns, &$search ) );
                        }
                        return $this->searchBackend( $ns, $search, $limit, $offset );
                }
@@ -79,7 +79,7 @@ abstract class PrefixSearch {
                        $namespaces = array( $title->getNamespace() );
                        $search = '';
                } else {
-                       wfRunHooks( 'PrefixSearchExtractNamespace', array( &$namespaces, &$search ) );
+                       Hooks::run( 'PrefixSearchExtractNamespace', array( &$namespaces, &$search ) );
                }
 
                return $this->searchBackend( $namespaces, $search, $limit, $offset );
@@ -157,7 +157,7 @@ abstract class PrefixSearch {
                        }
                }
                $srchres = array();
-               if ( wfRunHooks( 'PrefixSearchBackend', array( $namespaces, $search, $limit, &$srchres, $offset ) ) ) {
+               if ( Hooks::run( 'PrefixSearchBackend', array( $namespaces, $search, $limit, &$srchres, $offset ) ) ) {
                        return $this->titles( $this->defaultSearchBackend( $namespaces, $search, $limit, $offset ) );
                }
                return $this->strings( $this->handleResultFromHook( $srchres, $namespaces, $search, $limit ) );
@@ -199,19 +199,19 @@ abstract class PrefixSearch {
                                return $this->pullFront( $key, $srchres );
                        }
                        $redirectTargetsToRedirect = $this->redirectTargetsToRedirect( $srchres );
-                       if ( isset( $redirectTargetsToRedirect[ $target ] ) ) {
+                       if ( isset( $redirectTargetsToRedirect[$target] ) ) {
                                // The exact match and something in the results list are both redirects
                                // to the same thing!  In this case we'll pull the returned match to the
                                // top following the same logic above.  Again, it might not be a perfect
                                // choice but it'll do.
-                               return $this->pullFront( $redirectTargetsToRedirect[ $target ], $srchres );
+                               return $this->pullFront( $redirectTargetsToRedirect[$target], $srchres );
                        }
                } else {
                        $redirectTargetsToRedirect = $this->redirectTargetsToRedirect( $srchres );
-                       if ( isset( $redirectTargetsToRedirect[ $string ] ) ) {
+                       if ( isset( $redirectTargetsToRedirect[$string] ) ) {
                                // The exact match is the target of a redirect already in the results list so remove
                                // the redirect from the results list and push the exact match to the front
-                               array_splice( $srchres, $redirectTargetsToRedirect[ $string ], 1 );
+                               array_splice( $srchres, $redirectTargetsToRedirect[$string], 1 );
                                array_unshift( $srchres, $string );
                                return $srchres;
                        }
@@ -242,7 +242,7 @@ abstract class PrefixSearch {
                        if ( !$target ) {
                                continue;
                        }
-                       $result[ $target ] = $key;
+                       $result[$target] = $key;
                }
                return $result;
        }
index 7bad8b5..76ad252 100644 (file)
@@ -321,7 +321,7 @@ class ProtectionForm {
                 *             you can also return an array of message name and its parameters
                 */
                $errorMsg = '';
-               if ( !wfRunHooks( 'ProtectionForm::save', array( $this->mArticle, &$errorMsg, $reasonstr ) ) ) {
+               if ( !Hooks::run( 'ProtectionForm::save', array( $this->mArticle, &$errorMsg, $reasonstr ) ) ) {
                        if ( $errorMsg == '' ) {
                                $errorMsg = array( 'hookaborted' );
                        }
@@ -452,7 +452,7 @@ class ProtectionForm {
                        "</td></tr>";
                }
                # Give extensions a chance to add items to the form
-               wfRunHooks( 'ProtectionForm::buildForm', array( $this->mArticle, &$out ) );
+               Hooks::run( 'ProtectionForm::buildForm', array( $this->mArticle, &$out ) );
 
                $out .= Xml::closeElement( 'tbody' ) . Xml::closeElement( 'table' );
 
@@ -623,6 +623,6 @@ class ProtectionForm {
                $out->addHTML( Xml::element( 'h2', null, $protectLogPage->getName()->text() ) );
                LogEventsList::showLogExtract( $out, 'protect', $this->mTitle );
                # Let extensions add other relevant log extracts
-               wfRunHooks( 'ProtectionForm::showLogExtract', array( $this->mArticle, $out ) );
+               Hooks::run( 'ProtectionForm::showLogExtract', array( $this->mArticle, $out ) );
        }
 }
index e81ed75..8ba79df 100644 (file)
@@ -1419,7 +1419,7 @@ class Revision implements IDBAccessObject {
 
                $this->mId = $rev_id !== null ? $rev_id : $dbw->insertId();
 
-               wfRunHooks( 'RevisionInsertComplete', array( &$this, $data, $flags ) );
+               Hooks::run( 'RevisionInsertComplete', array( &$this, $data, $flags ) );
 
                wfProfileOut( __METHOD__ );
                return $this->mId;
index 1654643..11c30a2 100644 (file)
@@ -1855,7 +1855,7 @@ class Sanitizer {
         */
        public static function validateEmail( $addr ) {
                $result = null;
-               if ( !wfRunHooks( 'isValidEmailAddr', array( $addr, &$result ) ) ) {
+               if ( !Hooks::run( 'isValidEmailAddr', array( $addr, &$result ) ) ) {
                        return $result;
                }
 
index f61de7e..535b13d 100644 (file)
@@ -584,7 +584,7 @@ wfDebugLog( 'caches', 'main: ' . get_class( $wgMemc ) .
 wfProfileOut( $fname . '-memcached' );
 
 // Most of the config is out, some might want to run hooks here.
-wfRunHooks( 'SetupAfterCache' );
+Hooks::run( 'SetupAfterCache' );
 
 wfProfileIn( $fname . '-session' );
 
@@ -634,7 +634,7 @@ $wgParser = new StubObject( 'wgParser', $wgParserConf['class'], array( $wgParser
 
 if ( !is_object( $wgAuth ) ) {
        $wgAuth = new AuthPlugin;
-       wfRunHooks( 'AuthPluginSetup', array( &$wgAuth ) );
+       Hooks::run( 'AuthPluginSetup', array( &$wgAuth ) );
 }
 
 /**
index 265eae1..fb267bd 100644 (file)
@@ -469,7 +469,7 @@ class Status {
        public function __toString() {
                $status = $this->isOK() ? "OK" : "Error";
                if ( count( $this->errors ) ) {
-                       $errorcount = "collected " . ( count($this->errors) ) . " error(s) on the way";
+                       $errorcount = "collected " . ( count( $this->errors ) ) . " error(s) on the way";
                } else {
                        $errorcount = "no errors detected";
                }
@@ -486,16 +486,16 @@ class Status {
                        $errorcount,
                        $valstr
                );
-               if ( count ($this->errors ) > 0 ) {
+               if ( count$this->errors ) > 0 ) {
                        $hdr = sprintf( "+-%'-4s-+-%'-25s-+-%'-40s-+\n", "", "", "" );
                        $i = 1;
                        $out .= "\n";
                        $out .= $hdr;
-                       foreach( $this->getStatusArray() as $stat ) {
+                       foreach ( $this->getStatusArray() as $stat ) {
                                $out .= sprintf( "| %4d | %-25.25s | %-40.40s |\n",
                                        $i,
                                        $stat[0],
-                                       implode(" ", array_slice( $stat, 1 ) )
+                                       implode( " ", array_slice( $stat, 1 ) )
                                );
                                $i += 1;
                        }
index 638da08..cfdba5d 100644 (file)
@@ -747,7 +747,7 @@ class Title {
         * @param string $title The DB key form the title
         * @param string $fragment The link fragment (after the "#")
         * @param string $interwiki The interwiki prefix
-        * @param boolean $canoncialNamespace If true, use the canonical name for
+        * @param bool $canoncialNamespace If true, use the canonical name for
         *   $ns instead of the localized version.
         * @return string The prefixed form of the title
         */
@@ -1044,7 +1044,6 @@ class Title {
         * Is this in a namespace that allows actual pages?
         *
         * @return bool
-        * @internal note -- uses hardcoded namespace index instead of constants
         */
        public function canExist() {
                return $this->mNamespace >= NS_MAIN;
@@ -1180,7 +1179,7 @@ class Title {
                }
 
                $result = true;
-               wfRunHooks( 'TitleIsMovable', array( $this, &$result ) );
+               Hooks::run( 'TitleIsMovable', array( $this, &$result ) );
                return $result;
        }
 
@@ -1252,7 +1251,7 @@ class Title {
                #   It's called here again to make sure hook functions can force this
                #   method to return true even outside the MediaWiki namespace.
 
-               wfRunHooks( 'TitleIsCssOrJsPage', array( $this, &$isCssOrJsPage ), '1.25' );
+               Hooks::run( 'TitleIsCssOrJsPage', array( $this, &$isCssOrJsPage ), '1.25' );
 
                return $isCssOrJsPage;
        }
@@ -1659,7 +1658,7 @@ class Title {
                # Finally, add the fragment.
                $url .= $this->getFragmentForURL();
 
-               wfRunHooks( 'GetFullURL', array( &$this, &$url, $query ) );
+               Hooks::run( 'GetFullURL', array( &$this, &$url, $query ) );
                return $url;
        }
 
@@ -1705,7 +1704,7 @@ class Title {
                        $dbkey = wfUrlencode( $this->getPrefixedDBkey() );
                        if ( $query == '' ) {
                                $url = str_replace( '$1', $dbkey, $wgArticlePath );
-                               wfRunHooks( 'GetLocalURL::Article', array( &$this, &$url ) );
+                               Hooks::run( 'GetLocalURL::Article', array( &$this, &$url ) );
                        } else {
                                global $wgVariantArticlePath, $wgActionPaths, $wgContLang;
                                $url = false;
@@ -1750,7 +1749,7 @@ class Title {
                                }
                        }
 
-                       wfRunHooks( 'GetLocalURL::Internal', array( &$this, &$url, $query ) );
+                       Hooks::run( 'GetLocalURL::Internal', array( &$this, &$url, $query ) );
 
                        // @todo FIXME: This causes breakage in various places when we
                        // actually expected a local URL and end up with dupe prefixes.
@@ -1758,7 +1757,7 @@ class Title {
                                $url = $wgServer . $url;
                        }
                }
-               wfRunHooks( 'GetLocalURL', array( &$this, &$url, $query ) );
+               Hooks::run( 'GetLocalURL', array( &$this, &$url, $query ) );
                return $url;
        }
 
@@ -1808,7 +1807,7 @@ class Title {
                $query = self::fixUrlQueryArgs( $query, $query2 );
                $server = $wgInternalServer !== false ? $wgInternalServer : $wgServer;
                $url = wfExpandUrl( $server . $this->getLocalURL( $query ), PROTO_HTTP );
-               wfRunHooks( 'GetInternalURL', array( &$this, &$url, $query ) );
+               Hooks::run( 'GetInternalURL', array( &$this, &$url, $query ) );
                return $url;
        }
 
@@ -1826,7 +1825,7 @@ class Title {
        public function getCanonicalURL( $query = '', $query2 = false ) {
                $query = self::fixUrlQueryArgs( $query, $query2 );
                $url = wfExpandUrl( $this->getLocalURL( $query ) . $this->getFragmentForURL(), PROTO_CANONICAL );
-               wfRunHooks( 'GetCanonicalURL', array( &$this, &$url, $query ) );
+               Hooks::run( 'GetCanonicalURL', array( &$this, &$url, $query ) );
                return $url;
        }
 
@@ -1945,7 +1944,7 @@ class Title {
        private function checkQuickPermissions( $action, $user, $errors,
                $doExpensiveQueries, $short
        ) {
-               if ( !wfRunHooks( 'TitleQuickPermissions',
+               if ( !Hooks::run( 'TitleQuickPermissions',
                        array( $this, $user, $action, &$errors, $doExpensiveQueries, $short ) )
                ) {
                        return $errors;
@@ -2045,18 +2044,18 @@ class Title {
        private function checkPermissionHooks( $action, $user, $errors, $doExpensiveQueries, $short ) {
                // Use getUserPermissionsErrors instead
                $result = '';
-               if ( !wfRunHooks( 'userCan', array( &$this, &$user, $action, &$result ) ) ) {
+               if ( !Hooks::run( 'userCan', array( &$this, &$user, $action, &$result ) ) ) {
                        return $result ? array() : array( array( 'badaccess-group0' ) );
                }
                // Check getUserPermissionsErrors hook
-               if ( !wfRunHooks( 'getUserPermissionsErrors', array( &$this, &$user, $action, &$result ) ) ) {
+               if ( !Hooks::run( 'getUserPermissionsErrors', array( &$this, &$user, $action, &$result ) ) ) {
                        $errors = $this->resultToError( $errors, $result );
                }
                // Check getUserPermissionsErrorsExpensive hook
                if (
                        $doExpensiveQueries
                        && !( $short && count( $errors ) > 0 )
-                       && !wfRunHooks( 'getUserPermissionsErrorsExpensive', array( &$this, &$user, $action, &$result ) )
+                       && !Hooks::run( 'getUserPermissionsErrorsExpensive', array( &$this, &$user, $action, &$result ) )
                ) {
                        $errors = $this->resultToError( $errors, $result );
                }
@@ -2389,7 +2388,7 @@ class Title {
 
                if ( !$whitelisted ) {
                        # If the title is not whitelisted, give extensions a chance to do so...
-                       wfRunHooks( 'TitleReadWhitelist', array( $this, $user, &$whitelisted ) );
+                       Hooks::run( 'TitleReadWhitelist', array( $this, $user, &$whitelisted ) );
                        if ( !$whitelisted ) {
                                $errors[] = $this->missingPermissionError( $action, $short );
                        }
@@ -2523,7 +2522,7 @@ class Title {
                        $types = array_diff( $types, array( 'upload' ) );
                }
 
-               wfRunHooks( 'TitleGetRestrictionTypes', array( $this, &$types ) );
+               Hooks::run( 'TitleGetRestrictionTypes', array( $this, &$types ) );
 
                wfDebug( __METHOD__ . ': applicable restrictions to [[' .
                        $this->getPrefixedText() . ']] are {' . implode( ',', $types ) . "}\n" );
@@ -3576,7 +3575,7 @@ class Title {
                        $urls[] = $this->getInternalUrl( 'action=raw&ctype=text/css' );
                }
 
-               wfRunHooks( 'TitleSquidURLs', array( $this, &$urls ) );
+               Hooks::run( 'TitleSquidURLs', array( $this, &$urls ) );
                return $urls;
        }
 
@@ -4247,7 +4246,7 @@ class Title {
         */
        public function exists() {
                $exists = $this->getArticleID() != 0;
-               wfRunHooks( 'TitleExists', array( $this, &$exists ) );
+               Hooks::run( 'TitleExists', array( $this, &$exists ) );
                return $exists;
        }
 
@@ -4280,7 +4279,7 @@ class Title {
                 * @param Title $title
                 * @param bool|null $isKnown
                 */
-               wfRunHooks( 'TitleIsAlwaysKnown', array( $this, &$isKnown ) );
+               Hooks::run( 'TitleIsAlwaysKnown', array( $this, &$isKnown ) );
 
                if ( !is_null( $isKnown ) ) {
                        return $isKnown;
@@ -4603,7 +4602,7 @@ class Title {
                // on the Title object passed in, and should probably
                // tell the users to run updateCollations.php --force
                // in order to re-sort existing category relations.
-               wfRunHooks( 'GetDefaultSortkey', array( $this, &$unprefixed ) );
+               Hooks::run( 'GetDefaultSortkey', array( $this, &$unprefixed ) );
                if ( $prefix !== '' ) {
                        # Separate with a line feed, so the unprefixed part is only used as
                        # a tiebreaker when two pages have the exact same prefix.
@@ -4724,7 +4723,7 @@ class Title {
                        }
                }
 
-               wfRunHooks( 'TitleGetEditNotices', array( $this, $oldid, &$notices ) );
+               Hooks::run( 'TitleGetEditNotices', array( $this, $oldid, &$notices ) );
                return $notices;
        }
 }
index b67d9f4..0fb5b1e 100644 (file)
@@ -37,7 +37,7 @@ abstract class TitleArray implements Iterator {
         */
        static function newFromResult( $res ) {
                $array = null;
-               if ( !wfRunHooks( 'TitleArrayFromResult', array( &$array, $res ) ) ) {
+               if ( !Hooks::run( 'TitleArrayFromResult', array( &$array, $res ) ) ) {
                        return null;
                }
                if ( $array === null ) {
index 5348020..bda825f 100644 (file)
@@ -58,6 +58,12 @@ class User implements IDBAccessObject {
         */
        const MAX_WATCHED_ITEMS_CACHE = 100;
 
+       /**
+        * Exclude user options that are set to their default value.
+        * @since 1.25
+        */
+       const GETOPTIONS_EXCLUDE_DEFAULTS = 1;
+
        /**
         * @var PasswordFactory Lazily loaded factory object for passwords
         */
@@ -344,7 +350,7 @@ class User implements IDBAccessObject {
                                        // Loading from session failed. Load defaults.
                                        $this->loadDefaults();
                                }
-                               wfRunHooks( 'UserLoadAfterLoadFromSession', array( $this ) );
+                               Hooks::run( 'UserLoadAfterLoadFromSession', array( $this ) );
                                break;
                        default:
                                wfProfileOut( __METHOD__ );
@@ -703,7 +709,7 @@ class User implements IDBAccessObject {
                static $reservedUsernames = false;
                if ( !$reservedUsernames ) {
                        $reservedUsernames = $wgReservedUsernames;
-                       wfRunHooks( 'UserGetReservedNames', array( &$reservedUsernames ) );
+                       Hooks::run( 'UserGetReservedNames', array( &$reservedUsernames ) );
                }
 
                // Certain names may be reserved for batch processes.
@@ -811,7 +817,7 @@ class User implements IDBAccessObject {
 
                $result = false; //init $result to false for the internal checks
 
-               if ( !wfRunHooks( 'isValidPassword', array( $password, &$result, $this ) ) ) {
+               if ( !Hooks::run( 'isValidPassword', array( $password, &$result, $this ) ) ) {
                        $status->error( $result );
                        return $status;
                }
@@ -873,7 +879,7 @@ class User implements IDBAccessObject {
                        );
                }
                // Give extensions a chance to force an expiration
-               wfRunHooks( 'ResetPasswordExpiration', array( $this, &$newExpire ) );
+               Hooks::run( 'ResetPasswordExpiration', array( $this, &$newExpire ) );
                $this->mPasswordExpires = $newExpire;
        }
 
@@ -1043,7 +1049,7 @@ class User implements IDBAccessObject {
                $this->mRegistration = wfTimestamp( TS_MW );
                $this->mGroups = array();
 
-               wfRunHooks( 'UserLoadDefaults', array( $this, $name ) );
+               Hooks::run( 'UserLoadDefaults', array( $this, $name ) );
 
                wfProfileOut( __METHOD__ );
        }
@@ -1082,7 +1088,7 @@ class User implements IDBAccessObject {
         */
        private function loadFromSession() {
                $result = null;
-               wfRunHooks( 'UserLoadFromSession', array( $this, &$result ) );
+               Hooks::run( 'UserLoadFromSession', array( $this, &$result ) );
                if ( $result !== null ) {
                        return $result;
                }
@@ -1184,7 +1190,7 @@ class User implements IDBAccessObject {
                                : array()
                );
 
-               wfRunHooks( 'UserLoadFromDatabase', array( $this, &$s ) );
+               Hooks::run( 'UserLoadFromDatabase', array( $this, &$s ) );
 
                if ( $s !== false ) {
                        // Initialise user table data
@@ -1450,7 +1456,7 @@ class User implements IDBAccessObject {
                }
                $defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin );
 
-               wfRunHooks( 'UserGetDefaultOptions', array( &$defOpt ) );
+               Hooks::run( 'UserGetDefaultOptions', array( &$defOpt ) );
 
                return $defOpt;
        }
@@ -1556,7 +1562,7 @@ class User implements IDBAccessObject {
                }
 
                // Extensions
-               wfRunHooks( 'GetBlockedStatus', array( &$this ) );
+               Hooks::run( 'GetBlockedStatus', array( &$this ) );
 
                wfProfileOut( __METHOD__ );
        }
@@ -1696,7 +1702,7 @@ class User implements IDBAccessObject {
        public function pingLimiter( $action = 'edit', $incrBy = 1 ) {
                // Call the 'PingLimiter' hook
                $result = false;
-               if ( !wfRunHooks( 'PingLimiter', array( &$this, $action, &$result, $incrBy ) ) ) {
+               if ( !Hooks::run( 'PingLimiter', array( &$this, $action, &$result, $incrBy ) ) ) {
                        return $result;
                }
 
@@ -1840,7 +1846,7 @@ class User implements IDBAccessObject {
                        wfDebug( __METHOD__ . ": self-talk page, ignoring any blocks\n" );
                }
 
-               wfRunHooks( 'UserIsBlockedFrom', array( $this, $title, &$blocked, &$allowUsertalk ) );
+               Hooks::run( 'UserIsBlockedFrom', array( $this, $title, &$blocked, &$allowUsertalk ) );
 
                wfProfileOut( __METHOD__ );
                return $blocked;
@@ -1892,7 +1898,7 @@ class User implements IDBAccessObject {
                        $ip = $this->getRequest()->getIP();
                }
                $blocked = false;
-               wfRunHooks( 'UserIsBlockedGlobally', array( &$this, $ip, &$blocked ) );
+               Hooks::run( 'UserIsBlockedGlobally', array( &$this, $ip, &$blocked ) );
                $this->mBlockedGlobally = (bool)$blocked;
                return $this->mBlockedGlobally;
        }
@@ -2052,7 +2058,7 @@ class User implements IDBAccessObject {
         */
        public function getNewMessageLinks() {
                $talks = array();
-               if ( !wfRunHooks( 'UserRetrieveNewTalks', array( &$this, &$talks ) ) ) {
+               if ( !Hooks::run( 'UserRetrieveNewTalks', array( &$this, &$talks ) ) ) {
                        return $talks;
                } elseif ( !$this->getNewtalk() ) {
                        return array();
@@ -2429,7 +2435,7 @@ class User implements IDBAccessObject {
         */
        public function getEmail() {
                $this->load();
-               wfRunHooks( 'UserGetEmail', array( $this, &$this->mEmail ) );
+               Hooks::run( 'UserGetEmail', array( $this, &$this->mEmail ) );
                return $this->mEmail;
        }
 
@@ -2439,7 +2445,7 @@ class User implements IDBAccessObject {
         */
        public function getEmailAuthenticationTimestamp() {
                $this->load();
-               wfRunHooks( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
+               Hooks::run( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
                return $this->mEmailAuthenticated;
        }
 
@@ -2454,7 +2460,7 @@ class User implements IDBAccessObject {
                }
                $this->invalidateEmail();
                $this->mEmail = $str;
-               wfRunHooks( 'UserSetEmail', array( $this, &$this->mEmail ) );
+               Hooks::run( 'UserSetEmail', array( $this, &$this->mEmail ) );
        }
 
        /**
@@ -2547,9 +2553,12 @@ class User implements IDBAccessObject {
        /**
         * Get all user's options
         *
+        * @param int $flags Bitwise combination of:
+        *   User::GETOPTIONS_EXCLUDE_DEFAULTS  Exclude user options that are set
+        *                                      to the default value. (Since 1.25)
         * @return array
         */
-       public function getOptions() {
+       public function getOptions( $flags = 0 ) {
                global $wgHiddenPrefs;
                $this->loadOptions();
                $options = $this->mOptions;
@@ -2566,6 +2575,10 @@ class User implements IDBAccessObject {
                        }
                }
 
+               if ( $flags & self::GETOPTIONS_EXCLUDE_DEFAULTS ) {
+                       $options = array_diff_assoc( $options, self::getDefaultOptions() );
+               }
+
                return $options;
        }
 
@@ -2823,7 +2836,7 @@ class User implements IDBAccessObject {
                        }
                }
 
-               wfRunHooks( 'UserResetAllOptions', array( $this, &$newOptions, $this->mOptions, $resetKinds ) );
+               Hooks::run( 'UserResetAllOptions', array( $this, &$newOptions, $this->mOptions, $resetKinds ) );
 
                $this->mOptions = $newOptions;
                $this->mOptionsLoaded = true;
@@ -2859,7 +2872,7 @@ class User implements IDBAccessObject {
                        return false;
                } else {
                        $https = $this->getBoolOption( 'prefershttps' );
-                       wfRunHooks( 'UserRequiresHTTPS', array( $this, &$https ) );
+                       Hooks::run( 'UserRequiresHTTPS', array( $this, &$https ) );
                        if ( $https ) {
                                $https = wfCanIPUseHTTPS( $this->getRequest()->getIP() );
                        }
@@ -2890,7 +2903,7 @@ class User implements IDBAccessObject {
        public function getRights() {
                if ( is_null( $this->mRights ) ) {
                        $this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() );
-                       wfRunHooks( 'UserGetRights', array( $this, &$this->mRights ) );
+                       Hooks::run( 'UserGetRights', array( $this, &$this->mRights ) );
                        // Force reindexation of rights when a hook has unset one of them
                        $this->mRights = array_values( array_unique( $this->mRights ) );
                }
@@ -2923,7 +2936,7 @@ class User implements IDBAccessObject {
                                $this->getAutomaticGroups( $recache ) // implicit groups
                        ) );
                        // Hook for additional groups
-                       wfRunHooks( 'UserEffectiveGroups', array( &$this, &$this->mEffectiveGroups ) );
+                       Hooks::run( 'UserEffectiveGroups', array( &$this, &$this->mEffectiveGroups ) );
                        // Force reindexation of groups when a hook has unset one of them
                        $this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) );
                        wfProfileOut( __METHOD__ );
@@ -3020,7 +3033,7 @@ class User implements IDBAccessObject {
         * @param string $group Name of the group to add
         */
        public function addGroup( $group ) {
-               if ( wfRunHooks( 'UserAddGroup', array( $this, &$group ) ) ) {
+               if ( Hooks::run( 'UserAddGroup', array( $this, &$group ) ) ) {
                        $dbw = wfGetDB( DB_MASTER );
                        if ( $this->getId() ) {
                                $dbw->insert( 'user_groups',
@@ -3053,7 +3066,7 @@ class User implements IDBAccessObject {
         */
        public function removeGroup( $group ) {
                $this->load();
-               if ( wfRunHooks( 'UserRemoveGroup', array( $this, &$group ) ) ) {
+               if ( Hooks::run( 'UserRemoveGroup', array( $this, &$group ) ) ) {
                        $dbw = wfGetDB( DB_MASTER );
                        $dbw->delete( 'user_groups',
                                array(
@@ -3277,7 +3290,7 @@ class User implements IDBAccessObject {
 
                // If we're working on user's talk page, we should update the talk page message indicator
                if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
-                       if ( !wfRunHooks( 'UserClearNewTalkNotification', array( &$this, $oldid ) ) ) {
+                       if ( !Hooks::run( 'UserClearNewTalkNotification', array( &$this, $oldid ) ) ) {
                                return;
                        }
 
@@ -3422,7 +3435,7 @@ class User implements IDBAccessObject {
                        $cookies['Token'] = false;
                }
 
-               wfRunHooks( 'UserSetCookies', array( $this, &$session, &$cookies ) );
+               Hooks::run( 'UserSetCookies', array( $this, &$session, &$cookies ) );
 
                foreach ( $session as $name => $value ) {
                        $request->setSessionData( $name, $value );
@@ -3457,7 +3470,7 @@ class User implements IDBAccessObject {
         * Log this user out.
         */
        public function logout() {
-               if ( wfRunHooks( 'UserLogout', array( &$this ) ) ) {
+               if ( Hooks::run( 'UserLogout', array( &$this ) ) ) {
                        $this->doLogout();
                }
        }
@@ -3522,7 +3535,7 @@ class User implements IDBAccessObject {
 
                $this->saveOptions();
 
-               wfRunHooks( 'UserSaveSettings', array( $this ) );
+               Hooks::run( 'UserSaveSettings', array( $this ) );
                $this->clearSharedCache();
                $this->getUserPage()->invalidateCache();
        }
@@ -4120,7 +4133,7 @@ class User implements IDBAccessObject {
                // and fire the ConfirmEmailComplete hook on redundant confirmations.
                if ( !$this->isEmailConfirmed() ) {
                        $this->setEmailAuthenticationTimestamp( wfTimestampNow() );
-                       wfRunHooks( 'ConfirmEmailComplete', array( $this ) );
+                       Hooks::run( 'ConfirmEmailComplete', array( $this ) );
                }
                return true;
        }
@@ -4138,7 +4151,7 @@ class User implements IDBAccessObject {
                $this->mEmailTokenExpires = null;
                $this->setEmailAuthenticationTimestamp( null );
                $this->mEmail = '';
-               wfRunHooks( 'InvalidateEmailComplete', array( $this ) );
+               Hooks::run( 'InvalidateEmailComplete', array( $this ) );
                return true;
        }
 
@@ -4149,7 +4162,7 @@ class User implements IDBAccessObject {
        public function setEmailAuthenticationTimestamp( $timestamp ) {
                $this->load();
                $this->mEmailAuthenticated = $timestamp;
-               wfRunHooks( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
+               Hooks::run( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
        }
 
        /**
@@ -4163,7 +4176,7 @@ class User implements IDBAccessObject {
                        return false;
                }
                $canSend = $this->isEmailConfirmed();
-               wfRunHooks( 'UserCanSendEmail', array( &$this, &$canSend ) );
+               Hooks::run( 'UserCanSendEmail', array( &$this, &$canSend ) );
                return $canSend;
        }
 
@@ -4190,7 +4203,7 @@ class User implements IDBAccessObject {
                global $wgEmailAuthentication;
                $this->load();
                $confirmed = true;
-               if ( wfRunHooks( 'EmailConfirmed', array( &$this, &$confirmed ) ) ) {
+               if ( Hooks::run( 'EmailConfirmed', array( &$this, &$confirmed ) ) ) {
                        if ( $this->isAnon() ) {
                                return false;
                        }
@@ -4348,7 +4361,7 @@ class User implements IDBAccessObject {
                }
 
                // Allow extensions (e.g. OAuth) to say false
-               if ( !wfRunHooks( 'UserIsEveryoneAllowed', array( $right ) ) ) {
+               if ( !Hooks::run( 'UserIsEveryoneAllowed', array( $right ) ) ) {
                        $cache[$right] = false;
                        return false;
                }
@@ -4406,7 +4419,7 @@ class User implements IDBAccessObject {
                        } else {
                                self::$mAllRights = self::$mCoreRights;
                        }
-                       wfRunHooks( 'UserGetAllRights', array( &self::$mAllRights ) );
+                       Hooks::run( 'UserGetAllRights', array( &self::$mAllRights ) );
                }
                return self::$mAllRights;
        }
@@ -4420,7 +4433,7 @@ class User implements IDBAccessObject {
 
                $groups = $wgImplicitGroups;
                # Deprecated, use $wgImplicitGroups instead
-               wfRunHooks( 'UserGetImplicitGroups', array( &$groups ), '1.25' );
+               Hooks::run( 'UserGetImplicitGroups', array( &$groups ), '1.25' );
 
                return $groups;
        }
@@ -4854,7 +4867,7 @@ class User implements IDBAccessObject {
 
                $this->mOptionsLoaded = true;
 
-               wfRunHooks( 'UserLoadOptions', array( $this, &$this->mOptions ) );
+               Hooks::run( 'UserLoadOptions', array( $this, &$this->mOptions ) );
        }
 
        /**
@@ -4870,7 +4883,7 @@ class User implements IDBAccessObject {
 
                // Allow hooks to abort, for instance to save to a global profile.
                // Reset options to default state before saving.
-               if ( !wfRunHooks( 'UserSaveOptions', array( $this, &$saveOptions ) ) ) {
+               if ( !Hooks::run( 'UserSaveOptions', array( $this, &$saveOptions ) ) ) {
                        return;
                }
 
index 7da6582..e5621da 100644 (file)
@@ -27,7 +27,7 @@ abstract class UserArray implements Iterator {
         */
        static function newFromResult( $res ) {
                $userArray = null;
-               if ( !wfRunHooks( 'UserArrayFromResult', array( &$userArray, $res ) ) ) {
+               if ( !Hooks::run( 'UserArrayFromResult', array( &$userArray, $res ) ) ) {
                        return null;
                }
                if ( $userArray === null ) {
index bf99e95..e931f28 100644 (file)
@@ -138,7 +138,7 @@ class WebRequest {
                                        );
                                }
 
-                               wfRunHooks( 'WebRequestPathInfoRouter', array( $router ) );
+                               Hooks::run( 'WebRequestPathInfoRouter', array( $router ) );
 
                                $matches = $router->parse( $path );
                        }
@@ -1118,7 +1118,7 @@ HTML;
                }
 
                # Allow extensions to improve our guess
-               wfRunHooks( 'GetIP', array( &$ip ) );
+               Hooks::run( 'GetIP', array( &$ip ) );
 
                if ( !$ip ) {
                        throw new MWException( "Unable to determine IP." );
index d39f884..f977c20 100644 (file)
@@ -105,7 +105,7 @@ class WebResponse {
 
                $func = $options['raw'] ? 'setrawcookie' : 'setcookie';
 
-               if ( wfRunHooks( 'WebResponseSetCookie', array( &$name, &$value, &$expire, $options ) ) ) {
+               if ( Hooks::run( 'WebResponseSetCookie', array( &$name, &$value, &$expire, $options ) ) ) {
                        wfDebugLog( 'cookie',
                                $func . ': "' . implode( '", "',
                                        array(
index 159f711..c07ac73 100644 (file)
@@ -368,12 +368,10 @@ class Xml {
        public static function label( $label, $id, $attribs = array() ) {
                $a = array( 'for' => $id );
 
-               # FIXME avoid copy pasting below:
-               if ( isset( $attribs['class'] ) ) {
-                               $a['class'] = $attribs['class'];
-               }
-               if ( isset( $attribs['title'] ) ) {
-                               $a['title'] = $attribs['title'];
+               foreach ( array( 'class', 'title' ) as $attr ) {
+                       if ( isset( $attribs[$attr] ) ) {
+                               $a[$attr] = $attribs[$attr];
+                       }
                }
 
                return self::element( 'label', $a, $label );
index 8876724..6c8440a 100644 (file)
@@ -51,7 +51,7 @@ class EditAction extends FormlessAction {
                $page = $this->page;
                $user = $this->getUser();
 
-               if ( wfRunHooks( 'CustomEditor', array( $page, $user ) ) ) {
+               if ( Hooks::run( 'CustomEditor', array( $page, $user ) ) ) {
                        $editor = new EditPage( $page );
                        $editor->edit();
                }
index 4c9e85d..26f43cb 100644 (file)
@@ -63,7 +63,7 @@ abstract class FormAction extends Action {
                $this->fields = $this->getFormFields();
 
                // Give hooks a chance to alter the form, adding extra fields or text etc
-               wfRunHooks( 'ActionModifyFormFields', array( $this->getName(), &$this->fields, $this->page ) );
+               Hooks::run( 'ActionModifyFormFields', array( $this->getName(), &$this->fields, $this->page ) );
 
                $form = new HTMLForm( $this->fields, $this->getContext(), $this->getName() );
                $form->setSubmitCallback( array( $this, 'onSubmit' ) );
@@ -81,7 +81,7 @@ abstract class FormAction extends Action {
                $this->alterForm( $form );
 
                // Give hooks a chance to alter the form, adding extra fields or text etc
-               wfRunHooks( 'ActionBeforeFormDisplay', array( $this->getName(), &$form, $this->page ) );
+               Hooks::run( 'ActionBeforeFormDisplay', array( $this->getName(), &$form, $this->page ) );
 
                return $form;
        }
index 3be8aff..6ee5d2c 100644 (file)
@@ -204,7 +204,7 @@ class HistoryAction extends FormlessAction {
                        '</fieldset></form>'
                );
 
-               wfRunHooks( 'PageHistoryBeforeList', array( &$this->page, $this->getContext() ) );
+               Hooks::run( 'PageHistoryBeforeList', array( &$this->page, $this->getContext() ) );
 
                // Create and output the list.
                $pager = new HistoryPager( $this, $year, $month, $tagFilter, $conds );
@@ -420,7 +420,7 @@ class HistoryPager extends ReverseChronologicalPager {
                        $queryInfo['options'],
                        $this->tagFilter
                );
-               wfRunHooks( 'PageHistoryPager::getQueryInfo', array( &$this, &$queryInfo ) );
+               Hooks::run( 'PageHistoryPager::getQueryInfo', array( &$this, &$queryInfo ) );
 
                return $queryInfo;
        }
@@ -710,7 +710,7 @@ class HistoryPager extends ReverseChronologicalPager {
                        }
                }
                // Allow extension to add their own links here
-               wfRunHooks( 'HistoryRevisionTools', array( $rev, &$tools ) );
+               Hooks::run( 'HistoryRevisionTools', array( $rev, &$tools ) );
 
                if ( $tools ) {
                        $s2 .= ' ' . $this->msg( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped();
@@ -728,7 +728,7 @@ class HistoryPager extends ReverseChronologicalPager {
                        $s .= ' <span class="mw-changeslist-separator">. .</span> ' . $s2;
                }
 
-               wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row, &$s, &$classes ) );
+               Hooks::run( 'PageHistoryLineEnding', array( $this, &$row, &$s, &$classes ) );
 
                $attribs = array();
                if ( $classes ) {
index e7455f6..de51843 100644 (file)
@@ -114,7 +114,7 @@ class InfoAction extends FormlessAction {
                $pageInfo = $this->pageInfo();
 
                // Allow extensions to add additional information
-               wfRunHooks( 'InfoAction', array( $this->getContext(), &$pageInfo ) );
+               Hooks::run( 'InfoAction', array( $this->getContext(), &$pageInfo ) );
 
                // Render page information
                foreach ( $pageInfo as $header => $infoTable ) {
@@ -386,7 +386,7 @@ class InfoAction extends FormlessAction {
                // Page protection
                $pageInfo['header-restrictions'] = array();
 
-               // Is this page effected by the cascading protection of something which includes it?
+               // Is this page affected by the cascading protection of something which includes it?
                if ( $title->isCascadeProtected() ) {
                        $cascadingFrom = '';
                        $sources = $title->getCascadeProtectionSources(); // Array deferencing is in PHP 5.4 :(
index d0d956e..727bed2 100644 (file)
@@ -117,7 +117,7 @@ class RawAction extends FormlessAction {
                        $response->header( 'HTTP/1.x 404 Not Found' );
                }
 
-               if ( !wfRunHooks( 'RawPageViewBeforeOutput', array( &$this, &$text ) ) ) {
+               if ( !Hooks::run( 'RawPageViewBeforeOutput', array( &$this, &$text ) ) ) {
                        wfDebug( __METHOD__ . ": RawPageViewBeforeOutput hook broke raw page output.\n" );
                }
 
index 6481630..d025878 100644 (file)
@@ -144,8 +144,6 @@ class RevertAction extends FormAction {
        }
 
        protected function getDescription() {
-               $this->getOutput()->addBacklinkSubtitle( $this->getTitle() );
-
-               return '';
+               return OutputPage::buildBacklinkSubtitle( $this->getTitle() );
        }
 }
index 8c9a46a..f333efb 100644 (file)
@@ -132,10 +132,10 @@ class WatchAction extends FormAction {
                $page = WikiPage::factory( $title );
 
                $status = Status::newFatal( 'hookaborted' );
-               if ( wfRunHooks( 'WatchArticle', array( &$user, &$page, &$status ) ) ) {
+               if ( Hooks::run( 'WatchArticle', array( &$user, &$page, &$status ) ) ) {
                        $status = Status::newGood();
                        $user->addWatch( $title, $checkRights );
-                       wfRunHooks( 'WatchArticleComplete', array( &$user, &$page ) );
+                       Hooks::run( 'WatchArticleComplete', array( &$user, &$page ) );
                }
 
                return $status;
@@ -156,10 +156,10 @@ class WatchAction extends FormAction {
                $page = WikiPage::factory( $title );
 
                $status = Status::newFatal( 'hookaborted' );
-               if ( wfRunHooks( 'UnwatchArticle', array( &$user, &$page, &$status ) ) ) {
+               if ( Hooks::run( 'UnwatchArticle', array( &$user, &$page, &$status ) ) ) {
                        $status = Status::newGood();
                        $user->removeWatch( $title );
-                       wfRunHooks( 'UnwatchArticleComplete', array( &$user, &$page ) );
+                       Hooks::run( 'UnwatchArticleComplete', array( &$user, &$page ) );
                }
 
                return $status;
index f9960d8..9cb895d 100644 (file)
@@ -284,7 +284,8 @@ abstract class ApiBase extends ContextSource {
        }
 
        /**
-        * Indicates whether this module is "internal" or unstable
+        * Indicates whether this module is "internal"
+        * Internal API modules are not (yet) intended for 3rd party use and may be unstable.
         * @since 1.25
         * @return bool
         */
@@ -1956,7 +1957,7 @@ abstract class ApiBase extends ContextSource {
         */
        public function getFinalDescription() {
                $desc = $this->getDescription();
-               wfRunHooks( 'APIGetDescription', array( &$this, &$desc ) );
+               Hooks::run( 'APIGetDescription', array( &$this, &$desc ) );
                $desc = self::escapeWikiText( $desc );
                if ( is_array( $desc ) ) {
                        $desc = join( "\n", $desc );
@@ -1974,7 +1975,7 @@ abstract class ApiBase extends ContextSource {
                }
                $msgs = array( $msg );
 
-               wfRunHooks( 'APIGetDescriptionMessages', array( $this, &$msgs ) );
+               Hooks::run( 'APIGetDescriptionMessages', array( $this, &$msgs ) );
 
                return $msgs;
        }
@@ -2004,7 +2005,7 @@ abstract class ApiBase extends ContextSource {
                        ) + ( isset( $params['token'] ) ? $params['token'] : array() );
                }
 
-               wfRunHooks( 'APIGetAllowedParams', array( &$this, &$params, $flags ) );
+               Hooks::run( 'APIGetAllowedParams', array( &$this, &$params, $flags ) );
 
                return $params;
        }
@@ -2018,7 +2019,7 @@ abstract class ApiBase extends ContextSource {
         */
        public function getFinalParamDescription() {
                $desc = $this->getParamDescription();
-               wfRunHooks( 'APIGetParamDescription', array( &$this, &$desc ) );
+               Hooks::run( 'APIGetParamDescription', array( &$this, &$desc ) );
 
                if ( !$desc ) {
                        $desc = array();
@@ -2086,7 +2087,7 @@ abstract class ApiBase extends ContextSource {
                        }
                }
 
-               wfRunHooks( 'APIGetParamDescriptionMessages', array( $this, &$msgs ) );
+               Hooks::run( 'APIGetParamDescriptionMessages', array( $this, &$msgs ) );
 
                return $msgs;
        }
index 89f8481..a7ba48a 100644 (file)
@@ -83,7 +83,7 @@ class ApiCreateAccount extends ApiBase {
 
                $loginForm = new LoginForm();
                $loginForm->setContext( $context );
-               wfRunHooks( 'AddNewAccountApiForm', array( $this, $loginForm ) );
+               Hooks::run( 'AddNewAccountApiForm', array( $this, $loginForm ) );
                $loginForm->load();
 
                $status = $loginForm->addNewaccountInternal();
@@ -113,7 +113,7 @@ class ApiCreateAccount extends ApiBase {
                        // Save settings (including confirmation token)
                        $user->saveSettings();
 
-                       wfRunHooks( 'AddNewAccount', array( $user, $params['mailpassword'] ) );
+                       Hooks::run( 'AddNewAccount', array( $user, $params['mailpassword'] ) );
 
                        if ( $params['mailpassword'] ) {
                                $logAction = 'byemail';
@@ -160,7 +160,7 @@ class ApiCreateAccount extends ApiBase {
                }
 
                // Give extensions a chance to modify the API result data
-               wfRunHooks( 'AddNewAccountApiResult', array( $this, $loginForm, &$result ) );
+               Hooks::run( 'AddNewAccountApiResult', array( $this, $loginForm, &$result ) );
 
                $apiResult->addValue( null, 'createaccount', $result );
        }
index c1598c8..f663cc6 100644 (file)
@@ -195,9 +195,9 @@ class ApiEditPage extends ApiBase {
                                        list( $params['undo'], $params['undoafter'] ) =
                                                array( $params['undoafter'], $params['undo'] );
                                }
-                               $undoafterRev = Revision::newFromID( $params['undoafter'] );
+                               $undoafterRev = Revision::newFromId( $params['undoafter'] );
                        }
-                       $undoRev = Revision::newFromID( $params['undo'] );
+                       $undoRev = Revision::newFromId( $params['undo'] );
                        if ( is_null( $undoRev ) || $undoRev->isDeleted( Revision::DELETED_TEXT ) ) {
                                $this->dieUsageMsg( array( 'nosuchrevid', $params['undo'] ) );
                        }
@@ -253,7 +253,8 @@ class ApiEditPage extends ApiBase {
                        'model' => $contentHandler->getModelID(),
                        'wpEditToken' => $params['token'],
                        'wpIgnoreBlankSummary' => '',
-                       'wpIgnoreBlankArticle' => true
+                       'wpIgnoreBlankArticle' => true,
+                       'wpIgnoreSelfRedirect' => true,
                );
 
                if ( !is_null( $params['summary'] ) ) {
@@ -381,7 +382,7 @@ class ApiEditPage extends ApiBase {
                // Run hooks
                // Handle APIEditBeforeSave parameters
                $r = array();
-               if ( !wfRunHooks( 'APIEditBeforeSave', array( $ep, $content, &$r ) ) ) {
+               if ( !Hooks::run( 'APIEditBeforeSave', array( $ep, $content, &$r ) ) ) {
                        if ( count( $r ) ) {
                                $r['result'] = 'Failure';
                                $apiResult->addValue( null, $this->getModuleName(), $r );
@@ -406,7 +407,14 @@ class ApiEditPage extends ApiBase {
                switch ( $status->value ) {
                        case EditPage::AS_HOOK_ERROR:
                        case EditPage::AS_HOOK_ERROR_EXPECTED:
-                               $this->dieUsageMsg( 'hookaborted' );
+                               if ( isset( $status->apiHookResult ) ) {
+                                       $r = $status->apiHookResult;
+                                       $r['result'] = 'Failure';
+                                       $apiResult->addValue( null, $this->getModuleName(), $r );
+                                       return;
+                               } else {
+                                       $this->dieUsageMsg( 'hookaborted' );
+                               }
 
                        case EditPage::AS_PARSE_ERROR:
                                $this->dieUsage( $status->getMessage(), 'parseerror' );
index 913b8eb..7bbd968 100644 (file)
@@ -172,7 +172,7 @@ abstract class ApiFormatBase extends ApiBase {
                                )
                        );
 
-                       if ( wfRunHooks( 'ApiFormatHighlight', array( $context, $result, $mime, $format ) ) ) {
+                       if ( Hooks::run( 'ApiFormatHighlight', array( $context, $result, $mime, $format ) ) ) {
                                $out->addHTML(
                                        Html::element( 'pre', array( 'class' => 'api-pretty-content' ), $result )
                                );
index 5d46a07..8708fb7 100644 (file)
@@ -609,7 +609,7 @@ class ApiHelp extends ApiBase {
 
                        $module->modifyHelp( $help, $options );
 
-                       wfRunHooks( 'APIHelpModifyOutput', array( $module, &$help, $options ) );
+                       Hooks::run( 'APIHelpModifyOutput', array( $module, &$help, $options ) );
 
                        $out .= join( "\n", $help );
                }
index cc4dee4..920dbbf 100644 (file)
@@ -92,7 +92,7 @@ class ApiLogin extends ApiBase {
                                // @todo FIXME: Split back and frontend from this hook.
                                // @todo FIXME: This hook should be placed in the backend
                                $injected_html = '';
-                               wfRunHooks( 'UserLoginComplete', array( &$user, &$injected_html ) );
+                               Hooks::run( 'UserLoginComplete', array( &$user, &$injected_html ) );
 
                                $result['result'] = 'Success';
                                $result['lguserid'] = intval( $user->getId() );
index bf81723..bf0ca9c 100644 (file)
@@ -39,7 +39,7 @@ class ApiLogout extends ApiBase {
 
                // Give extensions to do something after user logout
                $injected_html = '';
-               wfRunHooks( 'UserLogoutComplete', array( &$user, &$injected_html, $oldName ) );
+               Hooks::run( 'UserLogoutComplete', array( &$user, &$injected_html, $oldName ) );
        }
 
        public function isReadMode() {
index 3d04f95..81353f6 100644 (file)
@@ -192,7 +192,7 @@ class ApiMain extends ApiBase {
                if ( $uselang === 'user' ) {
                        $uselang = $this->getUser()->getOption( 'language' );
                        $uselang = RequestContext::sanitizeLangCode( $uselang );
-                       wfRunHooks( 'UserGetLanguageObject', array( $this->getUser(), &$uselang, $this ) );
+                       Hooks::run( 'UserGetLanguageObject', array( $this->getUser(), &$uselang, $this ) );
                } elseif ( $uselang === 'content' ) {
                        global $wgContLang;
                        $uselang = $wgContLang->getCode();
@@ -418,7 +418,7 @@ class ApiMain extends ApiBase {
                }
 
                // Allow extra cleanup and logging
-               wfRunHooks( 'ApiMain::onException', array( $this, $e ) );
+               Hooks::run( 'ApiMain::onException', array( $this, $e ) );
 
                // Log it
                if ( !( $e instanceof UsageException ) ) {
@@ -878,7 +878,7 @@ class ApiMain extends ApiBase {
 
                // Allow extensions to stop execution for arbitrary reasons.
                $message = false;
-               if ( !wfRunHooks( 'ApiCheckCanExecute', array( $module, $user, &$message ) ) ) {
+               if ( !Hooks::run( 'ApiCheckCanExecute', array( $module, $user, &$message ) ) ) {
                        $this->dieUsageMsg( $message );
                }
        }
@@ -952,7 +952,7 @@ class ApiMain extends ApiBase {
                // Execute
                $module->profileIn();
                $module->execute();
-               wfRunHooks( 'APIAfterExecute', array( &$module ) );
+               Hooks::run( 'APIAfterExecute', array( &$module ) );
                $module->profileOut();
 
                $this->reportUnusedParams();
index 4a9e216..f4b99ae 100644 (file)
@@ -59,7 +59,7 @@ class ApiOpenSearch extends ApiBase {
        }
 
        public function getCustomPrinter() {
-               switch( $this->getFormat() ) {
+               switch ( $this->getFormat() ) {
                        case 'json':
                                return $this->getMain()->createPrinterByName( 'json' . $this->fm );
 
@@ -96,7 +96,7 @@ class ApiOpenSearch extends ApiBase {
                        $this->search( $search, $limit, $namespaces, $resolveRedir, $results );
 
                        // Allow hooks to populate extracts and images
-                       wfRunHooks( 'ApiOpenSearchSuggest', array( &$results ) );
+                       Hooks::run( 'ApiOpenSearchSuggest', array( &$results ) );
 
                        // Trim extracts, if necessary
                        $length = $this->getConfig()->get( 'OpenSearchDescriptionLength' );
@@ -124,6 +124,9 @@ class ApiOpenSearch extends ApiBase {
                // Find matching titles as Title objects
                $searcher = new TitlePrefixSearch;
                $titles = $searcher->searchWithVariants( $search, $limit, $namespaces );
+               if ( !$titles ) {
+                       return;
+               }
 
                if ( $resolveRedir ) {
                        // Query for redirects
index 78c33ed..1417ef7 100644 (file)
@@ -179,7 +179,7 @@ class ApiPageSet extends ApiBase {
 
                        if ( !$isDryRun ) {
                                $generator->executeGenerator( $this );
-                               wfRunHooks( 'APIQueryGeneratorAfterExecute', array( &$generator, &$this ) );
+                               Hooks::run( 'APIQueryGeneratorAfterExecute', array( &$generator, &$this ) );
                        } else {
                                // Prevent warnings from being reported on these parameters
                                $main = $this->getMain();
@@ -1213,7 +1213,7 @@ class ApiPageSet extends ApiBase {
         *
         * @param ApiResult|array &$result
         * @param array $path
-        * @return boolean Whether the data fit
+        * @return bool Whether the data fit
         */
        public function populateGeneratorData( &$result, array $path = array() ) {
                if ( $result instanceof ApiResult ) {
@@ -1334,8 +1334,7 @@ class ApiPageSet extends ApiBase {
                if ( !$this->mAllowGenerator ) {
                        unset( $result['generator'] );
                } elseif ( $flags & ApiBase::GET_VALUES_FOR_HELP ) {
-                       $result['generator'][ApiBase::PARAM_TYPE] = $this->getGenerators();
-                       foreach ( $result['generator'][ApiBase::PARAM_TYPE] as $g ) {
+                       foreach ( $this->getGenerators() as $g ) {
                                $result['generator'][ApiBase::PARAM_TYPE][] = $g;
                                $result['generator'][ApiBase::PARAM_VALUE_LINKS][$g] = "Special:ApiHelp/query+$g";
                        }
index 2bf1677..ff91b92 100644 (file)
@@ -87,7 +87,7 @@ class ApiParse extends ApiBase {
                if ( !is_null( $oldid ) || !is_null( $pageid ) || !is_null( $page ) ) {
                        if ( !is_null( $oldid ) ) {
                                // Don't use the parser cache
-                               $rev = Revision::newFromID( $oldid );
+                               $rev = Revision::newFromId( $oldid );
                                if ( !$rev ) {
                                        $this->dieUsage( "There is no revision ID $oldid", 'missingrev' );
                                }
@@ -267,7 +267,7 @@ class ApiParse extends ApiBase {
                                // Link flags are ignored for now, but may in the future be
                                // included in the result.
                                $linkFlags = array();
-                               wfRunHooks( 'LanguageLinks', array( $titleObj, &$langlinks, &$linkFlags ) );
+                               Hooks::run( 'LanguageLinks', array( $titleObj, &$langlinks, &$linkFlags ) );
                        }
                } else {
                        $langlinks = false;
index 3684461..779c418 100644 (file)
@@ -38,7 +38,7 @@ class ApiPatrol extends ApiBase {
                $this->requireOnlyOneParameter( $params, 'rcid', 'revid' );
 
                if ( isset( $params['rcid'] ) ) {
-                       $rc = RecentChange::newFromID( $params['rcid'] );
+                       $rc = RecentChange::newFromId( $params['rcid'] );
                        if ( !$rc ) {
                                $this->dieUsageMsg( array( 'nosuchrcid', $params['rcid'] ) );
                        }
index bd28408..514d559 100644 (file)
@@ -295,7 +295,7 @@ class ApiQuery extends ApiBase {
                                $cacheMode, $module->getCacheMode( $params ) );
                        $module->profileIn();
                        $module->execute();
-                       wfRunHooks( 'APIQueryAfterExecute', array( &$module ) );
+                       Hooks::run( 'APIQueryAfterExecute', array( &$module ) );
                        $module->profileOut();
                }
 
index 263ab0d..88b2074 100644 (file)
@@ -104,7 +104,7 @@ class ApiQueryInfo extends ApiQueryBase {
                        'import' => array( 'ApiQueryInfo', 'getImportToken' ),
                        'watch' => array( 'ApiQueryInfo', 'getWatchToken' ),
                );
-               wfRunHooks( 'APIQueryInfoTokens', array( &$this->tokenFunctions ) );
+               Hooks::run( 'APIQueryInfoTokens', array( &$this->tokenFunctions ) );
 
                return $this->tokenFunctions;
        }
@@ -463,7 +463,7 @@ class ApiQueryInfo extends ApiQueryBase {
                                $pageInfo['preload'] = '';
                        } else {
                                $text = null;
-                               wfRunHooks( 'EditFormPreloadText', array( &$text, &$title ) );
+                               Hooks::run( 'EditFormPreloadText', array( &$text, &$title ) );
 
                                $pageInfo['preload'] = $text;
                        }
index e20380e..cdc61cd 100644 (file)
@@ -64,7 +64,7 @@ class ApiQueryRecentChanges extends ApiQueryGeneratorBase {
                $this->tokenFunctions = array(
                        'patrol' => array( 'ApiQueryRecentChanges', 'getPatrolToken' )
                );
-               wfRunHooks( 'APIQueryRecentChangesTokens', array( &$this->tokenFunctions ) );
+               Hooks::run( 'APIQueryRecentChangesTokens', array( &$this->tokenFunctions ) );
 
                return $this->tokenFunctions;
        }
index 32355b9..7092fc4 100644 (file)
@@ -61,7 +61,7 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
                $this->tokenFunctions = array(
                        'rollback' => array( 'ApiQueryRevisions', 'getRollbackToken' )
                );
-               wfRunHooks( 'APIQueryRevisionsTokens', array( &$this->tokenFunctions ) );
+               Hooks::run( 'APIQueryRevisionsTokens', array( &$this->tokenFunctions ) );
 
                return $this->tokenFunctions;
        }
index 4d75a20..a658309 100644 (file)
@@ -78,7 +78,7 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
                        // DifferenceEngine returns a rather ambiguous empty
                        // string if that's not the case
                        if ( $params['diffto'] != 0 ) {
-                               $difftoRev = Revision::newFromID( $params['diffto'] );
+                               $difftoRev = Revision::newFromId( $params['diffto'] );
                                if ( !$difftoRev ) {
                                        $this->dieUsageMsg( array( 'nosuchrevid', $params['diffto'] ) );
                                }
index c6999df..16a491e 100644 (file)
@@ -206,7 +206,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
                $hasInterwikiResults = false;
                $totalhits = null;
                if ( $interwiki && $resultPageSet === null && $matches->hasInterwikiResults() ) {
-                       foreach( $matches->getInterwikiResults() as $matches ) {
+                       foreach ( $matches->getInterwikiResults() as $matches ) {
                                $matches = $matches->getInterwikiResults();
                                $hasInterwikiResults = true;
 
index 3b8a514..f373021 100644 (file)
@@ -274,7 +274,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                        $data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
                }
 
-               wfRunHooks( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
+               Hooks::run( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
 
                return $this->getResult()->addValue( 'query', $property, $data );
        }
@@ -490,7 +490,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
                $data['jobs'] = intval( SiteStats::jobs() );
 
-               wfRunHooks( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
+               Hooks::run( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
 
                return $this->getResult()->addValue( 'query', $property, $data );
        }
index 279e8e3..e8d7258 100644 (file)
@@ -63,7 +63,7 @@ class ApiQueryTokens extends ApiQueryBase {
                                'rollback' => 'rollback',
                                'userrights' => 'userrights',
                        );
-                       wfRunHooks( 'ApiQueryTokensRegisterTypes', array( &$salts ) );
+                       Hooks::run( 'ApiQueryTokensRegisterTypes', array( &$salts ) );
                        ksort( $salts );
                        wfProfileOut( __METHOD__ );
                }
index db8cc1c..b7f2f9a 100644 (file)
@@ -75,7 +75,7 @@ class ApiQueryUsers extends ApiQueryBase {
                $this->tokenFunctions = array(
                        'userrights' => array( 'ApiQueryUsers', 'getUserrightsToken' ),
                );
-               wfRunHooks( 'APIQueryUsersTokens', array( &$this->tokenFunctions ) );
+               Hooks::run( 'APIQueryUsersTokens', array( &$this->tokenFunctions ) );
 
                return $this->tokenFunctions;
        }
index 91f3266..f28e610 100644 (file)
@@ -99,7 +99,7 @@ class ApiRsd extends ApiBase {
                                )
                        ),
                );
-               wfRunHooks( 'ApiRsdServiceApis', array( &$apis ) );
+               Hooks::run( 'ApiRsdServiceApis', array( &$apis ) );
 
                return $apis;
        }
index 00f6814..2f9f37e 100644 (file)
@@ -48,7 +48,8 @@ class ApiStashEdit extends ApiBase {
                        $this->dieUsage( "Unsupported content model/format", 'badmodelformat' );
                }
 
-               $text = trim( $params['text'] ); // needed so the key SHA1's match
+               // Trim and fix newlines so the key SHA1's match (see RequestContext::getText())
+               $text = rtrim( str_replace( "\r\n", "\n", $params['text'] ) );
                $textContent = ContentHandler::makeContent(
                        $text, $title, $params['contentmodel'], $params['contentformat'] );
 
@@ -107,27 +108,23 @@ class ApiStashEdit extends ApiBase {
                        $editInfo = false;
                        $status = 'ratelimited';
                } elseif ( $wgMemc->lock( $key, 0, 30 ) ) {
-                       $contentFormat = $content->getDefaultFormat();
-                       $editInfo = $page->prepareContentForEdit( $content, null, $user, $contentFormat );
-                       $wgMemc->unlock( $key );
+                       $format = $content->getDefaultFormat();
+                       $editInfo = $page->prepareContentForEdit( $content, null, $user, $format, false );
                        $status = 'error'; // default
+                       $unlocker = new ScopedCallback( function() use ( $key ) {
+                               global $wgMemc;
+                               $wgMemc->unlock( $key );
+                       } );
                } else {
                        $editInfo = false;
                        $status = 'busy';
                }
 
                if ( $editInfo && $editInfo->output ) {
-                       $parserOutput = $editInfo->output;
-                       // If an item is renewed, mind the cache TTL determined by config and parser functions
-                       $since = time() - wfTimestamp( TS_UNIX, $parserOutput->getTimestamp() );
-                       $ttl = min( $parserOutput->getCacheExpiry() - $since, 5 * 60 );
-                       if ( $ttl > 0 && !$parserOutput->getFlag( 'vary-revision' ) ) {
-                               // Only store what is actually needed
-                               $stashInfo = (object)array(
-                                       'pstContent' => $editInfo->pstContent,
-                                       'output' => $editInfo->output,
-                                       'timestamp' => $editInfo->timestamp
-                               );
+                       list( $stashInfo, $ttl ) = self::buildStashValue(
+                               $editInfo->pstContent, $editInfo->output, $editInfo->timestamp
+                       );
+                       if ( $stashInfo ) {
                                $ok = $wgMemc->set( $key, $stashInfo, $ttl );
                                if ( $ok ) {
                                        $status = 'stashed';
@@ -146,24 +143,69 @@ class ApiStashEdit extends ApiBase {
        }
 
        /**
-        * Get the temporary prepared edit stash key for a user
+        * Attempt to cache PST content and corresponding parser output in passing
         *
-        * @param Title $title
-        * @param Content $content
-        * @param User $user User to get parser options from
-        * @return string
+        * This method can be called when the output was already generated for other
+        * reasons. Parsing should not be done just to call this method, however.
+        * $pstOpts must be that of the user doing the edit preview. If $pOpts does
+        * not match the options of WikiPage::makeParserOptions( 'canonical' ), this
+        * will do nothing. Provided the values are cacheable, they will be stored
+        * in memcached so that final edit submission might make use of them.
+        *
+        * @param Article|WikiPage $page Page title
+        * @param Content $content Proposed page content
+        * @param Content $pstContent The result of preSaveTransform() on $content
+        * @param ParserOutput $pOut The result of getParserOutput() on $pstContent
+        * @param ParserOptions $pstOpts Options for $pstContent (MUST be for prospective author)
+        * @param ParserOptions $pOpts Options for $pOut
+        * @param string $timestamp TS_MW timestamp of parser output generation
+        * @return bool Success
         */
-       protected static function getStashKey(
-               Title $title, Content $content, User $user
+       public static function stashEditFromPreview(
+               Page $page, Content $content, Content $pstContent, ParserOutput $pOut,
+               ParserOptions $pstOpts, ParserOptions $pOpts, $timestamp
        ) {
-               return wfMemcKey( 'prepared-edit',
-                       md5( $title->getPrefixedDBkey() ), // handle rename races
-                       $content->getModel(),
-                       $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
-               );
+               global $wgMemc;
+
+               // getIsPreview() controls parser function behavior that references things
+               // like user/revision that don't exists yet. The user/text should already
+               // be set correctly by callers, just double check the preview flag.
+               if ( !$pOpts->getIsPreview() ) {
+                       return false; // sanity
+               } elseif ( $pOpts->getIsSectionPreview() ) {
+                       return false; // short-circuit (need the full content)
+               }
+
+               // PST parser options are for the user (handles signatures, etc...)
+               $user = $pstOpts->getUser();
+               // Get a key based on the source text, format, and user preferences
+               $key = self::getStashKey( $page->getTitle(), $content, $user );
+
+               // Parser output options must match cannonical options.
+               // Treat some options as matching that are different but don't matter.
+               $canonicalPOpts = $page->makeParserOptions( 'canonical' );
+               $canonicalPOpts->setIsPreview( true ); // force match
+               $canonicalPOpts->setTimestamp( $pOpts->getTimestamp() ); // force match
+               if ( !$pOpts->matches( $canonicalPOpts ) ) {
+                       wfDebugLog( 'StashEdit', "Uncacheable preview output for key '$key' (options)." );
+                       return false;
+               }
+
+               // Build a value to cache with a proper TTL
+               list( $stashInfo, $ttl ) = self::buildStashValue( $pstContent, $pOut, $timestamp );
+               if ( !$stashInfo ) {
+                       wfDebugLog( 'StashEdit', "Uncacheable parser output for key '$key' (rev/TTL)." );
+                       return false;
+               }
+
+               $ok = $wgMemc->set( $key, $stashInfo, $ttl );
+               if ( !$ok ) {
+                       wfDebugLog( 'StashEdit', "Failed to cache preview parser output for key '$key'." );
+               } else {
+                       wfDebugLog( 'StashEdit', "Cached preview output for key '$key'." );
+               }
+
+               return $ok;
        }
 
        /**
@@ -195,12 +237,13 @@ class ApiStashEdit extends ApiBase {
                        if ( $wgMemc->lock( $key, 30, 30 ) ) {
                                $editInfo = $wgMemc->get( $key );
                                $wgMemc->unlock( $key );
-                               $sec = microtime( true ) - $start;
-                               wfDebugLog( 'StashEdit', "Waited $sec seconds on '$key'." );
                        }
+                       $sec = microtime( true ) - $start;
+                       wfDebugLog( 'StashEdit', "Waited $sec seconds on '$key'." );
                }
 
                if ( !is_object( $editInfo ) || !$editInfo->output ) {
+                       wfDebugLog( 'StashEdit', "No cache value for key '$key'." );
                        return false;
                }
 
@@ -248,6 +291,59 @@ class ApiStashEdit extends ApiBase {
                return $editInfo;
        }
 
+       /**
+        * Get the temporary prepared edit stash key for a user
+        *
+        * This key can be used for caching prepared edits provided:
+        *   - a) The $user was used for PST options
+        *   - b) The parser output was made from the PST using cannonical matching options
+        *
+        * @param Title $title
+        * @param Content $content
+        * @param User $user User to get parser options from
+        * @return string
+        */
+       protected static function getStashKey( Title $title, Content $content, User $user ) {
+               $hash = sha1( implode( ':', array(
+                       $content->getModel(),
+                       $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
+               ) ) );
+
+               return wfMemcKey( 'prepared-edit', md5( $title->getPrefixedDBkey() ), $hash );
+       }
+
+       /**
+        * Build a value to store in memcached based on the PST content and parser output
+        *
+        * This makes a simple version of WikiPage::prepareContentForEdit() as stash info
+        *
+        * @param Content $pstContent
+        * @param ParserOutput $parserOutput
+        * @param string $timestamp TS_MW
+        * @return array (stash info array, TTL in seconds) or (null, 0)
+        */
+       protected static function buildStashValue(
+               Content $pstContent, ParserOutput $parserOutput, $timestamp
+       ) {
+               // If an item is renewed, mind the cache TTL determined by config and parser functions
+               $since = time() - wfTimestamp( TS_UNIX, $parserOutput->getTimestamp() );
+               $ttl = min( $parserOutput->getCacheExpiry() - $since, 5 * 60 );
+               if ( $ttl > 0 && !$parserOutput->getFlag( 'vary-revision' ) ) {
+                       // Only store what is actually needed
+                       $stashInfo = (object)array(
+                               'pstContent' => $pstContent,
+                               'output'     => $parserOutput,
+                               'timestamp'  => $timestamp
+                       );
+                       return array( $stashInfo, $ttl );
+               }
+
+               return array( null, 0 );
+       }
+
        public function getAllowedParams() {
                return array(
                        'title' => array(
index 2a60af9..f7290af 100644 (file)
@@ -70,7 +70,7 @@ class ApiTokens extends ApiBase {
                foreach ( $names as $name ) {
                        $types[$name] = array( 'ApiQueryInfo', 'get' . ucfirst( $name ) . 'Token' );
                }
-               wfRunHooks( 'ApiTokensGetTokenTypes', array( &$types ) );
+               Hooks::run( 'ApiTokensGetTokenTypes', array( &$types ) );
                ksort( $types );
                wfProfileOut( __METHOD__ );
 
index 943ae8e..c23e9ff 100644 (file)
@@ -69,7 +69,7 @@ class ApiUndelete extends ApiBase {
                }
 
                if ( $retval[1] ) {
-                       wfRunHooks( 'FileUndeleteComplete',
+                       Hooks::run( 'FileUndeleteComplete',
                                array( $titleObj, $params['fileids'], $this->getUser(), $params['reason'] ) );
                }
 
index 8096504..d82b0d8 100644 (file)
@@ -1,7 +1,8 @@
 {
        "@metadata": {
                "authors": [
-                       "Meno25"
+                       "Meno25",
+                       "أحمد المحمودي"
                ]
        },
        "apihelp-main-param-format": "صيغة الخرج.",
@@ -17,5 +18,6 @@
        "apihelp-createaccount-param-name": "اسم المستخدم.",
        "apihelp-delete-description": "حذف صفحة.",
        "apihelp-delete-param-unwatch": "أزل الصفحة من قائمة مراقبتك.",
-       "apihelp-edit-description": "إنشاء وتعديل الصفحات."
+       "apihelp-edit-description": "إنشاء وتعديل الصفحات.",
+       "apihelp-query+prefixsearch-param-offset": "عدد النتائج المراد تخطيها."
 }
index 2d57aa2..cb2c9b3 100644 (file)
        "apihelp-block-param-user": "Імя ўдзельніка, IP-адрас або IP-дыяпазон, якія вы хочаце заблякаваць.",
        "apihelp-block-param-expiry": "Час заканчэньня. Можа быць адносным (напрыклад, «5 months» або «2 weeks») ці аблсалютным (напрыклад, «2014-09-18T12:34:56Z»). Калі выстаўлены на «infinite», «indefinite» ці «never», блякаваньне будзе бестэрміновым.",
        "apihelp-block-param-reason": "Прычына блякаваньня.",
-       "apihelp-block-param-anononly": "Заблякаваць толькі ананімных удзельнікаў (напрыклад, забараніць ананімныя праўкі з гэтага IP-адрасу)."
+       "apihelp-block-param-anononly": "Заблякаваць толькі ананімных удзельнікаў (напрыклад, забараніць ананімныя праўкі з гэтага IP-адрасу).",
+       "apihelp-block-param-nocreate": "Забарона стварэньня рахункаў.",
+       "apihelp-block-param-autoblock": "Аўтаматычна блякаваць апошні ўжыты IP-адрас, а таксама ўсе наступныя IP-адрасы, зь якіх будуць спробы ўваходу.",
+       "apihelp-block-param-noemail": "Забараняе ўдзельніку дасылаць лісты электроннай пошты празь вікі (трэба мець права «blockemail»).",
+       "apihelp-block-param-hidename": "Схаваць імя ўдзельніка з журналу блякаваньняў (патрабуе права «hideuser»).",
+       "apihelp-block-param-allowusertalk": "Дазволіць удзельніку рэдагаваць уласную старонку гутарак (залежыць ад $wgBlockAllowsUTEdit).",
+       "apihelp-block-param-reblock": "Калі ўдзельнік ужо заблякаваны, перапісаць дзейнае блякаваньне."
 }
diff --git a/includes/api/i18n/bs.json b/includes/api/i18n/bs.json
new file mode 100644 (file)
index 0000000..c8df203
--- /dev/null
@@ -0,0 +1,11 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Palapa"
+               ]
+       },
+       "apihelp-block-description": "Blokiraj korisnika",
+       "apihelp-block-param-reason": "Razlog za blokadu",
+       "apihelp-delete-description": "Obriši stranicu.",
+       "apihelp-edit-param-minor": "Mala izmjena."
+}
index f7e3a57..21b546c 100644 (file)
        "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-show": "Show only items that meet thse criteria, e.g. non minor edits only: $2show=!minor.\n\nIf $2show=patrolled or $2show=!patrolled is set, revisions older than [https://www.mediawiki.org/wiki/Manual:$wgRCMaxAge $wgRCMaxAge] ($1 {{PLURAL:$1|second|seconds}}) won't be shown.",
+       "apihelp-query+usercontribs-param-show": "Show only items that meet these criteria, e.g. non minor edits only: $2show=!minor.\n\nIf $2show=patrolled or $2show=!patrolled is set, revisions older than [https://www.mediawiki.org/wiki/Manual:$wgRCMaxAge $wgRCMaxAge] ($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.",
        "apihelp-query+usercontribs-example-user": "Show contributions of [[User:Example]]",
index 157b27b..4550a75 100644 (file)
@@ -11,7 +11,9 @@
        "apihelp-main-param-format": "El formato de la salida.",
        "apihelp-main-param-curtimestamp": "Incluir la marca de tiempo actual en el resultado.",
        "apihelp-block-description": "Bloquear usuario",
+       "apihelp-block-param-user": "El nombre de usuario, dirección IP o intervalo de IP que quieres bloquear.",
        "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 IP).",
        "apihelp-block-param-nocreate": "Prevenir la creación de cuentas.",
        "apihelp-compare-param-fromtitle": "Primer título para comparar",
        "apihelp-createaccount-description": "Crear una nueva cuenta de usuario.",
        "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.",
+       "apihelp-edit-param-createonly": "No editar la página si ya existe.",
+       "apihelp-edit-param-watch": "Añadir la página a tu lista de seguimiento.",
+       "apihelp-edit-param-unwatch": "Quitar la página de tu lista de seguimiento.",
        "apihelp-edit-example-edit": "Editar una página",
+       "apihelp-emailuser-description": "Enviar un mensaje de correo electrónico a un usuario.",
        "apihelp-expandtemplates-param-title": "Título de la página.",
        "apihelp-expandtemplates-param-text": "Sintaxis wiki que se convertirá.",
        "apihelp-feedcontributions-description": "Devuelve el canal de contribuciones de un usuario.",
        "apihelp-feedcontributions-param-feedformat": "El formato del canal.",
+       "apihelp-feedcontributions-param-year": "A partir del año (y anteriores).",
+       "apihelp-feedcontributions-param-month": "A partir del mes (y anteriores).",
+       "apihelp-feedcontributions-param-deletedonly": "Mostrar solo las contribuciones borradas.",
        "apihelp-feedrecentchanges-param-hideminor": "Ocultar cambios menores.",
+       "apihelp-import-param-summary": "Resumen de importación.",
        "apihelp-login-param-name": "Nombre de usuario.",
        "apihelp-login-param-password": "Contraseña.",
        "apihelp-login-param-domain": "Dominio (opcional).",
        "apihelp-move-description": "Mover una página.",
        "apihelp-opensearch-param-search": "Buscar cadena.",
+       "apihelp-options-example-reset": "Restablecer todas las preferencias",
        "apihelp-patrol-example-rcid": "Patrullar un cambio reciente",
        "apihelp-patrol-example-revid": "Patrullar una revisión",
        "apihelp-protect-example-protect": "Proteger una página",
index 265397f..91b4907 100644 (file)
        "apihelp-opensearch-param-format": "فرمت خروجی.",
        "apihelp-opensearch-example-te": "یافتن صفحه‌هایی که با «ته» آغاز می‌شوند",
        "apihelp-options-example-reset": "بازنشانی همه تنظیمات.",
+       "apihelp-paraminfo-param-helpformat": "ساختار راهنمای رشته‌ها",
        "apihelp-parse-example-page": "تجزیه یک صفحه.",
        "apihelp-parse-example-text": "تجزیه متن ویکی.",
        "apihelp-parse-example-summary": "تجزیه خلاصه.",
        "apihelp-query+allpages-param-filterredir": "صفحه‌هایی که باید فهرست شوند.",
        "apihelp-query+allpages-param-minsize": "محدودکردن به صفحه‌هایی که همراه دست کم این تعداد بایت است.",
        "apihelp-query+allredirects-param-limit": "تعداد آیتم‌ها برای بازگرداندن.",
+       "apihelp-query+blocks-example-simple": "فهرست بسته‌شده‌ها",
        "apihelp-query+categorymembers-description": "فهرست‌کردن همهٔ صفحه‌ها در یک ردهٔ مشخص‌شده.",
+       "apihelp-query+categorymembers-param-sort": "خصوصیت برای مرتب‌سازی",
+       "apihelp-query+categorymembers-param-dir": "جهت مرتب شدن",
        "apihelp-query+categorymembers-param-startsortkey": "جایش از $1starthexsortkey استفاده کنید.",
        "apihelp-query+imageinfo-param-urlheight": "مشابه $1urlwidth.",
        "apihelp-query+info-description": "دریافت اطلاعات سادهٔ صفحه.",
        "apihelp-query+iwbacklinks-param-limit": "تعداد صفحه‌ها برای بازگرداندن.",
        "apihelp-query+linkshere-param-limit": "تعداد برای بازگرداندن.",
        "apihelp-query+logevents-description": "دریافت رویدادها از سیاهه‌ها.",
+       "apihelp-query+prefixsearch-param-search": "جستجوی رشته",
+       "apihelp-query+prefixsearch-param-namespace": "فضاهای نامی برای جستجو",
+       "apihelp-query+prefixsearch-param-limit": "حداکثر تعداد نتایج برای بازگرداندن.",
+       "apihelp-query+prefixsearch-param-offset": "تعداد نتایج برای رها کردن.",
        "apihelp-query+protectedtitles-param-namespace": "فقط عنوان‌ها در این فضاهای نام را فهرست کنید.",
        "apihelp-query+protectedtitles-param-level": "فقط عنوان‌ها در این سطح‌های حفاظت را فهرست کنید.",
        "apihelp-query+protectedtitles-param-limit": "تعداد صفحه‌ها برای بازگرداندن.",
index 8676f43..2274371 100644 (file)
        "apihelp-rollback-example-summary": "Annuler les dernières modifications sur [[Main Page]] par l’utilisateur à l’adresse IP 192.0.2.5 avec le résumé « Annulation de vandalisme », et marquer ces modifications et l’annulation comme « robot »",
        "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-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).",
+       "apihelp-setnotificationtimestamp-param-newerthanrevid": "Révision pour fixer l’horodatage de notification plus récent (une page uniquement).",
+       "apihelp-setnotificationtimestamp-example-all": "Réinitialiser l’état de notification pour toute la liste de suivi",
+       "apihelp-setnotificationtimestamp-example-page": "Réinitialiser l’état de notification pour la « Page principale »",
+       "apihelp-setnotificationtimestamp-example-pagetimestamp": "Fixer l’horodatage de notification pour « Page principale » 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 Utilisateur",
+       "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).",
+       "apihelp-tokens-example-emailmove": "Récupérer un jeton de courriel et un jeton de déplacement.",
+       "apihelp-unblock-description": "Débloquer un utilisateur.",
+       "apihelp-unblock-param-id": "ID du blocage à lever (obtenu via list=blocks). Impossible à utiliser avec $1user.",
+       "apihelp-unblock-param-user": "Nom d’utilisateur, adresse IP ou plage d’adresse IP à débloquer. Impossible à utiliser avec $1id.",
+       "apihelp-unblock-param-reason": "Motif de déblocage.",
+       "apihelp-unblock-example-id": "Lever le blocage d’ID #105",
+       "apihelp-unblock-example-user": "Débloquer l’utilisateur Bob avec le motif « Désolé Bob »",
+       "apihelp-undelete-description": "Restaurer les révisions d’une page supprimée.\n\nUne liste des révisions supprimées (avec les horodatages) peut être récupérée via [[Special:ApiHelp/query+deletedrevs|list=deletedrevs]], et une liste d’IDs de fichier supprimé peut être récupérée via [[Special:ApiHelp/query+filearchive|list=filearchive]].",
+       "apihelp-undelete-param-title": "Titre de la page à restaurer.",
+       "apihelp-undelete-param-reason": "Motif de restauration.",
+       "apihelp-undelete-param-timestamps": "Horodatages des révisions à restaurer. Si $1timestamps et $1fileids sont vides, toutes seront restaurées.",
+       "apihelp-undelete-param-fileids": "IDs des révisions de fichier à restaurer. Si $1timestamps et $1fileids sont vides, toutes seront restaurées.",
+       "apihelp-undelete-param-watchlist": "Ajouter ou supprimer la page de votre liste de suivi sans condition, utiliser les préférences ou ne pas modifier le suivi.",
+       "apihelp-undelete-example-page": "Annuler la suppression de [[Main Page]]",
+       "apihelp-undelete-example-revisions": "Annuler la suppression de deux révisions de [[Main Page]]",
+       "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 « $1file ».\n* Télécharger le fichier par morceaux, en utilsiant les paramètres « $1filesize », « $1chunk » et « $1offset ».* Pour que le serveur MédiaWiki cherche un fichier depuis une URL, utiliser le paramètre « $1url ».\n* Terminer un téléchargement précédent qui a échoué à cause d’avertissements, en utilisant le paramètre « $1filekey ».\nNoter que le POST HTTP doit être fait comme un téléchargement de fichier (par ex. en utilisant multipart/form-data) en envoyant le « $1file ».",
+       "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 « $1text » n’est pas spécifié.",
+       "apihelp-upload-param-text": "Texte de page initiale pour les nouveaux fichiers.",
+       "apihelp-upload-param-watch": "Suivre la page.",
+       "apihelp-upload-param-watchlist": "Ajouter ou supprimer sans condition la page de votre liste de suivi, utiliser les préférences ou ne pas changer le suivi.",
+       "apihelp-upload-param-ignorewarnings": "Ignorer tous les avertissements.",
+       "apihelp-upload-param-file": "Contenu du fichier.",
+       "apihelp-upload-param-url": "URL où chercher le fichier.",
+       "apihelp-upload-param-filekey": "Clé identifiant un téléchargement précédent temporairement mis en attente.",
+       "apihelp-upload-param-sessionkey": "Comme $1filekey, conservé pour des raisons de compatibilité descendante.",
+       "apihelp-upload-param-stash": "Si positionné, le serveur conservera temporairement le fichier au lieu de l’ajouter au dépôt.",
+       "apihelp-upload-param-filesize": "Taille du fichier de tout le téléchargement.",
+       "apihelp-upload-param-offset": "Décalage du bloc en octets.",
+       "apihelp-upload-param-chunk": "Partie du contenu.",
+       "apihelp-upload-param-async": "Faire de façon asynchrone les grosses opérations sur les fichiers quand c’est possible.",
+       "apihelp-upload-param-asyncdownload": "Faire de façon asynchrone la recherche d’une URL.",
+       "apihelp-upload-param-leavemessage": "Si asyncdownload est utilisé, laisser un message sur la page de discussion de l’utilisateur quand c’est terminé.",
+       "apihelp-upload-param-statuskey": "Récupérer l’état de téléchargement pour cette clé de fichier (téléchargé par URL).",
+       "apihelp-upload-param-checkstatus": "Récupérer uniquement l’état de téléchargement pour la clé de fichier donnée.",
+       "apihelp-upload-example-url": "Télécharger depuis une URL",
+       "apihelp-upload-example-filekey": "Terminer un téléchargement qui a échoué à cause d’avertissements",
+       "apihelp-userrights-description": "Modifier l’appartenance d’un utilisateur à un groupe.",
+       "apihelp-userrights-param-user": "Nom d’utilisateur.",
+       "apihelp-userrights-param-userid": "ID de l’utilisateur.",
+       "apihelp-userrights-param-add": "Ajouter l’utilisateur à ces groupes.",
+       "apihelp-userrights-param-remove": "Supprimer l’utilisateur de ces groupes.",
+       "apihelp-userrights-param-reason": "Motif pour la modification.",
+       "apihelp-userrights-example-user": "Ajouter l’utilisateur FooBot au groupe « robot », et le supprimer des groupes « sysop » et « bureaucrate »",
+       "apihelp-userrights-example-userid": "Ajouter l’utilisateur d’ID 123 au groupe « robot », et le supprimer des groupes « sysop » et « bureaucrate »",
+       "apihelp-watch-description": "Ajouter ou supprimer des pages de la liste de suivi de l’utilisateur actuel.",
+       "apihelp-watch-param-title": "La page à (ne plus) suivre. Utiliser plutôt $1titles.",
+       "apihelp-watch-param-unwatch": "Si défini, la page ne sera plus suivie plutôt que suivie.",
+       "apihelp-watch-example-watch": "Suivre la page « Page principale »",
+       "apihelp-watch-example-unwatch": "Ne plus suivre la page « Page principale »",
+       "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-dbg-description": "Extraire les données au format de var_export() de PHP.",
        "apihelp-dbgfm-description": "Extraire les données au format de var_export() de PHP (affiché proprement en HTML).",
        "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-prettyprint-header": "Vous regardez 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 format pour modifier le format de sortie. Pour voir la représentation non HTML du format $1, mettez format=$2.\n\nVoyez la [https://www.mediawiki.org/wiki/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.",
+       "api-pageset-param-pageids": "Une liste des IDs de page sur lesquelles travailler.",
+       "api-pageset-param-revids": "Une liste des IDs de révision sur lesquelles travailler.",
+       "api-pageset-param-generator": "Obtenir la liste des pages sur lesquelles travailler en exécutant le module de recherche spécifié.\n\n'''NOTE :''' les noms de paramètre du générateur doivent être préfixés avec un « g », voir les exemples.",
+       "api-pageset-param-redirects-generator": "Résoudre automatiquement les redirections dans $1titles, $1pageids et $1revids, et dans les pages renvoyées par $1generator.",
+       "api-pageset-param-redirects-nogenerator": "Résoudre automatiquement les redirections dans $1titles, $1pageids et $1revids.",
+       "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-main-header": "Module principal",
        "api-help-param-default": "Par défaut : $1",
        "api-help-param-default-empty": "Par défaut : <span class=\"apihelp-empty\">(vide)</span>",
        "api-help-param-token": "Un jeton « $1 » récupéré par [[Special:ApiHelp/query+tokens|action=query&meta=tokens]]",
+       "api-help-param-token-webui": "Pour rester compatible, le jeton utilisé dans l’IHM web est aussi accepté.",
+       "api-help-param-disabled-in-miser-mode": "Désactivé à cause du [https://www.mediawiki.org/wiki/Manual:$wgMiserMode mode minimal].",
+       "api-help-param-limited-in-miser-mode": "'''NOTE :''' Du fait du [https://www.mediawiki.org/wiki/Manual:$wgMiserMode mode minimal], utiliser cela peut aboutir à moins de résultats que « $1limit » renvoyés avant de continuer ; dans les cas extrêmes, zéro résultats peuvent être renvoyés.",
+       "api-help-param-direction": "Dans quelle direction énumérer :\n;newer:Lister les plus anciens en premier. Note : $1start doit être avant $1end.\n;older:Lister les nouveaux en premier (par défaut). Note : $1start doit être postérieur à $1end.",
+       "api-help-param-continue": "Quand plus de résultats sont disponibles, utiliser cela pour continuer.",
        "api-help-param-no-description": "<span class=\"apihelp-empty\">(aucune description)</span>",
        "api-help-examples": "{{PLURAL:$1|Exemple|Exemples}} :",
        "api-help-permissions": "{{PLURAL:$1|Droit|Droits}} :",
diff --git a/includes/api/i18n/gl.json b/includes/api/i18n/gl.json
new file mode 100644 (file)
index 0000000..c029a62
--- /dev/null
@@ -0,0 +1,40 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Elisardojm"
+               ]
+       },
+       "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Documentación]\n* [https://www.mediawiki.org/wiki/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://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts 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 https://www.mediawiki.org/wiki/API:Errors_and_warnings.",
+       "apihelp-main-param-action": "Que acción se realizará.",
+       "apihelp-main-param-format": "O formato de saída.",
+       "apihelp-main-param-curtimestamp": "Incluir a marca de tempo actual no resultado.",
+       "apihelp-block-description": "Bloquear un usuario.",
+       "apihelp-block-param-reason": "Motivo para o bloqueo.",
+       "apihelp-block-param-anononly": "Bloquear só usuarios anónimos (é dicir, desactivar edicións anónimas desta IP).",
+       "apihelp-block-param-nocreate": "Previr a creación de contas.",
+       "apihelp-block-param-autoblock": "Bloquear automaticamente o último enderezo IP utilizado, e calquera outro enderezo desde o que intente conectarse.",
+       "apihelp-block-param-watchuser": "Vixiar a páxina de usuario ou IP e a de conversa deste usuario",
+       "apihelp-compare-param-fromtitle": "Primeiro título para comparar.",
+       "apihelp-compare-param-totitle": "Segundo título para comparar.",
+       "apihelp-createaccount-description": "Crear unha nova conta de usuario.",
+       "apihelp-createaccount-param-name": "Nome de usuario.",
+       "apihelp-createaccount-param-email": "Enderezo de correo eletrónico do usuario (opcional).",
+       "apihelp-createaccount-param-realname": "Nome real do usuario (opcional).",
+       "apihelp-delete-description": "Borrar a páxina.",
+       "apihelp-delete-param-watch": "Engadir esta páxina á lista de vixilancia.",
+       "apihelp-delete-param-unwatch": "Eliminar esta páxina da lista de vixilancia.",
+       "apihelp-delete-example-simple": "Borrar a Páxina Principal",
+       "apihelp-disabled-description": "Este módulo foi desactivado.",
+       "apihelp-edit-description": "Crear e editar páxinas.",
+       "apihelp-edit-param-text": "Contido da páxina.",
+       "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.",
+       "apihelp-edit-param-createonly": "Non editar a páxina se xa existe.",
+       "apihelp-edit-param-watch": "Engadir esta páxina á lista de vixilancia.",
+       "apihelp-edit-param-unwatch": "Eliminar esta páxina da lista de vixilancia.",
+       "apihelp-edit-example-edit": "Editar a páxina",
+       "apihelp-emailuser-description": "Enviar un correo electrónico a un usuario.",
+       "apihelp-expandtemplates-param-title": "Título da páxina.",
+       "apihelp-expandtemplates-param-text": "Sintaxis wiki a converter."
+}
index 3c708a7..ff06724 100644 (file)
        "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-watchuser": "Donn de Metmaachersigg un de Klaafsigg dohzoh op mig Oppaßleß säze.",
+       "apihelp-compare-description": "Donn de Ongerscheide zwesche zwai Sigge beschtemme.\n\nDo moß derför jeweils en Väsjohn, ene Tettel, 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-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-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\">$1mailpassword</code> jesaz es)",
+       "apihelp-createaccount-param-realname": "Dämm Medmaacher singe reschtejje Nahme - kann fott blihve.",
        "apihelp-delete-description": "Schmieß en Sigg fott.",
        "apihelp-delete-param-watch": "Donn die Sigg en Ding Oppassliss opnemme.",
        "apihelp-delete-param-unwatch": "Schmiiß di Sigg us Dinge Oppassless erus.",
diff --git a/includes/api/i18n/mg.json b/includes/api/i18n/mg.json
new file mode 100644 (file)
index 0000000..3126a28
--- /dev/null
@@ -0,0 +1,11 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Jagwar"
+               ]
+       },
+       "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Torohevitra be kokoa]\n* [https://www.mediawiki.org/wiki/API:FAQ Fanontaniana miverina matetika]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lisitry ny mailaka manaraka]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Filazana API]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts Baogy & hataka]\n</div>\n<strong>Status:</strong> \nTokony mandeha avokoa ny fitaovana aseho eto amin'ity pehy ity, na dia izany aza mbola am-panamboarana ny API ary mety hiova na oviana na oviana. Araho amin'ny alalan'ny fisoratana ny mailakao ao amin'ny [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce lisitra fampielezana] ny fiovana.\n\n<strong>Hataka diso:</strong> \nRehefa alefa ao amin'i API ny hata, ho alefa miaraka amin'ny lakile \"MediaWiki-API-Error\" ny header HTTP ary samy homen-tsanda mitovy ny header ary ny kaodin-kadisoana. Ho an'ny torohay fanampiny dia jereo https://www.mediawiki.org/wiki/API:Errors_and_warnings.",
+       "apihelp-main-param-action": "Inona ny zavatra ho atao.",
+       "apihelp-main-param-format": "Format mivoaka",
+       "apihelp-createaccount-param-name": "Anaram-pikambana."
+}
index 73d4b64..9d6b027 100644 (file)
@@ -4,7 +4,7 @@
                        "Bjankuloski06"
                ]
        },
-       "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Ð\94окÑ\83менÑ\82аÑ\86иÑ\98а]\n* [https://www.mediawiki.org/wiki/API:FAQ Ð§Ð\9fÐ\9f]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Ð\9fоÑ\88Ñ\82енÑ\81ки Ñ\81пиÑ\81ок]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Ð¡Ð¾Ð¾Ð¿Ñ\88Ñ\82ениÑ\98а Ð·Ð° Ð\9fÑ\80илогоÑ\82]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts Ð\93Ñ\80еÑ\88ки Ð¸ Ð±Ð°Ñ\80аÑ\9aа]\n</div>\n<strong>СÑ\82аÑ\82Ñ\83Ñ\81:</strong> Ð¡Ð¸Ñ\82е Ñ\81Ñ\82авки Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86ава Ð±Ð¸ Ñ\82Ñ\80ебало Ð´Ð° Ñ\80абоÑ\82аÑ\82, Ð½Ð¾ Ð\9fÑ\80илогоÑ\82 Ñ\81епак Ðµ Ð²Ð¾ Ð°ÐºÑ\82ивна Ñ\80азÑ\80абоÑ\82ка, Ñ\88Ñ\82о Ð·Ð½Ð°Ñ\87и Ð´ÐµÐºÐ° Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ñ\81е Ñ\81мени Ð²Ð¾ Ñ\81екое Ð²Ñ\80еме. Ð\9eбÑ\98авиÑ\82е Ð·Ð° Ð¸Ð·Ð¼ÐµÐ½Ð¸ Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð³Ð¸ Ð´Ð¾Ð·Ð½Ð°Ð²Ð°Ñ\82е Ð°ÐºÐ¾ Ñ\81е Ð¿Ñ\80иÑ\98авиÑ\82е Ð½Ð° [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ Ð¿Ð¾Ñ\88Ñ\82енÑ\81киоÑ\82 Ñ\81пиÑ\81ок â\80\9ethe mediawiki-api-announceâ\80\9c].\n\n<strong>Ð\9fогÑ\80еÑ\88ни Ð±Ð°Ñ\80аÑ\9aа:</strong> Ð\9aога Ð\9fÑ\80илогот ќе добие погрешни барања, ќе се испрати HTTP-заглавие со клучот „MediaWiki-API-Error“ и потоа на вредностите на заглавието и шифрата на грешката што ќе се појават ќе им биде зададена истата вредност. ПОвеќе информации ќе најдете на https://www.mediawiki.org/wiki/API:Errors_and_warnings.",
+       "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Ð\94окÑ\83менÑ\82аÑ\86иÑ\98а]\n* [https://www.mediawiki.org/wiki/API:FAQ Ð§Ð\9fÐ\9f]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Ð\9fоÑ\88Ñ\82енÑ\81ки Ñ\81пиÑ\81ок]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Ð¡Ð¾Ð¾Ð¿Ñ\88Ñ\82ениÑ\98а Ð·Ð° Ð\98звÑ\80Ñ\88никоÑ\82]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts Ð\93Ñ\80еÑ\88ки Ð¸ Ð±Ð°Ñ\80аÑ\9aа]\n</div>\n<strong>СÑ\82аÑ\82Ñ\83Ñ\81:</strong> Ð¡Ð¸Ñ\82е Ñ\81Ñ\82авки Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86ава Ð±Ð¸ Ñ\82Ñ\80ебало Ð´Ð° Ñ\80абоÑ\82аÑ\82, Ð½Ð¾ Ð\98звÑ\80Ñ\88никоÑ\82 Ñ\81епак Ðµ Ð²Ð¾ Ð°ÐºÑ\82ивна Ñ\80азÑ\80абоÑ\82ка, Ñ\88Ñ\82о Ð·Ð½Ð°Ñ\87и Ð´ÐµÐºÐ° Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ñ\81е Ñ\81мени Ð²Ð¾ Ñ\81екое Ð²Ñ\80еме. Ð\9eбÑ\98авиÑ\82е Ð·Ð° Ð¸Ð·Ð¼ÐµÐ½Ð¸ Ð¼Ð¾Ð¶ÐµÑ\82е Ð´Ð° Ð³Ð¸ Ð´Ð¾Ð·Ð½Ð°Ð²Ð°Ñ\82е Ð°ÐºÐ¾ Ñ\81е Ð¿Ñ\80иÑ\98авиÑ\82е Ð½Ð° [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ Ð¿Ð¾Ñ\88Ñ\82енÑ\81киоÑ\82 Ñ\81пиÑ\81ок â\80\9ethe mediawiki-api-announceâ\80\9c].\n\n<strong>Ð\9fогÑ\80еÑ\88ни Ð±Ð°Ñ\80аÑ\9aа:</strong> Ð\9aога Ð\98звÑ\80Ñ\88никот ќе добие погрешни барања, ќе се испрати HTTP-заглавие со клучот „MediaWiki-API-Error“ и потоа на вредностите на заглавието и шифрата на грешката што ќе се појават ќе им биде зададена истата вредност. ПОвеќе информации ќе најдете на https://www.mediawiki.org/wiki/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-options-example-reset": "Врати ги сите поставки по основно",
        "apihelp-options-example-change": "Смени ги поставките „skinЗ“ и „hideminor“",
        "apihelp-options-example-complex": "Врати ги сите нагодувања по основно, а потоа задај ги „skin“ и „nickname“",
-       "apihelp-paraminfo-description": "Ð\9dабави Ð¸Ð½Ñ\84оÑ\80маÑ\86ии Ð·Ð° Ð¿Ñ\80илоÑ\88ки (API) модули.",
+       "apihelp-paraminfo-description": "Ð\9dабави Ð¸Ð½Ñ\84оÑ\80маÑ\86ии Ð·Ð° Ð¸Ð·Ð²Ñ\80Ñ\88ниÑ\87ки (API) модули.",
        "apihelp-paraminfo-param-modules": "Список на називи на модули (вредности на параметрите action= и format=, или пак „main“). Може да се укажат подмодули со „+“.",
        "apihelp-paraminfo-param-helpformat": "Формат на помошните низи.",
        "apihelp-paraminfo-param-querymodules": "Список на називи на модули за барања (вредност на параметарот prop=, meta= или list=). Користете го „$1modules=query+foo“ наместо „$1querymodules=foo“.",
        "apihelp-protect-param-reason": "Причиина за (од)заштитување",
        "apihelp-protect-example-protect": "Заштити страница",
        "apihelp-purge-param-forcelinkupdate": "Поднови ги табелите со врски.",
-       "apihelp-purge-example-simple": "Ð\9fÑ\80евÑ\87иÑ\82аÑ\98 Ð³Ð¸ â\80\9eÐ\93лавна Ñ\81Ñ\82Ñ\80аниÑ\86аâ\80\9c Ð¸ â\80\9eÐ\9fÑ\80илог“",
+       "apihelp-purge-example-simple": "Ð\9fÑ\80евÑ\87иÑ\82аÑ\98 Ð³Ð¸ â\80\9eÐ\93лавна Ñ\81Ñ\82Ñ\80аниÑ\86аâ\80\9c Ð¸ â\80\9eÐ\98звÑ\80Ñ\88ник“",
        "apihelp-query-param-list": "Кои списоци да се набават.",
        "apihelp-query-param-meta": "Кои метаподатоци да се набават.",
        "apihelp-query+allcategories-description": "Наброј ги сите категории.",
        "apihelp-xmlfm-description": "Давај го изводот во XML-формат (подобрен испис во HTML).",
        "apihelp-yaml-description": "Давај го изводот во YAML-формат.",
        "apihelp-yamlfm-description": "Давај го изводот во YAML-формат (подобрен испис во HTML).",
-       "api-format-title": "РезÑ\83лÑ\82аÑ\82 Ð¾Ð´ Ð\9fÑ\80илогот на МедијаВики",
-       "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-title": "РезÑ\83лÑ\82аÑ\82 Ð¾Ð´ Ð\98звÑ\80Ñ\88никот на МедијаВики",
+       "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-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-help-title": "Ð\9fомоÑ\88 Ñ\81о Ð\9fÑ\80илогот на МедијаВики",
-       "api-help-lead": "Ð\9eва Ðµ Ñ\81амоÑ\81оздадена Ð´Ð¾ÐºÑ\83менÑ\82аÑ\86иÑ\81ка Ñ\81Ñ\82Ñ\80аниÑ\86а Ð·Ð° Ð\9fÑ\80илогоÑ\82 Ð½Ð° Ð\9cедиÑ\98аÐ\92ики.\n\nDocumentation and examples: https://www.mediawiki.org/wiki/API",
+       "api-help-title": "Ð\9fомоÑ\88 Ñ\81о Ð\98звÑ\80Ñ\88никот на МедијаВики",
+       "api-help-lead": "Ð\9eва Ðµ Ñ\81амоÑ\81оздадена Ð´Ð¾ÐºÑ\83менÑ\82аÑ\86иÑ\81ка Ñ\81Ñ\82Ñ\80аниÑ\86а Ð·Ð° Ð¸Ð·Ð²Ñ\80Ñ\88никоÑ\82 Ð½Ð° Ð\9cедиÑ\98аÐ\92ики.\n\nÐ\94окÑ\83менÑ\82аÑ\86иÑ\98а Ð¸ Ð¿Ñ\80имеÑ\80и: https://www.mediawiki.org/wiki/API",
        "api-help-main-header": "Главен модул",
        "api-help-flag-deprecated": "Овој модул е застарен.",
        "api-help-flag-internal": "<strong>Овој модул е внатрешен или нестабилен.</strong> Работењето може да му се промени без предупредување.",
        "api-help-permissions-granted-to": "{{PLURAL:$1|Доделена на}: $2",
        "api-help-right-apihighlimits": "Уоптреба на повисоки ограничувања за приложни барања (бавни барања: $1; брзи барања: $2). Ограничувањата за бавни барања важат и за повеќевредносни параметри.",
        "api-credits-header": "Признанија",
-       "api-credits": "РазÑ\80абоÑ\82Ñ\83ваÑ\87и Ð½Ð° Ð\9fÑ\80илогот:\n* Роан Катау (главен резработувач од септември 2007 до 2009 г.)\n* Виктор Василев\n* Брајан Тонг Мињ\n* Сем Рид\n* Јуриј Астрахан (создавач, главен разработувач од септември 2006 до септември 2007 г.)\n* Brad Jorsch (главен разработувач од 2013 г. до денес)\n\nВашите коментари, предлози и прашања испраќајте ги на mediawiki-api@lists.wikimedia.org\nа грешките пријавувајте ги на https://bugzilla.wikimedia.org/."
+       "api-credits": "РазÑ\80абоÑ\82Ñ\83ваÑ\87и Ð½Ð° Ð\98звÑ\80Ñ\88никот:\n* Роан Катау (главен резработувач од септември 2007 до 2009 г.)\n* Виктор Василев\n* Брајан Тонг Мињ\n* Сем Рид\n* Јуриј Астрахан (создавач, главен разработувач од септември 2006 до септември 2007 г.)\n* Brad Jorsch (главен разработувач од 2013 г. до денес)\n\nВашите коментари, предлози и прашања испраќајте ги на mediawiki-api@lists.wikimedia.org\nа грешките пријавувајте ги на https://bugzilla.wikimedia.org/."
 }
index 6b10584..ec494f4 100644 (file)
@@ -12,6 +12,7 @@
        "apihelp-help-example-main": "Bantuan untuk modul utama",
        "apihelp-help-example-recursive": "Segala bantuan dalam satu halaman",
        "apihelp-help-example-help": "Bantuan untuk modul bantuan",
+       "apihelp-query+prefixsearch-param-offset": "Bilangan hasil untuk dilangkau.",
        "apihelp-userrights-param-userid": "ID pengguna.",
        "apihelp-dbgfm-description": "Data output dalam format var_export() PHP (''pretty-print'' dalam HTML).",
        "apihelp-dump-description": "Output data dalam format var_dump() PHP.",
index 21db93a..450c641 100644 (file)
@@ -4,7 +4,8 @@
                        "Siebrand",
                        "Sjoerddebruin",
                        "Robin0van0der0vliet",
-                       "Mar(c)"
+                       "Mar(c)",
+                       "Valhallasw"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Documentatie]\n* [https://www.mediawiki.org/wiki/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://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts 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 https://www.mediawiki.org/wiki/API:Errors_and_warnings voor meer informatie.",
        "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 \"maxlag\" teruggegeven met een bericht als \"Waiting for $host: $lag seconds lagged\".<br />Zie https://www.mediawiki.org/wiki/Manual:Maxlag_parameter voor mee informatie.",
        "apihelp-main-param-smaxage": "Stelt de header \"s-maxage\" in op het aangegeven aantal seconden. Foutmeldingen komen nooit in de cache.",
        "apihelp-main-param-maxage": "Stelt de header \"max-age\" in op het aangegeven aantal seconden. Foutmeldingen komen nooit in de cache.",
+       "apihelp-main-param-assert": "Controleer of de gebruiker ingelogd is als \"user\" is meegegeven, en of de gebruiker het bot-gebruikersrecht heeft als \"bot\" 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.",
+       "apihelp-main-param-curtimestamp": "Voeg de huidige tijd toe aan het antwoord.",
        "apihelp-block-description": "Gebruiker blokkeren.",
        "apihelp-block-param-reason": "Reden voor blokkade.",
        "apihelp-edit-example-edit": "Pagina bewerken",
diff --git a/includes/api/i18n/te.json b/includes/api/i18n/te.json
new file mode 100644 (file)
index 0000000..8678f2a
--- /dev/null
@@ -0,0 +1,8 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Veeven"
+               ]
+       },
+       "apihelp-feedrecentchanges-example-simple": "ఇటీవలి మార్పులను చూడండి"
+}
index b0c3e4f..fe1b870 100644 (file)
@@ -12,6 +12,7 @@
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page/zh 文档]\n* [https://www.mediawiki.org/wiki/API:FAQ/zh 常见问题]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 邮件列表]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts 程序错误与功能请求]\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将会送回并设置为相同的值。详细信息请参阅 https://www.mediawiki.org/wiki/API:Errors_and_warnings 。",
        "apihelp-main-param-action": "要执行的操作。",
        "apihelp-main-param-format": "输出的格式。",
+       "apihelp-main-param-assert": "如果设置为“user”就验证用户是否登录,或如果设置为“bot”就验证是否有机器人用户权限。",
        "apihelp-main-param-servedby": "包含保存结果请求的主机名。",
        "apihelp-main-param-curtimestamp": "在结果中包括当前时间戳。",
        "apihelp-main-param-origin": "当通过跨域名AJAX请求(CORS)访问API时,设置此作为起始域名。这必须包括在任何pre-flight请求中,并因此必须是请求的URI的一部分(而不是POST正文)。这必须匹配Origin中的一个起点:从头到底,因此它已经设置为像http://zh.wikipedia.org或https://meta.wikimedia.org的东西。如果此参数不匹配Origin: header,就返回403错误响应。如果此参数匹配Origin: header并且起点被白名单,将设置一个Access-Control-Allow-Origin开头。",
@@ -35,7 +36,7 @@
        "apihelp-compare-param-fromid": "要比较的第一个页面 ID。",
        "apihelp-compare-param-fromrev": "要比较的第一个修订版本。",
        "apihelp-compare-param-totitle": "要比较的第二个标题。",
-       "apihelp-compare-param-toid": "è¦\81æ¯\94è¾\83ç\9a\84第ä¸\80个页面 ID。",
+       "apihelp-compare-param-toid": "è¦\81æ¯\94è¾\83ç\9a\84第äº\8c个页面 ID。",
        "apihelp-compare-param-torev": "要比较的第二个修订版本。",
        "apihelp-compare-example-1": "在版本1和2中创建差异",
        "apihelp-createaccount-description": "创建一个新用户账户。",
        "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "不能与$3user一起使用。",
        "apihelp-query+alldeletedrevisions-param-from": "从此标题开始列出。",
        "apihelp-query+alldeletedrevisions-param-to": "列出至此标题为止。",
+       "apihelp-query+alldeletedrevisions-param-user": "只列出此用户做出的修订。",
+       "apihelp-query+alldeletedrevisions-param-excludeuser": "不要列出此用户做出的修订。",
        "apihelp-query+alldeletedrevisions-param-namespace": "只列出此名字空间的页面。",
        "apihelp-query+alldeletedrevisions-param-miser-user-namespace": "'''注意:'''由于[https://www.mediawiki.org/wiki/Manual:$wgMiserMode miser模式],同时使用$1user和$1namespace将导致继续前返回少于“$1limit”个结果,在极端条件下可能不返回任何结果。",
        "apihelp-query+alldeletedrevisions-example-user": "列出由User:Example作出的最近50次已删除贡献",
        "apihelp-query+alldeletedrevisions-example-ns-main": "列出最近50次已删除的主名字空间修订",
+       "apihelp-query+allfileusages-param-prefix": "搜索此值开头的所有文件标题。",
+       "apihelp-query+allfileusages-param-limit": "要返回的总计项目。",
        "apihelp-query+allfileusages-param-dir": "罗列所采用的方向。",
        "apihelp-query+allfileusages-example-unique": "列出唯一性的文件标题",
        "apihelp-query+allfileusages-example-unique-generator": "获取所有文件标题,并标记出缺失者",
        "apihelp-query+categoryinfo-example-simple": "获取有关[[:Category:Foo]]和[[:Category:Bar]]的信息",
        "apihelp-query+categorymembers-description": "在指定的分类中列出所有页面。",
        "apihelp-query+categorymembers-param-sort": "要作为排序方式的属性。",
+       "apihelp-query+categorymembers-param-dir": "排序的方向。",
+       "apihelp-query+categorymembers-param-start": "开始列举的时间戳。不能与$1sort=timestamp一起使用。",
+       "apihelp-query+categorymembers-param-end": "列举的结尾时间戳。不能与$1sort=timestamp一起使用。",
        "apihelp-query+categorymembers-param-startsortkey": "请改用$1starthexsortkey。",
        "apihelp-query+categorymembers-param-endsortkey": "请改用$1endhexsortkey。",
        "apihelp-query+categorymembers-example-simple": "获取[[:Category:Physics]]中的前10个页面。",
        "apihelp-query+categorymembers-example-generator": "获取关于[[:Category:Physics]]中的前10个页面的页面信息。",
+       "apihelp-query+contributors-description": "获取对一个页面的登录贡献者列表和匿名贡献数。",
+       "apihelp-query+contributors-param-limit": "返回的贡献数。",
        "apihelp-query+contributors-example-simple": "显示[[首页]]的贡献",
        "apihelp-query+deletedrevisions-example-titles": "列出[[首页]]和[[Talk:首页]]的已删除修订,包含内容",
        "apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|模式}}:$2",
        "apihelp-query+deletedrevs-param-from": "从此标题开始列出。",
        "apihelp-query+deletedrevs-param-to": "列出至此标题为止。",
+       "apihelp-query+deletedrevs-param-user": "只列出此用户做出的修订。",
+       "apihelp-query+deletedrevs-param-excludeuser": "不要列出此用户做出的修订。",
        "apihelp-query+deletedrevs-param-namespace": "只列出此名字空间的页面。",
        "apihelp-query+deletedrevs-example-mode1": "列出最近已删除的对首页和Talk:首页的贡献,带内容(模式1)",
        "apihelp-query+deletedrevs-example-mode2": "列出由Bob作出的最近50次已删除贡献(模式2)",
        "apihelp-query+links-example-simple": "从[[首页]]获取链接",
        "apihelp-query+links-example-generator": "获取有关[[首页]]链接页面的信息",
        "apihelp-query+links-example-namespaces": "获取用户和模板名字空间中来自[[首页]]的链接",
+       "apihelp-query+linkshere-param-namespace": "只包括这些名字空间的页面。",
        "apihelp-query+linkshere-param-limit": "返回多少。",
+       "apihelp-query+linkshere-param-show": "只显示符合以下标准的项:\n;redirect:只显示重定向。\n;!redirects:只显示非重定向。",
        "apihelp-query+linkshere-example-simple": "获取链接至[[首页]]的页面列表",
        "apihelp-query+linkshere-example-generator": "获取有关链接至[[首页]]的页面的信息",
        "apihelp-query+logevents-description": "从日志获取事件。",
        "apihelp-yaml-description": "输出数据为YAML格式。",
        "apihelp-yamlfm-description": "输出数据为YAML格式(HTML优质打印效果)。",
        "api-format-title": "MediaWiki API 结果",
+       "api-format-prettyprint-header": "您正在查看$1格式的HTML表示。HTML对调试很有用,但不适合应用程序使用。\n\n指定格式参数以更改输出格式。要查看$1格式的非HTML表示,设置format=$2。\n\n参见[https://www.mediawiki.org/wiki/Special:MyLanguage/API 完整文档],或[[Special:ApiHelp/main|API帮助]]以获取更多信息。",
        "api-orm-param-props": "要查询的字段。",
        "api-help-title": "MediaWiki API 帮助",
        "api-help-lead": "这是自动生成的MediaWiki API文档页面。\n\n文档和例子:https://www.mediawiki.org/wiki/API:Main_page/zh",
index 05847db..1dedfdd 100644 (file)
@@ -67,7 +67,7 @@
        "apihelp-emailuser-param-text": "郵件內容。",
        "apihelp-emailuser-param-ccme": "寄送一份此郵件的複本給我。",
        "apihelp-emailuser-example-email": "寄送電子郵件給使用者 \"WikiSysop\" 使用內容 \"Content\"",
-       "apihelp-expandtemplates-description": "展開所有於 wikitext 中的樣板。",
+       "apihelp-expandtemplates-description": "展開所有於 wikitext 中板。",
        "apihelp-expandtemplates-param-title": "頁面標題。",
        "apihelp-expandtemplates-param-text": "要轉換的 Wikitext。",
        "apihelp-login-param-name": "使用者名稱。",
index ed62bba..753263c 100644 (file)
@@ -255,7 +255,7 @@ class BacklinkCache {
                        return $prefixes[$table];
                } else {
                        $prefix = null;
-                       wfRunHooks( 'BacklinkCacheGetPrefix', array( $table, &$prefix ) );
+                       Hooks::run( 'BacklinkCacheGetPrefix', array( $table, &$prefix ) );
                        if ( $prefix ) {
                                return $prefix;
                        } else {
@@ -303,7 +303,7 @@ class BacklinkCache {
                                break;
                        default:
                                $conds = null;
-                               wfRunHooks( 'BacklinkCacheGetConditions', array( $table, $this->title, &$conds ) );
+                               Hooks::run( 'BacklinkCacheGetConditions', array( $table, $this->title, &$conds ) );
                                if ( !$conds ) {
                                        throw new MWException( "Invalid table \"$table\" in " . __CLASS__ );
                                }
index 58ca2dc..c07032b 100644 (file)
@@ -131,7 +131,7 @@ class HTMLFileCache extends FileCacheBase {
                        return false;
                }
                // Allow extensions to disable caching
-               return wfRunHooks( 'HTMLFileCache::useFileCache', array( $context ) );
+               return Hooks::run( 'HTMLFileCache::useFileCache', array( $context ) );
        }
 
        /**
index 7d5450e..03162c0 100644 (file)
@@ -23,6 +23,7 @@
 use Cdb\Exception as CdbException;
 use Cdb\Reader as CdbReader;
 use Cdb\Writer as CdbWriter;
+
 /**
  * Class for caching the contents of localisation files, Messages*.php
  * and *.i18n.php.
@@ -944,7 +945,7 @@ class LocalisationCache {
 
                        # Allow extensions an opportunity to adjust the data for this
                        # fallback
-                       wfRunHooks( 'LocalisationCacheRecacheFallback', array( $this, $csCode, &$csData ) );
+                       Hooks::run( 'LocalisationCacheRecacheFallback', array( $this, $csCode, &$csData ) );
 
                        # Merge the data for this fallback into the final array
                        if ( $csCode === $code ) {
@@ -1002,7 +1003,7 @@ class LocalisationCache {
                }
                # Run hooks
                $purgeBlobs = true;
-               wfRunHooks( 'LocalisationCacheRecache', array( $this, $code, &$allData, &$purgeBlobs ) );
+               Hooks::run( 'LocalisationCacheRecache', array( $this, $code, &$allData, &$purgeBlobs ) );
 
                if ( is_null( $allData['namespaceNames'] ) ) {
                        wfProfileOut( __METHOD__ );
index 43e00cd..532236e 100644 (file)
@@ -575,7 +575,7 @@ class MessageCache {
                global $wgContLang;
                MessageBlobStore::getInstance()->updateMessage( $wgContLang->lcfirst( $msg ) );
 
-               wfRunHooks( 'MessageCacheReplace', array( $title, $text ) );
+               Hooks::run( 'MessageCacheReplace', array( $title, $text ) );
 
                wfProfileOut( __METHOD__ );
        }
@@ -736,7 +736,7 @@ class MessageCache {
                        $lckey = $wgContLang->lcfirst( $lckey );
                }
 
-               wfRunHooks( 'MessageCache::get', array( &$lckey ) );
+               Hooks::run( 'MessageCache::get', array( &$lckey ) );
 
                if ( ord( $lckey ) < 128 ) {
                        $uckey = ucfirst( $lckey );
@@ -909,7 +909,7 @@ class MessageCache {
                } else {
                        // XXX: This is not cached in process cache, should it?
                        $message = false;
-                       wfRunHooks( 'MessagesPreLoad', array( $title, &$message ) );
+                       Hooks::run( 'MessagesPreLoad', array( $title, &$message ) );
                        if ( $message !== false ) {
                                return $message;
                        }
index 55da52c..6d26a2d 100644 (file)
@@ -40,7 +40,9 @@ class ResourceFileCache extends FileCacheBase {
        public static function newFromContext( ResourceLoaderContext $context ) {
                $cache = new self();
 
-               if ( $context->getOnly() === 'styles' ) {
+               if ( $context->getImage() ) {
+                       $cache->mType = 'image';
+               } elseif ( $context->getOnly() === 'styles' ) {
                        $cache->mType = 'css';
                } else {
                        $cache->mType = 'js';
@@ -69,7 +71,8 @@ class ResourceFileCache extends FileCacheBase {
                // Get all query values
                $queryVals = $context->getRequest()->getValues();
                foreach ( $queryVals as $query => $val ) {
-                       if ( $query === 'modules' || $query === 'version' || $query === '*' ) {
+                       if ( in_array( $query, array( 'modules', 'image', 'variant', 'version', '*' ) ) ) {
+                               // Use file cache regardless of the value of this parameter
                                continue; // note: &* added as IE fix
                        } elseif ( $query === 'skin' && $val === $wgDefaultSkin ) {
                                continue;
@@ -79,6 +82,8 @@ class ResourceFileCache extends FileCacheBase {
                                continue;
                        } elseif ( $query === 'debug' && $val === 'false' ) {
                                continue;
+                       } elseif ( $query === 'format' && $val === 'rasterized' ) {
+                               continue;
                        }
 
                        return false;
index 03d1289..932006d 100644 (file)
@@ -67,7 +67,7 @@ class ChangesList extends ContextSource {
                $user = $context->getUser();
                $sk = $context->getSkin();
                $list = null;
-               if ( wfRunHooks( 'FetchChangesList', array( $user, &$sk, &$list ) ) ) {
+               if ( Hooks::run( 'FetchChangesList', array( $user, &$sk, &$list ) ) ) {
                        $new = $context->getRequest()->getBool( 'enhanced', $user->getOption( 'usenewrc' ) );
 
                        return $new ? new EnhancedChangesList( $context ) : new OldChangesList( $context );
@@ -180,7 +180,7 @@ class ChangesList extends ContextSource {
         * @param ResultWrapper|array $rows
         */
        public function initChangesListRows( $rows ) {
-               wfRunHooks( 'ChangesListInitRows', array( $this, $rows ) );
+               Hooks::run( 'ChangesListInitRows', array( $this, $rows ) );
        }
 
        /**
@@ -364,7 +364,7 @@ class ChangesList extends ContextSource {
                # RTL/LTR marker
                $articlelink .= $this->getLanguage()->getDirMark();
 
-               wfRunHooks( 'ChangesListInsertArticleLink',
+               Hooks::run( 'ChangesListInsertArticleLink',
                        array( &$this, &$articlelink, &$s, &$rc, $unpatrolled, $watched ) );
 
                $s .= " $articlelink";
index 4eed926..5067886 100644 (file)
@@ -56,7 +56,7 @@ class OldChangesList extends ChangesList {
                                $rc->mAttribs['rc_namespace'] . '-' . $rc->mAttribs['rc_title'] );
                }
 
-               if ( !wfRunHooks( 'OldChangesListRecentChangesLine', array( &$this, &$html, $rc, &$classes ) ) ) {
+               if ( !Hooks::run( 'OldChangesListRecentChangesLine', array( &$this, &$html, $rc, &$classes ) ) ) {
                        wfProfileOut( __METHOD__ );
 
                        return false;
@@ -73,7 +73,7 @@ class OldChangesList extends ChangesList {
        /**
         * @param RecentChange $rc
         * @param string[] &$classes
-        * @param boolean $watched
+        * @param bool $watched
         *
         * @return string
         */
index d187c54..c719d8d 100644 (file)
@@ -257,7 +257,7 @@ class RecentChange {
        public function getPerformer() {
                if ( $this->mPerformer === false ) {
                        if ( $this->mAttribs['rc_user'] ) {
-                               $this->mPerformer = User::newFromID( $this->mAttribs['rc_user'] );
+                               $this->mPerformer = User::newFromId( $this->mAttribs['rc_user'] );
                        } else {
                                $this->mPerformer = User::newFromName( $this->mAttribs['rc_user_text'], false );
                        }
@@ -309,7 +309,7 @@ class RecentChange {
                $this->mAttribs['rc_id'] = $dbw->insertId();
 
                # Notify extensions
-               wfRunHooks( 'RecentChange_save', array( &$this ) );
+               Hooks::run( 'RecentChange_save', array( &$this ) );
 
                # Notify external application via UDP
                if ( !$noudp ) {
@@ -321,7 +321,7 @@ class RecentChange {
                        $editor = $this->getPerformer();
                        $title = $this->getTitle();
 
-                       if ( wfRunHooks( 'AbortEmailNotification', array( $editor, $title, $this ) ) ) {
+                       if ( Hooks::run( 'AbortEmailNotification', array( $editor, $title, $this ) ) ) {
                                # @todo FIXME: This would be better as an extension hook
                                $enotif = new EmailNotification();
                                $enotif->notifyOnPageChange( $editor, $title,
@@ -445,7 +445,7 @@ class RecentChange {
                // Automatic patrol needs "autopatrol", ordinary patrol needs "patrol"
                $right = $auto ? 'autopatrol' : 'patrol';
                $errors = array_merge( $errors, $this->getTitle()->getUserPermissionsErrors( $right, $user ) );
-               if ( !wfRunHooks( 'MarkPatrolled', array( $this->getAttribute( 'rc_id' ), &$user, false ) ) ) {
+               if ( !Hooks::run( 'MarkPatrolled', array( $this->getAttribute( 'rc_id' ), &$user, false ) ) ) {
                        $errors[] = array( 'hookaborted' );
                }
                // Users without the 'autopatrol' right can't patrol their
@@ -466,7 +466,7 @@ class RecentChange {
                $this->reallyMarkPatrolled();
                // Log this patrol event
                PatrolLog::record( $this, $auto, $user );
-               wfRunHooks( 'MarkPatrolledComplete', array( $this->getAttribute( 'rc_id' ), &$user, false ) );
+               Hooks::run( 'MarkPatrolledComplete', array( $this->getAttribute( 'rc_id' ), &$user, false ) );
 
                return array();
        }
index cb39fac..816572c 100644 (file)
@@ -446,7 +446,7 @@ abstract class AbstractContent implements Content {
                $lossy = ( $lossy === 'lossy' ); // string flag, convert to boolean for convenience
                $result = false;
 
-               wfRunHooks( 'ConvertContent', array( $this, $toModel, $lossy, &$result ) );
+               Hooks::run( 'ConvertContent', array( $this, $toModel, $lossy, &$result ) );
 
                return $result;
        }
@@ -480,7 +480,7 @@ abstract class AbstractContent implements Content {
 
                $po = new ParserOutput();
 
-               if ( wfRunHooks( 'ContentGetParserOutput',
+               if ( Hooks::run( 'ContentGetParserOutput',
                        array( $this, $title, $revId, $options, $generateHtml, &$po ) ) ) {
 
                        // Save and restore the old value, just in case something is reusing
@@ -491,7 +491,7 @@ abstract class AbstractContent implements Content {
                        $options->setRedirectTarget( $oldRedir );
                }
 
-               wfRunHooks( 'ContentAlterParserOutput', array( $this, $title, $po ) );
+               Hooks::run( 'ContentAlterParserOutput', array( $this, $title, $po ) );
 
                return $po;
        }
index 9aa42dd..8c806c6 100644 (file)
@@ -201,7 +201,7 @@ abstract class ContentHandler {
                $model = MWNamespace::getNamespaceContentModel( $ns );
 
                // Hook can determine default model
-               if ( !wfRunHooks( 'ContentHandlerDefaultModelFor', array( $title, &$model ) ) ) {
+               if ( !Hooks::run( 'ContentHandlerDefaultModelFor', array( $title, &$model ) ) ) {
                        if ( !is_null( $model ) ) {
                                return $model;
                        }
@@ -214,7 +214,7 @@ abstract class ContentHandler {
                }
 
                // Hook can force JS/CSS
-               wfRunHooks( 'TitleIsCssOrJsPage', array( $title, &$isCssOrJsPage ), '1.25' );
+               Hooks::run( 'TitleIsCssOrJsPage', array( $title, &$isCssOrJsPage ), '1.25' );
 
                // Is this a .css subpage of a user page?
                $isJsCssSubpage = NS_USER == $ns
@@ -229,7 +229,7 @@ abstract class ContentHandler {
                $isWikitext = $isWikitext && !$isCssOrJsPage && !$isJsCssSubpage;
 
                // Hook can override $isWikitext
-               wfRunHooks( 'TitleIsWikitextPage', array( $title, &$isWikitext ), '1.25' );
+               Hooks::run( 'TitleIsWikitextPage', array( $title, &$isWikitext ), '1.25' );
 
                if ( !$isWikitext ) {
                        switch ( $ext ) {
@@ -318,7 +318,7 @@ abstract class ContentHandler {
                if ( empty( $wgContentHandlers[$modelId] ) ) {
                        $handler = null;
 
-                       wfRunHooks( 'ContentHandlerForModelID', array( $modelId, &$handler ) );
+                       Hooks::run( 'ContentHandlerForModelID', array( $modelId, &$handler ) );
 
                        if ( $handler === null ) {
                                throw new MWException( "No handler for model '$modelId' registered in \$wgContentHandlers" );
@@ -660,7 +660,7 @@ abstract class ContentHandler {
                        $pageLang = wfGetLangObj( $lang );
                }
 
-               wfRunHooks( 'PageContentLanguage', array( $title, &$pageLang, $wgLang ) );
+               Hooks::run( 'PageContentLanguage', array( $title, &$pageLang, $wgLang ) );
 
                return wfGetLangObj( $pageLang );
        }
@@ -719,7 +719,7 @@ abstract class ContentHandler {
        public function canBeUsedOn( Title $title ) {
                $ok = true;
 
-               wfRunHooks( 'ContentModelCanBeUsedOn', array( $this->getModelID(), $title, &$ok ) );
+               Hooks::run( 'ContentModelCanBeUsedOn', array( $this->getModelID(), $title, &$ok ) );
 
                return $ok;
        }
@@ -1151,7 +1151,7 @@ abstract class ContentHandler {
                }
 
                // call the hook functions
-               $ok = wfRunHooks( $event, $args );
+               $ok = Hooks::run( $event, $args );
 
                // see if the hook changed the text
                foreach ( $contentTexts as $k => $orig ) {
index 9a8ab3a..7593d7c 100644 (file)
@@ -93,7 +93,7 @@ class WikitextContent extends TextContent {
                        # Inserting a new section
                        $subject = $sectionTitle ? wfMessage( 'newsectionheaderdefaultlevel' )
                                        ->rawParams( $sectionTitle )->inContentLanguage()->text() . "\n\n" : '';
-                       if ( wfRunHooks( 'PlaceNewSection', array( $this, $oldtext, $subject, &$text ) ) ) {
+                       if ( Hooks::run( 'PlaceNewSection', array( $this, $oldtext, $subject, &$text ) ) ) {
                                $text = strlen( trim( $oldtext ) ) > 0
                                        ? "{$oldtext}\n\n{$subject}{$text}"
                                        : "{$subject}{$text}";
index d620be9..c76e3a9 100644 (file)
@@ -140,7 +140,7 @@ class RequestContext implements IContextSource {
                if ( $this->title === null ) {
                        global $wgTitle; # fallback to $wg till we can improve this
                        $this->title = $wgTitle;
-                       wfDebugLog( 'GlobalTitleFail', __METHOD__ . ' called by ' . wfGetAllCallers() . ' with no title set.' );
+                       wfDebugLog( 'GlobalTitleFail', __METHOD__ . ' called by ' . wfGetAllCallers( 5 ) . ' with no title set.' );
                }
 
                return $this->title;
@@ -182,9 +182,8 @@ class RequestContext implements IContextSource {
         * @param WikiPage $p
         */
        public function setWikiPage( WikiPage $p ) {
-               $contextTitle = $this->getTitle();
                $pageTitle = $p->getTitle();
-               if ( !$contextTitle || !$pageTitle->equals( $contextTitle ) ) {
+               if ( !$this->hasTitle() || !$pageTitle->equals( $this->getTitle() ) ) {
                        $this->setTitle( $pageTitle );
                }
                // Defer this to the end since setTitle sets it to null.
@@ -322,7 +321,7 @@ class RequestContext implements IContextSource {
                                $code = $request->getVal( 'uselang', $user->getOption( 'language' ) );
                                $code = self::sanitizeLangCode( $code );
 
-                               wfRunHooks( 'UserGetLanguageObject', array( $user, &$code, $this ) );
+                               Hooks::run( 'UserGetLanguageObject', array( $user, &$code, $this ) );
 
                                if ( $code === $this->getConfig()->get( 'LanguageCode' ) ) {
                                        $this->lang = $wgContLang;
@@ -362,7 +361,7 @@ class RequestContext implements IContextSource {
                        wfProfileIn( __METHOD__ . '-createskin' );
 
                        $skin = null;
-                       wfRunHooks( 'RequestContextCreateSkin', array( $this, &$skin ) );
+                       Hooks::run( 'RequestContextCreateSkin', array( $this, &$skin ) );
                        $factory = SkinFactory::getDefaultInstance();
 
                        // If the hook worked try to set a skin from it
index 6c53f6a..6d27d86 100644 (file)
@@ -46,9 +46,8 @@ abstract class DatabaseBase implements IDatabase {
        /** Maximum time to wait before retry */
        const DEADLOCK_DELAY_MAX = 1500000;
 
-# ------------------------------------------------------------------------------
-# Variables
-# ------------------------------------------------------------------------------
+       /** How many row changes in a write query trigger a log entry */
+       const LOG_WRITE_THRESHOLD = 300;
 
        protected $mLastQuery = '';
        protected $mDoneWrites = false;
@@ -157,11 +156,6 @@ abstract class DatabaseBase implements IDatabase {
         */
        protected $allViews = null;
 
-# ------------------------------------------------------------------------------
-# Accessors
-# ------------------------------------------------------------------------------
-       # These optionally set a variable and return the previous state
-
        /**
         * A string describing the current software version, and possibly
         * other details in a user-friendly way. Will be listed on Special:Version, etc.
@@ -588,9 +582,167 @@ abstract class DatabaseBase implements IDatabase {
                return $this->getSqlFilePath( 'update-keys.sql' );
        }
 
-# ------------------------------------------------------------------------------
-# Other functions
-# ------------------------------------------------------------------------------
+       /**
+        * 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
+        * @param string $fname Calling function name
+        * @return mixed Database-specific index description class or false if the index does not exist
+        */
+       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.
+        * @return string Slashed string.
+        */
+       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.
@@ -913,7 +1065,9 @@ abstract class DatabaseBase implements IDatabase {
                global $wgUser, $wgDebugDBTransactions, $wgDebugDumpSqlLength;
 
                $this->mLastQuery = $sql;
-               if ( $this->isWriteQuery( $sql ) ) {
+
+               $isWriteQuery = $this->isWriteQuery( $sql );
+               if ( $isWriteQuery ) {
                        # Set a flag indicating that writes have been done
                        wfDebug( __METHOD__ . ': Writes done: ' . DatabaseBase::generalizeSQL( $sql ) . "\n" );
                        $this->mDoneWrites = microtime( true );
@@ -952,7 +1106,7 @@ abstract class DatabaseBase implements IDatabase {
                }
 
                # Keep track of whether the transaction has write queries pending
-               if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $this->isWriteQuery( $sql ) ) {
+               if ( $this->mTrxLevel && !$this->mTrxDoneWrites && $isWriteQuery ) {
                        $this->mTrxDoneWrites = true;
                        Profiler::instance()->getTransactionProfiler()->transactionWritingIn(
                                $this->mServer, $this->mDBname, $this->mTrxShortId );
@@ -1003,7 +1157,7 @@ abstract class DatabaseBase implements IDatabase {
                if ( $queryProf != '' ) {
                        $queryStartTime = microtime( true );
                        $queryProfile = new ScopedCallback(
-                               function() use ( $queryStartTime, $queryProf, $isMaster ) {
+                               function () use ( $queryStartTime, $queryProf, $isMaster ) {
                                        $trxProfiler = Profiler::instance()->getTransactionProfiler();
                                        $trxProfiler->recordQueryCompletion( $queryProf, $queryStartTime, $isMaster );
                                }
@@ -1047,9 +1201,21 @@ abstract class DatabaseBase implements IDatabase {
 
                if ( false === $ret ) {
                        $this->reportQueryError( $this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore );
+               } else {
+                       $n = $this->affectedRows();
+                       if ( $isWriteQuery && $n > self::LOG_WRITE_THRESHOLD && PHP_SAPI !== 'cli' ) {
+                               wfDebugLog( 'DBPerformance',
+                                       "Query affected $n rows:\n$sql\n" . wfBacktrace( true ) );
+                       }
                }
 
-               return $this->resultObject( $ret );
+               $res = $this->resultObject( $ret );
+
+               // Destroy profile sections in the opposite order to their creation
+               $queryProfSection = false;
+               $totalProfSection = false;
+
+               return $res;
        }
 
        /**
index 7dfae63..430b20c 100644 (file)
@@ -1271,13 +1271,15 @@ class MySQLField implements Field {
 class MySQLMasterPos implements DBMasterPos {
        /** @var string */
        public $file;
-
-       /** @var int Timestamp */
+       /** @var int Position */
        public $pos;
+       /** @var float UNIX timestamp */
+       public $asOfTime = 0.0;
 
        function __construct( $file, $pos ) {
                $this->file = $file;
                $this->pos = $pos;
+               $this->asOfTime = microtime( true );
        }
 
        function __toString() {
@@ -1303,4 +1305,8 @@ class MySQLMasterPos implements DBMasterPos {
 
                return ( $thisPos && $thatPos && $thisPos >= $thatPos );
        }
+
+       function asOfTime() {
+               return $this->asOfTime;
+       }
 }
index f031f78..e150206 100644 (file)
@@ -229,7 +229,7 @@ class DatabaseOracle extends DatabaseBase {
                }
                $p['tablePrefix'] = strtoupper( $p['tablePrefix'] );
                parent::__construct( $p );
-               wfRunHooks( 'DatabaseOraclePostInit', array( $this ) );
+               Hooks::run( 'DatabaseOraclePostInit', array( $this ) );
        }
 
        function __destruct() {
index c1e80d3..4e5ed08 100644 (file)
@@ -339,4 +339,8 @@ class LikeMatch {
  * The implementation details of this opaque type are up to the database subclass.
  */
 interface DBMasterPos {
+       /**
+        * @return float UNIX timestamp
+        */
+       public function asOfTime();
 }
index e049a5d..4551e2d 100644 (file)
@@ -43,7 +43,7 @@ abstract class LBFactory {
         *
         * @return LBFactory
         */
-       public static function &singleton() {
+       public static function singleton() {
                global $wgLBFactoryConf;
 
                if ( is_null( self::$instance ) ) {
@@ -109,7 +109,7 @@ abstract class LBFactory {
         * Construct a factory based on a configuration array (typically from $wgLBFactoryConf)
         * @param array $conf
         */
-       public abstract function __construct( array $conf );
+       abstract public function __construct( array $conf );
 
        /**
         * Create a new load balancer object. The resulting object will be untracked,
@@ -118,7 +118,7 @@ abstract class LBFactory {
         * @param bool|string $wiki Wiki ID, or false for the current wiki
         * @return LoadBalancer
         */
-       public abstract function newMainLB( $wiki = false );
+       abstract public function newMainLB( $wiki = false );
 
        /**
         * Get a cached (tracked) load balancer object.
@@ -126,7 +126,7 @@ abstract class LBFactory {
         * @param bool|string $wiki Wiki ID, or false for the current wiki
         * @return LoadBalancer
         */
-       public abstract function getMainLB( $wiki = false );
+       abstract public function getMainLB( $wiki = false );
 
        /**
         * Create a new load balancer for external storage. The resulting object will be
@@ -137,7 +137,7 @@ abstract class LBFactory {
         * @param bool|string $wiki Wiki ID, or false for the current wiki
         * @return LoadBalancer
         */
-       protected abstract function newExternalLB( $cluster, $wiki = false );
+       abstract protected function newExternalLB( $cluster, $wiki = false );
 
        /**
         * Get a cached (tracked) load balancer for external storage
@@ -146,7 +146,7 @@ abstract class LBFactory {
         * @param bool|string $wiki Wiki ID, or false for the current wiki
         * @return LoadBalancer
         */
-       public abstract function &getExternalLB( $cluster, $wiki = false );
+       abstract public function &getExternalLB( $cluster, $wiki = false );
 
        /**
         * Execute a function for each tracked load balancer
@@ -156,7 +156,7 @@ abstract class LBFactory {
         * @param callable $callback
         * @param array $params
         */
-       public abstract function forEachLB( $callback, array $params = array() );
+       abstract public function forEachLB( $callback, array $params = array() );
 
        /**
         * Prepare all tracked load balancers for shutdown
@@ -172,7 +172,7 @@ abstract class LBFactory {
         * @param array $args
         */
        private function forEachLBCallMethod( $methodName, array $args = array() ) {
-               $this->forEachLB( function( LoadBalancer $loadBalancer, $methodName, array $args ) {
+               $this->forEachLB( function ( LoadBalancer $loadBalancer, $methodName, array $args ) {
                        call_user_func_array( array( $loadBalancer, $methodName ), $args );
                }, array( $methodName, $args ) );
        }
index 07645bd..f1b3238 100644 (file)
@@ -151,17 +151,23 @@ class LoadBalancer {
        /**
         * @param array $loads
         * @param bool|string $wiki Wiki to get non-lagged for
+        * @param float $maxLag Restrict the maximum allowed lag to this many seconds
         * @return bool|int|string
         */
-       private function getRandomNonLagged( array $loads, $wiki = false ) {
-               # Unset excessively lagged servers
+       private function getRandomNonLagged( array $loads, $wiki = false, $maxLag = INF ) {
                $lags = $this->getLagTimes( $wiki );
+
+               # Unset excessively lagged servers
                foreach ( $lags as $i => $lag ) {
                        if ( $i != 0 ) {
+                               $maxServerLag = $maxLag;
+                               if ( isset( $this->mServers[$i]['max lag'] ) ) {
+                                       $maxServerLag = min( $maxServerLag, $this->mServers[$i]['max lag'] );
+                               }
                                if ( $lag === false ) {
                                        wfDebugLog( 'replication', "Server #$i is not replicating" );
                                        unset( $loads[$i] );
-                               } elseif ( isset( $this->mServers[$i]['max lag'] ) && $lag > $this->mServers[$i]['max lag'] ) {
+                               } elseif ( $lag > $maxServerLag ) {
                                        wfDebugLog( 'replication', "Server #$i is excessively lagged ($lag seconds)" );
                                        unset( $loads[$i] );
                                }
@@ -252,7 +258,19 @@ class LoadBalancer {
                        if ( $wgReadOnly || $this->mAllowLagged || $laggedSlaveMode ) {
                                $i = ArrayUtils::pickRandom( $currentLoads );
                        } else {
-                               $i = $this->getRandomNonLagged( $currentLoads, $wiki );
+                               $i = false;
+                               if ( $this->mWaitForPos && $this->mWaitForPos->asOfTime() ) {
+                                       # ChronologyProtecter causes mWaitForPos to be set via sessions.
+                                       # This triggers doWait() after connect, so it's especially good to
+                                       # avoid lagged servers so as to avoid just blocking in that method.
+                                       $ago = microtime( true ) - $this->mWaitForPos->asOfTime();
+                                       # Aim for <= 1 second of waiting (being too picky can backfire)
+                                       $i = $this->getRandomNonLagged( $currentLoads, $wiki, $ago + 1 );
+                               }
+                               if ( $i === false ) {
+                                       # Any server with less lag than it's 'max lag' param is preferable
+                                       $i = $this->getRandomNonLagged( $currentLoads, $wiki );
+                               }
                                if ( $i === false && count( $currentLoads ) != 0 ) {
                                        # All slaves lagged. Switch to read-only mode
                                        wfDebugLog( 'replication', "All slaves lagged. Switch to read-only mode" );
@@ -438,7 +456,7 @@ class LoadBalancer {
         * @throws MWException
         * @return DatabaseBase
         */
-       public function &getConnection( $i, $groups = array(), $wiki = false ) {
+       public function getConnection( $i, $groups = array(), $wiki = false ) {
                wfProfileIn( __METHOD__ );
 
                if ( $i === null || $i === false ) {
@@ -451,17 +469,14 @@ class LoadBalancer {
                        $wiki = false;
                }
 
-               # Query groups
+               $groups = ( $groups === false || $groups === array() )
+                       ? array( false ) // check one "group": the generic pool
+                       : (array)$groups;
+
                if ( $i == DB_MASTER ) {
                        $i = $this->getWriterIndex();
-               } elseif ( !is_array( $groups ) ) {
-                       $groupIndex = $this->getReaderIndex( $groups, $wiki );
-                       if ( $groupIndex !== false ) {
-                               $serverName = $this->getServerName( $groupIndex );
-                               wfDebug( __METHOD__ . ": using server $serverName for group $groups\n" );
-                               $i = $groupIndex;
-                       }
                } else {
+                       # Try to find an available server in any the query groups (in order)
                        foreach ( $groups as $group ) {
                                $groupIndex = $this->getReaderIndex( $group, $wiki );
                                if ( $groupIndex !== false ) {
@@ -476,7 +491,10 @@ class LoadBalancer {
                # Operation-based index
                if ( $i == DB_SLAVE ) {
                        $this->mLastError = 'Unknown error'; // reset error string
-                       $i = $this->getReaderIndex( false, $wiki );
+                       # Try the general server pool if $groups are unavailable.
+                       $i = in_array( false, $groups, true )
+                               ? false // don't bother with this if that is what was tried above
+                               : $this->getReaderIndex( false, $wiki );
                        # Couldn't find a working server in getReaderIndex()?
                        if ( $i === false ) {
                                $this->mLastError = 'No working slave server: ' . $this->mLastError;
index c43e3d6..4ad5687 100644 (file)
@@ -218,7 +218,11 @@ class MWLoggerMonologSpi implements MWLoggerSpi {
                if ( !isset( $this->singletons['handlers'][$name] ) ) {
                        $spec = $this->config['handlers'][$name];
                        $handler = ObjectFactory::getObjectFromSpec( $spec );
-                       $handler->setFormatter( $this->getFormatter( $spec['formatter'] ) );
+                       if ( isset( $spec['formatter'] ) ) {
+                               $handler->setFormatter(
+                                       $this->getFormatter( $spec['formatter'] )
+                               );
+                       }
                        $this->singletons['handlers'][$name] = $handler;
                }
                return $this->singletons['handlers'][$name];
index 45d2664..4e5af0b 100644 (file)
@@ -140,16 +140,16 @@ class LinksUpdate extends SqlDataUpdate {
 
                $this->mRecursive = $recursive;
 
-               wfRunHooks( 'LinksUpdateConstructed', array( &$this ) );
+               Hooks::run( 'LinksUpdateConstructed', array( &$this ) );
        }
 
        /**
         * Update link tables with outgoing links from an updated article
         */
        public function doUpdate() {
-               wfRunHooks( 'LinksUpdate', array( &$this ) );
+               Hooks::run( 'LinksUpdate', array( &$this ) );
                $this->doIncrementalUpdate();
-               wfRunHooks( 'LinksUpdateComplete', array( &$this ) );
+               Hooks::run( 'LinksUpdateComplete', array( &$this ) );
        }
 
        protected function doIncrementalUpdate() {
@@ -339,7 +339,7 @@ class LinksUpdate extends SqlDataUpdate {
                }
                if ( count( $insertions ) ) {
                        $this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' );
-                       wfRunHooks( 'LinksUpdateAfterInsert', array( $this, $table, $insertions ) );
+                       Hooks::run( 'LinksUpdateAfterInsert', array( $this, $table, $insertions ) );
                }
        }
 
index 5d084af..8808c20 100644 (file)
@@ -80,7 +80,7 @@ class SearchUpdate implements DeferrableUpdate {
 
                wfProfileIn( __METHOD__ );
 
-               $page = WikiPage::newFromId( $this->id, WikiPage::READ_LATEST );
+               $page = WikiPage::newFromID( $this->id, WikiPage::READ_LATEST );
 
                foreach ( SearchEngine::getSearchTypes() as $type ) {
                        $search = SearchEngine::create( $type );
index dd5f3c7..c887193 100644 (file)
@@ -283,7 +283,7 @@ class DifferenceEngine extends ContextSource {
                        $samePage = true;
                        $oldHeader = '';
                } else {
-                       wfRunHooks( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) );
+                       Hooks::run( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) );
 
                        if ( $this->mNewPage->equals( $this->mOldPage ) ) {
                                $out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) );
@@ -387,7 +387,7 @@ class DifferenceEngine extends ContextSource {
                $rdel = $this->revisionDeleteLink( $this->mNewRev );
 
                # Allow extensions to define their own revision tools
-               wfRunHooks( 'DiffRevisionTools', array( $this->mNewRev, &$revisionTools, $this->mOldRev ) );
+               Hooks::run( 'DiffRevisionTools', array( $this->mNewRev, &$revisionTools, $this->mOldRev ) );
                $formattedRevisionTools = array();
                // Put each one in parentheses (poor man's button)
                foreach ( $revisionTools as $key => $tool ) {
@@ -555,7 +555,7 @@ class DifferenceEngine extends ContextSource {
                <h2 class='diff-currentversion-title'>{$revHeader}</h2>\n" );
                # Page content may be handled by a hooked call instead...
                # @codingStandardsIgnoreStart Ignoring long lines.
-               if ( wfRunHooks( 'ArticleContentOnDiff', array( $this, $out ) ) ) {
+               if ( Hooks::run( 'ArticleContentOnDiff', array( $this, $out ) ) ) {
                        $this->loadNewText();
                        $out->setRevisionId( $this->mNewid );
                        $out->setRevisionTimestamp( $this->mNewRev->getTimestamp() );
@@ -575,7 +575,7 @@ class DifferenceEngine extends ContextSource {
                                                $out->addParserOutputContent( $po );
                                        }
                                }
-                       } elseif ( !wfRunHooks( 'ArticleContentViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) {
+                       } elseif ( !Hooks::run( 'ArticleContentViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) {
                                // Handled by extension
                        } elseif ( !ContentHandler::runLegacyHooks( 'ArticleViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) {
                                // NOTE: deprecated hook, B/C only
@@ -742,7 +742,7 @@ class DifferenceEngine extends ContextSource {
                $difftext = $this->generateContentDiffBody( $this->mOldContent, $this->mNewContent );
 
                // Save to cache for 7 days
-               if ( !wfRunHooks( 'AbortDiffCache', array( &$this ) ) ) {
+               if ( !Hooks::run( 'AbortDiffCache', array( &$this ) ) ) {
                        wfIncrStats( 'diff_uncacheable' );
                } elseif ( $key !== false && $difftext !== false ) {
                        wfIncrStats( 'diff_cache_miss' );
@@ -1224,7 +1224,7 @@ class DifferenceEngine extends ContextSource {
                        $this->mNewid = 0;
                }
 
-               wfRunHooks(
+               Hooks::run(
                        'NewDifferenceEngine',
                        array( $this->getTitle(), &$this->mOldid, &$this->mNewid, $old, $new )
                );
index 9db04cb..83801b6 100644 (file)
  */
 class MWExceptionHandler {
 
+       protected static $reservedMemory;
+       protected static $fatalErrorTypes = array(
+               E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR,
+               /* HHVM's FATAL_ERROR level */ 16777217,
+       );
+
        /**
         * Install handlers with PHP.
         */
        public static function installHandler() {
                set_exception_handler( array( 'MWExceptionHandler', 'handleException' ) );
                set_error_handler( array( 'MWExceptionHandler', 'handleError' ) );
+
+               // Reserve 16k of memory so we can report OOM fatals
+               self::$reservedMemory = str_repeat( ' ', 16384 );
+               register_shutdown_function(
+                       array( 'MWExceptionHandler', 'handleFatalError' )
+               );
        }
 
        /**
@@ -194,6 +206,9 @@ class MWExceptionHandler {
                        case E_USER_DEPRECATED:
                                $levelName = 'Deprecated';
                                break;
+                       case /* HHVM's FATAL_ERROR */ 16777217:
+                               $levelName = 'Fatal';
+                               break;
                        default:
                                $levelName = 'Unknown error';
                                break;
@@ -207,6 +222,44 @@ class MWExceptionHandler {
                return false;
        }
 
+
+       /**
+        * Look for a fatal error as the cause of the request termination and log
+        * as an exception.
+        *
+        * 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
+        */
+       public static function handleFatalError() {
+               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']
+                       ) ) {
+                               $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;
+                       }
+                       $e = new ErrorException( $msg, 0, $lastError['type'] );
+                       self::logError( $e );
+               }
+       }
+
        /**
         * Generate a string representation of an exception's stack trace
         *
index 9aa4ca8..c00fb81 100644 (file)
@@ -454,10 +454,10 @@ class FSFileBackend extends FileBackendStore {
                        wfDebugLog( 'FSFileBackend', __METHOD__ . ": cannot create directory $dir" );
                        $status->fatal( 'directorycreateerror', $params['dir'] ); // fails on races
                } elseif ( !is_writable( $dir ) ) {
-                       wfDebugLog( 'FSFileBackend',  __METHOD__ . ": directory $dir is read-only" );
+                       wfDebugLog( 'FSFileBackend', __METHOD__ . ": directory $dir is read-only" );
                        $status->fatal( 'directoryreadonlyerror', $params['dir'] );
                } elseif ( !is_readable( $dir ) ) {
-                       wfDebugLog( 'FSFileBackend',  __METHOD__ . ": directory $dir is not readable" );
+                       wfDebugLog( 'FSFileBackend', __METHOD__ . ": directory $dir is not readable" );
                        $status->fatal( 'directorynotreadableerror', $params['dir'] );
                }
                $this->untrapWarnings();
index 8b6eaca..f2d13ee 100644 (file)
@@ -299,7 +299,7 @@ class FileBackendMultiWrite extends FileBackend {
 
        /**
         * Check that a set of files are consistent across all internal backends
-        * and re-synchronize those files againt the "multi master" if needed.
+        * and re-synchronize those files against the "multi master" if needed.
         *
         * @param array $paths List of storage paths
         * @return Status
index 450ccc8..affcf44 100644 (file)
@@ -52,7 +52,7 @@ abstract class DBLockManager extends QuorumLockManager {
        /**
         * Construct a new instance from configuration.
         *
-        * @param array $config Paramaters include:
+        * @param array $config Parameters include:
         *   - dbServers   : Associative array of DB names to server configuration.
         *                   Configuration is an associative array that includes:
         *                     - host        : DB server name
index 762bc66..9253f2e 100644 (file)
@@ -64,7 +64,7 @@ abstract class LockManager {
        /**
         * Construct a new instance from configuration
         *
-        * @param array $config Paramaters include:
+        * @param array $config Parameters include:
         *   - domain  : Domain (usually wiki ID) that all resources are relative to [optional]
         *   - lockTTL : Age (in seconds) at which resource locks should expire.
         *               This only applies if locks are not tied to a connection/process.
index 9bb01c2..16d3de1 100644 (file)
@@ -55,7 +55,7 @@ class MemcLockManager extends QuorumLockManager {
        /**
         * Construct a new instance from configuration.
         *
-        * @param array $config Paramaters include:
+        * @param array $config Parameters include:
         *   - lockServers  : Associative array of server names to "<IP>:<port>" strings.
         *   - srvsByBucket : Array of 1-16 consecutive integer keys, starting from 0,
         *                    each having an odd-numbered list of server names (peers) as values.
index c82be50..600421f 100644 (file)
@@ -138,10 +138,10 @@ abstract class File {
        /** @var Title */
        protected $redirectTitle;
 
-       /** @var bool Wether the output of transform() for this file is likely to be valid. */
+       /** @var bool Whether the output of transform() for this file is likely to be valid. */
        protected $canRender;
 
-       /** @var bool Wether this media file is in a format that is unlikely to
+       /** @var bool Whether this media file is in a format that is unlikely to
         *    contain viruses or malicious content
         */
        protected $isSafeFile;
@@ -492,7 +492,7 @@ abstract class File {
                sort( $sortedBuckets );
 
                foreach ( $sortedBuckets as $bucket ) {
-                       if ( $bucket > $imageWidth ) {
+                       if ( $bucket >= $imageWidth ) {
                                return false;
                        }
 
@@ -1125,7 +1125,7 @@ abstract class File {
                                $thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $transformParams, $flags );
                        }
                        // Give extensions a chance to do something with this thumbnail...
-                       wfRunHooks( 'FileTransformed', array( $this, $thumb, $tmpThumbPath, $thumbPath ) );
+                       Hooks::run( 'FileTransformed', array( $this, $thumb, $tmpThumbPath, $thumbPath ) );
                }
 
                // Purge. Useful in the event of Core -> Squid connection failure or squid
@@ -1460,7 +1460,7 @@ abstract class File {
 
        /**
         * Get the path of the file relative to the public zone root.
-        * This function is overriden in OldLocalFile to be like getArchiveRel().
+        * This function is overridden in OldLocalFile to be like getArchiveRel().
         *
         * @return string
         */
@@ -1504,7 +1504,7 @@ abstract class File {
 
        /**
         * Get urlencoded path of the file relative to the public zone root.
-        * This function is overriden in OldLocalFile to be like getArchiveUrl().
+        * This function is overridden in OldLocalFile to be like getArchiveUrl().
         *
         * @return string
         */
index 9f14669..eb0f654 100644 (file)
@@ -672,7 +672,7 @@ class LocalFile extends File {
        /** getURL inherited */
        /** getViewURL inherited */
        /** getPath inherited */
-       /** isVisible inhereted */
+       /** isVisible inherited */
 
        /**
         * @return bool
@@ -913,7 +913,7 @@ class LocalFile extends File {
                $files = $this->getThumbnails( $archiveName );
 
                // Purge any custom thumbnail caches
-               wfRunHooks( 'LocalFilePurgeThumbnails', array( $this, $archiveName ) );
+               Hooks::run( 'LocalFilePurgeThumbnails', array( $this, $archiveName ) );
 
                $dir = array_shift( $files );
                $this->purgeThumbList( $dir, $files );
@@ -958,7 +958,7 @@ class LocalFile extends File {
                }
 
                // Purge any custom thumbnail caches
-               wfRunHooks( 'LocalFilePurgeThumbnails', array( $this, false ) );
+               Hooks::run( 'LocalFilePurgeThumbnails', array( $this, false ) );
 
                $dir = array_shift( $files );
                $this->purgeThumbList( $dir, $files );
@@ -1035,7 +1035,7 @@ class LocalFile extends File {
                $opts['ORDER BY'] = "oi_timestamp $order";
                $opts['USE INDEX'] = array( 'oldimage' => 'oi_name_timestamp' );
 
-               wfRunHooks( 'LocalFile::getHistory', array( &$this, &$tables, &$fields,
+               Hooks::run( 'LocalFile::getHistory', array( &$this, &$tables, &$fields,
                        &$conds, &$opts, &$join_conds ) );
 
                $res = $dbr->select( $tables, $fields, $conds, __METHOD__, $opts, $join_conds );
@@ -1423,7 +1423,7 @@ class LocalFile extends File {
                        if ( !is_null( $nullRevision ) ) {
                                $nullRevision->insertOn( $dbw );
 
-                               wfRunHooks( 'NewRevisionFromEditComplete', array( $wikiPage, $nullRevision, $latest, $user ) );
+                               Hooks::run( 'NewRevisionFromEditComplete', array( $wikiPage, $nullRevision, $latest, $user ) );
                                $wikiPage->updateRevisionOn( $dbw, $nullRevision );
                        }
                }
@@ -1484,7 +1484,7 @@ class LocalFile extends File {
 
                # Hooks, hooks, the magic of hooks...
                wfProfileIn( __METHOD__ . '-hooks' );
-               wfRunHooks( 'FileUpload', array( $this, $reupload, $descTitle->exists() ) );
+               Hooks::run( 'FileUpload', array( $this, $reupload, $descTitle->exists() ) );
                wfProfileOut( __METHOD__ . '-hooks' );
 
                # Invalidate cache for all pages using this file
@@ -1987,7 +1987,7 @@ class LocalFileDeleteBatch {
        /** @var array Items to be processed in the deletion batch */
        private $deletionBatch;
 
-       /** @var bool Wether to suppress all suppressable fields when deleting */
+       /** @var bool Whether to suppress all suppressable fields when deleting */
        private $suppress;
 
        /** @var FileRepoStatus */
@@ -2243,23 +2243,7 @@ class LocalFileDeleteBatch {
                wfProfileIn( __METHOD__ );
 
                $this->file->lock();
-               // Leave private files alone
-               $privateFiles = array();
-               list( $oldRels, ) = $this->getOldRels();
-               $dbw = $this->file->repo->getMasterDB();
-
-               if ( !empty( $oldRels ) ) {
-                       $res = $dbw->select( 'oldimage',
-                               array( 'oi_archive_name' ),
-                               array( 'oi_name' => $this->file->getName(),
-                                       'oi_archive_name' => array_keys( $oldRels ),
-                                       $dbw->bitAnd( 'oi_deleted', File::DELETED_FILE ) => File::DELETED_FILE ),
-                               __METHOD__ );
 
-                       foreach ( $res as $row ) {
-                               $privateFiles[$row->oi_archive_name] = 1;
-                       }
-               }
                // Prepare deletion batch
                $hashes = $this->getHashes();
                $this->deletionBatch = array();
@@ -2267,9 +2251,8 @@ class LocalFileDeleteBatch {
                $dotExt = $ext === '' ? '' : ".$ext";
 
                foreach ( $this->srcRels as $name => $srcRel ) {
-                       // Skip files that have no hash (missing source).
-                       // Keep private files where they are.
-                       if ( isset( $hashes[$name] ) && !array_key_exists( $name, $privateFiles ) ) {
+                       // Skip files that have no hash (e.g. missing DB record, or sha1 field and file source)
+                       if ( isset( $hashes[$name] ) ) {
                                $hash = $hashes[$name];
                                $key = $hash . $dotExt;
                                $dstRel = $this->file->repo->getDeletedHashPath( $key ) . $key;
@@ -2286,6 +2269,7 @@ class LocalFileDeleteBatch {
                $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 );
@@ -2368,7 +2352,7 @@ class LocalFileRestoreBatch {
        /** @var bool Add all revisions of the file */
        private $all;
 
-       /** @var bool Wether to remove all settings for suppressed fields */
+       /** @var bool Whether to remove all settings for suppressed fields */
        private $unsuppress = false;
 
        /**
index b0a593d..bb9a903 100644 (file)
@@ -120,7 +120,7 @@ abstract class ImageGalleryBase extends ContextSource {
                                'packed-overlay' => 'PackedOverlayImageGallery',
                        );
                        // Allow extensions to make a new gallery format.
-                       wfRunHooks( 'GalleryGetModes', self::$modeMapping );
+                       Hooks::run( 'GalleryGetModes', self::$modeMapping );
                }
        }
 
index 37f2221..ac61067 100644 (file)
@@ -72,7 +72,7 @@ class TraditionalImageGallery extends ImageGalleryBase {
                                if ( $this->mParser instanceof Parser ) {
                                        # Give extensions a chance to select the file revision for us
                                        $options = array();
-                                       wfRunHooks( 'BeforeParserFetchFileAndTitle',
+                                       Hooks::run( 'BeforeParserFetchFileAndTitle',
                                                array( $this->mParser, $nt, &$options, &$descQuery ) );
                                        # Fetch and register the file (file title may be different via hooks)
                                        list( $img, $nt ) = $this->mParser->fetchFileAndTitle( $nt, $options );
index a5540db..ea1213c 100644 (file)
@@ -115,7 +115,7 @@ abstract class DatabaseUpdater {
                $this->maintenance->setDB( $db );
                $this->initOldGlobals();
                $this->loadExtensions();
-               wfRunHooks( 'LoadExtensionSchemaUpdates', array( $this ) );
+               Hooks::run( 'LoadExtensionSchemaUpdates', array( $this ) );
        }
 
        /**
@@ -1073,7 +1073,7 @@ abstract class DatabaseUpdater {
                        $out = $wgProfiler['output'];
                        if ( $out === 'db' ) {
                                $profileToDb = true;
-                       } elseif( is_array( $out ) && in_array( 'db', $out ) ) {
+                       } elseif ( is_array( $out ) && in_array( 'db', $out ) ) {
                                $profileToDb = true;
                        }
                }
index 8ff3d2f..44ca7d3 100644 (file)
@@ -298,7 +298,7 @@ class WebInstallerOutput {
        </div>
 <?php
        $message = wfMessage( 'config-sidebar' )->plain();
-       foreach( explode( '----', $message ) as $section ) {
+       foreach ( explode( '----', $message ) as $section ) {
                echo '<div class="portal"><div class="body">';
                echo $this->parent->parse( $section, true );
                echo '</div></div>';
index 32e4c39..1301e92 100644 (file)
@@ -69,6 +69,7 @@
        "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-diff3-bad": "GNU diff3 не беше намерен.",
+       "config-git-bad": "Не е намерен софтуер за контрол на версиите Git.",
        "config-imagemagick": "Открит е ImageMagick: <code>$1</code>.\nПреоразмеряването на картинки ще бъде включено ако качването на файлове бъде разрешено.",
        "config-gd": "Открита е вградена графичната библиотека GD.\nАко качването на файлове бъде включено, ще бъде включена възможността за преоразмеряване на картинки.",
        "config-no-scaling": "Не са открити библиотеките GD или ImageMagick.\nПреоразмеряването на картинки ще бъде изключено.",
        "config-extensions": "Разширения",
        "config-extensions-help": "Разширенията от списъка по-горе бяха открити в директорията <code>./extensions</code>.\n\nВъзможно е те да изискват допълнително конфигуриране, но сега могат да бъдат включени.",
        "config-skins": "Облици",
+       "config-skins-use-as-default": "Използване на този облик по подразбиране",
        "config-install-alreadydone": "'''Предупреждение:''' Изглежда вече сте инсталирали МедияУики и се опитвате да го инсталирате отново.\nПродължете към следващата страница.",
        "config-install-begin": "Инсталацията на МедияУики ще започне след натискане на бутона „{{int:config-continue}}“.\nВ случай, че е необходимо да се направят промени, използва се бутона „{{int:config-back}}“.",
        "config-install-step-done": "готово",
index 212c599..0aecb70 100644 (file)
@@ -4,7 +4,8 @@
                        "Bellayet",
                        "Wikitanvir",
                        "Aftab1995",
-                       "Tauhid16"
+                       "Tauhid16",
+                       "Aftabuzzaman"
                ]
        },
        "config-desc": "মিডিয়াউইকির জন্য ইন্সটলার",
@@ -46,7 +47,7 @@
        "config-db-name": "উপাত্তসংগ্রহশালা নামঃ",
        "config-db-install-account": "ইন্সটলের জন্য ব্যবহারকারী অ্যাকাউন্ট",
        "config-db-username": "ডেটাবেজের ব্যবহারকারী নাম:",
-       "config-db-password": "ডà§\87à¦\9fাবà§\87à¦\9cà§\87র à¦¶à¦¬à§\8dদà¦\9aাবি:",
+       "config-db-password": "ডà§\87à¦\9fাবà§\87à¦\9cà§\87র à¦ªà¦¾à¦¸à¦\93য়ারà§\8dড:",
        "config-db-username-empty": "আপনাকে অবশ্যই \"{{int:config-db-username}}\"-এর জন্য একটি মান প্রবেশ করাতে হবে।",
        "config-db-wiki-account": "সাধারণ অভিযানের জন্য ব্যবহারকারী একাউন্ট",
        "config-db-prefix": "উপাত্তশালা ছক প্রিফিক্স:",
@@ -66,7 +67,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-connection-error": "$1।\n\n\nদয়া à¦\95রà§\87 à¦ªà§\8dরসà§\8dতাবà¦\95ারà§\80, à¦¬à§\8dযবহারà¦\95ারà§\80 à¦¨à¦¾à¦® à¦\93 à¦¶à¦¬à§\8dদà¦\9aাবি দেখুন এবং পুনরায় চেষ্টা করুন।",
+       "config-connection-error": "$1।\n\n\nদয়া à¦\95রà§\87 à¦ªà§\8dরসà§\8dতাবà¦\95ারà§\80, à¦¬à§\8dযবহারà¦\95ারà§\80 à¦¨à¦¾à¦® à¦\93 à¦ªà¦¾à¦¸à¦\93য়ারà§\8dড দেখুন এবং পুনরায় চেষ্টা করুন।",
        "config-mysql-engine": "সংরক্ষণ ইঞ্জিন:",
        "config-mysql-innodb": "ইনোডিবি",
        "config-mysql-myisam": "মাইআইএসএএম",
        "config-ns-other-default": "মাইউইকি",
        "config-admin-box": "প্রশাসক অ্যাকাউন্ট",
        "config-admin-name": "আপনার ব্যবহারকারী নাম:",
-       "config-admin-password": "শবà§\8dদà¦\9aাবি:",
-       "config-admin-password-confirm": "শবà§\8dদà¦\9aাবি আবারও প্রবেশ করান:",
+       "config-admin-password": "পাসà¦\93য়ারà§\8dড:",
+       "config-admin-password-confirm": "পাসà¦\93য়ারà§\8dড আবারও প্রবেশ করান:",
        "config-admin-name-blank": "একটি প্রশাসক ব্যবহারকারী নাম প্রবেশ করান",
        "config-admin-password-blank": "প্রশাসক অ্যাকাউন্টের জন্য পাসওয়ার্ড প্রবেশ করান।",
-       "config-admin-password-mismatch": "à¦\86পনি à¦¯à§\87 à¦¦à§\81à¦\9fি à¦¶à¦¬à§\8dদà¦\9aাবি দিয়েছেন তারা পরস্পর মেলেনি।",
+       "config-admin-password-mismatch": "à¦\86পনি à¦¯à§\87 à¦¦à§\81à¦\9fি à¦ªà¦¾à¦¸à¦\93য়ারà§\8dড দিয়েছেন তারা পরস্পর মেলেনি।",
        "config-admin-email": "ইমেইল ঠিকানা:",
        "config-optional-continue": "আরও প্রশ্ন জিজ্ঞেস করুন।",
        "config-optional-skip": "আমি ইতিমধ্যেই বিরক্ত হয়ে গেছি, উইকিটি ইন্সটল করো।",
index e0c985b..2b8a08e 100644 (file)
        "config-mssql-sqlauth": "Autenticació de l’SQL Server",
        "config-mssql-windowsauth": "Autenticació del Windows",
        "config-site-name": "Nom del wiki:",
+       "config-site-name-help": "Això apareixerà en la barra de títol del navegador i en altres llocs diferents.",
        "config-site-name-blank": "Introduïu un nom per al lloc.",
        "config-project-namespace": "Espai de noms del projecte:",
        "config-ns-generic": "Projecte",
        "config-admin-password-blank": "Introduïu una contrasenya per al compte d'administrador.",
        "config-admin-password-mismatch": "Les dues contrasenyes que heu introduït no coincideixen.",
        "config-admin-email": "Adreça electrònica:",
+       "config-admin-error-user": "S'ha produït un error intern en crear un administrador amb el nom «<nowiki>$1</nowiki>».",
+       "config-admin-error-password": "S'ha produït un error intern en definir una contrasenya per a l'administrador «<nowiki>$1</nowiki>»: <pre>$2</pre>",
        "config-admin-error-bademail": "Heu introduït una adreça electrònica no vàlida.",
        "config-almost-done": "Gairebé ja heu acabat!\nPodeu ometre el que queda de la configuració i procedir amb la instal·lació del wiki.",
        "config-optional-continue": "Fes-me més preguntes.",
        "config-cache-help": "L'encauament d'objectes s'utilitza per a millorar la rapidesa del MediaWiki afegint a la memòria cau les dades que s'utilitzen de forma freqüent. És recomanable que els llocs web mitjans o grans ho habilitin. També els llocs web petits en veuran els beneficis.",
        "config-cache-none": "Sense encauament (no se suprimeix cap funcionalitat, però la velocitat pot veure's afectada en els llocs wiki més grans)",
        "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-extensions": "Extensions",
        "config-skins": "Aparences",
+       "config-skins-use-as-default": "Utilitza aquest tema per defecte",
+       "config-skins-missing": "No s'ha trobat cap tema; MediaWiki utilitzarà el tema per defecte fins que hi instal·leu alguns adequats.",
+       "config-skins-must-enable-some": "Heu de triar com a mínim un tema per habilitar.",
+       "config-skins-must-enable-default": "Cal habilitar el tema triat per defecte.",
        "config-install-step-done": "fet",
        "config-install-step-failed": "ha fallat",
        "config-install-extensions": "S'estan incloent les extensions",
        "config-install-pg-schema-not-exist": "No existeix un esquema PostgreSQL.",
        "config-install-pg-schema-failed": "La creació de les taules ha fallat.\nAssegureu-vos que l'usuari «$1» pot escriure a l'esquema «$2».",
        "config-install-pg-commit": "S'estan trametent els canvis",
+       "config-pg-no-create-privs": "El compte que heu especificat per a la instal·lació no té suficients permisos per crear un compte.",
        "config-install-user": "S'està creant l'usuari de la base de dades",
        "config-install-user-alreadyexists": "L'usuari «$1» ja existeix",
        "config-install-user-create-failed": "La creació de l'usuari «$1» ha fallat: $2",
        "config-install-interwiki-exists": "'''Avís:''' La taula d'interwiki sembla que ja té entrades. S'omet la llista per defecte.",
        "config-install-stats": "S'estan inicialitzant les estadístiques",
        "config-install-keys": "S'estan generant les claus secretes",
+       "config-install-updates": "Evita que s'executin actualitzacions no necessàries",
        "config-install-sysop": "S'està creant un compte d'usuari d'administrador",
        "config-install-subscribe-fail": "No s'ha pogut subscriure a mediawiki-announce: $1",
        "config-install-subscribe-notpossible": "El cURL no està instal·lat i <code>allow_url_fopen</code> no està disponible.",
index ab750a5..8444baa 100644 (file)
        "config-db-install-account": "Benutzerkonto für die Installation",
        "config-db-username": "Name des Datenbankbenutzers:",
        "config-db-password": "Passwort des Datenbankbenutzers:",
-       "config-db-password-empty": "Bitte ein Passwort für den neuen Datenbankbenutzer angeben: $1\nObzwar es möglich ist, Datenbankbenutzer ohne Passwort anzulegen, so ist dies aber nicht sicher.",
+       "config-db-password-empty": "Bitte ein Passwort für den neuen Datenbankbenutzer angeben: $1\nObwohl es möglich ist, Datenbankbenutzer ohne Passwort anzulegen, so ist dies nicht sicher.",
        "config-db-username-empty": "Du musst einen Wert für „{{int:config-db-username}}“ eingeben",
        "config-db-install-username": "Den Benutzernamen angeben, der für die Verbindung mit der Datenbank während des Installationsvorgangs genutzt werden soll. Es handelt sich dabei nicht um den Benutzernamen für das MediaWiki-Konto, sondern um den Benutzernamen der vorgesehenen Datenbank.",
        "config-db-install-password": "Das Passwort angeben, das für die Verbindung mit der Datenbank während des Installationsvorgangs genutzt werden soll. Es handelt sich dabei nicht um das Passwort für das MediaWiki-Konto, sondern um das Passwort der vorgesehenen Datenbank.",
index f88ab91..0a118f0 100644 (file)
@@ -14,7 +14,8 @@
                        "Lliehu",
                        "Syreeni",
                        "Stryn",
-                       "SMAUG"
+                       "SMAUG",
+                       "SuperPete"
                ]
        },
        "config-desc": "MediaWiki-asennin",
        "config-apc": "[http://www.php.net/apc APC] on asennettu.",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] on asennettu",
        "config-diff3-bad": "GNU diff3:a ei löytynyt.",
+       "config-git": "Löydetty Git versionhallintaohjelmisto: <code>$1</code>",
+       "config-git-bad": "Git versionhallintaohjelmistoa ei löydy.",
        "config-imagemagick": "Löydettiin ImageMagick: <code>$1</code>.\nKuvien esikatselukuvat otetaan samalla käyttöön jos otetaan tiedostojen tallennus.",
+       "config-gd": "Löydettiin sisäänrakennettu GD-grafiikkakirjasto.\nKuvista luodaan esikatseluversiot automaattisesti, jos otat käyttöön tiedostojen lähettämisen.",
+       "config-no-scaling": "GD-kirjastoa tai ImageMagick-ohjelmaa ei löydy. \nKuvista ei luoda esikatseluversioita.",
+       "config-no-uri": "Virhe: Tämänhetkistä URIa ei tunnisteta. Asennus keskeytetään.",
+       "config-no-cli-uri": "<strong>Varoitus:</strong> <code>--scriptpath</code> määrittämättä, käytetään oletusta: <code>$1</code>",
        "config-using-server": "Palvelimen nimenä käytetään \"<nowiki>$1</nowiki>\".",
        "config-using-uri": "Palvelinen URL-osoitteena käytetään \"<nowiki>$1$2</nowiki>\".",
+       "config-uploads-not-safe": "<strong>Varoitus:</strong> Tiedostojen lähetyshakemistoa <code>$1</code> ei ole suojattu haitalliselta koodilta. MediaWiki tarkistaa kaikki lähetetyt tiedostot, mutta suosittelemme toimimaan ohjeen [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security close this security vulnerability] mukaan ennen kuin tiedostojen lähetys otetaan käyttöön.",
+       "config-no-cli-uploads-check": "<strong>Varoitus:</strong> Tiedostojen lähetyshakemistoa (<code>$1</code>) ei ole tarkistettu haavoittuvuuksien varalta komentoriviasennuksen aikana.",
+       "config-brokenlibxml": "Järjestelmässäsi on käytössä PHP:n ja libxml2:n versioyhdistelmä, joka ei toimi kunnolla ja voi aiheuttaa tiedon vahingoittumista MediaWikissä ja muissa web-sovelluksissa.\nPäivitä libxml2 versioon 2.7.3 tai uudempaan ([https://bugs.php.net/bug.php?id=45996 bug filed with PHP]).\nAsennus keskeytetty.",
+       "config-suhosin-max-value-length": "Suhosin on asennettu ja se rajoittaa GET-parametrin <code>length</code> $1 tavuun.\nMediaWikin ResourceLoader-komponentti pystyy toimimaan tämän kanssa, mutta ohjelmiston suorituskyky heikkenee.\nMikäli mahdollista, aseta muuttuja <code>suhosin.get.max_value_length</code> arvoon 1024 (tai suurempaan) tiedostossa <code>php.ini</code> ja aseta myös <code>$wgResourceLoaderMaxQueryLength</code> samaksi arvoksi tiedostossa <code>LocalSettings.php</code>.",
        "config-db-type": "Tietokannan tyyppi",
        "config-db-host": "Tietokantapalvelin",
+       "config-db-host-help": "Jos tietokantapalvelimesi sijaitsee eri palvelimella, syötä palvelimen nimi tai ip-osoite tähän.\n\nJos käytössäsi on ulkoinen palveluntarjoaja, pitäisi palvelimen nimen löytyä yrityksen ohjesivuilta.\n\nJos asennat MediaWikiä Windows-palvelimelle ja käytät MySQL:ää ei palvelimen nimi \"localhost\" välttämättä toimi. Tässä tapauksessa koita käyttää osoitetta 127.0.0.1.\n\nJos käytät PostgreSQL:ää jätä tämä kenttä tyhjäksi.",
+       "config-db-host-oracle": "Tietokannan TNS:",
        "config-db-wiki-settings": "Identifioi tämä wiki",
        "config-db-name": "Tietokannan nimi",
+       "config-db-name-help": "Valitse wikiäsi kuvaava nimi.\nNimessä ei saa olla välilyöntejä.\n\nMikäli et pysty itse hallitsemaan tietokantojasi, pyydä palveluntarjoajaasi luomaan tietokanta tai tee se palveluntarjoajasi hallintapaneelissa.",
+       "config-db-name-oracle": "Tietokannan rakenne:",
        "config-db-install-account": "Asennuksessa käytettävä käyttäjätili",
        "config-db-username": "Tietokannan käyttäjätunnus",
        "config-db-password": "Tietokannan salasana",
        "config-db-password-empty": "Syötä salasana uudelle tietokannan käyttäjälle: $1.\nVaikka käyttäjä voidaan luoda ilman salasanaa, se ei ole turvallista.",
+       "config-db-username-empty": "Syötä arvo tiedolle \"{{int:config-db-username}}\".",
        "config-db-install-username": "Syötä käyttäjänimi jota käytetään muodostettaessa yhteys tietokantaan asennuksen aikana.\nTämä ei ole MediaWiki tilin käyttäjänimi; tämä on tietokannan käyttäjänimi.",
        "config-db-install-password": "Syötä salasana jota käytetään muodostettaessa yhteys tietokantaan asennuksen aikana.\nTämä ei ole MediaWiki tilin salasana; tämä on tietokannan salasana.",
        "config-db-install-help": "Anna käyttäjätunnus ja salasana, joita käytetään asennuksen aikana.",
        "config-charset-mysql4": "MySQL 4.0, taaksepäin yhteensopiva UTF-8",
        "config-mysql-old": "MediaWiki tarvitsee MySQL:n version $1 tai uudemman. Nykyinen versio on $2.",
        "config-db-port": "Tietokannan portti:",
+       "config-db-schema": "MediaWikin rakenne:",
+       "config-db-schema-help": "Tämä rakenne on normaalisti toimiva.\nMuuta rakennetta vain, mikäli on pakko ja tiedät, mitä teet.",
        "config-pg-test-error": "Tietokantaan <strong>$1 ei voida muodostaa yhteyttä</strong>: $2",
+       "config-sqlite-dir": "SQLiten datahakemisto:",
+       "config-sqlite-dir-help": "SQLite tallentaa kaiken sisällön yhteen tiedostoon.\n\nPalvelimen pitää pystyä kirjoittamaan tietoa hakemistoon asennuksen aikana.\n\nHakemiston <strong>ei</strong> tulisi olla nähtävissä www-selaimella. Siksi hakemisto on eri kuin missä PHP-tiedostot sijaitsevat.\n\nAsennusohjelma luo <code>.htaccess</code>-tiedoston, mutta jos sen luomisessa ilmenee ongelmia joku voi päästä käsiksi tietokantaasi. \nTietokannassa on kaikki sähköpostiosoitteet, salasanat, poistetut versiot ja kaikki muu tieto, joka ei näy wikissä.\n\nSuosittelemme tallentamaan tietokannan eri hakemistoon, esimerkiksi <code>/var/lib/mediawiki/yourwiki</code>.",
        "config-type-mysql": "MySQL (tai yhteensopiva)",
        "config-type-postgres": "PostgreSQL",
        "config-type-sqlite": "SQLite",
        "config-extensions": "Laajennukset",
        "config-extensions-help": "Yllä luetellut laajennukset löytyvät <code>./extensions</code> hakemistosta.\n\nNe saattavat vaatia lisäasetuksia, mutta voit ottaa ne käyttöön nyt.",
        "config-skins": "Ulkoasut",
+       "config-skins-help": "Seuraavat teemat löydettiin hakemistosta <code>./skins</code>. Ota käyttöön vähintään yksi teema ja aseta se oletukseksi.",
+       "config-skins-use-as-default": "Käytä tätä teemaa oletuksena.",
+       "config-skins-missing": "Teemoja ei löytynyt; MediaWiki käyttää väliaikaista teemaa, kunnes asennat toimivia.",
        "config-skins-must-enable-some": "Sinut täytyy valita ainakin yksi ulkoasu.",
+       "config-skins-must-enable-default": "Oletusteeman pitää olla käytössä.",
        "config-install-alreadydone": "<strong>Varoitus:</strong> MediaWiki on jo asennettu ja yrität asentaa sitä uudestaan.\nSiirry seuraavalle sivulle.",
        "config-install-begin": "Painamalla \"{{int:config-continue}}\", aloitetaan MediaWikin asentaminen. \nJos haluat vielä tehdä muutoksia, paina \"{{int:config-back}}\".",
        "config-install-step-done": "valmis",
        "config-install-step-failed": "epäonnistui",
        "config-install-extensions": "Sisällytetään laajennukset",
        "config-install-database": "Asennetaan tietokantaa",
+       "config-install-schema": "Luodaan rakennetta",
+       "config-install-pg-schema-not-exist": "PostgreSQL-rakennetta ei ole olemassa.",
+       "config-install-pg-schema-failed": "Taulun luominen epäonnistui.\nVarmista, että käyttäjätunnus \"$1\" pystyy kirjoittamaan rakenteeseen \"$2\".",
+       "config-install-pg-commit": "Muutoksia tallennetaan",
+       "config-install-pg-plpgsql": "Tarkistetaan PL/pgSQL:n kieltä.",
+       "config-pg-no-plpgsql": "PL/pgSQL-kieli pitää asentaa tietokantaan $1",
        "config-pg-no-create-privs": "Määrittelemälläsi tilillä ei ole riittävästi oikeuksia luoda tiliä.",
+       "config-pg-not-in-role": "Määrittelemäsi web-käyttäjän tili on jo olemassa.\nMäärittelemälläsi käyttäjätilillä ei ole pääkäyttäjäoikeuksia eikä se toimi web-käyttäjän roolissa. Käyttäjätili ei pysty luomaan tarvittavia objekteja.\n\nMediaWiki vaatii, että web-käyttäjän pitää pystyä hallitsemaan tauluja. Anna toinen web-käyttäjätunnus tai klikkaa \"takaisin\" ja määrittele käyttäjätunnus, joka toimii asennuksessa.",
        "config-install-user": "Luodaan tietokannalle käyttäjää",
        "config-install-user-alreadyexists": "Käyttäjä $1 on jo olemassa",
        "config-install-user-create-failed": "Käyttäjän \"$1\" luonti epäonnistui: $2",
        "config-install-tables": "Luodaan tauluja",
        "config-install-tables-exist": "<strong>Varoitus:</strong> MediaWiki taulut ovat jo olemassa.\nOhitetaan taulujen luonti.",
        "config-install-tables-failed": "<strong>Virhe:</strong> Taulujen luominen epäonnistui seuraavaan virheen takia: $1",
+       "config-install-interwiki": "Luodaan oletustaulua interwikille",
        "config-install-interwiki-list": "Tiedostoa <code>interwiki.list</code> ei voitu lukea.",
+       "config-install-interwiki-exists": "<strong>Varoitus:</strong> interwiki-taulussa on jo tietueita, ohitetaan oletuslista.",
+       "config-install-stats": "Alustetaan tilastoja",
        "config-install-keys": "Muodostetaan salausavaimia",
+       "config-install-updates": "Estä tarpeettomien päivitysten asennus",
        "config-install-sysop": "Luodaan ylläpitäjän tiliä",
        "config-install-subscribe-fail": "Liittyminen mediawiki-announce listalle epäonnistui: $1",
+       "config-install-subscribe-notpossible": "cURL-ohjelmaa ei ole asennettu eikä <code>allow_url_fopen</code> ole saatavilla.",
        "config-install-mainpage": "Luodaan etusivu oletussisällöllä",
        "config-install-extension-tables": "Luodaan tauluja käyttöönotetuille laajuennuksille",
        "config-install-mainpage-failed": "Etusivun lisääminen ei onnistunut: $1",
+       "config-install-done": "<strong>Onnittelut!</strong>\nMediaWiki on asennettu onnistuneesti\n\nAsennusohjelma on luonut <code>LocalSettings.php</code> -tiedoston.\nSiinä on kaikki MediaWikin asetukset.\n\nLataa tiedosto ja laita se MediaWikin asennushakemistoon (sama kuin missä on index.php). Lataamisen olisi pitänyt alkaa automaattisesti.\n\nMikäli keskeytit latauksen, käynnistä se uudestaan tästä linkistä:\n\n$3\n\n<strong>HUOM!</strong> Mikäli et nyt lataa tiedostoa, joudut aloittamaan asennuksen alusta.\n\nKun olet laittanut tiedoston oikeaan paikkaan voit <strong>[$2 mennä wikiisi]</strong>.",
        "config-download-localsettings": "Lataa <code>LocalSettings.php</code>",
        "config-help": "ohje",
+       "config-help-tooltip": "Klikkaa laajentaaksesi",
        "config-nofile": "Tiedostoa \"$1\" ei löytynyt. Onko se poistettu?",
        "config-extension-link": "Tiesitkö että wiki tukee [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions laajennuksia]?\n\nLaajennuksia voi hakea myös [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category luokittain].",
        "mainpagetext": "'''MediaWiki on onnistuneesti asennettu.'''",
index 86b760c..ba84435 100644 (file)
@@ -48,7 +48,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": "యూనికోడు నార్మలైజేషన్ కోసం బ్రయాన్ విబర్ గారి utf8_normalize.so ను వాడుతున్నాం.",
        "config-unicode-using-intl": "యూనికోడు నార్మలైజేషన్ కోసం [http://pecl.php.net/intl intl PECL పొడిగింత] ను వాడుతున్నాం.",
        "config-outdated-sqlite": "<strong>హెచ్చరిక:</strong> మీ వద్ద SQLite $1 ఉంది. అదికావలసిన వెర్షను $2 కంటే దిగువది. SQLite అందుబాటులో ఉండదు.",
        "config-memcache-badport": "Memcached పోర్టు సఖ్యలు $1, $2 ల మధ్య ఉండాలి.",
        "config-extensions": "పొడిగింతలు",
        "config-extensions-help": "పైన చూపిన పొడిగింతలు మీ <code>./extensions</code> డైరెక్టరీలో ఉన్నాయి.\n\nవాటికి అదనంగా కాన్ఫిగరేషన్ అవసరం కావచ్చు. అయితే మీరు వాటిని చేతనం చెయ్యవచ్చు.",
+       "config-skins": "అలంకారాలు",
        "config-install-alreadydone": "<strong>హెచ్చరిక:</strong> మీరు ఈసరికే MediaWiki ని స్థాపించినట్లుగా అనిపిస్తోంది. మళ్ళీ స్థాపించే ప్రయత్నం చేస్తున్నట్లున్నారు.\nతరువాత పేజీకి వెళ్ళండి.",
        "config-install-begin": "\"{{int:config-continue}}\" నొక్కి, MediaWiki స్థాపనను మొదలుపెట్టవచ్చు.\nఇంకా మార్పులు చెయ్యదలిస్తే, \"{{int:config-back}}\" నొక్కండి.",
        "config-install-step-done": "పూర్తయింది",
index 4be4d98..923a80d 100644 (file)
@@ -3,14 +3,18 @@
                "authors": [
                        "පසිඳු කාවින්ද",
                        "Minh Nguyen",
-                       "Withoutaname"
+                       "Withoutaname",
+                       "Dinhxuanduyet"
                ]
        },
        "config-desc": "Trình cài đặt MediaWiki",
        "config-title": "Cài đặt MediaWiki $1",
        "config-information": "Thông tin",
+       "config-localsettings-upgrade": "Một file <code>LocalSettings.php</code> đã được phát hiện.\nĐể nâng cấp cài đặt này, xin nhập giá trị của  <code>$wgUpgradeKey</code> trong hộp thoại bên dưới đây.\nBạn sẽ tìm thấy nó trong<code>LocalSettings.php</code>.",
+       "config-localsettings-cli-upgrade": "Một file <code>LocalSettings.php</code> đã được phát hiện.\nĐể nâng cấp cài đặt này, hãy chạy <code>update.php</code>",
        "config-localsettings-key": "Chìa khóa nâng cấp:",
        "config-localsettings-badkey": "Bạn đã cung cấp một chìa khóa sai.",
+       "config-upgrade-key-missing": "Có một bản cài đặt của MediaWiki sẵn trước đó đã được phát hiện.\nĐể nâng cấp cài đặt này, hãy đặt dòng sau vào dưới của của <code>LocalSettings.php</code>:\n\n$1",
        "config-session-error": "Lỗi khi bắt đầu phiên làm việc: $1",
        "config-your-language": "Ngôn ngữ của bạn:",
        "config-your-language-help": "Chọn một ngôn ngữ để sử dụng trong quá trình cài đặt.",
index e12137e..0e03296 100644 (file)
        "config-license-gfdl": "GNU 自由文件授權條款 1.3 或更高版本",
        "config-license-pd": "公共領域",
        "config-license-cc-choose": "請選擇一個自訂的創作共用授權條款",
-       "config-license-help": "許多開放式 Wiki 會以 [http://freedomdefined.org/Definition 自由授權條款] 的方式釋放出編者的所有貢獻,這有助於構建社群的所有權,並且能鼓勵長期貢獻。對於封閉式的 Wiki 或公司 Wiki 則是非必要的。\n\n如果您希望使用來自維基百科(Wikipedia)的內容,並希望維基百科能接受您的 Wiki 內容,請應選擇 <strong>{{int:config-license-cc-by-sa}}</strong> 授權條款。\n\n維基百科̽(Wikipedia)先前是使用 GNU 自由文件授權條款,\n但該授權條款的內容較難理解,因此較難再利用在該條款底下的內容。",
+       "config-license-help": "許多開放式 Wiki 會以 [http://freedomdefined.org/Definition 自由授權條款] 的方式釋放出編者的所有貢獻,這有助於構建社群的所有權,並且能鼓勵長期貢獻。對於封閉式的 Wiki 或公司 Wiki 則是非必要的。\n\n如果您希望使用來自維基百科(Wikipedia)的內容,並希望維基百科能接受您的 Wiki 內容,請應選擇 <strong>{{int:config-license-cc-by-sa}}</strong> 授權條款。\n\n維基百科(Wikipedia)先前是使用 GNU 自由文件授權條款,\n但該授權條款的內容較難理解,因此較難再利用在該條款底下的內容。",
        "config-email-settings": "E-mail 設定",
        "config-enable-email": "開啟外寄電子郵件",
        "config-enable-email-help": "如果您要使用電子郵件功能,請正確設定 [http://www.php.net/manual/en/mail.configuration.php PHP 的郵件設定]。\n如果您不需要使用電子郵件功能,請在此處關閉。",
index 37a9fcf..02fbb08 100644 (file)
@@ -194,7 +194,7 @@ class Interwiki {
                global $wgMemc, $wgInterwikiExpiry;
 
                $iwData = array();
-               if ( !wfRunHooks( 'InterwikiLoadPrefix', array( $prefix, &$iwData ) ) ) {
+               if ( !Hooks::run( 'InterwikiLoadPrefix', array( $prefix, &$iwData ) ) ) {
                        return Interwiki::loadFromArray( $iwData );
                }
 
index c4301ee..4186204 100644 (file)
@@ -72,7 +72,7 @@ class JobQueueFederated extends JobQueue {
         *                          have explicitly defined sections.
         *  - configByPartition   : Map of queue partition names to configuration arrays.
         *                          These configuration arrays are passed to JobQueue::factory().
-        *                          The options set here are overriden by those passed to this
+        *                          The options set here are overridden by those passed to this
         *                          the federated queue itself (e.g. 'order' and 'claimTTL').
         *  - partitionsNoPush    : List of partition names that can handle pop() but not push().
         *                          This can be used to migrate away from a certain partition.
index db8a7ec..93ae83b 100644 (file)
@@ -117,7 +117,7 @@ abstract class GenericArrayObject extends ArrayObject {
         *
         * @param mixed $value
         *
-        * @return boolean
+        * @return bool
         */
        protected function hasValidType( $value ) {
                $class = $this->getObjectType();
@@ -171,7 +171,7 @@ abstract class GenericArrayObject extends ArrayObject {
         * @param integer|string $index
         * @param mixed $value
         *
-        * @return boolean
+        * @return bool
         */
        protected function preSetElement( $index, $value ) {
                return true;
@@ -232,7 +232,7 @@ abstract class GenericArrayObject extends ArrayObject {
         *
         * @since 1.20
         *
-        * @return boolean
+        * @return bool
         */
        public function isEmpty() {
                return $this->count() === 0;
index 3b9f1a8..c1c841e 100644 (file)
@@ -162,7 +162,7 @@ class IPSet {
         * Match an IP address against the set
         *
         * @param string $ip string IPv[46] address
-        * @return boolean true is match success, false is match failure
+        * @return bool true is match success, false is match failure
         *
         * If $ip is unparseable, inet_pton may issue an E_WARNING to that effect
         */
index 96e195c..ec8c36a 100644 (file)
@@ -54,7 +54,7 @@ class ObjectFactory {
         * @throws InvalidArgumentException when object specification does not
         * contain 'class' or 'factory' keys
         * @throws ReflectionException when 'args' are supplied and 'class'
-        * constructor is non-public or non-existant
+        * constructor is non-public or non-existent
         */
        public static function getObjectFromSpec( $spec ) {
                $args = isset( $spec['args'] ) ? $spec['args'] : array();
index 631b651..629c269 100644 (file)
 class ScopedCallback {
        /** @var callable */
        protected $callback;
+       /** @var array */
+       protected $params;
 
        /**
         * @param callable $callback
+        * @param array $params Callback arguments (since 1.25)
         * @throws Exception
         */
-       public function __construct( $callback ) {
+       public function __construct( $callback, array $params = array() ) {
                if ( !is_callable( $callback ) ) {
                        throw new InvalidArgumentException( "Provided callback is not valid." );
                }
                $this->callback = $callback;
+               $this->params = $params;
        }
 
        /**
@@ -67,7 +71,7 @@ class ScopedCallback {
         */
        function __destruct() {
                if ( $this->callback !== null ) {
-                       call_user_func( $this->callback );
+                       call_user_func_array( $this->callback, $this->params );
                }
        }
 }
index 990e2c3..98ff675 100644 (file)
@@ -267,13 +267,16 @@ class Xhprof {
                                foreach ( $stats as $name => $value ) {
                                        if ( $value instanceof RunningStat ) {
                                                $total = $value->m1 * $value->n;
+                                               $percent = ( isset( $main[$name] ) && $main[$name] )
+                                                       ? 100 * $total / $main[$name]
+                                                       : 0;
                                                $this->inclusive[$func][$name] = array(
                                                        'total' => $total,
                                                        'min' => $value->min,
                                                        'mean' => $value->m1,
                                                        'max' => $value->max,
                                                        'variance' => $value->m2,
-                                                       'percent' => 100 * $total / $main[$name],
+                                                       'percent' => $percent,
                                                );
                                        }
                                }
index aca857e..0d6c3a6 100644 (file)
@@ -70,7 +70,7 @@ class XmlTypeCheck {
         *        SAX element handler event. This gives you access to the element
         *        namespace, name, attributes, and text contents.
         *        Filter should return 'true' to toggle on $this->filterMatch
-        * @param boolean $isFile (optional) indicates if the first parameter is a
+        * @param bool $isFile (optional) indicates if the first parameter is a
         *        filename (default, true) or if it is a string (false)
         * @param array $options list of additional parsing options:
         *        processing_instruction_handler: Callback for xml_set_processing_instruction_handler
index e03cf1c..f7eaec3 100644 (file)
@@ -273,7 +273,7 @@ class LogEventsList extends ContextSource {
                        } else {
                                // Allow extensions to add their own extra inputs
                                $input = '';
-                               wfRunHooks( 'LogEventsListGetExtraInputs', array( $types[0], $this, &$input ) );
+                               Hooks::run( 'LogEventsListGetExtraInputs', array( $types[0], $this, &$input ) );
                                return $input;
                        }
                }
@@ -632,7 +632,7 @@ class LogEventsList extends ContextSource {
                }
 
                /* hook can return false, if we don't want the message to be emitted (Wikia BugId:7093) */
-               if ( wfRunHooks( 'LogEventsListShowLogExtract', array( &$s, $types, $page, $user, $param ) ) ) {
+               if ( Hooks::run( 'LogEventsListShowLogExtract', array( &$s, $types, $page, $user, $param ) ) ) {
                        // $out can be either an OutputPage object or a String-by-reference
                        if ( $out instanceof OutputPage ) {
                                $out->addHTML( $s );
index bbe2f42..464b723 100644 (file)
@@ -812,7 +812,7 @@ class LegacyLogFormatter extends LogFormatter {
 
                $params = $this->entry->getParameters();
 
-               wfRunHooks( 'LogLine', array( $type, $subtype, $title, $params,
+               Hooks::run( 'LogLine', array( $type, $subtype, $title, $params,
                        &$this->comment, &$this->revert, $this->entry->getTimestamp() ) );
 
                return $this->revert;
index 8215403..220c6b1 100644 (file)
@@ -224,7 +224,7 @@ class EmailNotification {
 
                $formattedPageStatus = array( 'deleted', 'created', 'moved', 'restored', 'changed' );
 
-               wfRunHooks( 'UpdateUserMailerFormattedPageStatus', array( &$formattedPageStatus ) );
+               Hooks::run( 'UpdateUserMailerFormattedPageStatus', array( &$formattedPageStatus ) );
                if ( !in_array( $this->pageStatus, $formattedPageStatus ) ) {
                        wfProfileOut( __METHOD__ );
                        throw new MWException( 'Not a valid page status!' );
@@ -251,7 +251,7 @@ class EmailNotification {
                                                && $watchingUser->isEmailConfirmed()
                                                && $watchingUser->getID() != $userTalkId
                                        ) {
-                                               if ( wfRunHooks( 'SendWatchlistEmailNotification', array( $watchingUser, $title, $this ) ) ) {
+                                               if ( Hooks::run( 'SendWatchlistEmailNotification', array( $watchingUser, $title, $this ) ) ) {
                                                        $this->compose( $watchingUser );
                                                }
                                        }
@@ -295,7 +295,7 @@ class EmailNotification {
                        ) {
                                if ( !$targetUser->isEmailConfirmed() ) {
                                        wfDebug( __METHOD__ . ": talk page owner doesn't have validated email\n" );
-                               } elseif ( !wfRunHooks( 'AbortTalkPageEmailNotification', array( $targetUser, $title ) ) ) {
+                               } elseif ( !Hooks::run( 'AbortTalkPageEmailNotification', array( $targetUser, $title ) ) ) {
                                        wfDebug( __METHOD__ . ": talk page update notification is aborted for this user\n" );
                                } else {
                                        wfDebug( __METHOD__ . ": sending talk page update notification\n" );
index b5a57a8..3cabdae 100644 (file)
@@ -191,7 +191,7 @@ class UserMailer {
                $extraParams = $wgAdditionalMailParams;
 
                // Hook to generate custom VERP address for 'Return-Path'
-               wfRunHooks( 'UserMailerChangeReturnPath', array( $to, &$returnPath ) );
+               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.
@@ -250,7 +250,7 @@ class UserMailer {
                        $headers['Content-transfer-encoding'] = '8bit';
                }
 
-               $ret = wfRunHooks( 'AlternateUserMailer', array( $headers, $to, $from, $subject, $body ) );
+               $ret = Hooks::run( 'AlternateUserMailer', array( $headers, $to, $from, $subject, $body ) );
                if ( $ret === false ) {
                        // the hook implementation will return false to skip regular mail sending
                        return Status::newGood();
index 0292af8..cd77f3e 100644 (file)
@@ -204,7 +204,7 @@ class BitmapHandler extends TransformationalImageHandler {
                                        / ( $params['srcWidth'] + $params['srcHeight'] )
                                        < $wgSharpenReductionThreshold
                                ) {
-                                       // Hack, since $wgSharpenParamater is written specifically for the command line convert
+                                       // Hack, since $wgSharpenParameter is written specifically for the command line convert
                                        list( $radius, $sigma ) = explode( 'x', $wgSharpenParameter );
                                        $im->sharpenImage( $radius, $sigma );
                                }
@@ -344,7 +344,7 @@ class BitmapHandler extends TransformationalImageHandler {
 
                $src_image = call_user_func( $loader, $params['srcPath'] );
 
-               $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] )  ? $this->getRotation( $image ) : 0;
+               $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] ) ? $this->getRotation( $image ) : 0;
                list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
                $dst_image = imagecreatetruecolor( $width, $height );
 
index 07d7618..8cf95dd 100644 (file)
@@ -1614,7 +1614,7 @@ class FormatMetadata extends ContextSource {
                $cachedValue = $wgMemc->get( $cacheKey );
                if (
                        $cachedValue
-                       && wfRunHooks( 'ValidateExtendedMetadataCache', array( $cachedValue['timestamp'], $file ) )
+                       && Hooks::run( 'ValidateExtendedMetadataCache', array( $cachedValue['timestamp'], $file ) )
                ) {
                        $extendedMetadata = $cachedValue['data'];
                } else {
@@ -1717,7 +1717,7 @@ class FormatMetadata extends ContextSource {
        ) {
                wfProfileIn( __METHOD__ );
 
-               wfRunHooks( 'GetExtendedMetadata', array(
+               Hooks::run( 'GetExtendedMetadata', array(
                        &$extendedMetadata,
                        $file,
                        $this->getContext(),
index 64ca011..b88a1b1 100644 (file)
@@ -162,7 +162,7 @@ abstract class MediaHandler {
         */
        static function getMetadataVersion() {
                $version = array( '2' ); // core metadata version
-               wfRunHooks( 'GetMetadataVersion', array( &$version ) );
+               Hooks::run( 'GetMetadataVersion', array( &$version ) );
 
                return implode( ';', $version );
        }
index d9327fb..98f7552 100644 (file)
@@ -352,6 +352,11 @@ class ThumbnailImage extends MediaTransformOutput {
 
                $query = isset( $options['desc-query'] ) ? $options['desc-query'] : '';
 
+               $attribs = array(
+                       'alt' => $alt,
+                       'src' => $this->url,
+               );
+
                if ( !empty( $options['custom-url-link'] ) ) {
                        $linkAttribs = array( 'href' => $options['custom-url-link'] );
                        if ( !empty( $options['title'] ) ) {
@@ -381,13 +386,11 @@ class ThumbnailImage extends MediaTransformOutput {
                        $linkAttribs = array( 'href' => $this->file->getURL() );
                } else {
                        $linkAttribs = false;
+                       if ( !empty( $options['title'] ) ) {
+                               $attribs['title'] = $options['title'];
+                       }
                }
 
-               $attribs = array(
-                       'alt' => $alt,
-                       'src' => $this->url,
-               );
-
                if ( empty( $options['no-dimensions'] ) ) {
                        $attribs['width'] = $this->width;
                        $attribs['height'] = $this->height;
@@ -410,7 +413,7 @@ class ThumbnailImage extends MediaTransformOutput {
                        $attribs['srcset'] = Html::srcSet( $this->responsiveUrls );
                }
 
-               wfRunHooks( 'ThumbnailBeforeProduceHTML', array( $this, &$attribs, &$linkAttribs ) );
+               Hooks::run( 'ThumbnailBeforeProduceHTML', array( $this, &$attribs, &$linkAttribs ) );
 
                return $this->linkWrap( $linkAttribs, Xml::element( 'img', $attribs ) );
        }
index b3ae296..5b9982d 100644 (file)
@@ -64,7 +64,7 @@ abstract class TransformationalImageHandler extends ImageHandler {
                # Check if the file is smaller than the maximum image area for thumbnailing
                # For historical reasons, hook starts with BitmapHandler
                $checkImageAreaHookResult = null;
-               wfRunHooks(
+               Hooks::run(
                        'BitmapHandlerCheckImageArea',
                        array( $image, &$params, &$checkImageAreaHookResult )
                );
@@ -240,7 +240,7 @@ abstract class TransformationalImageHandler extends ImageHandler {
                # Try a hook. Called "Bitmap" for historical reasons.
                /** @var $mto MediaTransformOutput */
                $mto = null;
-               wfRunHooks( 'BitmapHandlerTransform', array( $this, $image, &$scalerParams, &$mto ) );
+               Hooks::run( 'BitmapHandlerTransform', array( $this, $image, &$scalerParams, &$mto ) );
                if ( !is_null( $mto ) ) {
                        wfDebug( __METHOD__ . ": Hook to BitmapHandlerTransform created an mto\n" );
                        $scaler = 'hookaborted';
index cdbd5ab..5b46af1 100644 (file)
@@ -173,7 +173,7 @@ class XMPReader {
 
                $data = $this->results;
 
-               wfRunHooks( 'XMPGetResults', array( &$data ) );
+               Hooks::run( 'XMPGetResults', array( &$data ) );
 
                if ( isset( $data['xmp-special']['AuthorsPosition'] )
                        && is_string( $data['xmp-special']['AuthorsPosition'] )
index 7e47ec1..e0a491c 100644 (file)
@@ -34,7 +34,7 @@ class XMPInfo {
                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.
-                       wfRunHooks( 'XMPGetInfo', array( &self::$items ) );
+                       Hooks::run( 'XMPGetInfo', array( &self::$items ) );
                        self::$ranHooks = true; // Only want to do this once.
                }
 
index e3541bd..0318f65 100644 (file)
@@ -120,7 +120,7 @@ class Article implements Page {
                }
 
                $page = null;
-               wfRunHooks( 'ArticleFromTitle', array( &$title, &$page, $context ) );
+               Hooks::run( 'ArticleFromTitle', array( &$title, &$page, $context ) );
                if ( !$page ) {
                        switch ( $title->getNamespace() ) {
                                case NS_FILE:
@@ -428,7 +428,7 @@ class Article implements Page {
                );
                $this->mRevIdFetched = $this->mRevision->getId();
 
-               wfRunHooks( 'ArticleAfterFetchContentObject', array( &$this, &$this->mContentObject ) );
+               Hooks::run( 'ArticleAfterFetchContentObject', array( &$this, &$this->mContentObject ) );
 
                wfProfileOut( __METHOD__ );
 
@@ -602,7 +602,7 @@ class Article implements Page {
                while ( !$outputDone && ++$pass ) {
                        switch ( $pass ) {
                                case 1:
-                                       wfRunHooks( 'ArticleViewHeader', array( &$this, &$outputDone, &$useParserCache ) );
+                                       Hooks::run( 'ArticleViewHeader', array( &$this, &$outputDone, &$useParserCache ) );
                                        break;
                                case 2:
                                        # Early abort if the page doesn't exist
@@ -665,7 +665,7 @@ class Article implements Page {
                                                wfDebug( __METHOD__ . ": showing CSS/JS source\n" );
                                                $this->showCssOrJsPage();
                                                $outputDone = true;
-                                       } elseif ( !wfRunHooks( 'ArticleContentViewCustom',
+                                       } elseif ( !Hooks::run( 'ArticleContentViewCustom',
                                                        array( $this->fetchContentObject(), $this->getTitle(), $outputPage ) ) ) {
 
                                                # Allow extensions do their own custom view for certain pages
@@ -995,7 +995,7 @@ class Article implements Page {
                if ( isset( $this->mRedirectedFrom ) ) {
                        // This is an internally redirected page view.
                        // We'll need a backlink to the source page for navigation.
-                       if ( wfRunHooks( 'ArticleViewRedirect', array( &$this ) ) ) {
+                       if ( Hooks::run( 'ArticleViewRedirect', array( &$this ) ) ) {
                                $redir = Linker::linkKnown(
                                        $this->mRedirectedFrom,
                                        null,
@@ -1073,7 +1073,7 @@ class Article implements Page {
                // Show a footer allowing the user to patrol the shown revision or page if possible
                $patrolFooterShown = $this->showPatrolFooter();
 
-               wfRunHooks( 'ArticleViewFooter', array( $this, $patrolFooterShown ) );
+               Hooks::run( 'ArticleViewFooter', array( $this, $patrolFooterShown ) );
        }
 
        /**
@@ -1244,12 +1244,12 @@ class Article implements Page {
                        }
                }
 
-               wfRunHooks( 'ShowMissingArticle', array( $this ) );
+               Hooks::run( 'ShowMissingArticle', array( $this ) );
 
                // Give extensions a chance to hide their (unrelated) log entries
                $logTypes = array( 'delete', 'move' );
                $conds = array( "log_action != 'revision'" );
-               wfRunHooks( 'Article::MissingArticleConditions', array( &$conds, $logTypes ) );
+               Hooks::run( 'Article::MissingArticleConditions', array( &$conds, $logTypes ) );
 
                # Show delete and move logs
                LogEventsList::showLogExtract( $outputPage, $logTypes, $title, '',
@@ -1270,7 +1270,7 @@ class Article implements Page {
                $outputPage->setIndexPolicy( $policy['index'] );
                $outputPage->setFollowPolicy( $policy['follow'] );
 
-               $hookResult = wfRunHooks( 'BeforeDisplayNoArticleText', array( $this ) );
+               $hookResult = Hooks::run( 'BeforeDisplayNoArticleText', array( $this ) );
 
                if ( !$hookResult ) {
                        return;
@@ -1346,7 +1346,7 @@ class Article implements Page {
         * @param int $oldid Revision ID of this article revision
         */
        public function setOldSubtitle( $oldid = 0 ) {
-               if ( !wfRunHooks( 'DisplayOldSubtitle', array( &$this, &$oldid ) ) ) {
+               if ( !Hooks::run( 'DisplayOldSubtitle', array( &$this, &$oldid ) ) ) {
                        return;
                }
 
@@ -1697,7 +1697,7 @@ class Article implements Page {
                }
                $outputPage->addWikiMsg( 'confirmdeletetext' );
 
-               wfRunHooks( 'ArticleConfirmDelete', array( $this, $outputPage, &$reason ) );
+               Hooks::run( 'ArticleConfirmDelete', array( $this, $outputPage, &$reason ) );
 
                $user = $this->getContext()->getUser();
 
@@ -1808,7 +1808,7 @@ class Article implements Page {
 
                        $outputPage->addWikiMsg( 'deletedtext', wfEscapeWikiText( $deleted ), $loglink );
 
-                       wfRunHooks( 'ArticleDeleteAfterSuccess', array( $this->getTitle(), $outputPage ) );
+                       Hooks::run( 'ArticleDeleteAfterSuccess', array( $this->getTitle(), $outputPage ) );
 
                        $outputPage->returnToMain( false );
                } else {
@@ -1882,7 +1882,7 @@ class Article implements Page {
                                && !$this->mRedirectedFrom && !$this->getTitle()->isRedirect();
                        // Extension may have reason to disable file caching on some pages.
                        if ( $cacheable ) {
-                               $cacheable = wfRunHooks( 'IsFileCacheable', array( &$this ) );
+                               $cacheable = Hooks::run( 'IsFileCacheable', array( &$this ) );
                        }
                }
 
index 9abc6a8..03a5b89 100644 (file)
@@ -61,7 +61,7 @@ class CategoryPage extends Article {
                        return;
                }
 
-               if ( !wfRunHooks( 'CategoryPageView', array( &$this ) ) ) {
+               if ( !Hooks::run( 'CategoryPageView', array( &$this ) ) ) {
                        return;
                }
 
index 348eff1..b9f99c8 100644 (file)
@@ -76,7 +76,7 @@ class ImagePage extends Article {
                $this->fileLoaded = true;
 
                $this->displayImg = $img = false;
-               wfRunHooks( 'ImagePageFindFile', array( $this, &$img, &$this->displayImg ) );
+               Hooks::run( 'ImagePageFindFile', array( $this, &$img, &$this->displayImg ) );
                if ( !$img ) { // not set by hook?
                        $img = wfFindFile( $this->getTitle() );
                        if ( !$img ) {
@@ -196,7 +196,7 @@ class ImagePage extends Article {
 
                # Allow extensions to add something after the image links
                $html = '';
-               wfRunHooks( 'ImagePageAfterImageLinks', array( $this, &$html ) );
+               Hooks::run( 'ImagePageAfterImageLinks', array( $this, &$html ) );
                if ( $html ) {
                        $out->addHTML( $html );
                }
@@ -245,7 +245,7 @@ class ImagePage extends Article {
                        $r[] = '<li><a href="#metadata">' . wfMessage( 'metadata' )->escaped() . '</a></li>';
                }
 
-               wfRunHooks( 'ImagePageShowTOC', array( $this, &$r ) );
+               Hooks::run( 'ImagePageShowTOC', array( $this, &$r ) );
 
                return '<ul id="filetoc">' . implode( "\n", $r ) . '</ul>';
        }
@@ -336,7 +336,7 @@ class ImagePage extends Article {
                        $filename = wfEscapeWikiText( $this->displayImg->getName() );
                        $linktext = $filename;
 
-                       wfRunHooks( 'ImageOpenShowImageInlineBefore', array( &$this, &$out ) );
+                       Hooks::run( 'ImageOpenShowImageInlineBefore', array( &$this, &$out ) );
 
                        if ( $this->displayImg->allowInlineDisplay() ) {
                                # image
@@ -1384,7 +1384,7 @@ class ImageHistoryList extends ContextSource {
                }
 
                $rowClass = null;
-               wfRunHooks( 'ImagePageFileHistoryLine', array( $this, $file, &$row, &$rowClass ) );
+               Hooks::run( 'ImagePageFileHistoryLine', array( $this, $file, &$row, &$rowClass ) );
                $classAttr = $rowClass ? " class='$rowClass'" : '';
 
                return "<tr{$classAttr}>{$row}</tr>\n";
index 8b26c23..b9f7eda 100644 (file)
@@ -308,11 +308,11 @@ class WikiPage implements Page, IDBAccessObject {
        protected function pageData( $dbr, $conditions, $options = array() ) {
                $fields = self::selectFields();
 
-               wfRunHooks( 'ArticlePageDataBefore', array( &$this, &$fields ) );
+               Hooks::run( 'ArticlePageDataBefore', array( &$this, &$fields ) );
 
                $row = $dbr->selectRow( 'page', $fields, $conditions, __METHOD__, $options );
 
-               wfRunHooks( 'ArticlePageDataAfter', array( &$this, &$row ) );
+               Hooks::run( 'ArticlePageDataAfter', array( &$this, &$row ) );
 
                return $row;
        }
@@ -1178,7 +1178,7 @@ class WikiPage implements Page, IDBAccessObject {
        public function doPurge() {
                global $wgUseSquid;
 
-               if ( !wfRunHooks( 'ArticlePurge', array( &$this ) ) ) {
+               if ( !Hooks::run( 'ArticlePurge', array( &$this ) ) ) {
                        return false;
                }
 
@@ -1749,7 +1749,7 @@ class WikiPage implements Page, IDBAccessObject {
                $hook_args = array( &$this, &$user, &$content, &$summary,
                                                        $flags & EDIT_MINOR, null, null, &$flags, &$status );
 
-               if ( !wfRunHooks( 'PageContentSave', $hook_args )
+               if ( !Hooks::run( 'PageContentSave', $hook_args )
                        || !ContentHandler::runLegacyHooks( 'ArticleSave', $hook_args ) ) {
 
                        wfDebug( __METHOD__ . ": ArticleSave or ArticleSaveContent hook aborted save!\n" );
@@ -1783,7 +1783,7 @@ class WikiPage implements Page, IDBAccessObject {
                        $summary = $handler->getAutosummary( $old_content, $content, $flags );
                }
 
-               $editInfo = $this->prepareContentForEdit( $content, null, $user, $serialFormat, true );
+               $editInfo = $this->prepareContentForEdit( $content, null, $user, $serialFormat );
                $serialized = $editInfo->pst;
 
                /**
@@ -1860,7 +1860,7 @@ class WikiPage implements Page, IDBAccessObject {
                                                return $status;
                                        }
 
-                                       wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) );
+                                       Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) );
                                        // Update recentchanges
                                        if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
                                                // Mark as patrolled if the user can do so
@@ -1965,7 +1965,7 @@ class WikiPage implements Page, IDBAccessObject {
                                // Update the page record with revision data
                                $this->updateRevisionOn( $dbw, $revision, 0 );
 
-                               wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
+                               Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
 
                                // Update recentchanges
                                if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
@@ -1996,7 +1996,7 @@ class WikiPage implements Page, IDBAccessObject {
                                                                $flags & EDIT_MINOR, null, null, &$flags, $revision );
 
                        ContentHandler::runLegacyHooks( 'ArticleInsertComplete', $hook_args );
-                       wfRunHooks( 'PageContentInsertComplete', $hook_args );
+                       Hooks::run( 'PageContentInsertComplete', $hook_args );
                }
 
                // Do updates right now unless deferral was requested
@@ -2011,7 +2011,7 @@ class WikiPage implements Page, IDBAccessObject {
                                                        $flags & EDIT_MINOR, null, null, &$flags, $revision, &$status, $baseRevId );
 
                ContentHandler::runLegacyHooks( 'ArticleSaveComplete', $hook_args );
-               wfRunHooks( 'PageContentSaveComplete', $hook_args );
+               Hooks::run( 'PageContentSaveComplete', $hook_args );
 
                // Promote user to any groups they meet the criteria for
                $dbw->onTransactionIdle( function () use ( $user ) {
@@ -2076,7 +2076,7 @@ class WikiPage implements Page, IDBAccessObject {
         * @since 1.21
         */
        public function prepareContentForEdit(
-               Content $content, $revid = null, User $user = null, $serialFormat = null, $useCache = false
+               Content $content, $revid = null, User $user = null, $serialFormat = null, $useCache = true
        ) {
                global $wgContLang, $wgUser;
 
@@ -2105,7 +2105,7 @@ class WikiPage implements Page, IDBAccessObject {
                        : false;
 
                $popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
-               wfRunHooks( 'ArticlePrepareTextForEdit', array( $this, $popts ) );
+               Hooks::run( 'ArticlePrepareTextForEdit', array( $this, $popts ) );
 
                $edit = (object)array();
                if ( $cachedEdit ) {
@@ -2203,9 +2203,9 @@ class WikiPage implements Page, IDBAccessObject {
                        DataUpdate::runUpdates( $updates );
                }
 
-               wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
+               Hooks::run( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
 
-               if ( wfRunHooks( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) {
+               if ( Hooks::run( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) {
                        if ( 0 == mt_rand( 0, 99 ) ) {
                                // Flush old entries from the `recentchanges` table; we do this on
                                // random requests so as to avoid an increase in writes for no good reason
@@ -2250,7 +2250,7 @@ class WikiPage implements Page, IDBAccessObject {
                                wfDebug( __METHOD__ . ": invalid username\n" );
                        } else {
                                // Allow extensions to prevent user notification when a new message is added to their talk page
-                               if ( wfRunHooks( 'ArticleEditUpdateNewTalk', array( &$this, $recipient ) ) ) {
+                               if ( Hooks::run( 'ArticleEditUpdateNewTalk', array( &$this, $recipient ) ) ) {
                                        if ( User::isIP( $shortTitle ) ) {
                                                // An anonymous user
                                                $recipient->setNewtalk( true, $revision );
@@ -2333,7 +2333,7 @@ class WikiPage implements Page, IDBAccessObject {
                $revision->insertOn( $dbw );
                $this->updateRevisionOn( $dbw, $revision );
 
-               wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
+               Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
 
                wfProfileOut( __METHOD__ );
        }
@@ -2432,7 +2432,7 @@ class WikiPage implements Page, IDBAccessObject {
                $logRelationsField = null;
 
                if ( $id ) { // Protection of existing page
-                       if ( !wfRunHooks( 'ArticleProtect', array( &$this, &$user, $limit, $reason ) ) ) {
+                       if ( !Hooks::run( 'ArticleProtect', array( &$this, &$user, $limit, $reason ) ) ) {
                                return Status::newGood();
                        }
 
@@ -2512,8 +2512,8 @@ class WikiPage implements Page, IDBAccessObject {
                                __METHOD__
                        );
 
-                       wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $nullRevision, $latest, $user ) );
-                       wfRunHooks( 'ArticleProtectComplete', array( &$this, &$user, $limit, $reason ) );
+                       Hooks::run( 'NewRevisionFromEditComplete', array( $this, $nullRevision, $latest, $user ) );
+                       Hooks::run( 'ArticleProtectComplete', array( &$this, &$user, $limit, $reason ) );
                } else { // Protection of non-existing page (also known as "title protection")
                        // Cascade protection is meaningless in this case
                        $cascade = false;
@@ -2775,7 +2775,7 @@ class WikiPage implements Page, IDBAccessObject {
                }
 
                $user = is_null( $user ) ? $wgUser : $user;
-               if ( !wfRunHooks( 'ArticleDelete', array( &$this, &$user, &$reason, &$error, &$status ) ) ) {
+               if ( !Hooks::run( 'ArticleDelete', array( &$this, &$user, &$reason, &$error, &$status ) ) ) {
                        if ( $status->isOK() ) {
                                // Hook aborted but didn't set a fatal status
                                $status->fatal( 'delete-hook-aborted' );
@@ -2891,7 +2891,7 @@ class WikiPage implements Page, IDBAccessObject {
 
                $this->doDeleteUpdates( $id, $content );
 
-               wfRunHooks( 'ArticleDeleteComplete', array( &$this, &$user, $reason, $id, $content, $logEntry ) );
+               Hooks::run( 'ArticleDeleteComplete', array( &$this, &$user, $reason, $id, $content, $logEntry ) );
                $status->value = $logid;
                return $status;
        }
@@ -3133,7 +3133,7 @@ class WikiPage implements Page, IDBAccessObject {
 
                $revId = $status->value['revision']->getId();
 
-               wfRunHooks( 'ArticleRollbackComplete', array( $this, $guser, $target, $current ) );
+               Hooks::run( 'ArticleRollbackComplete', array( $this, $guser, $target, $current ) );
 
                $resultDetails = array(
                        'summary' => $summary,
@@ -3385,12 +3385,12 @@ class WikiPage implements Page, IDBAccessObject {
 
                                foreach ( $added as $catName ) {
                                        $cat = Category::newFromName( $catName );
-                                       wfRunHooks( 'CategoryAfterPageAdded', array( $cat, $that ) );
+                                       Hooks::run( 'CategoryAfterPageAdded', array( $cat, $that ) );
                                }
 
                                foreach ( $deleted as $catName ) {
                                        $cat = Category::newFromName( $catName );
-                                       wfRunHooks( 'CategoryAfterPageRemoved', array( $cat, $that ) );
+                                       Hooks::run( 'CategoryAfterPageRemoved', array( $cat, $that ) );
                                }
                        }
                );
@@ -3543,7 +3543,7 @@ class WikiPage implements Page, IDBAccessObject {
                        $updates = $content->getDeletionUpdates( $this );
                }
 
-               wfRunHooks( 'WikiPageDeletionUpdates', array( $this, $content, &$updates ) );
+               Hooks::run( 'WikiPageDeletionUpdates', array( $this, $content, &$updates ) );
                return $updates;
        }
 }
index 6c15993..0121072 100644 (file)
@@ -378,7 +378,7 @@ class LinkHolderArray {
                }
                if ( count( $linkcolour_ids ) ) {
                        //pass an array of page_ids to an extension
-                       wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
+                       Hooks::run( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
                }
                wfProfileOut( __METHOD__ . '-check' );
 
@@ -615,7 +615,7 @@ class LinkHolderArray {
                                        }
                                }
                        }
-                       wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
+                       Hooks::run( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
 
                        // rebuild the categories in original order (if there are replacements)
                        if ( count( $varCategories ) > 0 ) {
index ff62e9b..7b53776 100644 (file)
@@ -131,12 +131,12 @@ class MWTidy {
                $wrappedtext = $wrapper->getWrapped( $text );
 
                $retVal = null;
-               $correctedtext = self::clean( $wrappedtext, false, $retVal );
+               list( $correctedtext, $errors ) = self::clean( $wrappedtext, $retVal );
 
                if ( $retVal < 0 ) {
                        wfDebug( "Possible tidy configuration error!\n" );
                        return $text . "\n<!-- Tidy was unable to run -->\n";
-               } elseif ( is_null( $correctedtext ) ) {
+               } elseif ( $correctedtext === '' && $text !== '' ) {
                        wfDebug( "Tidy error detected!\n" );
                        return $text . "\n<!-- Tidy found serious XHTML errors -->\n";
                }
@@ -155,31 +155,23 @@ class MWTidy {
         */
        public static function checkErrors( $text, &$errorStr = null ) {
                $retval = 0;
-               $errorStr = self::clean( $text, true, $retval );
+               list( $outputStr, $errorStr ) = self::clean( $text, $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 string|null
         */
-       private static function clean( $text, $stderr = false, &$retval = null ) {
+       private static function clean( $text, &$retval = null ) {
                global $wgTidyInternal;
 
                if ( $wgTidyInternal ) {
-                       if ( wfIsHHVM() ) {
-                               if ( $stderr ) {
-                                       throw new MWException( __METHOD__.": error text return from HHVM tidy is not supported" );
-                               }
-                               return self::hhvmClean( $text, $retval );
-                       } else {
-                               return self::phpClean( $text, $stderr, $retval );
-                       }
+                       return self::internalClean( $text, $retval );
                } else {
-                       return self::externalClean( $text, $stderr, $retval );
+                       return self::externalClean( $text, $retval );
                }
        }
 
@@ -188,32 +180,23 @@ class MWTidy {
         * 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 ) {
+       private static function externalClean( $text, &$retval = null ) {
                global $wgTidyConf, $wgTidyBin, $wgTidyOpts;
                wfProfileIn( __METHOD__ );
 
-               $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' )
-                       );
-               }
+               $descriptorspec = array(
+                       0 => array( 'pipe', 'r' ),
+                       1 => array( 'pipe', 'w' ),
+                       2 => array( 'pipe', 'w' ),
+               );
 
-               $readpipe = $stderr ? 2 : 1;
+               $outputBuffer = '';
+               $errorBuffer = '';
                $pipes = array();
 
                $process = proc_open(
@@ -230,24 +213,25 @@ class MWTidy {
                        // for tidyParseStdin and tidySaveStdout in console/tidy.c
                        fwrite( $pipes[0], $text );
                        fclose( $pipes[0] );
-                       while ( !feof( $pipes[$readpipe] ) ) {
-                               $cleansource .= fgets( $pipes[$readpipe], 1024 );
+
+                       while ( !feof( $pipes[1] ) ) {
+                               $outputBuffer .= fgets( $pipes[1], 1024 );
                        }
-                       fclose( $pipes[$readpipe] );
+                       fclose( $pipes[1] );
+
+                       while ( !feof( $pipes[2] ) ) {
+                               $errorBuffer .= fgets( $pipes[2], 1024 );
+                       }
+                       fclose( $pipes[2] );
+
                        $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;
-               }
-
                wfProfileOut( __METHOD__ );
-               return $cleansource;
+               return array( $outputBuffer, $errorBuffer );
        }
 
        /**
@@ -255,15 +239,16 @@ class MWTidy {
         * 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
         */
-       private static function phpClean( $text, $stderr = false, &$retval = null ) {
+       private static function internalClean( $text, &$retval = null ) {
                global $wgTidyConf, $wgDebugTidy;
                wfProfileIn( __METHOD__ );
 
-               if ( !class_exists( 'tidy' ) ) {
+               if ( ( !wfIsHHVM() && !class_exists( 'tidy' ) ) ||
+                       ( wfIsHHVM() && !function_exists( 'tidy_repair_string' ) )
+               ) {
                        wfWarn( "Unable to load internal tidy class." );
                        $retval = -1;
 
@@ -271,57 +256,36 @@ class MWTidy {
                        return null;
                }
 
-               $tidy = new tidy;
-               $tidy->parseString( $text, $wgTidyConf, 'utf8' );
-
-               if ( $stderr ) {
-                       $retval = $tidy->getStatus();
-
-                       wfProfileOut( __METHOD__ );
-                       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;
+               $outputBuffer = '';
+               $errorBuffer = '';
+
+               if ( wfIsHHVM() ) {
+                       // 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.
+                       $result = tidy_repair_string( $text, $wgTidyConf, 'utf8' );
+                       $outputBuffer .= $result;
+                       $retval = $result === false ? -1 : 0;
                } else {
-                       $cleansource = tidy_get_output( $tidy );
-                       if ( $wgDebugTidy && $retval > 0 ) {
-                               $cleansource .= "<!--\nTidy reports:\n" .
-                                       str_replace( '-->', '--&gt;', $tidy->errorBuffer ) .
-                                       "\n-->";
+                       $tidy = new tidy;
+                       $tidy->parseString( $text, $wgTidyConf, 'utf8' );
+                       $tidy->cleanRepair();
+                       $retval = $tidy->getStatus();
+                       $outputBuffer .= tidy_get_output( $tidy );
+                       if ( $retval > 0 ) {
+                               $errorBuffer .= $tidy->errorBuffer;
                        }
                }
 
-               wfProfileOut( __METHOD__ );
-               return $cleansource;
-       }
-
-       /**
-        * 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
-        */
-       private static function hhvmClean( $text, &$retval ) {
-               global $wgTidyConf;
-               wfProfileIn( __METHOD__ );
-               $cleansource = tidy_repair_string( $text, $wgTidyConf, 'utf8' );
-               if ( $cleansource === false ) {
-                       $cleansource = null;
-                       $retval = -1;
-               } else {
-                       $retval = 0;
+               if ( $wgDebugTidy && $errorBuffer && $retval > 0 ) {
+                       $outputBuffer .= "<!--\nTidy reports:\n" .
+                               str_replace( '-->', '--&gt;', $tidy->errorBuffer ) .
+                               "\n-->";
                }
+
                wfProfileOut( __METHOD__ );
-               return $cleansource;
+               return array( $outputBuffer, $errorBuffer );
        }
 }
index 1b926c4..5c8253a 100644 (file)
@@ -283,7 +283,7 @@ class Parser {
                        unset( $tmp );
                }
 
-               wfRunHooks( 'ParserCloned', array( $this ) );
+               Hooks::run( 'ParserCloned', array( $this ) );
        }
 
        /**
@@ -301,7 +301,7 @@ class Parser {
                CoreTagHooks::register( $this );
                $this->initialiseVariables();
 
-               wfRunHooks( 'ParserFirstCallInit', array( &$this ) );
+               Hooks::run( 'ParserFirstCallInit', array( &$this ) );
                wfProfileOut( __METHOD__ );
        }
 
@@ -369,7 +369,7 @@ class Parser {
 
                $this->mProfiler = new SectionProfiler();
 
-               wfRunHooks( 'ParserClearState', array( &$this ) );
+               Hooks::run( 'ParserClearState', array( &$this ) );
                wfProfileOut( __METHOD__ );
        }
 
@@ -428,11 +428,11 @@ class Parser {
                        $this->mRevisionSize = null;
                }
 
-               wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
                # No more strip!
-               wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
                $text = $this->internalParse( $text );
-               wfRunHooks( 'ParserAfterParse', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserAfterParse', array( &$this, &$text, &$this->mStripState ) );
 
                $text = $this->internalParseHalfParsed( $text, true, $linestart );
 
@@ -498,14 +498,14 @@ class Parser {
                        $this->mOutput->setLimitReportData( 'limitreport-expensivefunctioncount',
                                array( $this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit() )
                        );
-                       wfRunHooks( 'ParserLimitReportPrepare', array( $this, $this->mOutput ) );
+                       Hooks::run( 'ParserLimitReportPrepare', array( $this, $this->mOutput ) );
 
                        $limitReport = "NewPP limit report\n";
                        if ( $wgShowHostnames ) {
                                $limitReport .= 'Parsed by ' . wfHostname() . "\n";
                        }
                        foreach ( $this->mOutput->getLimitReportData() as $key => $value ) {
-                               if ( wfRunHooks( 'ParserLimitReportFormat',
+                               if ( Hooks::run( 'ParserLimitReportFormat',
                                        array( $key, &$value, &$limitReport, false, false )
                                ) ) {
                                        $keyMsg = wfMessage( $key )->inLanguage( 'en' )->useDatabase( false );
@@ -523,7 +523,7 @@ class Parser {
                        // Since we're not really outputting HTML, decode the entities and
                        // then re-encode the things that need hiding inside HTML comments.
                        $limitReport = htmlspecialchars_decode( $limitReport );
-                       wfRunHooks( 'ParserLimitReport', array( $this, &$limitReport ) );
+                       Hooks::run( 'ParserLimitReport', array( $this, &$limitReport ) );
 
                        // Sanitize for comment. Note '‐' in the replacement is U+2010,
                        // which looks much like the problematic '-'.
@@ -532,14 +532,14 @@ class Parser {
 
                        // Add on template profiling data
                        $dataByFunc = $this->mProfiler->getFunctionStats();
-                       uasort( $dataByFunc, function( $a, $b ) {
+                       uasort( $dataByFunc, function ( $a, $b ) {
                                return $a['real'] < $b['real']; // descending order
                        } );
                        $profileReport = "Transclusion expansion time report (%,ms,calls,template)\n";
                        foreach ( array_slice( $dataByFunc, 0, 10 ) as $item ) {
                                $profileReport .= sprintf( "%6.2f%% %8.3f %6d - %s\n",
                                        $item['%real'], $item['real'], $item['calls'],
-                                       htmlspecialchars($item['name'] ) );
+                                       htmlspecialchars( $item['name'] ) );
                        }
                        $text .= "\n<!-- \n$profileReport-->\n";
 
@@ -587,8 +587,8 @@ class Parser {
         */
        public function recursiveTagParse( $text, $frame = false ) {
                wfProfileIn( __METHOD__ );
-               wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
-               wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
                $text = $this->internalParse( $text, false, $frame );
                wfProfileOut( __METHOD__ );
                return $text;
@@ -637,8 +637,8 @@ class Parser {
                if ( $revid !== null ) {
                        $this->mRevisionId = $revid;
                }
-               wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
-               wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
                $text = $this->replaceVariables( $text, $frame );
                $text = $this->mStripState->unstripBoth( $text );
                wfProfileOut( __METHOD__ );
@@ -1223,7 +1223,7 @@ class Parser {
                $origText = $text;
 
                # Hook to suspend the parser in this state
-               if ( !wfRunHooks( 'ParserBeforeInternalParse', array( &$this, &$text, &$this->mStripState ) ) ) {
+               if ( !Hooks::run( 'ParserBeforeInternalParse', array( &$this, &$text, &$this->mStripState ) ) ) {
                        wfProfileOut( __METHOD__ );
                        return $text;
                }
@@ -1244,14 +1244,14 @@ class Parser {
                        $text = $this->replaceVariables( $text );
                }
 
-               wfRunHooks( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
                $text = Sanitizer::removeHTMLtags(
                        $text,
                        array( &$this, 'attributeStripCallback' ),
                        false,
                        array_keys( $this->mTransparentTagHooks )
                );
-               wfRunHooks( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
 
                # Tables need to come after variable replacement for things to work
                # properly; putting them before other transformations should keep
@@ -1329,7 +1329,7 @@ class Parser {
                $text = $this->mStripState->unstripNoWiki( $text );
 
                if ( $isMain ) {
-                       wfRunHooks( 'ParserBeforeTidy', array( &$this, &$text ) );
+                       Hooks::run( 'ParserBeforeTidy', array( &$this, &$text ) );
                }
 
                $text = $this->replaceTransparentTags( $text );
@@ -1368,7 +1368,7 @@ class Parser {
                }
 
                if ( $isMain ) {
-                       wfRunHooks( 'ParserAfterTidy', array( &$this, &$text ) );
+                       Hooks::run( 'ParserAfterTidy', array( &$this, &$text ) );
                }
 
                return $text;
@@ -1393,13 +1393,13 @@ class Parser {
                        '!(?:                           # 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" . '
-                               (?:RFC|PMID)\s+([0-9]+) |   # m[4]: RFC or PMID, capture number
-                               ISBN\s+(\b                  # m[5]: ISBN, capture number
+                               (\b(?i:$prots)$urlChar+) |  # m[3]: Free external links" . '
+                               \b(?:RFC|PMID)\s+([0-9]+)\b |# m[4]: RFC or PMID, capture number
+                               \bISBN\s+(                  # m[5]: ISBN, capture number
                                        (?: 97[89] [\ \-]? )?   # optional 13-digit ISBN prefix
                                        (?: [0-9]  [\ \-]? ){9} # 9 digits with opt. delimiters
                                        [0-9Xx]                 # check digit
-                                       \b)
+                                       )\b
                        )!xu', array( &$this, 'magicLinkCallback' ), $text );
                wfProfileOut( __METHOD__ );
                return $text;
@@ -2318,7 +2318,7 @@ class Parser {
                                # Give extensions a chance to select the file revision for us
                                $options = array();
                                $descQuery = false;
-                               wfRunHooks( 'BeforeParserFetchFileAndTitle',
+                               Hooks::run( 'BeforeParserFetchFileAndTitle',
                                        array( $this, $nt, &$options, &$descQuery ) );
                                # Fetch and register the file (file title may be different via hooks)
                                list( $file, $nt ) = $this->fetchFileAndTitle( $nt, $options );
@@ -2945,14 +2945,14 @@ class Parser {
                 * Some of these require message or data lookups and can be
                 * expensive to check many times.
                 */
-               if ( wfRunHooks( 'ParserGetVariableValueVarCache', array( &$this, &$this->mVarCache ) ) ) {
+               if ( Hooks::run( 'ParserGetVariableValueVarCache', array( &$this, &$this->mVarCache ) ) ) {
                        if ( isset( $this->mVarCache[$index] ) ) {
                                return $this->mVarCache[$index];
                        }
                }
 
                $ts = wfTimestamp( TS_UNIX, $this->mOptions->getTimestamp() );
-               wfRunHooks( 'ParserGetVariableValueTs', array( &$this, &$ts ) );
+               Hooks::run( 'ParserGetVariableValueTs', array( &$this, &$ts ) );
 
                $pageLang = $this->getFunctionLang();
 
@@ -3260,7 +3260,7 @@ class Parser {
                                break;
                        default:
                                $ret = null;
-                               wfRunHooks(
+                               Hooks::run(
                                        'ParserGetVariableValueSwitch',
                                        array( &$this, &$this->mVarCache, &$index, &$ret, &$frame )
                                );
@@ -4011,7 +4011,7 @@ class Parser {
                for ( $i = 0; $i < 2 && is_object( $title ); $i++ ) {
                        # Give extensions a chance to select the revision instead
                        $id = false; # Assume current
-                       wfRunHooks( 'BeforeParserFetchTemplateAndtitle',
+                       Hooks::run( 'BeforeParserFetchTemplateAndtitle',
                                array( $parser, $title, &$skip, &$id ) );
 
                        if ( $skip ) {
@@ -4820,7 +4820,7 @@ class Parser {
                         * &$sectionContent : ref to the content of the section
                         * $showEditLinks : boolean describing whether this section has an edit link
                         */
-                       wfRunHooks( 'ParserSectionCreate', array( $this, $i, &$sections[$i], $showEditLink ) );
+                       Hooks::run( 'ParserSectionCreate', array( $this, $i, &$sections[$i], $showEditLink ) );
 
                        $i++;
                }
@@ -5403,7 +5403,7 @@ class Parser {
                }
                $ig->setAdditionalOptions( $params );
 
-               wfRunHooks( 'BeforeParserrenderImageGallery', array( &$this, &$ig ) );
+               Hooks::run( 'BeforeParserrenderImageGallery', array( &$this, &$ig ) );
 
                $lines = StringUtils::explode( "\n", $text );
                foreach ( $lines as $line ) {
@@ -5430,7 +5430,7 @@ class Parser {
                        # file (which potentially could be of a different type and have different handler).
                        $options = array();
                        $descQuery = false;
-                       wfRunHooks( 'BeforeParserFetchFileAndTitle',
+                       Hooks::run( 'BeforeParserFetchFileAndTitle',
                                array( $this, $title, &$options, &$descQuery ) );
                        # Don't register it now, as ImageGallery does that later.
                        $file = $this->fetchFileNoRegister( $title, $options );
@@ -5511,7 +5511,7 @@ class Parser {
                        $ig->add( $title, $label, $alt, $link, $handlerOptions );
                }
                $html = $ig->toHTML();
-               wfRunHooks( 'AfterParserFetchFileAndTitle', array( $this, $ig, &$html ) );
+               Hooks::run( 'AfterParserFetchFileAndTitle', array( $this, $ig, &$html ) );
                wfProfileOut( __METHOD__ );
                return $html;
        }
@@ -5600,7 +5600,7 @@ class Parser {
                # Give extensions a chance to select the file revision for us
                $options = array();
                $descQuery = false;
-               wfRunHooks( 'BeforeParserFetchFileAndTitle',
+               Hooks::run( 'BeforeParserFetchFileAndTitle',
                        array( $this, $title, &$options, &$descQuery ) );
                # Fetch and register the file (file title may be different via hooks)
                list( $file, $title ) = $this->fetchFileAndTitle( $title, $options );
@@ -5764,7 +5764,7 @@ class Parser {
                        $params['frame']['title'] = $this->stripAltText( $caption, $holders );
                }
 
-               wfRunHooks( 'ParserMakeImageParams', array( $title, $file, &$params, $this ) );
+               Hooks::run( 'ParserMakeImageParams', array( $title, $file, &$params, $this ) );
 
                # Linker does the rest
                $time = isset( $options['time'] ) ? $options['time'] : false;
index b570fa5..7ad85a9 100644 (file)
@@ -641,6 +641,7 @@ class ParserOptions {
 
                wfProfileIn( __METHOD__ );
 
+               // *UPDATE* ParserOptions::matches() if any of this changes as needed
                $this->mInterwikiMagic = $wgInterwikiMagic;
                $this->mAllowExternalImages = $wgAllowExternalImages;
                $this->mAllowExternalImagesFrom = $wgAllowExternalImagesFrom;
@@ -666,6 +667,32 @@ class ParserOptions {
                wfProfileOut( __METHOD__ );
        }
 
+       /**
+        * Check if these options match that of another options set
+        *
+        * This ignores report limit settings that only affect HTML comments
+        *
+        * @return bool
+        * @since 1.25
+        */
+       public function matches( ParserOptions $other ) {
+               $fields = array_keys( get_class_vars( __CLASS__ ) );
+               $fields = array_diff( $fields, array(
+                       'mEnableLimitReport', // only effects HTML comments
+                       'onAccessCallback', // only used for ParserOutput option tracking
+               ) );
+               foreach ( $fields as $field ) {
+                       if ( !is_object( $this->$field ) && $this->$field !== $other->$field ) {
+                               return false;
+                       }
+               }
+               // Check the object and lazy-loaded options
+               return (
+                       $this->mUserLang->getCode() === $other->mUserLang->getCode() &&
+                       $this->getDateFormat() === $other->getDateFormat()
+               );
+       }
+
        /**
         * Registers a callback for tracking which ParserOptions which are used.
         * This is a private API with the parser.
@@ -784,7 +811,7 @@ class ParserOptions {
 
                // Give a chance for extensions to modify the hash, if they have
                // extra options or other effects on the parser cache.
-               wfRunHooks( 'PageRenderingHash', array( &$confstr, $this->getUser(), &$forOptions ) );
+               Hooks::run( 'PageRenderingHash', array( &$confstr, $this->getUser(), &$forOptions ) );
 
                // Make it a valid memcached key fragment
                $confstr = str_replace( ' ', '_', $confstr );
index 2be142f..667a9e2 100644 (file)
@@ -241,14 +241,16 @@ abstract class Profiler {
         * This makes filtering them out easier and follows the xhprof style.
         *
         * @return array List of method entries arrays, each having:
-        *   - name    : method name
-        *   - calls   : the number of invoking calls
-        *   - real    : real time ellapsed (ms)
-        *   - %real   : percent real time
-        *   - cpu     : CPU time ellapsed (ms)
-        *   - %cpu    : percent CPU time
-        *   - memory  : memory used (bytes)
-        *   - %memory : percent memory used
+        *   - name     : method name
+        *   - calls    : the number of invoking calls
+        *   - real     : real time ellapsed (ms)
+        *   - %real    : percent real time
+        *   - cpu      : CPU time ellapsed (ms)
+        *   - %cpu     : percent CPU time
+        *   - memory   : memory used (bytes)
+        *   - %memory  : percent memory used
+        *   - min_real : min real time in a call (ms)
+        *   - max_real : max real time in a call (ms)
         * @since 1.25
         */
        abstract public function getFunctionStats();
index 87706e6..4ce88bd 100644 (file)
@@ -222,7 +222,7 @@ class ProfilerStandard extends Profiler {
                $this->profileIn( $section );
 
                $that = $this;
-               return new ScopedCallback( function() use ( $that, $section ) {
+               return new ScopedCallback( function () use ( $that, $section ) {
                        $that->profileOut( $section );
                } );
        }
@@ -345,7 +345,9 @@ class ProfilerStandard extends Profiler {
                $this->close(); // set "-total" entry
 
                if ( $this->collateOnly ) {
-                       return; // already collated as methods exited
+                       // already collated as methods exited
+                       $this->sortCollated();
+                       return;
                }
 
                $this->collated = array();
@@ -400,7 +402,21 @@ class ProfilerStandard extends Profiler {
                }
 
                $this->collated['-overhead-total']['count'] = $profileCount;
-               arsort( $this->collated, SORT_NUMERIC );
+               $this->sortCollated();
+       }
+
+       protected function sortCollated() {
+               uksort( $this->collated, function ( $a, $b ) {
+                       $ca = $this->collated[$a]['real'];
+                       $cb = $this->collated[$b]['real'];
+                       if ( $ca > $cb ) {
+                               return -1;
+                       } elseif ( $cb > $ca ) {
+                               return 1;
+                       } else {
+                               return 0;
+                       }
+               } );
        }
 
        /**
@@ -485,8 +501,8 @@ class ProfilerStandard extends Profiler {
                                '%cpu' => $totalCpu ? 100 * $data['cpu'] / $totalCpu : 0,
                                'memory' => $data['memory'],
                                '%memory' => $totalMem ? 100 * $data['memory'] / $totalMem : 0,
-                               'min' => $data['min_real'] * 1000,
-                               'max' => $data['max_real'] * 1000
+                               'min_real' => $data['min_real'] * 1000,
+                               'max_real' => $data['max_real'] * 1000
                        );
                }
 
index 2db06e4..9a7ec8c 100644 (file)
@@ -34,7 +34,7 @@ class ProfilerStub extends Profiler {
        }
 
        public function scopedProfileIn( $section ) {
-               return new ScopedCallback( function() {
+               return new ScopedCallback( function () {
                        // no-op
                } );
        }
index d91b429..a40c44a 100644 (file)
  * @see https://github.com/facebook/hhvm/blob/master/hphp/doc/profiling.md
  */
 class ProfilerXhprof extends Profiler {
-
        /**
         * @var Xhprof $xhprof
         */
        protected $xhprof;
 
        /**
-        * Type of report to send when logData() is called.
-        * @var string $logType
-        */
-       protected $logType;
-
-       /**
-        * Should profile report sent to in page content be visible?
-        * @var bool $visible
+        * Profiler for explicit, arbitrary, frame labels
+        * @var SectionProfiler
         */
-       protected $visible;
+       protected $sprofiler;
 
        /**
         * @param array $params
         * @see Xhprof::__construct()
         */
        public function __construct( array $params = array() ) {
-               $params = array_merge(
-                       array(
-                               'log' => 'text',
-                               'visible' => false
-                       ),
-                       $params
-               );
                parent::__construct( $params );
-               $this->logType = $params['log'];
-               $this->visible = $params['visible'];
                $this->xhprof = new Xhprof( $params );
+               $this->sprofiler = new SectionProfiler();
        }
 
        /**
@@ -118,22 +103,7 @@ class ProfilerXhprof extends Profiler {
        }
 
        public function scopedProfileIn( $section ) {
-               static $exists = null;
-               // Only HHVM supports this, not the standard PECL extension
-               if ( $exists === null ) {
-                       $exists = function_exists( 'xhprof_frame_begin' );
-               }
-
-               if ( $exists ) {
-                       xhprof_frame_begin( $section );
-                       return new ScopedCallback( function() {
-                               xhprof_frame_end();
-                       } );
-               }
-
-               return new ScopedCallback( function() {
-                       // no-op
-               } );
+               return $this->sprofiler->scopedProfileIn( $section );
        }
 
        /**
@@ -146,9 +116,10 @@ class ProfilerXhprof extends Profiler {
                $metrics = $this->xhprof->getCompleteMetrics();
                $profile = array();
 
+               $main = null; // units in ms
                foreach ( $metrics as $fname => $stats ) {
                        // Convert elapsed times from μs to ms to match ProfilerStandard
-                       $profile[] = array(
+                       $entry = array(
                                'name' => $fname,
                                'calls' => $stats['ct'],
                                'real' => $stats['wt']['total'] / 1000,
@@ -157,9 +128,22 @@ class ProfilerXhprof extends Profiler {
                                '%cpu' => isset( $stats['cpu'] ) ? $stats['cpu']['percent'] : 0,
                                'memory' => isset( $stats['mu'] ) ? $stats['mu']['total'] : 0,
                                '%memory' => isset( $stats['mu'] ) ? $stats['mu']['percent'] : 0,
-                               'min' => $stats['wt']['min'] / 1000,
-                               'max' => $stats['wt']['max'] / 1000
+                               'min_real' => $stats['wt']['min'] / 1000,
+                               'max_real' => $stats['wt']['max'] / 1000
                        );
+                       $profile[] = $entry;
+                       if ( $fname === 'main()' ) {
+                               $main = $entry;
+                       }
+               }
+
+               // Merge in all of the custom profile sections
+               foreach ( $this->sprofiler->getFunctionStats() as $stats ) {
+                       // @note: getFunctionStats() values already in ms
+                       $stats['%real'] = $stats['real'] / $main['real'];
+                       $stats['%cpu'] = $main['cpu'] ? $stats['cpu'] / $main['cpu'] * 100 : 0;
+                       $stats['%memory'] = $main['memory'] ? $stats['memory'] / $main['memory'] * 100 : 0;
+                       $profile[] = $stats; // assume no section names collide with $metrics
                }
 
                return $profile;
@@ -191,8 +175,13 @@ class ProfilerXhprof extends Profiler {
         * @return string
         */
        protected function getFunctionReport() {
-               $data = $this->xhprof->getInclusiveMetrics();
-               uasort( $data, Xhprof::makeSortFunction( 'wt', 'total' ) );
+               $data = $this->getFunctionStats();
+               usort( $data, function( $a, $b ) {
+                       if ( $a['real'] === $b['real'] ) {
+                               return 0;
+                       }
+                       return ( $a['real'] > $b['real'] ) ? -1 : 1; // descending
+               } );
 
                $width = 140;
                $nameWidth = $width - 65;
@@ -201,50 +190,18 @@ class ProfilerXhprof extends Profiler {
                $out[] = sprintf( "%-{$nameWidth}s %6s %9s %9s %9s %9s %7s %9s",
                        'Name', 'Calls', 'Total', 'Min', 'Each', 'Max', '%', 'Mem'
                );
-               foreach ( $data as $func => $stats ) {
-                       $out[] = sprintf( $format,
-                               $func,
-                               $stats['ct'],
-                               $stats['wt']['total'],
-                               $stats['wt']['min'],
-                               $stats['wt']['mean'],
-                               $stats['wt']['max'],
-                               $stats['wt']['percent'],
-                               isset( $stats['mu'] ) ? $stats['mu']['total'] : 0
-                       );
-               }
-               return implode( "\n", $out );
-       }
-
-       /**
-        * Get a brief report of profiled functions sorted by inclusive wall clock
-        * time in descending order.
-        *
-        * Each line of the report includes this data:
-        * - Percentage of total wall clock time spent in function
-        * - Total wall clock time spent in function in seconds
-        * - Number of times function was called
-        * - Function name
-        *
-        * @param string $header Header text to prepend to report
-        * @param string $footer Footer text to append to report
-        * @return string
-        */
-       protected function getSummaryReport( $header = '', $footer = '' ) {
-               $data = $this->xhprof->getInclusiveMetrics();
-               uasort( $data, Xhprof::makeSortFunction( 'wt', 'total' ) );
-
-               $format = '%6.2f%% %3.6f %6d - %s';
-               $out = array( $header );
-               foreach ( $data as $func => $stats ) {
+               foreach ( $data as $stats ) {
                        $out[] = sprintf( $format,
-                               $stats['wt']['percent'],
-                               $stats['wt']['total'] / 1e6,
-                               $stats['ct'],
-                               $func
+                               $stats['name'],
+                               $stats['calls'],
+                               $stats['real'] * 1000,
+                               $stats['min_real'] * 1000,
+                               $stats['real'] / $stats['calls'] * 1000,
+                               $stats['max_real'] * 1000,
+                               $stats['%real'],
+                               $stats['memory']
                        );
                }
-               $out[] = $footer;
                return implode( "\n", $out );
        }
 }
index 89eebbe..2c36b68 100644 (file)
  * @since 1.25
  */
 class SectionProfiler {
+       /** @var array Map of (mem,real,cpu) */
+       protected $start;
+       /** @var array Map of (mem,real,cpu) */
+       protected $end;
        /** @var array List of resolved profile calls with start/end data */
        protected $stack = array();
        /** @var array Queue of open profile calls with start data */
@@ -37,11 +41,13 @@ class SectionProfiler {
        protected $collated = array();
        /** @var bool */
        protected $collateDone = false;
+
        /** @var bool Whether to collect the full stack trace or just aggregates */
        protected $collateOnly = true;
-
        /** @var array Cache of a standard broken collation entry */
        protected $errorEntry;
+       /** @var callable Cache of a profile out callback */
+       protected $profileOutCallback;
 
        /**
         * @param array $params
@@ -49,6 +55,9 @@ class SectionProfiler {
        public function __construct( array $params = array() ) {
                $this->errorEntry = $this->getErrorEntry();
                $this->collateOnly = empty( $params['trace'] );
+               $this->profileOutCallback = function ( $profiler, $section ) {
+                       $profiler->profileOutInternal( $section );
+               };
        }
 
        /**
@@ -59,9 +68,7 @@ class SectionProfiler {
                $this->profileInInternal( $section );
 
                $that = $this;
-               return new ScopedCallback( function() use ( $that, $section ) {
-                       $that->profileOutInternal( $section );
-               } );
+               return new ScopedCallback( $this->profileOutCallback, array( $that, $section ) );
        }
 
        /**
@@ -89,18 +96,15 @@ class SectionProfiler {
         *   - %cpu    : percent real time
         *   - memory  : memory used (bytes)
         *   - %memory : percent memory used
+        *   - min_real : min real time in a call (ms)
+        *   - max_real : max real time in a call (ms)
         */
        public function getFunctionStats() {
                $this->collateData();
 
-               $totalCpu = 0.0;
-               $totalReal = 0.0;
-               $totalMem = 0;
-               foreach ( $this->collated as $fname => $data ) {
-                       $totalCpu += $data['cpu'];
-                       $totalReal += $data['real'];
-                       $totalMem += $data['memory'];
-               }
+               $totalCpu = max( $this->end['cpu'] - $this->start['cpu'], 0 );
+               $totalReal = max( $this->end['real'] - $this->start['real'], 0 );
+               $totalMem = max( $this->end['memory'] - $this->start['memory'], 0 );
 
                $profile = array();
                foreach ( $this->collated as $fname => $data ) {
@@ -113,6 +117,8 @@ class SectionProfiler {
                                '%cpu' => $totalCpu ? 100 * $data['cpu'] / $totalCpu : 0,
                                'memory' => $data['memory'],
                                '%memory' => $totalMem ? 100 * $data['memory'] / $totalMem : 0,
+                               'min_real' => 1000 * $data['min_real'],
+                               'max_real' => 1000 * $data['max_real']
                        );
                }
 
@@ -125,11 +131,25 @@ class SectionProfiler {
                        '%cpu' => 100,
                        'memory' => $totalMem,
                        '%memory' => 100,
+                       'min_real' => 1000 * $totalReal,
+                       'max_real' => 1000 * $totalReal
                );
 
                return $profile;
        }
 
+       /**
+        * Clear all of the profiling data for another run
+        */
+       public function reset() {
+               $this->start = null;
+               $this->end = null;
+               $this->stack = array();
+               $this->workStack = array();
+               $this->collated = array();
+               $this->collateDone = false;
+       }
+
        /**
         * @return array Initial collation entry
         */
@@ -138,7 +158,9 @@ class SectionProfiler {
                        'cpu'      => 0.0,
                        'real'     => 0.0,
                        'memory'   => 0,
-                       'count'    => 0
+                       'count'    => 0,
+                       'min_real' => 0.0,
+                       'max_real' => 0.0
                );
        }
 
@@ -169,6 +191,8 @@ class SectionProfiler {
                $entry['real'] += $elapsedReal;
                $entry['memory'] += $memChange > 0 ? $memChange : 0;
                $entry['count']++;
+               $entry['min_real'] = min( $entry['min_real'], $elapsedReal );
+               $entry['max_real'] = max( $entry['max_real'], $elapsedReal );
        }
 
        /**
@@ -177,12 +201,25 @@ class SectionProfiler {
         * @param string $functionname
         */
        public function profileInInternal( $functionname ) {
+               // Once the data is collated for reports, any future calls
+               // should clear the collation cache so the next report will
+               // reflect them. This matters when trace mode is used.
+               $this->collateDone = false;
+
+               $cpu = $this->getTime( 'cpu' );
+               $real = $this->getTime( 'wall' );
+               $memory = memory_get_usage();
+
+               if ( $this->start === null ) {
+                       $this->start = array( 'cpu' => $cpu, 'real' => $real, 'memory' => $memory );
+               }
+
                $this->workStack[] = array(
                        $functionname,
                        count( $this->workStack ),
-                       $this->getTime( 'time' ),
-                       $this->getTime( 'cpu' ),
-                       memory_get_usage()
+                       $real,
+                       $cpu,
+                       $memory
                );
        }
 
@@ -217,17 +254,25 @@ class SectionProfiler {
                                $this->stack[] = array( $message, 0, 0.0, 0.0, 0, 0.0, 0.0, 0 );
                        }
                }
+
                $realTime = $this->getTime( 'wall' );
                $cpuTime = $this->getTime( 'cpu' );
+               $memUsage = memory_get_usage();
+
                if ( $this->collateOnly ) {
                        $elapsedcpu = $cpuTime - $octime;
                        $elapsedreal = $realTime - $ortime;
-                       $memchange = memory_get_usage() - $omem;
+                       $memchange = $memUsage - $omem;
                        $this->updateEntry( $functionname, $elapsedcpu, $elapsedreal, $memchange );
                } else {
-                       $this->stack[] = array_merge( $item,
-                               array( $realTime, $cpuTime,     memory_get_usage() ) );
+                       $this->stack[] = array_merge( $item, array( $realTime, $cpuTime, $memUsage ) );
                }
+
+               $this->end = array(
+                       'cpu'      => $cpuTime,
+                       'real'     => $realTime,
+                       'memory'   => $memUsage
+               );
        }
 
        /**
@@ -320,6 +365,7 @@ class SectionProfiler {
                $this->collated = array();
 
                # Estimate profiling overhead
+               $oldEnd = $this->end;
                $profileCount = count( $this->stack );
                $this->calculateOverhead( $profileCount );
 
@@ -355,7 +401,7 @@ class SectionProfiler {
                        $subcalls = $this->calltreeCount( $this->stack, $index );
 
                        if ( substr( $fname, 0, 9 ) !== '-overhead' ) {
-                               # Adjust for profiling overhead (except special values with elapsed=0
+                               # Adjust for profiling overhead (except special values with elapsed=0)
                                if ( $elapsed ) {
                                        $elapsed -= $overheadInternal;
                                        $elapsed -= ( $subcalls * $overheadTotal );
@@ -368,6 +414,9 @@ class SectionProfiler {
 
                $this->collated['-overhead-total']['count'] = $profileCount;
                arsort( $this->collated, SORT_NUMERIC );
+
+               // Unclobber the end info map (the overhead checking alters it)
+               $this->end = $oldEnd;
        }
 
        /**
index ab42802..76d62d2 100644 (file)
@@ -38,7 +38,7 @@ class ProfilerOutputDb extends ProfilerOutput {
                // Initialize per-host profiling from config, back-compat if available
                if ( isset( $this->params['perHost'] ) ) {
                        $this->perHost = $this->params['perHost'];
-               } elseif( $wgProfilePerHost ) {
+               } elseif ( $wgProfilePerHost ) {
                        $this->perHost = $wgProfilePerHost;
                }
        }
index b24bbef..d37d74f 100644 (file)
@@ -43,11 +43,11 @@ class ProfilerOutputText extends ProfilerOutput {
 
                        // Filter out really tiny entries
                        $min = $this->thresholdMs;
-                       $stats = array_filter( $stats, function( $a ) use ( $min ) {
+                       $stats = array_filter( $stats, function ( $a ) use ( $min ) {
                                return $a['real'] > $min;
                        } );
                        // Sort descending by time elapsed
-                       usort( $stats, function( $a, $b ) {
+                       usort( $stats, function ( $a, $b ) {
                                return $a['real'] < $b['real'];
                        } );
 
index d5c7e5c..7da03c1 100644 (file)
@@ -45,19 +45,19 @@ class ProfilerOutputUdp extends ProfilerOutput {
                // Initialize port, host, and format from config, back-compat if available
                if ( isset( $this->params['udpport'] ) ) {
                        $this->port = $this->params['udpport'];
-               } elseif( $wgUDPProfilerPort ) {
+               } elseif ( $wgUDPProfilerPort ) {
                        $this->port = $wgUDPProfilerPort;
                }
 
                if ( isset( $this->params['udphost'] ) ) {
                        $this->host = $this->params['udphost'];
-               } elseif( $wgUDPProfilerHost ) {
+               } elseif ( $wgUDPProfilerHost ) {
                        $this->host = $wgUDPProfilerHost;
                }
 
                if ( isset( $this->params['udpformat'] ) ) {
                        $this->format = $this->params['udpformat'];
-               } elseif( $wgUDPProfilerFormatString ) {
+               } elseif ( $wgUDPProfilerFormatString ) {
                        $this->format = $wgUDPProfilerFormatString;
                }
        }
index 02a8d7e..30be343 100644 (file)
@@ -56,7 +56,7 @@ class IRCColourfulRCFeedFormatter implements RCFeedFormatter {
                                $query .= '&rcid=' . $attribs['rc_id'];
                        }
                        // HACK: We need this hook for WMF's secure server setup
-                       wfRunHooks( 'IRCLineURL', array( &$url, &$query, $rc ) );
+                       Hooks::run( 'IRCLineURL', array( &$url, &$query, $rc ) );
                        $url .= $query;
                }
 
index 2c54f69..933397c 100644 (file)
@@ -63,8 +63,11 @@ class ResourceLoader {
         */
        protected $sources = array();
 
-       /** @var bool */
-       protected $hasErrors = false;
+       /**
+        * Errors accumulated during current respond() call.
+        * @var array
+        */
+       protected $errors = array();
 
        /**
         * Load information stored in the database about modules.
@@ -140,7 +143,7 @@ class ResourceLoader {
                foreach ( array_keys( $modulesWithoutMessages ) as $name ) {
                        $module = $this->getModule( $name );
                        if ( $module ) {
-                               $module->setMsgBlobMtime( $lang, 0 );
+                               $module->setMsgBlobMtime( $lang, 1 );
                        }
                }
        }
@@ -209,9 +212,7 @@ class ResourceLoader {
                } catch ( Exception $e ) {
                        MWExceptionHandler::logException( $e );
                        wfDebugLog( 'resourceloader', __METHOD__ . ": minification failed: $e" );
-                       $this->hasErrors = true;
-                       // Return exception as a comment
-                       $result = self::formatException( $e );
+                       $this->errors[] = self::formatExceptionNoComment( $e );
                }
 
                wfProfileOut( __METHOD__ );
@@ -246,7 +247,7 @@ class ResourceLoader {
                // Register core modules
                $this->register( include "$IP/resources/Resources.php" );
                // Register extension modules
-               wfRunHooks( 'ResourceLoaderRegisterModules', array( &$this ) );
+               Hooks::run( 'ResourceLoaderRegisterModules', array( &$this ) );
                $this->register( $config->get( 'ResourceModules' ) );
 
                if ( $config->get( 'EnableJavaScriptTest' ) === true ) {
@@ -376,7 +377,7 @@ class ResourceLoader {
                $testModules = array();
                $testModules['qunit'] = array();
                // Get other test suites (e.g. from extensions)
-               wfRunHooks( 'ResourceLoaderTestModules', array( &$testModules, &$this ) );
+               Hooks::run( 'ResourceLoaderTestModules', array( &$testModules, &$this ) );
 
                // Add the testrunner (which configures QUnit) to the dependencies.
                // Since it must be ready before any of the test suites are executed.
@@ -579,7 +580,6 @@ class ResourceLoader {
                ob_start();
 
                wfProfileIn( __METHOD__ );
-               $errors = '';
 
                // Find out which modules are missing and instantiate the others
                $modules = array();
@@ -591,10 +591,7 @@ class ResourceLoader {
                                // This is a security issue, see bug 34907.
                                if ( $module->getGroup() === 'private' ) {
                                        wfDebugLog( 'resourceloader', __METHOD__ . ": request for private module '$name' denied" );
-                                       $this->hasErrors = true;
-                                       // Add exception to the output as a comment
-                                       $errors .= self::makeComment( "Cannot show private module \"$name\"" );
-
+                                       $this->errors[] = "Cannot show private module \"$name\"";
                                        continue;
                                }
                                $modules[$name] = $module;
@@ -609,9 +606,7 @@ class ResourceLoader {
                } catch ( Exception $e ) {
                        MWExceptionHandler::logException( $e );
                        wfDebugLog( 'resourceloader', __METHOD__ . ": preloading module info failed: $e" );
-                       $this->hasErrors = true;
-                       // Add exception to the output as a comment
-                       $errors .= self::formatException( $e );
+                       $this->errors[] = self::formatExceptionNoComment( $e );
                }
 
                wfProfileIn( __METHOD__ . '-getModifiedTime' );
@@ -629,9 +624,7 @@ class ResourceLoader {
                        } catch ( Exception $e ) {
                                MWExceptionHandler::logException( $e );
                                wfDebugLog( 'resourceloader', __METHOD__ . ": calculating maximum modified time failed: $e" );
-                               $this->hasErrors = true;
-                               // Add exception to the output as a comment
-                               $errors .= self::formatException( $e );
+                               $this->errors[] = self::formatExceptionNoComment( $e );
                        }
                }
 
@@ -646,19 +639,15 @@ class ResourceLoader {
                // Generate a response
                $response = $this->makeModuleResponse( $context, $modules, $missing );
 
-               // Prepend comments indicating exceptions
-               $response = $errors . $response;
-
                // Capture any PHP warnings from the output buffer and append them to the
-               // response in a comment if we're in debug mode.
+               // error list if we're in debug mode.
                if ( $context->getDebug() && strlen( $warnings = ob_get_contents() ) ) {
-                       $response = self::makeComment( $warnings ) . $response;
-                       $this->hasErrors = true;
+                       $this->errors[] = $warnings;
                }
 
                // Save response to file cache unless there are errors
-               if ( isset( $fileCache ) && !$errors && !count( $missing ) ) {
-                       // Cache single modules...and other requests if there are enough hits
+               if ( isset( $fileCache ) && !$this->errors && !count( $missing ) ) {
+                       // Cache single modules and images...and other requests if there are enough hits
                        if ( ResourceFileCache::useFileCache( $context ) ) {
                                if ( $fileCache->isCacheWorthy() ) {
                                        $fileCache->saveText( $response );
@@ -669,10 +658,28 @@ class ResourceLoader {
                }
 
                // Send content type and cache related headers
-               $this->sendResponseHeaders( $context, $mtime, $this->hasErrors );
+               $this->sendResponseHeaders( $context, $mtime, (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;
+               } elseif ( $this->errors ) {
+                       // Prepend comments indicating errors
+                       $errorText = '';
+                       foreach ( $this->errors as $error ) {
+                               $errorText .= self::makeComment( $error );
+                       }
+                       $response = $errorText . $response;
+               }
+
+               $this->errors = array();
                echo $response;
 
                wfProfileOut( __METHOD__ );
@@ -682,7 +689,7 @@ class ResourceLoader {
         * Send content type and last modified headers to the client.
         * @param ResourceLoaderContext $context
         * @param string $mtime TS_MW timestamp to use for last-modified
-        * @param bool $errors Whether there are commented-out errors in the response
+        * @param bool $errors Whether there are errors in the response
         * @return void
         */
        protected function sendResponseHeaders( ResourceLoaderContext $context, $mtime, $errors ) {
@@ -699,7 +706,14 @@ class ResourceLoader {
                        $maxage = $rlMaxage['versioned']['client'];
                        $smaxage = $rlMaxage['versioned']['server'];
                }
-               if ( $context->getOnly() === 'styles' ) {
+               if ( $context->getImageObj() ) {
+                       // Output different headers if we're outputting textual errors.
+                       if ( $errors ) {
+                               header( 'Content-Type: text/plain; charset=utf-8' );
+                       } else {
+                               $context->getImageObj()->sendResponseHeaders( $context );
+                       }
+               } elseif ( $context->getOnly() === 'styles' ) {
                        header( 'Content-Type: text/css; charset=utf-8' );
                        header( 'Access-Control-Allow-Origin: *' );
                } else {
@@ -823,15 +837,26 @@ class ResourceLoader {
         * Handle exception display.
         *
         * @param Exception $e Exception to be shown to the user
-        * @return string Sanitized text that can be returned to the user
+        * @return string Sanitized text in a CSS/JS comment that can be returned to the user
         */
        public static function formatException( $e ) {
+               return self::makeComment( self::formatExceptionNoComment( $e ) );
+       }
+
+       /**
+        * Handle exception display.
+        *
+        * @since 1.25
+        * @param Exception $e Exception to be shown to the user
+        * @return string Sanitized text that can be returned to the user
+        */
+       protected static function formatExceptionNoComment( $e ) {
                global $wgShowExceptionDetails;
 
                if ( $wgShowExceptionDetails ) {
-                       return self::makeComment( $e->__toString() );
+                       return $e->__toString();
                } else {
-                       return self::makeComment( wfMessage( 'internalerror' )->text() );
+                       return wfMessage( 'internalerror' )->text();
                }
        }
 
@@ -847,7 +872,6 @@ class ResourceLoader {
                array $modules, array $missing = array()
        ) {
                $out = '';
-               $exceptions = '';
                $states = array();
 
                if ( !count( $modules ) && !count( $missing ) ) {
@@ -858,6 +882,17 @@ class ResourceLoader {
 
                wfProfileIn( __METHOD__ );
 
+               $image = $context->getImageObj();
+               if ( $image ) {
+                       $data = $image->getImageData( $context );
+                       if ( $data === false ) {
+                               $data = '';
+                               $this->errors[] = 'Image generation failed';
+                       }
+                       wfProfileOut( __METHOD__ );
+                       return $data;
+               }
+
                // Pre-fetch blobs
                if ( $context->shouldIncludeMessages() ) {
                        try {
@@ -868,9 +903,7 @@ class ResourceLoader {
                                        'resourceloader',
                                        __METHOD__ . ": pre-fetching blobs from MessageBlobStore failed: $e"
                                );
-                               $this->hasErrors = true;
-                               // Add exception to the output as a comment
-                               $exceptions .= self::formatException( $e );
+                               $this->errors[] = self::formatExceptionNoComment( $e );
                        }
                } else {
                        $blobs = array();
@@ -994,9 +1027,7 @@ class ResourceLoader {
                        } catch ( Exception $e ) {
                                MWExceptionHandler::logException( $e );
                                wfDebugLog( 'resourceloader', __METHOD__ . ": generating module package failed: $e" );
-                               $this->hasErrors = true;
-                               // Add exception to the output as a comment
-                               $exceptions .= self::formatException( $e );
+                               $this->errors[] = self::formatExceptionNoComment( $e );
 
                                // Respond to client with error-state instead of module implementation
                                $states[$name] = 'error';
@@ -1022,9 +1053,8 @@ class ResourceLoader {
                        }
                } else {
                        if ( count( $states ) ) {
-                               $exceptions .= self::makeComment(
-                                       'Problematic modules: ' . FormatJson::encode( $states, ResourceLoader::inDebugMode() )
-                               );
+                               $this->errors[] = 'Problematic modules: ' .
+                                       FormatJson::encode( $states, ResourceLoader::inDebugMode() );
                        }
                }
 
@@ -1037,7 +1067,7 @@ class ResourceLoader {
                }
 
                wfProfileOut( __METHOD__ );
-               return $exceptions . $out;
+               return $out;
        }
 
        /* Static Methods */
@@ -1188,6 +1218,27 @@ class ResourceLoader {
                );
        }
 
+       /**
+        * Remove empty values from the end of an array.
+        *
+        * Values considered empty:
+        *
+        * - null
+        * - empty array
+        *
+        * @param Array $array
+        */
+       private static function trimArray( Array &$array ) {
+               $i = count( $array );
+               while ( $i-- ) {
+                       if ( $array[$i] === null || $array[$i] === array() ) {
+                               unset( $array[$i] );
+                       } else {
+                               break;
+                       }
+               }
+       }
+
        /**
         * Returns JS code which calls mw.loader.register with the given
         * parameters. Has three calling conventions:
@@ -1219,16 +1270,37 @@ class ResourceLoader {
                $dependencies = null, $group = null, $source = null, $skip = null
        ) {
                if ( is_array( $name ) ) {
+                       // Build module name index
+                       $index = array();
+                       foreach ( $name as $i => &$module ) {
+                               $index[$module[0]] = $i;
+                       }
+
+                       // Transform dependency names into indexes when possible, they will be resolved by
+                       // mw.loader.register on the other end
+                       foreach ( $name as &$module ) {
+                               if ( isset( $module[2] ) ) {
+                                       foreach ( $module[2] as &$dependency ) {
+                                               if ( isset( $index[$dependency] ) ) {
+                                                       $dependency = $index[$dependency];
+                                               }
+                                       }
+                               }
+                       }
+
+                       array_walk( $name, array( 'self', 'trimArray' ) );
+
                        return Xml::encodeJsCall(
                                'mw.loader.register',
                                array( $name ),
                                ResourceLoader::inDebugMode()
                        );
                } else {
-                       $version = (int)$version > 1 ? (int)$version : 1;
+                       $registration = array( $name, $version, $dependencies, $group, $source, $skip );
+                       self::trimArray( $registration );
                        return Xml::encodeJsCall(
                                'mw.loader.register',
-                               array( $name, $version, $dependencies, $group, $source, $skip ),
+                               $registration,
                                ResourceLoader::inDebugMode()
                        );
                }
index 02744a6..a6a7d34 100644 (file)
@@ -41,7 +41,11 @@ class ResourceLoaderContext {
        protected $version;
        protected $hash;
        protected $raw;
+       protected $image;
+       protected $variant;
+       protected $format;
        protected $userObj;
+       protected $imageObj;
 
        /* Methods */
 
@@ -66,6 +70,10 @@ class ResourceLoaderContext {
                $this->only = $request->getVal( 'only' );
                $this->version = $request->getVal( 'version' );
                $this->raw = $request->getFuzzyBool( 'raw' );
+               // Image requests
+               $this->image = $request->getVal( 'image' );
+               $this->variant = $request->getVal( 'variant' );
+               $this->format = $request->getVal( 'format' );
 
                $skinnames = Skin::getSkinNames();
                // If no skin is specified, or we don't recognize the skin, use the default skin
@@ -232,6 +240,62 @@ class ResourceLoaderContext {
                return $this->raw;
        }
 
+       /**
+        * @return string|null
+        */
+       public function getImage() {
+               return $this->image;
+       }
+
+       /**
+        * @return string|null
+        */
+       public function getVariant() {
+               return $this->variant;
+       }
+
+       /**
+        * @return string|null
+        */
+       public function getFormat() {
+               return $this->format;
+       }
+
+       /**
+        * If this is a request for an image, get the ResourceLoaderImage object.
+        *
+        * @since 1.25
+        * @return ResourceLoaderImage|bool false if a valid object cannot be created
+        */
+       public function getImageObj() {
+               if ( $this->imageObj === null ) {
+                       $this->imageObj = false;
+
+                       if ( !$this->image ) {
+                               return $this->imageObj;
+                       }
+
+                       $modules = $this->getModules();
+                       if ( count( $modules ) !== 1 ) {
+                               return $this->imageObj;
+                       }
+
+                       $module = $this->getResourceLoader()->getModule( $modules[0] );
+                       if ( !$module || !$module instanceof ResourceLoaderImageModule ) {
+                               return $this->imageObj;
+                       }
+
+                       $image = $module->getImage( $this->image );
+                       if ( !$image ) {
+                               return $this->imageObj;
+                       }
+
+                       $this->imageObj = $image;
+               }
+
+               return $this->imageObj;
+       }
+
        /**
         * @return bool
         */
@@ -260,6 +324,7 @@ class ResourceLoaderContext {
                if ( !isset( $this->hash ) ) {
                        $this->hash = implode( '|', array(
                                $this->getLanguage(), $this->getDirection(), $this->getSkin(), $this->getUser(),
+                               $this->getImage(), $this->getVariant(), $this->getFormat(),
                                $this->getDebug(), $this->getOnly(), $this->getVersion()
                        ) );
                }
diff --git a/includes/resourceloader/ResourceLoaderImage.php b/includes/resourceloader/ResourceLoaderImage.php
new file mode 100644 (file)
index 0000000..0e43f65
--- /dev/null
@@ -0,0 +1,356 @@
+<?php
+/**
+ * Class encapsulating an image used in a ResourceLoaderImageModule.
+ *
+ * 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 encapsulating an image used in a ResourceLoaderImageModule.
+ *
+ * @since 1.25
+ */
+class ResourceLoaderImage {
+
+       /**
+        * Map of allowed file extensions to their MIME types.
+        * @var array
+        */
+       protected static $fileTypes = array(
+               'svg' => 'image/svg+xml',
+               'png' => 'image/png',
+               'gif' => 'image/gif',
+               'jpg' => 'image/jpg',
+       );
+
+       /**
+        * @param string $name Image name
+        * @param string $module Module name
+        * @param string|array $descriptor Path to image file, or array structure containing paths
+        * @param string $basePath Directory to which paths in descriptor refer
+        * @param array $variants
+        * @throws MWException
+        */
+       public function __construct( $name, $module, $descriptor, $basePath, $variants ) {
+               $this->name = $name;
+               $this->module = $module;
+               $this->descriptor = $descriptor;
+               $this->basePath = $basePath;
+               $this->variants = $variants;
+
+               // Ensure that all files have common extension.
+               $extensions = array();
+               $descriptor = (array)$descriptor;
+               array_walk_recursive( $descriptor, function ( $path ) use ( &$extensions ) {
+                       $extensions[] = pathinfo( $path, PATHINFO_EXTENSION );
+               } );
+               $extensions = array_unique( $extensions );
+               if ( count( $extensions ) !== 1 ) {
+                       throw new MWException( 'Image type for various images differs.' );
+               }
+               $ext = $extensions[0];
+               if ( !isset( self::$fileTypes[$ext] ) ) {
+                       throw new MWException( 'Invalid image type; svg, png, gif or jpg required.' );
+               }
+               $this->extension = $ext;
+       }
+
+       /**
+        * Get name of this image.
+        *
+        * @return string
+        */
+       public function getName() {
+               return $this->name;
+       }
+
+       /**
+        * Get name of the module this image belongs to.
+        *
+        * @return string
+        */
+       public function getModule() {
+               return $this->module;
+       }
+
+       /**
+        * Get the list of variants this image can be converted to.
+        *
+        * @return string[]
+        */
+       public function getVariants() {
+               return array_keys( $this->variants );
+       }
+
+       /**
+        * Get the path to image file for given context.
+        *
+        * @param ResourceLoaderContext $context Any context
+        * @return string
+        */
+       protected 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() ];
+               } else {
+                       return $this->basePath . '/' . $desc['default'];
+               }
+       }
+
+       /**
+        * Get the extension of the image.
+        *
+        * @param string $format Format to get the extension for, 'original' or 'rasterized'
+        * @return string Extension without leading dot, e.g. 'png'
+        */
+       public function getExtension( $format = 'original' ) {
+               if ( $format === 'rasterized' && $this->extension === 'svg' ) {
+                       return 'png';
+               } else {
+                       return $this->extension;
+               }
+       }
+
+       /**
+        * Get the MIME type of the image.
+        *
+        * @param string $format Format to get the MIME type for, 'original' or 'rasterized'
+        * @return string
+        */
+       public function getMimeType( $format = 'original' ) {
+               $ext = $this->getExtension( $format );
+               return self::$fileTypes[$ext];
+       }
+
+       /**
+        * Get the load.php URL that will produce this image.
+        *
+        * @param ResourceLoaderContext $context Any context
+        * @param string $script URL to load.php
+        * @param string|null $variant Variant to get the URL for
+        * @param string $format Format to get the URL for, 'original' or 'rasterized'
+        * @return string
+        */
+       public function getUrl( ResourceLoaderContext $context, $script, $variant, $format ) {
+               $query = array(
+                       'modules' => $this->getModule(),
+                       'image' => $this->getName(),
+                       'variant' => $variant,
+                       'format' => $format,
+                       'lang' => $context->getLanguage(),
+                       'version' => $context->getVersion(),
+               );
+
+               return wfExpandUrl( wfAppendQuery( $script, $query ), PROTO_RELATIVE );
+       }
+
+       /**
+        * Get the data: URI that will produce this image.
+        *
+        * @param ResourceLoaderContext $context Any context
+        * @param string|null $variant Variant to get the URI for
+        * @param string $format Format to get the URI for, 'original' or 'rasterized'
+        * @return string
+        */
+       public function getDataUri( ResourceLoaderContext $context, $variant, $format ) {
+               $type = $this->getMimeType( $format );
+               $contents = $this->getImageData( $context, $variant, $format );
+               return CSSMin::encodeStringAsDataURI( $contents, $type );
+       }
+
+       /**
+        * Get actual image data for this image. This can be saved to a file or sent to the browser to
+        * produce the converted image.
+        *
+        * Call getExtension() or getMimeType() with the same $format argument to learn what file type the
+        * returned data uses.
+        *
+        * @param ResourceLoaderContext $context Image context, or any context of $variant and $format
+        *     given.
+        * @param string|null $variant Variant to get the data for. Optional, if given, overrides the data
+        *     from $context.
+        * @param string $format Format to get the data for, 'original' or 'rasterized'. Optional, if
+        *     given, overrides the data from $context.
+        * @return string|false Possibly binary image data, or false on failure
+        */
+       public function getImageData( ResourceLoaderContext $context, $variant = false, $format = false ) {
+               if ( $variant === false ) {
+                       $variant = $context->getVariant();
+               }
+               if ( $format === false ) {
+                       $format = $context->getFormat();
+               }
+
+               if ( $this->getExtension() !== 'svg' ) {
+                       return file_get_contents( $this->getPath( $context ) );
+               }
+
+               if ( $variant && isset( $this->variants[$variant] ) ) {
+                       $data = $this->variantize( $this->variants[$variant], $context );
+               } else {
+                       $data = file_get_contents( $this->getPath( $context ) );
+               }
+
+               if ( $format === 'rasterized' ) {
+                       $data = $this->rasterize( $data );
+               }
+
+               return $data;
+       }
+
+       /**
+        * Send response headers (using the header() function) that are necessary to correctly serve the
+        * image data for this image, as returned by getImageData().
+        *
+        * Note that the headers are independent of the language or image variant.
+        *
+        * @param ResourceLoaderContext $context Image context
+        */
+       public function sendResponseHeaders( ResourceLoaderContext $context ) {
+               $format = $context->getFormat();
+               $mime = $this->getMimeType( $format );
+               $filename = $this->getName() . '.' . $this->getExtension( $format );
+
+               header( 'Content-Type: ' . $mime );
+               header( 'Content-Disposition: ' .
+                       FileBackend::makeContentDisposition( 'inline', $filename ) );
+       }
+
+       /**
+        * Convert this image, which is assumed to be SVG, to given variant.
+        *
+        * @param array $variantConf Array with a 'color' key, its value will be used as fill color
+        * @param ResourceLoaderContext $context Image context
+        * @return string New SVG file data
+        */
+       protected function variantize( $variantConf, ResourceLoaderContext $context ) {
+               $dom = new DomDocument;
+               $dom->load( $this->getPath( $context ) );
+               $root = $dom->documentElement;
+               $wrapper = $dom->createElement( 'g' );
+               while ( $root->firstChild ) {
+                       $wrapper->appendChild( $root->firstChild );
+               }
+               $root->appendChild( $wrapper );
+               $wrapper->setAttribute( 'fill', $variantConf['color'] );
+               return $dom->saveXml();
+       }
+
+       /**
+        * Massage the SVG image data for converters which doesn't understand some path data syntax.
+        *
+        * This is necessary for rsvg and ImageMagick when compiled with rsvg support.
+        * Upstream bug is https://bugzilla.gnome.org/show_bug.cgi?id=620923, fixed 2014-11-10, so
+        * this will be needed for a while. (T76852)
+        *
+        * @param string $svg SVG image data
+        * @return string Massaged SVG image data
+        */
+       protected function massageSvgPathdata( $svg ) {
+               $dom = new DomDocument;
+               $dom->loadXml( $svg );
+               foreach ( $dom->getElementsByTagName( 'path' ) as $node ) {
+                       $pathData = $node->getAttribute( 'd' );
+                       // Make sure there is at least one space between numbers, and that leading zero is not omitted.
+                       // rsvg has issues with syntax like "M-1-2" and "M.445.483" and especially "M-.445-.483".
+                       $pathData = preg_replace( '/(-?)(\d*\.\d+|\d+)/', ' ${1}0$2 ', $pathData );
+                       // Strip unnecessary leading zeroes for prettiness, not strictly necessary
+                       $pathData = preg_replace( '/([ -])0(\d)/', '$1$2', $pathData );
+                       $node->setAttribute( 'd', $pathData );
+               }
+               return $dom->saveXml();
+       }
+
+       /**
+        * Convert passed image data, which is assumed to be SVG, to PNG.
+        *
+        * @param string $svg SVG image data
+        * @return string|bool PNG image data, or false on failure
+        */
+       protected function rasterize( $svg ) {
+               // This code should be factored out to a separate method on SvgHandler, or perhaps a separate
+               // class, with a separate set of configuration settings.
+               //
+               // This is a distinct use case from regular SVG rasterization:
+               // * we can skip many sanity and security checks (as the images come from a trusted source,
+               //   rather than from the user)
+               // * we need to provide extra options to some converters to achieve acceptable quality for very
+               //   small images, which might cause performance issues in the general case
+               // * we need to directly pass image data to the converter instead of a file path
+               //
+               // See https://phabricator.wikimedia.org/T76473#801446 for examples of what happens with the
+               // default settings.
+               //
+               // For now, we special-case rsvg (used in WMF production) and do a messy workaround for other
+               // converters.
+
+               global $wgSVGConverter, $wgSVGConverterPath;
+
+               $svg = $this->massageSvgPathdata( $svg );
+
+               if ( $wgSVGConverter === 'rsvg' ) {
+                       $command = 'rsvg-convert'; // Should be just 'rsvg'? T76476
+                       if ( $wgSVGConverterPath ) {
+                               $command = wfEscapeShellArg( "$wgSVGConverterPath/" ) . $command;
+                       }
+
+                       $process = proc_open(
+                               $command,
+                               array( 0 => array( 'pipe', 'r' ), 1 => array( 'pipe', 'w' ) ),
+                               $pipes
+                       );
+
+                       if ( is_resource( $process ) ) {
+                               fwrite( $pipes[0], $svg );
+                               fclose( $pipes[0] );
+                               $png = stream_get_contents( $pipes[1] );
+                               fclose( $pipes[1] );
+                               proc_close( $process );
+
+                               return $png ?: false;
+                       }
+                       return false;
+
+               } else {
+                       // Write input to and read output from a temporary file
+                       $tempFilenameSvg = tempnam( wfTempDir(), 'ResourceLoaderImage' );
+                       $tempFilenamePng = tempnam( wfTempDir(), 'ResourceLoaderImage' );
+
+                       file_put_contents( $tempFilenameSvg, $svg );
+
+                       $metadata = SVGMetadataExtractor::getMetadata( $tempFilenameSvg );
+                       if ( !isset( $metadata['width'] ) || !isset( $metadata['height'] ) ) {
+                               return false;
+                       }
+
+                       $handler = new SvgHandler;
+                       $handler->rasterize( $tempFilenameSvg, $tempFilenamePng, $metadata['width'], $metadata['height'] );
+
+                       $png = file_get_contents( $tempFilenamePng );
+
+                       unlink( $tempFilenameSvg );
+                       unlink( $tempFilenamePng );
+
+                       return $png ?: false;
+               }
+       }
+}
diff --git a/includes/resourceloader/ResourceLoaderImageModule.php b/includes/resourceloader/ResourceLoaderImageModule.php
new file mode 100644 (file)
index 0000000..9246df7
--- /dev/null
@@ -0,0 +1,295 @@
+<?php
+/**
+ * Resource loader module for generated and embedded images.
+ *
+ * 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 Trevor Parscal
+ */
+
+/**
+ * Resource loader module for generated and embedded images.
+ *
+ * @since 1.25
+ */
+class ResourceLoaderImageModule extends ResourceLoaderModule {
+
+       /**
+        * Local base path, see __construct()
+        * @var string
+        */
+       protected $localBasePath = '';
+
+       protected $origin = self::ORIGIN_CORE_SITEWIDE;
+
+       protected $images = array();
+       protected $variants = array();
+       protected $prefix = array();
+       protected $targets = array( 'desktop', 'mobile' );
+
+       /**
+        * Constructs a new module from an options array.
+        *
+        * @param array $options List of options; if not given or empty, an empty module will be
+        *     constructed
+        * @param string $localBasePath Base path to prepend to all local paths in $options. Defaults
+        *     to $IP
+        *
+        * Below is a description for the $options array:
+        * @par Construction options:
+        * @code
+        *     array(
+        *         // Base path to prepend to all local paths in $options. Defaults to $IP
+        *         'localBasePath' => [base path],
+        *         // CSS class prefix to use in all style rules
+        *         'prefix' => [CSS class prefix],
+        *         // List of variants that may be used for the image files
+        *         'variants' => array(
+        *             // ([image type] is a string, used in generated CSS class names and to match variants to images)
+        *             [image type] => 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(
+        *             [image type] => array(
+        *                 [file path string],
+        *                 [file path string] => array(
+        *                     'name' => [image name string, defaults to file name],
+        *                     'variants' => [array of variant name strings, variants available for this image],
+        *                 ),
+        *             )
+        *         ),
+        *     )
+        * @endcode
+        * @throws MWException
+        */
+       public function __construct( $options = array(), $localBasePath = null ) {
+               $this->localBasePath = self::extractLocalBasePath( $options, $localBasePath );
+
+               if ( !isset( $options['prefix'] ) || !$options['prefix'] ) {
+                       throw new MWException(
+                               "Required 'prefix' option not given or empty."
+                       );
+               }
+
+               foreach ( $options as $member => $option ) {
+                       switch ( $member ) {
+                               case 'images':
+                                       if ( !is_array( $option ) ) {
+                                               throw new MWException(
+                                                       "Invalid collated file path list error. '$option' given, array expected."
+                                               );
+                                       }
+                                       foreach ( $option as $key => $value ) {
+                                               if ( !is_string( $key ) ) {
+                                                       throw new MWException(
+                                                               "Invalid collated file path list key error. '$key' given, string expected."
+                                                       );
+                                               }
+                                               $this->{$member}[$key] = (array)$value;
+                                       }
+                                       break;
+
+                               case 'variants':
+                                       if ( !is_array( $option ) ) {
+                                               throw new MWException(
+                                                       "Invalid variant list error. '$option' given, array expected."
+                                               );
+                                       }
+                                       $this->{$member} = $option;
+                                       break;
+
+                               case 'prefix':
+                                       $this->{$member} = (string)$option;
+                                       break;
+                       }
+               }
+       }
+
+       /**
+        * Get CSS class prefix used by this module.
+        * @return string
+        */
+       public function getPrefix() {
+               return $this->prefix;
+       }
+
+       /**
+        * Get a ResourceLoaderImage object for given image.
+        * @param string $name Image name
+        * @return ResourceLoaderImage|null
+        */
+       public function getImage( $name ) {
+               $images = $this->getImages();
+               return isset( $images[$name] ) ? $images[$name] : null;
+       }
+
+       /**
+        * Get ResourceLoaderImage objects for all images.
+        * @return ResourceLoaderImage[] Array keyed by image name
+        */
+       public function getImages() {
+               if ( !isset( $this->imageObjects ) ) {
+                       $this->imageObjects = array();
+
+                       foreach ( $this->images as $type => $list ) {
+                               foreach ( $list as $name => $options ) {
+                                       $imageDesc = is_string( $options ) ? $options : $options['image'];
+
+                                       $allowedVariants = array_merge(
+                                               isset( $options['variants'] ) ? $options['variants'] : array(),
+                                               $this->getGlobalVariants( $type )
+                                       );
+                                       $variantConfig = array_intersect_key(
+                                               $this->variants[$type],
+                                               array_fill_keys( $allowedVariants, true )
+                                       );
+
+                                       $image = new ResourceLoaderImage( $name, $this->getName(), $imageDesc, $this->localBasePath, $variantConfig );
+                                       $this->imageObjects[ $image->getName() ] = $image;
+                               }
+                       }
+               }
+
+               return $this->imageObjects;
+       }
+
+       /**
+        * Get list of variants in this module that are 'global' for given type of images, i.e., available
+        * for every image of given type regardless of image options.
+        * @param string $type Image type
+        * @return string[]
+        */
+       public function getGlobalVariants( $type ) {
+               if ( !isset( $this->globalVariants[$type] ) ) {
+                       $this->globalVariants[$type] = array();
+
+                       foreach ( $this->variants[$type] as $name => $config ) {
+                               if ( isset( $config['global'] ) && $config['global'] ) {
+                                       $this->globalVariants[$type][] = $name;
+                               }
+                       }
+               }
+
+               return $this->globalVariants[$type];
+       }
+
+       /**
+        * Get the type of given image.
+        * @param string $imageName Image name
+        * @return string
+        */
+       public function getImageType( $imageName ) {
+               foreach ( $this->images as $type => $list ) {
+                       foreach ( $list as $key => $value ) {
+                               $file = is_int( $key ) ? $value : $key;
+                               $options = is_array( $value ) ? $value : array();
+                               $name = isset( $options['name'] ) ? $options['name'] : pathinfo( $file, PATHINFO_FILENAME );
+                               if ( $name === $imageName ) {
+                                       return $type;
+                               }
+                       }
+               }
+       }
+
+       /**
+        * @param ResourceLoaderContext $context
+        * @return array
+        */
+       public function getStyles( ResourceLoaderContext $context ) {
+               // Build CSS rules
+               $rules = array();
+               $script = $context->getResourceLoader()->getLoadScript( $this->getSource() );
+               $prefix = $this->getPrefix();
+
+               foreach ( $this->getImages() as $name => $image ) {
+                       $type = $this->getImageType( $name );
+
+                       $declarations = $this->getCssDeclarations(
+                               $image->getDataUri( $context, null, 'original' ),
+                               $image->getUrl( $context, $script, null, 'rasterized' )
+                       );
+                       $declarations = implode( "\n\t", $declarations );
+                       $rules[] = ".$prefix-$type-$name {\n\t$declarations\n}";
+
+                       // TODO: Get variant configurations from $context->getSkin()
+                       foreach ( $image->getVariants() as $variant ) {
+                               $declarations = $this->getCssDeclarations(
+                                       $image->getDataUri( $context, $variant, 'original' ),
+                                       $image->getUrl( $context, $script, $variant, 'rasterized' )
+                               );
+                               $declarations = implode( "\n\t", $declarations );
+                               $rules[] = ".$prefix-$type-$name-$variant {\n\t$declarations\n}";
+                       }
+               }
+
+               $style = implode( "\n", $rules );
+               if ( $this->getFlip( $context ) ) {
+                       $style = CSSJanus::transform( $style, true, false );
+               }
+               return array( 'all' => $style );
+       }
+
+       /**
+        * @param string $primary Primary URI
+        * @param string $fallback Fallback URI
+        * @return string[] CSS declarations to use given URIs as background-image
+        */
+       protected function getCssDeclarations( $primary, $fallback ) {
+               // SVG support using a transparent gradient to guarantee cross-browser
+               // compatibility (browsers able to understand gradient syntax support also SVG).
+               // http://pauginer.tumblr.com/post/36614680636/invisible-gradient-technique
+               return array(
+                       "background-image: url($fallback);",
+                       "background-image: -webkit-linear-gradient(transparent, transparent), url($primary);",
+                       "background-image: linear-gradient(transparent, transparent), url($primary);",
+               );
+       }
+
+       /**
+        * @return bool
+        */
+       public function supportsURLLoading() {
+               return false;
+       }
+
+       /**
+        * Extract a local base path from module definition information.
+        *
+        * @param array $options Module definition
+        * @param string $localBasePath Path to use if not provided in module definition. Defaults
+        *     to $IP
+        * @return string Local base path
+        */
+       public static function extractLocalBasePath( $options, $localBasePath = null ) {
+               global $IP;
+
+               if ( $localBasePath === null ) {
+                       $localBasePath = $IP;
+               }
+
+               if ( array_key_exists( 'localBasePath', $options ) ) {
+                       $localBasePath = (string)$options['localBasePath'];
+               }
+
+               return $localBasePath;
+       }
+}
index 4c49fae..3f95ce6 100644 (file)
@@ -388,12 +388,12 @@ abstract class ResourceLoaderModule {
         * Get the last modification timestamp of the message blob for this
         * module in a given language.
         * @param string $lang Language code
-        * @return int UNIX timestamp, or 0 if the module doesn't have messages
+        * @return int UNIX timestamp
         */
        public function getMsgBlobMtime( $lang ) {
                if ( !isset( $this->msgBlobMtime[$lang] ) ) {
                        if ( !count( $this->getMessages() ) ) {
-                               return 0;
+                               return 1;
                        }
 
                        $dbr = wfGetDB( DB_SLAVE );
@@ -416,7 +416,7 @@ abstract class ResourceLoaderModule {
         * Set a preloaded message blob last modification timestamp. Used so we
         * can load this information for all modules at once.
         * @param string $lang Language code
-        * @param int $mtime UNIX timestamp or 0 if there is no such blob
+        * @param int $mtime UNIX timestamp
         */
        public function setMsgBlobMtime( $lang, $mtime ) {
                $this->msgBlobMtime[$lang] = $mtime;
@@ -443,7 +443,6 @@ abstract class ResourceLoaderModule {
         * @return int UNIX timestamp
         */
        public function getModifiedTime( ResourceLoaderContext $context ) {
-               // 0 would mean now
                return 1;
        }
 
@@ -451,13 +450,12 @@ abstract class ResourceLoaderModule {
         * Helper method for calculating when the module's hash (if it has one) changed.
         *
         * @param ResourceLoaderContext $context
-        * @return int UNIX timestamp or 0 if no hash was provided
-        *  by getModifiedHash()
+        * @return int UNIX timestamp
         */
        public function getHashMtime( ResourceLoaderContext $context ) {
                $hash = $this->getModifiedHash( $context );
                if ( !is_string( $hash ) ) {
-                       return 0;
+                       return 1;
                }
 
                $cache = wfGetCache( CACHE_ANYTHING );
@@ -469,7 +467,7 @@ abstract class ResourceLoaderModule {
                        return $data['timestamp'];
                }
 
-               $timestamp = wfTimestamp();
+               $timestamp = time();
                $cache->set( $key, array(
                        'hash' => $hash,
                        'timestamp' => $timestamp,
@@ -497,15 +495,14 @@ abstract class ResourceLoaderModule {
         * @since 1.23
         *
         * @param ResourceLoaderContext $context
-        * @return int UNIX timestamp or 0 if no definition summary was provided
-        *  by getDefinitionSummary()
+        * @return int UNIX timestamp
         */
        public function getDefinitionMtime( ResourceLoaderContext $context ) {
                wfProfileIn( __METHOD__ );
                $summary = $this->getDefinitionSummary( $context );
                if ( $summary === null ) {
                        wfProfileOut( __METHOD__ );
-                       return 0;
+                       return 1;
                }
 
                $hash = md5( json_encode( $summary ) );
@@ -640,16 +637,12 @@ 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
-        * @return int UNIX timestamp, or 1 if the file doesn't exist
+        * @return int UNIX timestamp
         */
        protected static function safeFilemtime( $filename ) {
-               if ( file_exists( $filename ) ) {
-                       return filemtime( $filename );
-               } else {
-                       // We only ever map this function on an array if we're gonna call max() after,
-                       // so return our standard minimum timestamps here. This is 1, not 0, because
-                       // wfTimestamp(0) == NOW
+               if ( !file_exists( $filename ) ) {
                        return 1;
                }
+               return filemtime( $filename );
        }
 }
index 6de1be0..9835932 100644 (file)
@@ -41,7 +41,7 @@ class ResourceLoaderSkinModule extends ResourceLoaderFileModule {
 
        /**
         * @param $context ResourceLoaderContext
-        * @return boolean
+        * @return bool
         */
        public function isKnownEmpty( ResourceLoaderContext $context ) {
                // Regardless of whether the files are specified, we always
index ee66288..a0764de 100644 (file)
@@ -106,7 +106,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        'wgResourceLoaderStorageEnabled' => $conf->get( 'ResourceLoaderStorageEnabled' ),
                );
 
-               wfRunHooks( 'ResourceLoaderGetConfigVars', array( &$vars ) );
+               Hooks::run( 'ResourceLoaderGetConfigVars', array( &$vars ) );
 
                $this->configVars[$hash] = $vars;
                return $this->configVars[$hash];
@@ -147,7 +147,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
        }
 
        /**
-        * Optimize the dependency tree in $this->modules and return it.
+        * Optimize the dependency tree in $this->modules.
         *
         * The optimization basically works like this:
         *      Given we have module A with the dependencies B and C
@@ -155,11 +155,11 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
         *      Now we don't have to tell the client to explicitly fetch module
         *              C as that's already included in module B.
         *
-        * This way we can reasonably reduce the amout of module registration
+        * This way we can reasonably reduce the amount of module registration
         * data send to the client.
         *
         * @param array &$registryData Modules keyed by name with properties:
-        *  - string 'version'
+        *  - number 'version'
         *  - array 'dependencies'
         *  - string|null 'group'
         *  - string 'source'
@@ -211,12 +211,10 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                                continue;
                        }
 
-                       // getModifiedTime() is supposed to return a UNIX timestamp, but it doesn't always
-                       // seem to do that, and custom implementations might forget. Coerce it to TS_UNIX
+                       // 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 ) );
-                       $mtime = max( $moduleMtime, wfTimestamp( TS_UNIX, $this->getConfig()->get( 'CacheEpoch' ) ) );
-
-                       // FIXME: Convert to numbers, wfTimestamp always gives us stings, even for TS_UNIX
 
                        $skipFunction = $module->getSkipFunction();
                        if ( $skipFunction !== null && !ResourceLoader::inDebugMode() ) {
@@ -229,8 +227,14 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                                );
                        }
 
+                       $mtime = max(
+                               $moduleMtime,
+                               wfTimestamp( TS_UNIX, $this->getConfig()->get( 'CacheEpoch' ) )
+                       );
+
                        $registryData[$name] = array(
-                               'version' => $mtime,
+                               // Convert to numbers as wfTimestamp always returns a string, even for TS_UNIX
+                               'version' => (int) $mtime,
                                'dependencies' => $module->getDependencies(),
                                'group' => $module->getGroup(),
                                'source' => $module->getSource(),
@@ -251,7 +255,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        if ( $data['loader'] !== false ) {
                                $out .= ResourceLoader::makeCustomLoaderScript(
                                        $name,
-                                       wfTimestamp( TS_ISO_8601_BASIC, $data['version'] ),
+                                       $data['version'],
                                        $data['dependencies'],
                                        $data['group'],
                                        $data['source'],
@@ -260,57 +264,16 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                                continue;
                        }
 
-                       if (
-                               !count( $data['dependencies'] ) &&
-                               $data['group'] === null &&
-                               $data['source'] === 'local' &&
-                               $data['skip'] === null
-                       ) {
-                               // Modules with no dependencies, group, foreign source or skip function;
-                               // call mw.loader.register(name, timestamp)
-                               $registrations[] = array( $name, $data['version'] );
-                       } elseif (
-                               $data['group'] === null &&
-                               $data['source'] === 'local' &&
-                               $data['skip'] === null
-                       ) {
-                               // Modules with dependencies but no group, foreign source or skip function;
-                               // call mw.loader.register(name, timestamp, dependencies)
-                               $registrations[] = array( $name, $data['version'], $data['dependencies'] );
-                       } elseif (
-                               $data['source'] === 'local' &&
-                               $data['skip'] === null
-                       ) {
-                               // Modules with a group but no foreign source or skip function;
-                               // call mw.loader.register(name, timestamp, dependencies, group)
-                               $registrations[] = array(
-                                       $name,
-                                       $data['version'],
-                                       $data['dependencies'],
-                                       $data['group']
-                               );
-                       } elseif ( $data['skip'] === null ) {
-                               // Modules with a foreign source but no skip function;
-                               // call mw.loader.register(name, timestamp, dependencies, group, source)
-                               $registrations[] = array(
-                                       $name,
-                                       $data['version'],
-                                       $data['dependencies'],
-                                       $data['group'],
-                                       $data['source']
-                               );
-                       } else {
-                               // Modules with a skip function;
-                               // call mw.loader.register(name, timestamp, dependencies, group, source, skip)
-                               $registrations[] = array(
-                                       $name,
-                                       $data['version'],
-                                       $data['dependencies'],
-                                       $data['group'],
-                                       $data['source'],
-                                       $data['skip']
-                               );
-                       }
+                       // Call mw.loader.register(name, timestamp, dependencies, group, source, skip)
+                       $registrations[] = array(
+                               $name,
+                               $data['version'],
+                               $data['dependencies'],
+                               $data['group'],
+                               // Swap default (local) for null
+                               $data['source'] === 'local' ? null : $data['source'],
+                               $data['skip']
+                       );
                }
 
                // Register modules
@@ -352,7 +315,7 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
 
                // Get the latest version
                $loader = $context->getResourceLoader();
-               $version = 0;
+               $version = 1;
                foreach ( $moduleNames as $moduleName ) {
                        $version = max( $version,
                                $loader->getModule( $moduleName )->getModifiedTime( $context )
index 9d97eea..472ceb2 100644 (file)
@@ -90,11 +90,4 @@ class ResourceLoaderUserCSSPrefsModule extends ResourceLoaderModule {
        public function getGroup() {
                return 'private';
        }
-
-       /**
-        * @return array
-        */
-       public function getDependencies() {
-               return array( 'mediawiki.user' );
-       }
 }
diff --git a/includes/resourceloader/ResourceLoaderUserDefaultsModule.php b/includes/resourceloader/ResourceLoaderUserDefaultsModule.php
new file mode 100644 (file)
index 0000000..d78fa9d
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Resource loader module for default user preferences.
+ *
+ * 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 Ori Livneh
+ */
+
+/**
+ * Module for default user preferences.
+ */
+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
+        */
+       public function getModifiedTime( ResourceLoaderContext $context ) {
+               return $this->getHashMtime( $context );
+       }
+
+       /**
+        * @param ResourceLoaderContext $context
+        * @return string
+        */
+       public function getScript( ResourceLoaderContext $context ) {
+               return Xml::encodeJsCall( 'mw.user.options.set', array( User::getDefaultOptions() ) );
+       }
+}
index e6b07c1..84c1906 100644 (file)
@@ -37,9 +37,16 @@ class ResourceLoaderUserOptionsModule extends ResourceLoaderModule {
 
        /* Methods */
 
+       /**
+        * @return array List of module names as strings
+        */
+       public function getDependencies() {
+               return array( 'user.defaults' );
+       }
+
        /**
         * @param ResourceLoaderContext $context
-        * @return array|int|mixed
+        * @return int
         */
        public function getModifiedTime( ResourceLoaderContext $context ) {
                $hash = $context->getHash();
@@ -56,7 +63,7 @@ class ResourceLoaderUserOptionsModule extends ResourceLoaderModule {
         */
        public function getScript( ResourceLoaderContext $context ) {
                return Xml::encodeJsCall( 'mw.user.options.set',
-                       array( $context->getUserObj()->getOptions() ),
+                       array( $context->getUserObj()->getOptions( User::GETOPTIONS_EXCLUDE_DEFAULTS ) ),
                        ResourceLoader::inDebugMode()
                );
        }
index e195cf2..1a1a6d0 100644 (file)
@@ -164,10 +164,10 @@ abstract class ResourceLoaderWikiModule extends ResourceLoaderModule {
 
        /**
         * @param ResourceLoaderContext $context
-        * @return int|mixed
+        * @return int
         */
        public function getModifiedTime( ResourceLoaderContext $context ) {
-               $modifiedTime = 1; // wfTimestamp() interprets 0 as "now"
+               $modifiedTime = 1;
                $titleInfo = $this->getTitleInfo( $context );
                if ( count( $titleInfo ) ) {
                        $mtimes = array_map( function ( $value ) {
@@ -226,8 +226,8 @@ abstract class ResourceLoaderWikiModule extends ResourceLoaderModule {
         * 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, with value is an array with 'length' and 'timestamp'
-        *               keys, where the timestamp is a unix one
+        * @return array Keyed by page dbkey. Value is an array with 'length' and 'timestamp'
+        *               keys, where the timestamp is a UNIX timestamp
         */
        protected function getTitleInfo( ResourceLoaderContext $context ) {
                $dbr = $this->getDB();
index e7aed73..6ae0afc 100644 (file)
@@ -32,7 +32,7 @@ class RevDelArchiveList extends RevDelRevisionList {
        }
 
        /**
-        * @param DatabaseBase $db
+        * @param IDatabase $db
         * @return mixed
         */
        public function doQuery( $db ) {
index aec51b1..f2b99ae 100644 (file)
@@ -32,7 +32,7 @@ class RevDelArchivedFileList extends RevDelFileList {
        }
 
        /**
-        * @param DatabaseBase $db
+        * @param IDatabase $db
         * @return mixed
         */
        public function doQuery( $db ) {
index 57e15d8..2295eaa 100644 (file)
@@ -49,7 +49,7 @@ class RevDelFileList extends RevDelList {
        }
 
        /**
-        * @param DatabaseBase $db
+        * @param IDatabase $db
         * @return mixed
         */
        public function doQuery( $db ) {
index a0ff667..b4ac628 100644 (file)
@@ -247,7 +247,7 @@ abstract class RevDelList extends RevisionListBase {
                } else {
                        $logType = 'delete';
                }
-               // Add params for effected page and ids
+               // Add params for affected page and ids
                $logParams = $this->getLogParams( $params );
                // Actually add the deletion log entry
                $log = new LogPage( $logType );
index ad04042..86c5af3 100644 (file)
@@ -55,7 +55,7 @@ class RevDelLogList extends RevDelList {
        }
 
        /**
-        * @param DatabaseBase $db
+        * @param IDatabase $db
         * @return mixed
         */
        public function doQuery( $db ) {
index 2545072..7315538 100644 (file)
@@ -54,7 +54,7 @@ class RevDelRevisionList extends RevDelList {
        }
 
        /**
-        * @param DatabaseBase $db
+        * @param IDatabase $db
         * @return mixed
         */
        public function doQuery( $db ) {
@@ -137,7 +137,7 @@ class RevDelRevisionList extends RevDelList {
        public function doPostCommitUpdates() {
                $this->title->purgeSquid();
                // Extensions that require referencing previous revisions may need this
-               wfRunHooks( 'ArticleRevisionVisibilitySet', array( &$this->title ) );
+               Hooks::run( 'ArticleRevisionVisibilitySet', array( &$this->title ) );
                return Status::newGood();
        }
 }
index 55c46c5..79802d6 100644 (file)
@@ -36,14 +36,14 @@ class RevisionDeleteUser {
         * @param string $name Username
         * @param int $userId User id
         * @param string $op Operator '|' or '&'
-        * @param null|DatabaseBase $dbw If you happen to have one lying around
+        * @param null|IDatabase $dbw If you happen to have one lying around
         * @return bool
         */
        private static function setUsernameBitfields( $name, $userId, $op, $dbw ) {
                if ( !$userId || ( $op !== '|' && $op !== '&' ) ) {
                        return false; // sanity check
                }
-               if ( !$dbw instanceof DatabaseBase ) {
+               if ( !$dbw instanceof IDatabase ) {
                        $dbw = wfGetDB( DB_MASTER );
                }
 
index c6cbfbe..cd6cf7d 100644 (file)
@@ -137,7 +137,7 @@ class SearchEngine {
        public static function getNearMatch( $searchterm ) {
                $title = self::getNearMatchInternal( $searchterm );
 
-               wfRunHooks( 'SearchGetNearMatchComplete', array( $searchterm, &$title ) );
+               Hooks::run( 'SearchGetNearMatchComplete', array( $searchterm, &$title ) );
                return $title;
        }
 
@@ -170,7 +170,7 @@ class SearchEngine {
                }
 
                $titleResult = null;
-               if ( !wfRunHooks( 'SearchGetNearMatchBefore', array( $allSearchTerms, &$titleResult ) ) ) {
+               if ( !Hooks::run( 'SearchGetNearMatchBefore', array( $allSearchTerms, &$titleResult ) ) ) {
                        return $titleResult;
                }
 
@@ -197,7 +197,7 @@ class SearchEngine {
                                return $title;
                        }
 
-                       if ( !wfRunHooks( 'SearchAfterNoDirectMatch', array( $term, &$title ) ) ) {
+                       if ( !Hooks::run( 'SearchAfterNoDirectMatch', array( $term, &$title ) ) ) {
                                return $title;
                        }
 
@@ -227,7 +227,7 @@ class SearchEngine {
 
                        // Give hooks a chance at better match variants
                        $title = null;
-                       if ( !wfRunHooks( 'SearchGetNearMatch', array( $term, &$title ) ) ) {
+                       if ( !Hooks::run( 'SearchGetNearMatch', array( $term, &$title ) ) ) {
                                return $title;
                        }
                }
@@ -356,7 +356,7 @@ class SearchEngine {
                        }
                }
 
-               wfRunHooks( 'SearchableNamespaces', array( &$arr ) );
+               Hooks::run( 'SearchableNamespaces', array( &$arr ) );
                return $arr;
        }
 
index 2cdf9f4..d384ae9 100644 (file)
@@ -71,7 +71,7 @@ class SearchResult {
                $this->mTitle = $title;
                if ( !is_null( $this->mTitle ) ) {
                        $id = false;
-                       wfRunHooks( 'SearchResultInitFromTitle', array( $title, &$id ) );
+                       Hooks::run( 'SearchResultInitFromTitle', array( $title, &$id ) );
                        $this->mRevision = Revision::newFromTitle(
                                $this->mTitle, $id, Revision::READ_NORMAL );
                        if ( $this->mTitle->getNamespace() === NS_FILE ) {
index c0ecab1..f2a95a8 100644 (file)
@@ -72,7 +72,7 @@ class SiteListFileCache {
                $sites = new SiteList();
 
                // @todo lazy initialize the site objects in the site list (e.g. only when needed to access)
-               foreach( $data['sites'] as $siteArray ) {
+               foreach ( $data['sites'] as $siteArray ) {
                        $sites[] = $this->newSiteFromArray( $siteArray );
                }
 
@@ -116,7 +116,7 @@ class SiteListFileCache {
                $site->setExtraData( $data['data'] );
                $site->setExtraConfig( $data['config'] );
 
-               foreach( $data['identifiers'] as $identifier ) {
+               foreach ( $data['identifiers'] as $identifier ) {
                        $site->addLocalId( $identifier['type'], $identifier['key'] );
                }
 
index 0a71aae..7307a6f 100644 (file)
@@ -81,7 +81,7 @@ class SiteListFileCacheBuilder {
                $siteIdentifiers = $this->buildLocalIdentifiers( $site );
                $identifiersArray = array();
 
-               foreach( $siteIdentifiers as $identifier ) {
+               foreach ( $siteIdentifiers as $identifier ) {
                        $identifiersArray[] = $identifier;
                }
 
index 7217000..3cdfca0 100644 (file)
@@ -112,7 +112,7 @@ abstract class BaseTemplate extends QuickTemplate {
                        $toolbox['info']['id'] = 't-info';
                }
 
-               wfRunHooks( 'BaseTemplateToolbox', array( &$this, &$toolbox ) );
+               Hooks::run( 'BaseTemplateToolbox', array( &$this, &$toolbox ) );
                wfProfileOut( __METHOD__ );
                return $toolbox;
        }
@@ -228,7 +228,7 @@ abstract class BaseTemplate extends QuickTemplate {
                        ob_start();
                        // We pass an extra 'true' at the end so extensions using BaseTemplateToolbox
                        // can abort and avoid outputting double toolbox links
-                       wfRunHooks( 'SkinTemplateToolboxEnd', array( &$this, true ) );
+                       Hooks::run( 'SkinTemplateToolboxEnd', array( &$this, true ) );
                        $hookContents = ob_get_contents();
                        ob_end_clean();
                        if ( !trim( $hookContents ) ) {
@@ -285,7 +285,7 @@ abstract class BaseTemplate extends QuickTemplate {
         */
        protected function renderAfterPortlet( $name ) {
                $content = '';
-               wfRunHooks( 'BaseTemplateAfterPortlet', array( $this, $name, &$content ) );
+               Hooks::run( 'BaseTemplateAfterPortlet', array( $this, $name, &$content ) );
 
                if ( $content !== '' ) {
                        echo "<div class='after-portlet after-portlet-$name'>$content</div>";
index 5604bc2..ce0c640 100644 (file)
@@ -259,7 +259,7 @@ abstract class Skin extends ContextSource {
                        $titles[] = $title->getTalkPage();
                }
 
-               wfRunHooks( 'SkinPreloadExistence', array( &$titles, $this ) );
+               Hooks::run( 'SkinPreloadExistence', array( &$titles, $this ) );
 
                if ( count( $titles ) ) {
                        $lb = new LinkBatch( $titles );
@@ -587,7 +587,7 @@ abstract class Skin extends ContextSource {
        protected function afterContentHook() {
                $data = '';
 
-               if ( wfRunHooks( 'SkinAfterContent', array( &$data, $this ) ) ) {
+               if ( Hooks::run( 'SkinAfterContent', array( &$data, $this ) ) ) {
                        // adding just some spaces shouldn't toggle the output
                        // of the whole <div/>, so we use trim() here
                        if ( trim( $data ) != '' ) {
@@ -624,7 +624,7 @@ abstract class Skin extends ContextSource {
                // OutputPage::getBottomScripts() which takes a Skin param. This should be cleaned
                // up at some point
                $bottomScriptText = $this->getOutput()->getBottomScripts();
-               wfRunHooks( 'SkinAfterBottomScripts', array( $this, &$bottomScriptText ) );
+               Hooks::run( 'SkinAfterBottomScripts', array( $this, &$bottomScriptText ) );
 
                return $bottomScriptText;
        }
@@ -684,7 +684,7 @@ abstract class Skin extends ContextSource {
                $out = $this->getOutput();
                $subpages = '';
 
-               if ( !wfRunHooks( 'SkinSubPageSubtitle', array( &$subpages, $this, $out ) ) ) {
+               if ( !Hooks::run( 'SkinSubPageSubtitle', array( &$subpages, $this, $out ) ) ) {
                        return $subpages;
                }
 
@@ -793,7 +793,7 @@ abstract class Skin extends ContextSource {
                // @todo Remove deprecated $forContent param from hook handlers and then remove here.
                $forContent = true;
 
-               wfRunHooks(
+               Hooks::run(
                        'SkinCopyrightFooter',
                        array( $this->getTitle(), $type, &$msg, &$link, &$forContent )
                );
@@ -840,7 +840,7 @@ abstract class Skin extends ContextSource {
                $url = htmlspecialchars( "$wgResourceBasePath/resources/assets/poweredby_mediawiki_88x31.png" );
                $text = '<a href="//www.mediawiki.org/"><img src="' . $url
                        . '" height="31" width="88" alt="Powered by MediaWiki" /></a>';
-               wfRunHooks( 'SkinGetPoweredBy', array( &$text, $this ) );
+               Hooks::run( 'SkinGetPoweredBy', array( &$text, $this ) );
                return $text;
        }
 
@@ -1224,7 +1224,7 @@ abstract class Skin extends ContextSource {
                if ( $wgEnableSidebarCache ) {
                        $cachedsidebar = $wgMemc->get( $key );
                        if ( $cachedsidebar ) {
-                               wfRunHooks( 'SidebarBeforeOutput', array( $this, &$cachedsidebar ) );
+                               Hooks::run( 'SidebarBeforeOutput', array( $this, &$cachedsidebar ) );
 
                                wfProfileOut( __METHOD__ );
                                return $cachedsidebar;
@@ -1234,12 +1234,12 @@ abstract class Skin extends ContextSource {
                $bar = array();
                $this->addToSidebar( $bar, 'sidebar' );
 
-               wfRunHooks( 'SkinBuildSidebar', array( $this, &$bar ) );
+               Hooks::run( 'SkinBuildSidebar', array( $this, &$bar ) );
                if ( $wgEnableSidebarCache ) {
                        $wgMemc->set( $key, $bar, $wgSidebarCacheExpiry );
                }
 
-               wfRunHooks( 'SidebarBeforeOutput', array( $this, &$bar ) );
+               Hooks::run( 'SidebarBeforeOutput', array( $this, &$bar ) );
 
                wfProfileOut( __METHOD__ );
                return $bar;
@@ -1379,7 +1379,7 @@ abstract class Skin extends ContextSource {
                $out = $this->getOutput();
 
                // Allow extensions to disable or modify the new messages alert
-               if ( !wfRunHooks( 'GetNewMessagesAlert', array( &$newMessagesAlert, $newtalks, $user, $out ) ) ) {
+               if ( !Hooks::run( 'GetNewMessagesAlert', array( &$newMessagesAlert, $newtalks, $user, $out ) ) ) {
                        return '';
                }
                if ( $newMessagesAlert ) {
@@ -1542,7 +1542,7 @@ abstract class Skin extends ContextSource {
                wfProfileIn( __METHOD__ );
                $siteNotice = '';
 
-               if ( wfRunHooks( 'SiteNoticeBefore', array( &$siteNotice, $this ) ) ) {
+               if ( Hooks::run( 'SiteNoticeBefore', array( &$siteNotice, $this ) ) ) {
                        if ( is_object( $this->getUser() ) && $this->getUser()->isLoggedIn() ) {
                                $siteNotice = $this->getCachedNotice( 'sitenotice' );
                        } else {
@@ -1558,7 +1558,7 @@ abstract class Skin extends ContextSource {
                        }
                }
 
-               wfRunHooks( 'SiteNoticeAfter', array( &$siteNotice, $this ) );
+               Hooks::run( 'SiteNoticeAfter', array( &$siteNotice, $this ) );
                wfProfileOut( __METHOD__ );
                return $siteNotice;
        }
@@ -1602,7 +1602,7 @@ abstract class Skin extends ContextSource {
                        . '<span class="mw-editsection-bracket">]</span>'
                        . '</span>';
 
-               wfRunHooks( 'DoEditSectionLink', array( $this, $nt, $section, $tooltip, &$result, $lang ) );
+               Hooks::run( 'DoEditSectionLink', array( $this, $nt, $section, $tooltip, &$result, $lang ) );
                return $result;
        }
 
index 3a39fee..d393280 100644 (file)
@@ -163,7 +163,7 @@ class SkinTemplate extends Skin {
                                        'lang' => $ilInterwikiCodeBCP47,
                                        'hreflang' => $ilInterwikiCodeBCP47,
                                );
-                               wfRunHooks(
+                               Hooks::run(
                                        'SkinTemplateGetLanguageLink',
                                        array( &$languageLink, $languageLinkTitle, $this->getTitle(), $this->getOutput() )
                                );
@@ -484,7 +484,7 @@ class SkinTemplate extends Skin {
                $tpl->set( 'reporttime', wfReportTime() );
 
                // original version by hansm
-               if ( !wfRunHooks( 'SkinTemplateOutputPageBeforeExec', array( &$this, &$tpl ) ) ) {
+               if ( !Hooks::run( 'SkinTemplateOutputPageBeforeExec', array( &$this, &$tpl ) ) ) {
                        wfDebug( __METHOD__ . ": Hook SkinTemplateOutputPageBeforeExec broke outputPage execution!\n" );
                }
 
@@ -703,7 +703,7 @@ class SkinTemplate extends Skin {
                        $personal_urls['login'] = $login_url;
                }
 
-               wfRunHooks( 'PersonalUrls', array( &$personal_urls, &$title, $this ) );
+               Hooks::run( 'PersonalUrls', array( &$personal_urls, &$title, $this ) );
                wfProfileOut( __METHOD__ );
                return $personal_urls;
        }
@@ -749,7 +749,7 @@ class SkinTemplate extends Skin {
                }
 
                $result = array();
-               if ( !wfRunHooks( 'SkinTemplateTabAction', array( &$this,
+               if ( !Hooks::run( 'SkinTemplateTabAction', array( &$this,
                                $title, $message, $selected, $checkEdit,
                                &$classes, &$query, &$text, &$result ) ) ) {
                        return $result;
@@ -845,7 +845,7 @@ class SkinTemplate extends Skin {
                $userCanRead = $title->quickUserCan( 'read', $user );
 
                $preventActiveTabs = false;
-               wfRunHooks( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$preventActiveTabs ) );
+               Hooks::run( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$preventActiveTabs ) );
 
                // Checks if page is some kind of content
                if ( $title->canExist() ) {
@@ -1054,7 +1054,7 @@ class SkinTemplate extends Skin {
                                }
                        }
 
-                       wfRunHooks( 'SkinTemplateNavigation', array( &$this, &$content_navigation ) );
+                       Hooks::run( 'SkinTemplateNavigation', array( &$this, &$content_navigation ) );
 
                        if ( $userCanRead && !$wgDisableLangConversion ) {
                                $pageLang = $title->getPageLanguage();
@@ -1096,12 +1096,12 @@ class SkinTemplate extends Skin {
                                'context' => 'subject'
                        );
 
-                       wfRunHooks( 'SkinTemplateNavigation::SpecialPage',
+                       Hooks::run( 'SkinTemplateNavigation::SpecialPage',
                                array( &$this, &$content_navigation ) );
                }
 
                // Equiv to SkinTemplateContentActions
-               wfRunHooks( 'SkinTemplateNavigation::Universal', array( &$this, &$content_navigation ) );
+               Hooks::run( 'SkinTemplateNavigation::Universal', array( &$this, &$content_navigation ) );
 
                // Setup xml ids and tooltip info
                foreach ( $content_navigation as $section => &$links ) {
@@ -1243,7 +1243,7 @@ class SkinTemplate extends Skin {
                        }
 
                        // Use the copy of revision ID in case this undocumented, shady hook tries to mess with internals
-                       wfRunHooks( 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink',
+                       Hooks::run( 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink',
                                array( &$this, &$nav_urls, &$revid, &$revid ) );
                }
 
index c28aa86..3476c26 100644 (file)
@@ -154,7 +154,7 @@ abstract class ChangesListSpecialPage extends SpecialPage {
        protected function getCustomFilters() {
                if ( $this->customFilters === null ) {
                        $this->customFilters = array();
-                       wfRunHooks( 'ChangesListSpecialPageFilters', array( $this, &$this->customFilters ) );
+                       Hooks::run( 'ChangesListSpecialPageFilters', array( $this, &$this->customFilters ) );
                }
 
                return $this->customFilters;
@@ -310,16 +310,16 @@ abstract class ChangesListSpecialPage extends SpecialPage {
        }
 
        protected function runMainQueryHook( &$tables, &$fields, &$conds, &$query_options, &$join_conds, $opts ) {
-               return wfRunHooks(
+               return Hooks::run(
                        'ChangesListSpecialPageQuery',
                        array( $this->getName(), &$tables, &$fields, &$conds, &$query_options, &$join_conds, $opts )
                );
        }
 
        /**
-        * Return a DatabaseBase object for reading
+        * Return a IDatabase object for reading
         *
-        * @return DatabaseBase
+        * @return IDatabase
         */
        protected function getDB() {
                return wfGetDB( DB_SLAVE );
index bf86ab2..fd3bc7b 100644 (file)
@@ -106,7 +106,7 @@ abstract class FormSpecialPage extends SpecialPage {
                $this->alterForm( $form );
 
                // Give hooks a chance to alter the form, adding extra fields or text etc
-               wfRunHooks( 'SpecialPageBeforeFormDisplay', array( $this->getName(), &$form ) );
+               Hooks::run( 'SpecialPageBeforeFormDisplay', array( $this->getName(), &$form ) );
 
                return $form;
        }
index c837d1a..c4e53ee 100644 (file)
@@ -35,7 +35,7 @@ abstract class ImageQueryPage extends QueryPage {
         *
         * @param OutputPage $out OutputPage to print to
         * @param Skin $skin User skin to use [unused]
-        * @param DatabaseBase $dbr (read) connection to use
+        * @param IDatabase $dbr (read) connection to use
         * @param ResultWrapper $res Result pointer
         * @param int $num Number of available result rows
         * @param int $offset Paging offset
index afc0227..d72744b 100644 (file)
@@ -32,7 +32,7 @@ abstract class PageQueryPage extends QueryPage {
         * like page existence and information for stub color and redirect hints.
         * This should be done for live data and cached data.
         *
-        * @param DatabaseBase $db
+        * @param IDatabase $db
         * @param ResultWrapper $res
         */
        public function preprocessResults( $db, $res ) {
index 167135b..dd21af4 100644 (file)
@@ -100,7 +100,7 @@ abstract class QueryPage extends SpecialPage {
                                array( 'UnusedtemplatesPage', 'Unusedtemplates' ),
                                array( 'WithoutInterwikiPage', 'Withoutinterwiki' ),
                        );
-                       wfRunHooks( 'wgQueryPages', array( &$qp ) );
+                       Hooks::run( 'wgQueryPages', array( &$qp ) );
                }
 
                return $qp;
@@ -346,7 +346,7 @@ abstract class QueryPage extends SpecialPage {
 
        /**
         * Get a DB connection to be used for slow recache queries
-        * @return DatabaseBase
+        * @return IDatabase
         */
        function getRecacheDB() {
                return wfGetDB( DB_SLAVE, array( $this->getName(), 'QueryPage::recache', 'vslow' ) );
@@ -576,7 +576,7 @@ abstract class QueryPage extends SpecialPage {
         *
         * @param OutputPage $out OutputPage to print to
         * @param Skin $skin User skin to use
-        * @param DatabaseBase $dbr Database (read) connection to use
+        * @param IDatabase $dbr Database (read) connection to use
         * @param ResultWrapper $res Result pointer
         * @param int $num Number of available result rows
         * @param int $offset Paging offset
@@ -649,7 +649,7 @@ abstract class QueryPage extends SpecialPage {
 
        /**
         * Do any necessary preprocessing of the result object.
-        * @param DatabaseBase $db
+        * @param IDatabase $db
         * @param ResultWrapper $res
         */
        function preprocessResults( $db, $res ) {
index 4226ee0..2e6e55a 100644 (file)
@@ -203,7 +203,7 @@ abstract class RedirectSpecialArticle extends RedirectSpecialPage {
                        'ctype', 'maxage', 'smaxage',
                );
 
-               wfRunHooks( "RedirectSpecialArticleRedirectParams", array( &$redirectParams ) );
+               Hooks::run( "RedirectSpecialArticleRedirectParams", array( &$redirectParams ) );
                $this->mAllowedRedirectParams = $redirectParams;
        }
 }
index 072f87f..31d679a 100644 (file)
@@ -330,7 +330,7 @@ class SpecialPage {
 
        /**
         * Helper function for implementations of prefixSearchSubpages() that
-        * filter the values in memory (as oppposed to making a query).
+        * filter the values in memory (as opposed to making a query).
         *
         * @since 1.24
         * @param string $search
@@ -377,7 +377,7 @@ class SpecialPage {
                 * @param SpecialPage $this
                 * @param string|null $subPage
                 */
-               wfRunHooks( 'SpecialPageBeforeExecute', array( $this, $subPage ) );
+               Hooks::run( 'SpecialPageBeforeExecute', array( $this, $subPage ) );
 
                $this->beforeExecute( $subPage );
                $this->execute( $subPage );
@@ -391,7 +391,7 @@ class SpecialPage {
                 * @param SpecialPage $this
                 * @param string|null $subPage
                 */
-               wfRunHooks( 'SpecialPageAfterExecute', array( $this, $subPage ) );
+               Hooks::run( 'SpecialPageAfterExecute', array( $this, $subPage ) );
        }
 
        /**
index 1531f69..e31ebf6 100644 (file)
@@ -252,7 +252,7 @@ class SpecialPageFactory {
 
                        // Run hooks
                        // This hook can be used to remove undesired built-in special pages
-                       wfRunHooks( 'SpecialPage_initList', array( &self::$list ) );
+                       Hooks::run( 'SpecialPage_initList', array( &self::$list ) );
 
                        wfProfileOut( __METHOD__ );
                }
index be2f1e8..c4140de 100644 (file)
@@ -37,7 +37,7 @@ abstract class WantedQueryPage extends QueryPage {
 
        /**
         * Cache page existence for performance
-        * @param DatabaseBase $db
+        * @param IDatabase $db
         * @param ResultWrapper $res
         */
        function preprocessResults( $db, $res ) {
@@ -109,7 +109,7 @@ abstract class WantedQueryPage extends QueryPage {
         * @note This will only be run if the page is cached (ie $wgMiserMode = true)
         *   unless forceExistenceCheck() is true.
         * @since 1.24
-        * @return boolean
+        * @return bool
         */
        protected function existenceCheck( Title $title ) {
                return $title->isKnown();
index a4269d1..14d97eb 100644 (file)
@@ -220,7 +220,7 @@ class SpecialBlock extends FormSpecialPage {
                $this->maybeAlterFormDefaults( $a );
 
                // Allow extensions to add more fields
-               wfRunHooks( 'SpecialBlockModifyFormFields', array( $this, &$a ) );
+               Hooks::run( 'SpecialBlockModifyFormFields', array( $this, &$a ) );
 
                return $a;
        }
@@ -317,7 +317,7 @@ class SpecialBlock extends FormSpecialPage {
                $otherBlockMessages = array();
                if ( $this->target !== null ) {
                        # Get other blocks, i.e. from GlobalBlocking or TorBlock extension
-                       wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockMessages, $this->target ) );
+                       Hooks::run( 'OtherBlockLogLink', array( &$otherBlockMessages, $this->target ) );
 
                        if ( count( $otherBlockMessages ) ) {
                                $s = Html::rawElement(
@@ -626,7 +626,7 @@ class SpecialBlock extends FormSpecialPage {
                        # permission anyway, although the code does allow for it.
                        # Note: Important to use $target instead of $data['Target']
                        # since both $data['PreviousTarget'] and $target are normalized
-                       # but $data['target'] gets overriden by (non-normalized) request variable
+                       # but $data['target'] gets overridden by (non-normalized) request variable
                        # from previous request.
                        if ( $target === $performer->getName() &&
                                ( $data['PreviousTarget'] !== $target || !$data['Confirm'] )
@@ -701,7 +701,7 @@ class SpecialBlock extends FormSpecialPage {
                $block->mHideName = $data['HideUser'];
 
                $reason = array( 'hookaborted' );
-               if ( !wfRunHooks( 'BlockIp', array( &$block, &$performer, &$reason ) ) ) {
+               if ( !Hooks::run( 'BlockIp', array( &$block, &$performer, &$reason ) ) ) {
                        return $reason;
                }
 
@@ -762,7 +762,7 @@ class SpecialBlock extends FormSpecialPage {
                        $logaction = 'block';
                }
 
-               wfRunHooks( 'BlockIpComplete', array( $block, $performer ) );
+               Hooks::run( 'BlockIpComplete', array( $block, $performer ) );
 
                # Set *_deleted fields if requested
                if ( $data['HideUser'] ) {
index 02b2626..da6f4c0 100644 (file)
@@ -170,7 +170,7 @@ class SpecialBlockList extends SpecialPage {
 
                # Check for other blocks, i.e. global/tor blocks
                $otherBlockLink = array();
-               wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockLink, $this->target ) );
+               Hooks::run( 'OtherBlockLogLink', array( &$otherBlockLink, $this->target ) );
 
                $out = $this->getOutput();
 
index d8eec7d..91a148d 100644 (file)
@@ -161,7 +161,7 @@ class SpecialBookSources extends SpecialPage {
 
                # Hook to allow extensions to insert additional HTML,
                # e.g. for API-interacting plugins and so on
-               wfRunHooks( 'BookInformation', array( $this->isbn, $this->getOutput() ) );
+               Hooks::run( 'BookInformation', array( $this->isbn, $this->getOutput() ) );
 
                # Check for a local page such as Project:Book_sources and use that if available
                $page = $this->msg( 'booksources' )->inContentLanguage()->text();
index 12bbd2a..e09c8ac 100644 (file)
@@ -183,7 +183,7 @@ class SpecialChangeEmail extends FormSpecialPage {
                        return $status;
                }
 
-               wfRunHooks( 'PrefsEmailAudit', array( $user, $oldaddr, $newaddr ) );
+               Hooks::run( 'PrefsEmailAudit', array( $user, $oldaddr, $newaddr ) );
 
                $user->saveSettings();
 
index 24664ed..168095f 100644 (file)
@@ -118,7 +118,7 @@ class SpecialChangePassword extends FormSpecialPage {
                }
 
                $extraFields = array();
-               wfRunHooks( 'ChangePasswordForm', array( &$extraFields ) );
+               Hooks::run( 'ChangePasswordForm', array( &$extraFields ) );
                foreach ( $extraFields as $extra ) {
                        list( $name, $label, $type, $default ) = $extra;
                        $fields[$name] = array(
@@ -248,7 +248,7 @@ class SpecialChangePassword extends FormSpecialPage {
                }
 
                if ( $newpass !== $retype ) {
-                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
+                       Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
                        throw new PasswordError( $this->msg( 'badretype' )->text() );
                }
 
@@ -264,7 +264,7 @@ class SpecialChangePassword extends FormSpecialPage {
 
                // @todo Make these separate messages, since the message is written for both cases
                if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) {
-                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
+                       Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
                        throw new PasswordError( $this->msg( 'resetpass-wrong-oldpass' )->text() );
                }
 
@@ -276,8 +276,8 @@ class SpecialChangePassword extends FormSpecialPage {
                // Do AbortChangePassword after checking mOldpass, so we don't leak information
                // by possibly aborting a new password before verifying the old password.
                $abortMsg = 'resetpass-abort-generic';
-               if ( !wfRunHooks( 'AbortChangePassword', array( $user, $oldpass, $newpass, &$abortMsg ) ) ) {
-                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'abortreset' ) );
+               if ( !Hooks::run( 'AbortChangePassword', array( $user, $oldpass, $newpass, &$abortMsg ) ) ) {
+                       Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'abortreset' ) );
                        throw new PasswordError( $this->msg( $abortMsg )->text() );
                }
 
@@ -288,9 +288,9 @@ class SpecialChangePassword extends FormSpecialPage {
 
                try {
                        $user->setPassword( $newpass );
-                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
+                       Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
                } catch ( PasswordError $e ) {
-                       wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
+                       Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
                        throw new PasswordError( $e->getMessage() );
                }
 
index 1e829b1..5030c1c 100644 (file)
@@ -176,7 +176,7 @@ class SpecialContributions extends IncludableSpecialPage {
                // Add RSS/atom links
                $this->addFeedLinks( $feedParams );
 
-               if ( wfRunHooks( 'SpecialContributionsBeforeMainOutput', array( $id, $userObj, $this ) ) ) {
+               if ( Hooks::run( 'SpecialContributionsBeforeMainOutput', array( $id, $userObj, $this ) ) ) {
                        if ( !$this->including() ) {
                                $out->addHTML( $this->getForm() );
                        }
@@ -386,7 +386,7 @@ class SpecialContributions extends IncludableSpecialPage {
                        );
                }
 
-               wfRunHooks( 'ContributionsToolLinks', array( $id, $userpage, &$tools ) );
+               Hooks::run( 'ContributionsToolLinks', array( $id, $userpage, &$tools ) );
 
                return $tools;
        }
@@ -672,10 +672,7 @@ class ContribsPager extends ReverseChronologicalPager {
                $msgs = array(
                        'diff',
                        'hist',
-                       'newarticle',
                        'pipe-separator',
-                       'rev-delundel',
-                       'rollbacklink',
                        'uctop'
                );
 
@@ -714,7 +711,7 @@ class ContribsPager extends ReverseChronologicalPager {
 
        /**
         * This method basically executes the exact same code as the parent class, though with
-        * a hook added, to allow extentions to add additional queries.
+        * a hook added, to allow extensions to add additional queries.
         *
         * @param string $offset Index offset, inclusive
         * @param int $limit Exact query limit
@@ -750,7 +747,7 @@ class ContribsPager extends ReverseChronologicalPager {
                $data = array( $this->mDb->select(
                        $tables, $fields, $conds, $fname, $options, $join_conds
                ) );
-               wfRunHooks(
+               Hooks::run(
                        'ContribsPager::reallyDoQuery',
                        array( &$data, $pager, $offset, $limit, $descending )
                );
@@ -827,7 +824,7 @@ class ContribsPager extends ReverseChronologicalPager {
                        $this->tagFilter
                );
 
-               wfRunHooks( 'ContribsPager::getQueryInfo', array( &$this, &$queryInfo ) );
+               Hooks::run( 'ContribsPager::getQueryInfo', array( &$this, &$queryInfo ) );
 
                return $queryInfo;
        }
@@ -1112,7 +1109,7 @@ class ContribsPager extends ReverseChronologicalPager {
                }
 
                // Let extensions add data
-               wfRunHooks( 'ContributionsLineEnding', array( $this, &$ret, $row, &$classes ) );
+               Hooks::run( 'ContributionsLineEnding', array( $this, &$ret, $row, &$classes ) );
 
                if ( $classes === array() && $ret === '' ) {
                        wfDebug( "Dropping Special:Contribution row that could not be formatted\n" );
index 29c3fd4..7e5d13c 100644 (file)
@@ -466,7 +466,7 @@ class DeletedContributionsPage extends SpecialPage {
                                );
                        }
 
-                       wfRunHooks( 'ContributionsToolLinks', array( $id, $nt, &$tools ) );
+                       Hooks::run( 'ContributionsToolLinks', array( $id, $nt, &$tools ) );
 
                        $links = $this->getLanguage()->pipeList( $tools );
 
index cb97420..50a52b8 100644 (file)
@@ -256,7 +256,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                // Do a batch existence check
                $batch = new LinkBatch();
                if ( count( $titles ) >= 100 ) {
-                       $output = wfMessage( 'watchlistedit-too-many' )->parse();
+                       $output = $this->msg( 'watchlistedit-too-many' )->parse();
                        return;
                }
                foreach ( $titles as $title ) {
@@ -513,7 +513,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                                );
 
                                $page = WikiPage::factory( $title );
-                               wfRunHooks( 'UnwatchArticleComplete', array( $this->getUser(), &$page ) );
+                               Hooks::run( 'UnwatchArticleComplete', array( $this->getUser(), &$page ) );
                        }
                }
        }
@@ -551,7 +551,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                // Allow subscribers to manipulate the list of watched pages (or use it
                // to preload lots of details at once)
                $watchlistInfo = $this->getWatchlistInfo();
-               wfRunHooks(
+               Hooks::run(
                        'WatchlistEditorBeforeFormRender',
                        array( &$watchlistInfo )
                );
@@ -645,7 +645,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                        );
                }
 
-               wfRunHooks(
+               Hooks::run(
                        'WatchlistEditorBuildRemoveLine',
                        array( &$tools, $title, $title->isRedirect(), $this->getSkin(), &$link )
                );
index 20532a9..c55fa94 100644 (file)
@@ -160,7 +160,7 @@ class SpecialEmailUser extends UnlistedSpecialPage {
                $form->setWrapperLegendMsg( 'email-legend' );
                $form->loadData();
 
-               if ( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ) {
+               if ( !Hooks::run( 'EmailUserForm', array( &$form ) ) ) {
                        return;
                }
 
@@ -243,8 +243,8 @@ class SpecialEmailUser extends UnlistedSpecialPage {
 
                $hookErr = false;
 
-               wfRunHooks( 'UserCanSendEmail', array( &$user, &$hookErr ) );
-               wfRunHooks( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) );
+               Hooks::run( 'UserCanSendEmail', array( &$user, &$hookErr ) );
+               Hooks::run( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) );
 
                if ( $hookErr ) {
                        return $hookErr;
@@ -324,7 +324,7 @@ class SpecialEmailUser extends UnlistedSpecialPage {
                        $from->name, $to->name )->inContentLanguage()->text();
 
                $error = '';
-               if ( !wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) {
+               if ( !Hooks::run( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) {
                        return $error;
                }
 
@@ -367,12 +367,12 @@ class SpecialEmailUser extends UnlistedSpecialPage {
                        if ( $data['CCMe'] && $to != $from ) {
                                $cc_subject = $context->msg( 'emailccsubject' )->rawParams(
                                        $target->getName(), $subject )->text();
-                               wfRunHooks( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) );
+                               Hooks::run( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) );
                                $ccStatus = UserMailer::send( $from, $from, $cc_subject, $text );
                                $status->merge( $ccStatus );
                        }
 
-                       wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $text ) );
+                       Hooks::run( 'EmailUserComplete', array( $to, $from, $subject, $text ) );
 
                        return $status;
                }
index 0831c20..da2df2d 100644 (file)
@@ -579,7 +579,7 @@ class ImportReporter extends ContextSource {
                                $page = WikiPage::factory( $title );
                                # Update page record
                                $page->updateRevisionOn( $dbw, $nullRevision );
-                               wfRunHooks(
+                               Hooks::run(
                                        'NewRevisionFromEditComplete',
                                        array( $page, $nullRevision, $latest, $this->getUser() )
                                );
index fa20994..68c5346 100644 (file)
@@ -150,7 +150,7 @@ class UsersPager extends AlphabeticPager {
                        'conds' => $conds
                );
 
-               wfRunHooks( 'SpecialListusersQueryInfo', array( $this, &$query ) );
+               Hooks::run( 'SpecialListusersQueryInfo', array( $this, &$query ) );
 
                return $query;
        }
@@ -211,7 +211,7 @@ class UsersPager extends AlphabeticPager {
                        ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() :
                        '';
 
-               wfRunHooks( 'SpecialListusersFormatRow', array( &$item, $row ) );
+               Hooks::run( 'SpecialListusersFormatRow', array( &$item, $row ) );
 
                return Html::rawElement( 'li', array(), "{$item}{$edits}{$created}{$blocked}" );
        }
@@ -284,12 +284,12 @@ class UsersPager extends AlphabeticPager {
                );
                $out .= '<br />';
 
-               wfRunHooks( 'SpecialListusersHeaderForm', array( $this, &$out ) );
+               Hooks::run( 'SpecialListusersHeaderForm', array( $this, &$out ) );
 
                # Submit button and form bottom
                $out .= Html::hidden( 'limit', $this->mLimit );
                $out .= Xml::submitButton( $this->msg( 'allpagessubmit' )->text() );
-               wfRunHooks( 'SpecialListusersHeader', array( $this, &$out ) );
+               Hooks::run( 'SpecialListusersHeader', array( $this, &$out ) );
                $out .= Xml::closeElement( 'fieldset' ) .
                        Xml::closeElement( 'form' );
 
@@ -322,7 +322,7 @@ class UsersPager extends AlphabeticPager {
                if ( $this->requestedUser != '' ) {
                        $query['username'] = $this->requestedUser;
                }
-               wfRunHooks( 'SpecialListusersDefaultQuery', array( $this, &$query ) );
+               Hooks::run( 'SpecialListusersDefaultQuery', array( $this, &$query ) );
 
                return $query;
        }
index 04c2fe9..923283e 100644 (file)
@@ -97,13 +97,13 @@ class SpecialLog extends SpecialPage {
                        }
                } else {
                        // Allow extensions to add relations to their search types
-                       wfRunHooks( 'SpecialLogAddLogSearchRelations', array( $opts->getValue( 'type' ), $this->getRequest(), &$qc ) );
+                       Hooks::run( 'SpecialLogAddLogSearchRelations', array( $opts->getValue( 'type' ), $this->getRequest(), &$qc ) );
                }
 
                # Some log types are only for a 'User:' title but we might have been given
                # only the username instead of the full title 'User:username'. This part try
                # to lookup for a user by that name and eventually fix user input. See bug 1697.
-               wfRunHooks( 'GetLogTypesOnUser', array( &$this->typeOnUser ) );
+               Hooks::run( 'GetLogTypesOnUser', array( &$this->typeOnUser ) );
                if ( in_array( $opts->getValue( 'type' ), $this->typeOnUser ) ) {
                        # ok we have a type of log which expect a user title.
                        $target = Title::newFromText( $opts->getValue( 'page' ) );
index f533234..c072491 100644 (file)
@@ -72,7 +72,7 @@ class LonelyPagesPage extends PageQueryPage {
                );
 
                // Allow extensions to modify the query
-               wfRunHooks( 'LonelyPagesQuery', array( &$tables, &$conds, &$joinConds ) );
+               Hooks::run( 'LonelyPagesQuery', array( &$tables, &$conds, &$joinConds ) );
 
                return array(
                        'tables' => $tables,
index c71ef76..07a18b0 100644 (file)
@@ -485,7 +485,7 @@ class SpecialMergeHistory extends SpecialPage {
                        $targetTitle->getPrefixedText(), $destTitle->getPrefixedText() )->numParams(
                        $count )->text() );
 
-               wfRunHooks( 'ArticleMergeComplete', array( $targetTitle, $destTitle ) );
+               Hooks::run( 'ArticleMergeComplete', array( $targetTitle, $destTitle ) );
 
                return true;
        }
index 4cbf584..2a7e435 100644 (file)
@@ -604,7 +604,7 @@ class MovePageForm extends UnlistedSpecialPage {
                        $newLink )->params( $oldText, $newText )->parseAsBlock() );
                $out->addWikiMsg( $msgName );
 
-               wfRunHooks( 'SpecialMovepageAfterMove', array( &$this, &$ot, &$nt ) );
+               Hooks::run( 'SpecialMovepageAfterMove', array( &$this, &$ot, &$nt ) );
 
                # Now we move extra pages we've been asked to move: subpages and talk
                # pages.  First, if the old page or the new page is a talk page, we
index b3b3d48..9dad5a2 100644 (file)
@@ -56,7 +56,7 @@ class SpecialNewpages extends IncludableSpecialPage {
                $opts->add( 'invert', false );
 
                $this->customFilters = array();
-               wfRunHooks( 'SpecialNewPagesFilters', array( $this, &$this->customFilters ) );
+               Hooks::run( 'SpecialNewPagesFilters', array( $this, &$this->customFilters ) );
                foreach ( $this->customFilters as $key => $params ) {
                        $opts->add( $key, $params['default'] );
                }
@@ -236,7 +236,7 @@ class SpecialNewpages extends IncludableSpecialPage {
                        'tagFilter' => array(
                                'type' => 'tagfilter',
                                'name' => 'tagfilter',
-                               'label-raw' => wfMessage( 'tag-filter' )->parse(),
+                               'label-raw' => $this->msg( 'tag-filter' )->parse(),
                                'default' => $tagFilterVal,
                        ),
                        'username' => array(
@@ -548,7 +548,7 @@ class NewPagesPager extends ReverseChronologicalPager {
                );
                $join_conds = array( 'page' => array( 'INNER JOIN', 'page_id=rc_cur_id' ) );
 
-               wfRunHooks( 'SpecialNewpagesConditions',
+               Hooks::run( 'SpecialNewpagesConditions',
                        array( &$this, $this->opts, &$conds, &$tables, &$fields, &$join_conds ) );
 
                $options = array();
index 2acf23c..52c2460 100644 (file)
@@ -93,7 +93,7 @@ class SpecialPageLanguage extends FormSpecialPage {
        public function alterForm( HTMLForm $form ) {
                $form->setDisplayFormat( 'vform' );
                $form->setWrapperLegend( false );
-               wfRunHooks( 'LanguageSelector', array( $this->getOutput(), 'mw-languageselector' ) );
+               Hooks::run( 'LanguageSelector', array( $this->getOutput(), 'mw-languageselector' ) );
        }
 
        /**
index 3061c85..6ee3290 100644 (file)
@@ -195,7 +195,7 @@ class SpecialPasswordReset extends FormSpecialPage {
 
                // Check for hooks (captcha etc), and allow them to modify the users list
                $error = array();
-               if ( !wfRunHooks( 'SpecialPasswordResetOnSubmit', array( &$users, $data, &$error ) ) ) {
+               if ( !Hooks::run( 'SpecialPasswordResetOnSubmit', array( &$users, $data, &$error ) ) ) {
                        return array( $error );
                }
 
@@ -246,7 +246,7 @@ class SpecialPasswordReset extends FormSpecialPage {
                        return array( 'badipaddress' );
                }
                $caller = $this->getUser();
-               wfRunHooks( 'User::mailPasswordInternal', array( &$caller, &$ip, &$firstUser ) );
+               Hooks::run( 'User::mailPasswordInternal', array( &$caller, &$ip, &$firstUser ) );
                $username = $caller->getName();
                $msg = IP::isValid( $username )
                        ? 'passwordreset-emailtext-ip'
index 6d8f59b..73a88b9 100644 (file)
@@ -106,7 +106,7 @@ class RandomPage extends SpecialPage {
                $randstr = wfRandom();
                $title = null;
 
-               if ( !wfRunHooks(
+               if ( !Hooks::run(
                        'SpecialRandomGetRandomTitle',
                        array( &$randstr, &$this->isRedir, &$this->namespaces, &$this->extra, &$title )
                ) ) {
index 58b51b3..efb870b 100644 (file)
@@ -95,7 +95,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
        protected function getCustomFilters() {
                if ( $this->customFilters === null ) {
                        $this->customFilters = parent::getCustomFilters();
-                       wfRunHooks( 'SpecialRecentChangesFilters', array( $this, &$this->customFilters ), '1.23' );
+                       Hooks::run( 'SpecialRecentChangesFilters', array( $this, &$this->customFilters ), '1.23' );
                }
 
                return $this->customFilters;
@@ -254,7 +254,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
 
        protected function runMainQueryHook( &$tables, &$fields, &$conds, &$query_options, &$join_conds, $opts ) {
                return parent::runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds, $opts )
-                       && wfRunHooks(
+                       && Hooks::run(
                                'SpecialRecentChangesQuery',
                                array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$fields ),
                                '1.23'
@@ -475,7 +475,7 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
 
                // Don't fire the hook for subclasses. (Or should we?)
                if ( $this->getName() === 'Recentchanges' ) {
-                       wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) );
+                       Hooks::run( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) );
                }
 
                return $extraOpts;
index 4add742..ba2b9a5 100644 (file)
@@ -44,7 +44,7 @@ class SpecialResetTokens extends FormSpecialPage {
                        $tokens = array(
                                array( 'preference' => 'watchlisttoken', 'label-message' => 'resettokens-watchlist-token' ),
                        );
-                       wfRunHooks( 'SpecialResetTokensTokens', array( &$tokens ) );
+                       Hooks::run( 'SpecialResetTokensTokens', array( &$tokens ) );
 
                        $hiddenPrefs = $this->getConfig()->get( 'HiddenPrefs' );
                        $tokens = array_filter( $tokens, function ( $tok ) use ( $hiddenPrefs ) {
index 448b802..c77c786 100644 (file)
@@ -196,7 +196,7 @@ class SpecialSearch extends SpecialPage {
                # No match, generate an edit URL
                $title = Title::newFromText( $term );
                if ( !is_null( $title ) ) {
-                       wfRunHooks( 'SpecialSearchNogomatch', array( &$title ) );
+                       Hooks::run( 'SpecialSearchNogomatch', array( &$title ) );
                }
                $this->showResults( $term );
        }
@@ -214,7 +214,7 @@ class SpecialSearch extends SpecialPage {
                $search->prefix = $this->mPrefix;
                $term = $search->transformSearchTerm( $term );
 
-               wfRunHooks( 'SpecialSearchSetupEngine', array( $this, $this->profile, $search ) );
+               Hooks::run( 'SpecialSearchSetupEngine', array( $this, $this->profile, $search ) );
 
                $this->setupPage( $term );
 
@@ -293,7 +293,7 @@ class SpecialSearch extends SpecialPage {
                                . $this->msg( 'search-suggest' )->rawParams( $suggestLink )->text() . '</div>';
                }
 
-               if ( !wfRunHooks( 'SpecialSearchResultsPrepend', array( $this, $out, $term ) ) ) {
+               if ( !Hooks::run( 'SpecialSearchResultsPrepend', array( $this, $out, $term ) ) ) {
                        # Hook requested termination
                        return;
                }
@@ -361,7 +361,7 @@ class SpecialSearch extends SpecialPage {
                                );
                        }
                }
-               wfRunHooks( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) );
+               Hooks::run( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) );
 
                $out->parserOptions()->setEditSection( false );
                if ( $titleMatches ) {
@@ -444,7 +444,7 @@ class SpecialSearch extends SpecialPage {
                        wfEscapeWikiText( $title->getPrefixedText() ),
                        Message::numParam( $num )
                );
-               wfRunHooks( 'SpecialSearchCreateLink', array( $title, &$params ) );
+               Hooks::run( 'SpecialSearchCreateLink', array( $title, &$params ) );
 
                // Extensions using the hook might still return an empty $messageName
                if ( $messageName ) {
@@ -595,7 +595,7 @@ class SpecialSearch extends SpecialPage {
 
                $link_t = clone $title;
 
-               wfRunHooks( 'ShowSearchHitTitle',
+               Hooks::run( 'ShowSearchHitTitle',
                        array( &$link_t, &$titleSnippet, $result, $terms, $this ) );
 
                $link = Linker::linkKnown(
@@ -713,7 +713,7 @@ class SpecialSearch extends SpecialPage {
                $html = null;
 
                $score = '';
-               if ( wfRunHooks( 'ShowSearchHit', array(
+               if ( Hooks::run( 'ShowSearchHit', array(
                        $this, $result, $terms,
                        &$link, &$redirect, &$section, &$extract,
                        &$score, &$size, &$date, &$related,
@@ -907,7 +907,7 @@ class SpecialSearch extends SpecialPage {
 
                $showSections = array( 'namespaceTables' => $namespaceTables );
 
-               wfRunHooks( 'SpecialSearchPowerBox', array( &$showSections, $term, $opts ) );
+               Hooks::run( 'SpecialSearchPowerBox', array( &$showSections, $term, $opts ) );
 
                $hidden = '';
                foreach ( $opts as $key => $value ) {
@@ -919,7 +919,7 @@ class SpecialSearch extends SpecialPage {
                $user = $this->getUser();
                if ( $user->isLoggedIn() ) {
                        $remember .= Xml::checkLabel(
-                               wfMessage( 'powersearch-remember' )->text(),
+                               $this->msg( 'powersearch-remember' )->text(),
                                'nsRemember',
                                'mw-search-powersearch-remember',
                                false,
@@ -978,7 +978,7 @@ class SpecialSearch extends SpecialPage {
                        )
                );
 
-               wfRunHooks( 'SpecialSearchProfiles', array( &$profiles ) );
+               Hooks::run( 'SpecialSearchProfiles', array( &$profiles ) );
 
                foreach ( $profiles as &$data ) {
                        if ( !is_array( $data['namespaces'] ) ) {
@@ -1044,7 +1044,7 @@ class SpecialSearch extends SpecialPage {
                        $out .= $this->powerSearchBox( $term, $opts );
                } else {
                        $form = '';
-                       wfRunHooks( 'SpecialSearchProfileForm', array( $this, &$form, $this->profile, $term, $opts ) );
+                       Hooks::run( 'SpecialSearchProfileForm', array( $this, &$form, $this->profile, $term, $opts ) );
                        $out .= $form;
                }
 
index 1bbc2f3..4429022 100644 (file)
@@ -78,7 +78,7 @@ class SpecialStatistics extends SpecialPage {
 
                # Statistic - other
                $extraStats = array();
-               if ( wfRunHooks( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) {
+               if ( Hooks::run( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) {
                        $text .= $this->getOtherStats( $extraStats );
                }
 
index bcf83c8..2ea1b12 100644 (file)
@@ -421,7 +421,7 @@ class PageArchive {
                $logEntry->setTarget( $this->title );
                $logEntry->setComment( $reason );
 
-               wfRunHooks( 'ArticleUndeleteLogEntry', array( $this, &$logEntry, $user ) );
+               Hooks::run( 'ArticleUndeleteLogEntry', array( $this, &$logEntry, $user ) );
 
                $logid = $logEntry->insert();
                $logEntry->publish( $logid );
@@ -605,7 +605,7 @@ class PageArchive {
                        $revision->insertOn( $dbw );
                        $restored++;
 
-                       wfRunHooks( 'ArticleRevisionUndeleted', array( &$this->title, $revision, $row->ar_page_id ) );
+                       Hooks::run( 'ArticleRevisionUndeleted', array( &$this->title, $revision, $row->ar_page_id ) );
                }
                # Now that it's safely stored, take it out of the archive
                $dbw->delete( 'archive',
@@ -631,7 +631,7 @@ class PageArchive {
                        );
                }
 
-               wfRunHooks( 'ArticleUndelete', array( &$this->title, $created, $comment, $oldPageId ) );
+               Hooks::run( 'ArticleUndelete', array( &$this->title, $created, $comment, $oldPageId ) );
 
                if ( $this->title->getNamespace() == NS_FILE ) {
                        $update = new HTMLCacheUpdate( $this->title, 'imagelinks' );
@@ -908,7 +908,7 @@ class SpecialUndelete extends SpecialPage {
                }
 
                $archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
-               if ( !wfRunHooks( 'UndeleteForm::showRevision', array( &$archive, $this->mTargetObj ) ) ) {
+               if ( !Hooks::run( 'UndeleteForm::showRevision', array( &$archive, $this->mTargetObj ) ) ) {
                        return;
                }
                $rev = $archive->getRevision( $timestamp );
@@ -992,7 +992,7 @@ class SpecialUndelete extends SpecialPage {
                $out->addHTML( $this->msg( 'undelete-revision' )->rawParams( $link )->params(
                        $time )->rawParams( $userLink )->params( $d, $t )->parse() . '</div>' );
 
-               if ( !wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ) ) {
+               if ( !Hooks::run( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ) ) {
                        return;
                }
 
@@ -1215,7 +1215,7 @@ class SpecialUndelete extends SpecialPage {
                );
 
                $archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
-               wfRunHooks( 'UndeleteForm::showHistory', array( &$archive, $this->mTargetObj ) );
+               Hooks::run( 'UndeleteForm::showHistory', array( &$archive, $this->mTargetObj ) );
                /*
                $text = $archive->getLastRevisionText();
                if( is_null( $text ) ) {
@@ -1640,7 +1640,7 @@ class SpecialUndelete extends SpecialPage {
 
                $out = $this->getOutput();
                $archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
-               wfRunHooks( 'UndeleteForm::undelete', array( &$archive, $this->mTargetObj ) );
+               Hooks::run( 'UndeleteForm::undelete', array( &$archive, $this->mTargetObj ) );
                $ok = $archive->undelete(
                        $this->mTargetTimestamp,
                        $this->mComment,
@@ -1651,7 +1651,7 @@ class SpecialUndelete extends SpecialPage {
 
                if ( is_array( $ok ) ) {
                        if ( $ok[1] ) { // Undeleted file count
-                               wfRunHooks( 'FileUndeleteComplete', array(
+                               Hooks::run( 'FileUndeleteComplete', array(
                                        $this->mTargetObj, $this->mFileVersions,
                                        $this->getUser(), $this->mComment ) );
                        }
index ccc5dea..ee89b0a 100644 (file)
@@ -186,7 +186,7 @@ class SpecialUpload extends SpecialPage {
                        $this->processUpload();
                } else {
                        # Backwards compatibility hook
-                       if ( !wfRunHooks( 'UploadForm:initial', array( &$this ) ) ) {
+                       if ( !Hooks::run( 'UploadForm:initial', array( &$this ) ) ) {
                                wfDebug( "Hook 'UploadForm:initial' broke output of the upload form\n" );
 
                                return;
@@ -414,7 +414,7 @@ class SpecialUpload extends SpecialPage {
                        return;
                }
 
-               if ( !wfRunHooks( 'UploadForm:BeforeProcessing', array( &$this ) ) ) {
+               if ( !Hooks::run( 'UploadForm:BeforeProcessing', array( &$this ) ) ) {
                        wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file.\n" );
                        // This code path is deprecated. If you want to break upload processing
                        // do so by hooking into the appropriate hooks in UploadBase::verifyUpload
@@ -474,7 +474,7 @@ class SpecialUpload extends SpecialPage {
 
                // Success, redirect to description page
                $this->mUploadSuccessful = true;
-               wfRunHooks( 'SpecialUploadComplete', array( &$this ) );
+               Hooks::run( 'SpecialUploadComplete', array( &$this ) );
                $this->getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() );
        }
 
@@ -731,7 +731,7 @@ class SpecialUpload extends SpecialPage {
                }
 
                return '<li>' .
-                       wfMessage( 'file-exists-duplicate' )->numParams( count( $dupes ) )->parse() .
+                       $this->msg( 'file-exists-duplicate' )->numParams( count( $dupes ) )->parse() .
                        $gallery->toHTML() . "</li>\n";
        }
 
@@ -795,7 +795,7 @@ class UploadForm extends HTMLForm {
                        + $this->getDescriptionSection()
                        + $this->getOptionsSection();
 
-               wfRunHooks( 'UploadFormInitDescriptor', array( &$descriptor ) );
+               Hooks::run( 'UploadFormInitDescriptor', array( &$descriptor ) );
                parent::__construct( $descriptor, $context, 'upload' );
 
                # Add a link to edit MediaWik:Licenses
@@ -907,7 +907,7 @@ class UploadForm extends HTMLForm {
                                'checked' => $selectedSourceType == 'url',
                        );
                }
-               wfRunHooks( 'UploadFormSourceDescriptors', array( &$descriptor, &$radio, $selectedSourceType ) );
+               Hooks::run( 'UploadFormSourceDescriptors', array( &$descriptor, &$radio, $selectedSourceType ) );
 
                $descriptor['Extensions'] = array(
                        'type' => 'info',
index 83b9089..b261cbf 100644 (file)
@@ -122,7 +122,7 @@ class LoginForm extends SpecialPage {
                static $messages = null;
                if ( !$messages ) {
                        $messages = self::$validErrorMessages;
-                       wfRunHooks( 'LoginFormValidErrorMessages', array( &$messages ) );
+                       Hooks::run( 'LoginFormValidErrorMessages', array( &$messages ) );
                }
 
                return $messages;
@@ -352,7 +352,7 @@ class LoginForm extends SpecialPage {
                $u->saveSettings();
                $result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
 
-               wfRunHooks( 'AddNewAccount', array( $u, true ) );
+               Hooks::run( 'AddNewAccount', array( $u, true ) );
                $u->addNewUserLogEntry( 'byemail', $this->mReason );
 
                $out = $this->getOutput();
@@ -427,7 +427,7 @@ class LoginForm extends SpecialPage {
                        // which is needed or the personal links will be
                        // wrong.
                        $this->getContext()->setUser( $u );
-                       wfRunHooks( 'AddNewAccount', array( $u, false ) );
+                       Hooks::run( 'AddNewAccount', array( $u, false ) );
                        $u->addNewUserLogEntry( 'create' );
                        if ( $this->hasSessionCookie() ) {
                                $this->successfulCreation();
@@ -439,7 +439,7 @@ class LoginForm extends SpecialPage {
                        $out->setPageTitle( $this->msg( 'accountcreated' ) );
                        $out->addWikiMsg( 'accountcreatedtext', $u->getName() );
                        $out->addReturnTo( $this->getPageTitle() );
-                       wfRunHooks( 'AddNewAccount', array( $u, false ) );
+                       Hooks::run( 'AddNewAccount', array( $u, false ) );
                        $u->addNewUserLogEntry( 'create2', $this->mReason );
                }
 
@@ -573,7 +573,7 @@ class LoginForm extends SpecialPage {
 
                $abortError = '';
                $abortStatus = null;
-               if ( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError, &$abortStatus ) ) ) {
+               if ( !Hooks::run( 'AbortNewAccount', array( $u, &$abortError, &$abortStatus ) ) ) {
                        // Hook point to add extra creation throttles and blocks
                        wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
                        if ( $abortStatus === null ) {
@@ -593,7 +593,7 @@ class LoginForm extends SpecialPage {
                }
 
                // Hook point to check for exempt from account creation throttle
-               if ( !wfRunHooks( 'ExemptFromAccountCreationThrottle', array( $ip ) ) ) {
+               if ( !Hooks::run( 'ExemptFromAccountCreationThrottle', array( $ip ) ) ) {
                        wfDebug( "LoginForm::exemptFromAccountCreationThrottle: a hook " .
                                "allowed account creation w/o throttle\n" );
                } else {
@@ -716,7 +716,7 @@ class LoginForm extends SpecialPage {
 
                // Give extensions a way to indicate the username has been updated,
                // rather than telling the user the account doesn't exist.
-               if ( !wfRunHooks( 'LoginUserMigrated', array( $u, &$msg ) ) ) {
+               if ( !Hooks::run( 'LoginUserMigrated', array( $u, &$msg ) ) ) {
                        $this->mAbortLoginErrorMsg = $msg;
                        return self::USER_MIGRATED;
                }
@@ -740,7 +740,7 @@ class LoginForm extends SpecialPage {
                // Give general extensions, such as a captcha, a chance to abort logins
                $abort = self::ABORTED;
                $msg = null;
-               if ( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$msg ) ) ) {
+               if ( !Hooks::run( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$msg ) ) ) {
                        $this->mAbortLoginErrorMsg = $msg;
 
                        return $abort;
@@ -801,12 +801,12 @@ class LoginForm extends SpecialPage {
 
                        if ( $isAutoCreated ) {
                                // Must be run after $wgUser is set, for correct new user log
-                               wfRunHooks( 'AuthPluginAutoCreate', array( $u ) );
+                               Hooks::run( 'AuthPluginAutoCreate', array( $u ) );
                        }
 
                        $retval = self::SUCCESS;
                }
-               wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
+               Hooks::run( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
 
                return $retval;
        }
@@ -887,7 +887,7 @@ class LoginForm extends SpecialPage {
                }
 
                $abortError = '';
-               if ( !wfRunHooks( 'AbortAutoAccount', array( $user, &$abortError ) ) ) {
+               if ( !Hooks::run( 'AbortAutoAccount', array( $user, &$abortError ) ) ) {
                        // Hook point to add extra creation throttles and blocks
                        wfDebug( "LoginForm::attemptAutoCreate: a hook blocked creation: $abortError\n" );
                        $this->mAbortLoginErrorMsg = $abortError;
@@ -1040,7 +1040,7 @@ class LoginForm extends SpecialPage {
         */
        protected function resetLoginForm( Message $msg ) {
                // Allow hooks to explain this password reset in more detail
-               wfRunHooks( 'LoginPasswordResetMessage', array( &$msg, $this->mUsername ) );
+               Hooks::run( 'LoginPasswordResetMessage', array( &$msg, $this->mUsername ) );
                $reset = new SpecialChangePassword();
                $derivative = new DerivativeContext( $this->getContext() );
                $derivative->setTitle( $reset->getPageTitle() );
@@ -1073,7 +1073,7 @@ class LoginForm extends SpecialPage {
                }
 
                $currentUser = $this->getUser();
-               wfRunHooks( 'User::mailPasswordInternal', array( &$currentUser, &$ip, &$u ) );
+               Hooks::run( 'User::mailPasswordInternal', array( &$currentUser, &$ip, &$u ) );
 
                $np = $u->randomPassword();
                $u->setNewpassword( $np, $throttle );
@@ -1104,7 +1104,7 @@ class LoginForm extends SpecialPage {
                # Run any hooks; display injected HTML if any, else redirect
                $currentUser = $this->getUser();
                $injected_html = '';
-               wfRunHooks( 'UserLoginComplete', array( &$currentUser, &$injected_html ) );
+               Hooks::run( 'UserLoginComplete', array( &$currentUser, &$injected_html ) );
 
                if ( $injected_html !== '' ) {
                        $this->displaySuccessfulAction( 'success', $this->msg( 'loginsuccesstitle' ),
@@ -1126,14 +1126,14 @@ class LoginForm extends SpecialPage {
                $injected_html = '';
                $welcome_creation_msg = 'welcomecreation-msg';
 
-               wfRunHooks( 'UserLoginComplete', array( &$currentUser, &$injected_html ) );
+               Hooks::run( 'UserLoginComplete', array( &$currentUser, &$injected_html ) );
 
                /**
                 * Let any extensions change what message is shown.
                 * @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforeWelcomeCreation
                 * @since 1.18
                 */
-               wfRunHooks( 'BeforeWelcomeCreation', array( &$welcome_creation_msg, &$injected_html ) );
+               Hooks::run( 'BeforeWelcomeCreation', array( &$welcome_creation_msg, &$injected_html ) );
 
                $this->displaySuccessfulAction(
                        'signup',
@@ -1243,7 +1243,7 @@ class LoginForm extends SpecialPage {
                }
 
                // Allow modification of redirect behavior
-               wfRunHooks( 'PostLoginRedirect', array( &$returnTo, &$returnToQuery, &$type ) );
+               Hooks::run( 'PostLoginRedirect', array( &$returnTo, &$returnToQuery, &$type ) );
 
                $returnToTitle = Title::newFromText( $returnTo );
                if ( !$returnToTitle ) {
@@ -1335,7 +1335,7 @@ class LoginForm extends SpecialPage {
                                'mediawiki.special.userlogin.signup.styles'
                        ) );
 
-                       $template = new UsercreateTemplate();
+                       $template = new UsercreateTemplate( $this->getConfig() );
 
                        // Must match number of benefits defined in messages
                        $template->set( 'benefitCount', 3 );
@@ -1348,7 +1348,7 @@ class LoginForm extends SpecialPage {
                                'mediawiki.special.userlogin.login.styles'
                        ) );
 
-                       $template = new UserloginTemplate();
+                       $template = new UserloginTemplate( $this->getConfig() );
 
                        $q = 'action=submitlogin&type=login';
                        $linkq = 'type=signup';
@@ -1447,9 +1447,9 @@ class LoginForm extends SpecialPage {
                // Give authentication and captcha plugins a chance to modify the form
                $wgAuth->modifyUITemplate( $template, $this->mType );
                if ( $this->mType == 'signup' ) {
-                       wfRunHooks( 'UserCreateForm', array( &$template ) );
+                       Hooks::run( 'UserCreateForm', array( &$template ) );
                } else {
-                       wfRunHooks( 'UserLoginForm', array( &$template ) );
+                       Hooks::run( 'UserLoginForm', array( &$template ) );
                }
 
                $out->disallowUserJs(); // just in case...
index d65ac85..080dc11 100644 (file)
@@ -56,7 +56,7 @@ class SpecialUserlogout extends UnlistedSpecialPage {
 
                // Hook.
                $injected_html = '';
-               wfRunHooks( 'UserLogoutComplete', array( &$user, &$injected_html, $oldName ) );
+               Hooks::run( 'UserLogoutComplete', array( &$user, &$injected_html, $oldName ) );
                $out->addHTML( $injected_html );
 
                $out->returnToMain();
index 6ca57aa..3e9313c 100644 (file)
@@ -267,7 +267,7 @@ class UserrightsPage extends SpecialPage {
 
                wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) . "\n" );
                wfDebug( 'newGroups: ' . print_r( $newGroups, true ) . "\n" );
-               wfRunHooks( 'UserRights', array( &$user, $add, $remove ) );
+               Hooks::run( 'UserRights', array( &$user, $add, $remove ) );
 
                if ( $newGroups != $oldGroups ) {
                        $this->addLogEntry( $user, $oldGroups, $newGroups, $reason );
index 34f434f..d057b7c 100644 (file)
@@ -220,7 +220,7 @@ class SpecialVersion extends SpecialPage {
                $software[$dbr->getSoftwareLink()] = $dbr->getServerInfo();
 
                // Allow a hook to add/remove items.
-               wfRunHooks( 'SoftwareInfo', array( &$software ) );
+               Hooks::run( 'SoftwareInfo', array( &$software ) );
 
                $out = Xml::element(
                                'h2',
@@ -341,7 +341,7 @@ class SpecialVersion extends SpecialPage {
        private static function getwgVersionLinked() {
                global $wgVersion;
                $versionUrl = "";
-               if ( wfRunHooks( 'SpecialVersionVersionUrl', array( $wgVersion, &$versionUrl ) ) ) {
+               if ( Hooks::run( 'SpecialVersionVersionUrl', array( $wgVersion, &$versionUrl ) ) ) {
                        $versionParts = array();
                        preg_match( "/^(\d+\.\d+)/", $wgVersion, $versionParts );
                        $versionUrl = "https://www.mediawiki.org/wiki/MediaWiki_{$versionParts[1]}";
@@ -402,7 +402,7 @@ class SpecialVersion extends SpecialPage {
                                'other' => wfMessage( 'version-other' )->text(),
                        );
 
-                       wfRunHooks( 'ExtensionTypes', array( &self::$extensionTypes ) );
+                       Hooks::run( 'ExtensionTypes', array( &self::$extensionTypes ) );
                }
 
                return self::$extensionTypes;
@@ -1039,7 +1039,7 @@ class SpecialVersion extends SpecialPage {
         * Convert an array or object to a string for display.
         *
         * @param mixed $list Will convert an array to string if given and return
-        *   the paramater unaltered otherwise
+        *   the parameter unaltered otherwise
         *
         * @return mixed
         */
index 16127d9..8a1a6c6 100644 (file)
@@ -99,7 +99,7 @@ class WantedFilesPage extends WantedQueryPage {
         * Use wfFindFile so we still think file namespace pages without
         * files are missing, but valid file redirects and foreign files are ok.
         *
-        * @return boolean
+        * @return bool
         */
        protected function existenceCheck( Title $title ) {
                return (bool)wfFindFile( $title );
index 38f1808..cad2348 100644 (file)
@@ -86,7 +86,7 @@ class WantedPagesPage extends WantedQueryPage {
                        )
                );
                // Replacement for the WantedPages::getSQL hook
-               wfRunHooks( 'WantedPages::getQueryInfo', array( &$this, &$query ) );
+               Hooks::run( 'WantedPages::getQueryInfo', array( &$this, &$query ) );
 
                return $query;
        }
index a7c2052..ca3386c 100644 (file)
@@ -123,7 +123,7 @@ class SpecialWatchlist extends ChangesListSpecialPage {
        protected function getCustomFilters() {
                if ( $this->customFilters === null ) {
                        $this->customFilters = parent::getCustomFilters();
-                       wfRunHooks( 'SpecialWatchlistFilters', array( $this, &$this->customFilters ), '1.23' );
+                       Hooks::run( 'SpecialWatchlistFilters', array( $this, &$this->customFilters ), '1.23' );
                }
 
                return $this->customFilters;
@@ -201,7 +201,7 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                } else {
                        # Top log Ids for a page are not stored
                        $nonRevisionTypes = array( RC_LOG );
-                       wfRunHooks( 'SpecialWatchlistGetNonRevisionTypes', array( &$nonRevisionTypes ) );
+                       Hooks::run( 'SpecialWatchlistGetNonRevisionTypes', array( &$nonRevisionTypes ) );
                        if ( $nonRevisionTypes ) {
                                $conds[] = $dbr->makeList(
                                        array(
@@ -286,7 +286,7 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                &$join_conds, $opts
        ) {
                return parent::runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds, $opts )
-                       && wfRunHooks(
+                       && Hooks::run(
                                'SpecialWatchlistQuery',
                                array( &$conds, &$tables, &$join_conds, &$fields, $opts ),
                                '1.23'
index e373cff..11ec363 100644 (file)
@@ -335,7 +335,7 @@ class SpecialWhatLinksHere extends IncludableSpecialPage {
                        $props[] = $msgcache['isimage'];
                }
 
-               wfRunHooks( 'WhatLinksHereProps', array( $row, $nt, $target, &$props ) );
+               Hooks::run( 'WhatLinksHereProps', array( $row, $nt, $target, &$props ) );
 
                if ( count( $props ) ) {
                        $propsText = $this->msg( 'parentheses' )
index a278652..4c96dc8 100644 (file)
@@ -150,7 +150,7 @@ abstract class UploadBase {
 
                // Give hooks the chance to handle this request
                $className = null;
-               wfRunHooks( 'UploadCreateFromRequest', array( $type, &$className ) );
+               Hooks::run( 'UploadCreateFromRequest', array( $type, &$className ) );
                if ( is_null( $className ) ) {
                        $className = 'UploadFrom' . $type;
                        wfDebug( __METHOD__ . ": class name: $className\n" );
@@ -335,7 +335,7 @@ abstract class UploadBase {
                }
 
                $error = '';
-               if ( !wfRunHooks( 'UploadVerification',
+               if ( !Hooks::run( 'UploadVerification',
                        array( $this->mDestName, $this->mTempPath, &$error ) )
                ) {
                        wfProfileOut( __METHOD__ );
@@ -469,7 +469,7 @@ abstract class UploadBase {
                        }
                }
 
-               wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &$status ) );
+               Hooks::run( 'UploadVerifyFile', array( $this, $mime, &$status ) );
                if ( $status !== true ) {
                        wfProfileOut( __METHOD__ );
 
@@ -755,7 +755,7 @@ abstract class UploadBase {
                                        WatchedItem::IGNORE_USER_RIGHTS
                                );
                        }
-                       wfRunHooks( 'UploadComplete', array( &$this ) );
+                       Hooks::run( 'UploadComplete', array( &$this ) );
 
                        $this->postProcessUpload();
                }
index b605640..14a6da6 100644 (file)
@@ -118,7 +118,7 @@ class UploadFromUrl extends UploadBase {
        public static function isAllowedUrl( $url ) {
                if ( !isset( self::$allowedUrls[$url] ) ) {
                        $allowed = true;
-                       wfRunHooks( 'IsUploadAllowedFromUrl', array( $url, &$allowed ) );
+                       Hooks::run( 'IsUploadAllowedFromUrl', array( $url, &$allowed ) );
                        self::$allowedUrls[$url] = $allowed;
                }
 
index 727f485..4e65e11 100644 (file)
@@ -227,7 +227,7 @@ class ClassCollector {
                if ( is_string( $token ) ) {
                        return;
                }
-               switch( $token[0] ) {
+               switch ( $token[0] ) {
                case T_NAMESPACE:
                case T_CLASS:
                case T_INTERFACE:
@@ -241,7 +241,7 @@ class ClassCollector {
         * @param array
         */
        protected function tryEndExpect( $token ) {
-               switch( $this->startToken[0] ) {
+               switch ( $this->startToken[0] ) {
                case T_NAMESPACE:
                        if ( $token === ';' || $token === '{' ) {
                                $this->namespace = $this->implodeTokens() . '\\';
index 77f9cd1..55a8994 100644 (file)
@@ -717,7 +717,7 @@ class IP {
         */
        public static function isTrustedProxy( $ip ) {
                $trusted = self::isConfiguredProxy( $ip );
-               wfRunHooks( 'IsTrustedProxy', array( &$ip, &$trusted ) );
+               Hooks::run( 'IsTrustedProxy', array( &$ip, &$trusted ) );
                return $trusted;
        }
 
index fb04255..01fb986 100644 (file)
@@ -500,7 +500,7 @@ class Language {
                        # Re-order by namespace ID number...
                        ksort( $this->namespaceNames );
 
-                       wfRunHooks( 'LanguageGetNamespaces', array( &$this->namespaceNames ) );
+                       Hooks::run( 'LanguageGetNamespaces', array( &$this->namespaceNames ) );
                }
 
                return $this->namespaceNames;
@@ -898,7 +898,7 @@ class Language {
 
                if ( $inLanguage ) {
                        # TODO: also include when $inLanguage is null, when this code is more efficient
-                       wfRunHooks( 'LanguageGetTranslatedLanguageNames', array( &$names, $inLanguage ) );
+                       Hooks::run( 'LanguageGetTranslatedLanguageNames', array( &$names, $inLanguage ) );
                }
 
                $mwNames = $wgExtraLanguageNames + $coreLanguageNames;
@@ -3162,7 +3162,7 @@ class Language {
                }
                $this->mMagicHookDone = true;
                wfProfileIn( 'LanguageGetMagic' );
-               wfRunHooks( 'LanguageGetMagic', array( &$this->mMagicExtensions, $this->getCode() ) );
+               Hooks::run( 'LanguageGetMagic', array( &$this->mMagicExtensions, $this->getCode() ) );
                wfProfileOut( 'LanguageGetMagic' );
        }
 
@@ -3218,7 +3218,7 @@ class Language {
                        // Initialise array
                        $this->mExtendedSpecialPageAliases =
                                self::$dataCache->getItem( $this->mCode, 'specialPageAliases' );
-                       wfRunHooks( 'LanguageGetSpecialPageAliases',
+                       Hooks::run( 'LanguageGetSpecialPageAliases',
                                array( &$this->mExtendedSpecialPageAliases, $this->getCode() ) );
                }
 
@@ -3345,7 +3345,7 @@ class Language {
                                // the string does not have any number part. Eg: .12345
                                return $sign . $groupedNumber;
                        }
-                       $start = $end = strlen( $integerPart[0] );
+                       $start = $end = ($integerPart) ? strlen( $integerPart[0] ) : 0;
                        while ( $start > 0 ) {
                                $match = $matches[0][$numMatches - 1];
                                $matchLen = strlen( $match );
@@ -4261,7 +4261,7 @@ class Language {
        public static function getMessagesFileName( $code ) {
                global $IP;
                $file = self::getFileName( "$IP/languages/messages/Messages", $code, '.php' );
-               wfRunHooks( 'Language::getMessagesFileName', array( $code, &$file ) );
+               Hooks::run( 'Language::getMessagesFileName', array( $code, &$file ) );
                return $file;
        }
 
index 1ee398d..353b59a 100644 (file)
@@ -26,7 +26,7 @@
  * This does not affect untranslated messages.
  *
  * NOTE: It returns a valid title, because there are some poorly written
- * extentions that assume the contents of some messages are valid.
+ * extensions that assume the contents of some messages are valid.
  *
  * @ingroup Language
  */
index 31c8f1a..7a907fc 100644 (file)
@@ -46,7 +46,8 @@
                        "Test Create account",
                        "Kuwaity26",
                        "Calak",
-                       "Omda4wady"
+                       "Omda4wady",
+                       "Bibas"
                ]
        },
        "tog-underline": "سطر تحت الوصلات:",
@@ -74,7 +75,7 @@
        "tog-shownumberswatching": "اعرض عدد المستخدمين المراقبين",
        "tog-oldsig": "التوقيع الحالي:",
        "tog-fancysig": "وضع الوصلة يدويا واستعمال نص الويكي",
-       "tog-uselivepreview": "استعمال المعاينة المباشرة (تجريبي)",
+       "tog-uselivepreview": "استعمال المعاينة المباشرة",
        "tog-forceeditsummary": "نبهني عند عدم إدخال ملخص تعديل",
        "tog-watchlisthideown": "أخف تعديلاتي من قائمة المراقبة",
        "tog-watchlisthidebots": "أخف تعديلات البوتات من قائمة المراقبة",
        "filerenameerror": "تعذّر تغيير اسم الملف \"$1\" إلى \"$2\".",
        "filedeleteerror": "تعذّر حذف الملف \"$1\".",
        "directorycreateerror": "تعذّر إنشاء الدليل \"$1\".",
+       "directoryreadonlyerror": "المجلد «$1» للقراءة فقط.",
+       "directorynotreadableerror": "المجلد «$1» لا يمكن قراءته.",
        "filenotfound": "تعذّر إيجاد الملف \"$1\".",
        "unexpected": "قيمة غير متوقعة: \"$1\"=\"$2\".",
        "formerror": "عطل: تعذّر إيداع الاستمارة",
        "content-model-text": "نص عادي",
        "content-model-javascript": "جافاسكربت",
        "content-model-css": "CSS",
+       "duplicate-args-category": "صفحات تستعمل قالبا ببيانات مكررة",
        "expensive-parserfunction-warning": "'''تحذير:''' هذه الصفحة تحتوي على استدعاءات دالة محلل كثيرة مكلفة.\n\nينبغي أن تكون أقل من {{PLURAL:$2||استدعاء واحد|استدعاءين|$2 استدعاءات|$2 استدعاء}}، يوجد الآن {{PLURAL:$1|استدعاء واحد|استدعاءان|$2 استدعاءات|$2 استدعاء}}.",
        "expensive-parserfunction-category": "تجاوزات الدوال المكلفة",
        "post-expand-template-inclusion-warning": "'''تحذير:''' حجم تضمين القالب كبير جدا.\nبعض القوالب لن تضمن.",
        "revdelete-show-file-confirm": "هل أنت متأكد أنك تريد رؤية مراجعة محذوفة للملف \"<nowiki>$1</nowiki>\" بتاريخ $2 الساعة $3؟",
        "revdelete-show-file-submit": "نعم",
        "revdelete-selected-text": "{{PLURAL:$1|نسخة مختارة|نسخ مختارة}} ل[[:$2]]:",
+       "revdelete-selected-file": "{{PLURAL:$1|النسخة المختارة من الملف|النسخ المختارة من الملف}} لـ [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|حدث السجل المختار|أحداث السجل المختارة}}:",
+       "revdelete-text-text": "المراجعات المحذوفة ستظل تظهر في تاريخ الصفحة، ولكن أجزاءا من محتواها سيكون محجوبا عن الجميع.",
        "revdelete-text-others": "سيتمكن الإداريون الآخرون على {{SITENAME}} من الوصول إلى المحتوى المخفي وإلغاء حذفه مجددا من خلال ذات الواجهة ما لم تطبق قيود إضافية.",
        "revdelete-confirm": "الإداريون الآخرون في {{SITENAME}} سيظل بإمكانهم رؤية المحتوى المخفي ويمكنهم استرجاعه مجددا من خلال هذه الواجهة نفسها، مالم يتم وضع قيود إضافية.\nمن فضلك أكد أنك تنوي فعل هذا، وأنك تفهم العواقب، وأنك تفعل هذا بالتوافق مع [[{{MediaWiki:Policy-url}}|السياسة]].",
        "revdelete-suppress-text": "ينبغي للإخفاء أن يستخدم '''فقط''' في الحالات التالية:\n* معلومات يحتمل أن تكون تشهيرية\n* معلومات شخصية غير ملائمة\n*: ''عناوين المنازل وأرقام الهواتف وأرقام الهويات الوطنية إلى آخره.''",
        "unwatchedpages": "صفحات غير مراقبة",
        "listredirects": "عرض التحويلات",
        "listduplicatedfiles": "قائمة الملفات مع المكررات",
+       "listduplicatedfiles-entry": "[[:File:$1|$1]] مكرر في [[$3|{{PLURAL:$2||مكان آخر واحد|مكانين آخرين اثنين|$2 أماكن أخرى|$2 مكاناً آخر|$2مكان آخر}}]].",
        "unusedtemplates": "قوالب غير مستخدمة",
        "unusedtemplatestext": "هذه الصفحة تعرض كل الصفحات في نطاق {{ns:template}} غير المضمنة في صفحة أخرى.\nتذكر بأن تتحقق من الوصلات الأخرى للقوالب قبل حذفها.",
        "unusedtemplateswlh": "وصلات أخرى",
        "suppress": "أوفرسايت",
        "querypage-disabled": "تم تعطيل هذه الصفحة الخاصة لأسباب تتعلق بالأداء.",
        "apihelp": "مساعدة API",
+       "apihelp-no-such-module": "الوحدة \"$1\" غير موجودة.",
        "booksources": "مصادر كتاب",
        "booksources-search-legend": "البحث عن مصادر الكتب",
        "booksources-isbn": "ردمك:",
        "listgrouprights-removegroup-self-all": "يمكنه إزالة كل المجموعات من حسابه الخاص",
        "listgrouprights-namespaceprotection-header": "قيود النطاق",
        "listgrouprights-namespaceprotection-namespace": "النطاق",
+       "listgrouprights-namespaceprotection-restrictedto": "الصلاحيات التي تسمح للمستخدم بالتعديل",
        "trackingcategories": "تصانيف التتبع",
        "trackingcategories-summary": "تسرد هذه الصفحة تصانيف التتبع التي ينشئها برنامج ميدياويكي. يمكن تغيير أسمائها بتغيير رسائل النظام في نطاق {{ns:8}}.",
        "trackingcategories-msg": "تصانيف التتبع",
        "delete-edit-reasonlist": "عدل أسباب الحذف",
        "delete-toobig": "لهذه الصفحة تاريخ تعديل طويل، أكثر من {{PLURAL:$1||مراجعة واحدة|مراجعتين|$1 مراجعات|$1 مراجعة}}.\nقُيّد محذف مثل هذه الصفحات لمنع الاضطراب المفاجئة في {{SITENAME}}.",
        "delete-warning-toobig": "لهذه الصفحة تاريخ تعديل طويل، أكثر من {{PLURAL:$1||مراجعة واحدة|مراجعتين|$1 مراجعات|$1 مراجعة}}.\nقد يؤدي حذفها إلى اضطراب عمليات قاعدة البيانات في {{SITENAME}}؛\nاستمر مع الحذر.",
+       "deleteprotected": "لا يمكنك حذف هذه الصفحة لأنها محمية.",
        "deleting-backlinks-warning": "[[Special:WhatLinksHere/{{FULLPAGENAME}}|تتصل صفحات أخرى]] بالصفحة التي تريد حذفها.",
        "rollback": "استرجاع التعديلات",
        "rollback_short": "استرجع",
        "sp-contributions-newbies-sub": "للحسابات الجديدة",
        "sp-contributions-newbies-title": "مساهمات المستخدم للحسابات الجديدة",
        "sp-contributions-blocklog": "سجل المنع",
+       "sp-contributions-suppresslog": "مساهمات المستخدم المحذوفة",
        "sp-contributions-deleted": "مساهمات المستخدم المحذوفة",
        "sp-contributions-uploads": "مرفوعات",
        "sp-contributions-logs": "سجلات",
        "import-logentry-upload": "استورد [[$1]] بواسطة رفع ملف",
        "import-logentry-upload-detail": "{{PLURAL:$1|لا مراجعات|مراجعة واحدة|مراجعتان|$1 مراجعات|$1 مراجعة}}",
        "import-logentry-interwiki": "استورد عبر الويكي $1",
-       "import-logentry-interwiki-detail": "{{PLURAL:$1||مراجعة واحدة|مراجعتان|$1 مراجعات|$1 مراجعة}} من $2",
+       "import-logentry-interwiki-detail": "تم استيراد {{PLURAL:$1||مراجعة واحدة|مراجعتين|$1 مراجعات|$1 مراجعة}} من $2",
        "javascripttest": "اختبار جافاسكربت",
        "javascripttest-title": "تشغيل أختبارات $1",
        "javascripttest-pagetext-noframework": "هذه الصفحة محجوزة لإجراء أختبارات الجافا سكريبت.",
        "revdelete-uname-unhid": "اسم المستخدم غير مخفي",
        "revdelete-restricted": "طبق الضوابط لمديري النظام",
        "revdelete-unrestricted": "أزال الضوابط لمديري النظام",
+       "logentry-merge-merge": "{{GENDER:$2|دمج|دمجت}} $1 $3 إلى $4 (المراجعات حتى $5).",
        "logentry-move-move": "{{GENDER:$2|نقل|نقلت}} $1 صفحة $3 إلى $4",
        "logentry-move-move-noredirect": "{{GENDER:$2|نقل|نقلت}} $1 صفحة $3 إلى $4 دون ترك تحويلة",
        "logentry-move-move_redir": "{{GENDER:$2|نقل|نقلت}} $1 صفحة $3 إلى $4 على تحويلة",
        "logentry-rights-rights": "{{GENDER:$2|غيّر|غيّرت}} $1 عضوية $3 من $4 إلى $5",
        "logentry-rights-rights-legacy": "{{GENDER:$2|غيّر|غيّرت}} $1 عضوية $3",
        "logentry-rights-autopromote": "تمت تلقائيا ترقية {{GENDER:$2|المستخدم|المستخدمة}} $1 من  $4 إلى $5",
+       "logentry-upload-upload": " {{GENDER:$2|رفع|رفعت}} $1 $3",
+       "logentry-upload-overwrite": "{{GENDER:$2|رفع|رفعت}} $1 نسخة جديدة من  $3",
+       "logentry-upload-revert": "{{GENDER:$2|رفع|رفعت}} $1 $3",
        "rightsnone": "(لا شيء)",
        "revdelete-summary": "ملخص التعديل",
        "feedback-bugornote": "إن كنت مستعدا لشرح  مشكلة تقنية بالتفصيل، رجاءا [$1 قدم تقريرا بالخلل].\nبخلاف ذلك، يمكنك أستخدام الطريقة الأسهل أسفله، سيتم إضافة تعليقك للصفحة \"[$3 $2]\"، بالإضافة إلى اسم المستخدم و نوع المتصفح الذي تستخدمه حاليا.",
        "right-pagelang": "تغيير لغة الصفحة",
        "action-pagelang": "تغيير لغة الصفحة",
        "log-name-pagelang": "تغيير سجل الصفحة",
+       "logentry-pagelang-pagelang": " {{GENDER:$2|غيّر|غيّرت}} $1 لغة الصفحة «$3» من $4 إلى $5.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (مفعل)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''معطل''')",
        "mediastatistics": "إحصاءات الميديا",
index d417347..1b350c0 100644 (file)
@@ -42,7 +42,7 @@
        "tog-shownumberswatching": "Паказваць колькасьць назіральнікаў",
        "tog-oldsig": "Цяперашні подпіс:",
        "tog-fancysig": "Апрацоўваць подпіс як вікітэкст (без аўтаматычнай спасылкі)",
-       "tog-uselivepreview": "Выкарыстоўваць хуткі папярэдні прагляд (экспэрымэнтальна)",
+       "tog-uselivepreview": "Выкарыстоўваць хуткі папярэдні прагляд",
        "tog-forceeditsummary": "Папярэджваць пра адсутнасьць кароткага апісаньня зьменаў",
        "tog-watchlisthideown": "Хаваць мае праўкі ў сьпісе назіраньня",
        "tog-watchlisthidebots": "Хаваць праўкі робатаў у сьпісе назіраньня",
        "filecopyerror": "Немагчыма cкапіяваць файл «$1» у «$2».",
        "filerenameerror": "Немагчыма перайменаваць файл «$1» у «$2».",
        "filedeleteerror": "Немагчыма выдаліць файл «$1».",
-       "directorycreateerror": "Ð\9dемагÑ\87Ñ\8bма Ñ\81Ñ\82ваÑ\80Ñ\8bÑ\86Ñ\8c Ð´Ñ\8bÑ\80Ñ\8dкÑ\82оÑ\80Ñ\8bÑ\8e «$1».",
+       "directorycreateerror": "Ð\9dемагÑ\87Ñ\8bма Ñ\81Ñ\82ваÑ\80Ñ\8bÑ\86Ñ\8c ÐºÐ°Ñ\82алÑ\91г «$1».",
        "directoryreadonlyerror": "Тэчка «$1» толькі для чытаньня.",
        "directorynotreadableerror": "Тэчка «$1» не чытаецца.",
        "filenotfound": "Немагчыма знайсьці файл «$1».",
        "unexpected": "Нечаканае значэньне: «$1»=«$2».",
-       "formerror": "Памылка: не атрымалася адаслаць зьвесткі формы",
+       "formerror": "Памылка: не атрымалася адаслаць зьвесткі формы.",
        "badarticleerror": "Гэтае дзеяньне немагчыма выканаць на гэтай старонцы.",
        "cannotdelete": "Немагчыма выдаліць старонку альбо файл «$1». Магчыма, яна ўжо выдаленая кімсьці іншым.",
        "cannotdelete-title": "Немагчыма выдаліць старонку «$1»",
        "anoneditwarning": "<strong>Папярэджаньне</strong>: вы не ўвайшлі ў сыстэму. Ваш IP-адрас будзе бачны ўсім, калі вы адрэдагуеце старонку. Калі вы <strong>[$1 ўвойдзеце]</strong> або <strong>[$2 створыце рахунак]</strong>, вашыя рэдагаваньні будуць зьвязаныя з вашым імем карыстальніка, а таксама вам будуць даступныя дадатковыя перавагі.",
        "anonpreviewwarning": "''Вы не ўвайшлі ў сыстэму. Падчас захаваньня Ваш IP-адрас будзе дададзены ў гісторыю рэдагаваньняў старонкі.''",
        "missingsummary": "'''Напамін:''' Вы не пазначылі кароткае апісаньне зьменаў.\nКалі Вы націсьніце кнопку «Запісаць» яшчэ раз, Вашае рэдагаваньне будзе запісанае без апісаньня.",
+       "selfredirect": "<strong>Папярэджаньне:</strong> вы ствараеце перанакіраваньне на гэты самы артыкул.\nКалі вы націсьніце «{{int:savearticle}}» яшчэ раз, перанакіраваньне будзе створанае.",
        "missingcommenttext": "Калі ласка, увядзіце камэнтар ніжэй.",
        "missingcommentheader": "'''Напамін:''' Вы не пазначылі загаловак камэнтара.\nКалі Вы націсьніце кнопку «{{int:savearticle}}» яшчэ раз, Ваш камэнтар захаваецца бяз тэмы.",
        "summary-preview": "Папярэдні прагляд апісаньня:",
index a6192ee..2ef4cd7 100644 (file)
@@ -21,7 +21,8 @@
                        "Usarker",
                        "Wikitanvir",
                        "Zaheen",
-                       "לערי ריינהארט"
+                       "לערי ריינהארט",
+                       "Aftabuzzaman"
                ]
        },
        "tog-underline": "সংযোগগুলির নিচে দাগ দেখানো হোক:",
@@ -49,7 +50,7 @@
        "tog-shownumberswatching": "নজরদারী করছে, এমন ব্যবহারকারীর সংখ্যা দেখানো হোক",
        "tog-oldsig": "বর্তমান স্বাক্ষর:",
        "tog-fancysig": "স্বাক্ষরকে উইকিটেক্সট হিসেবে মনে করুন (কোন সয়ংক্রিয় লিঙ্ক ছাড়া)",
-       "tog-uselivepreview": "তাৎক্ষণিক প্রাকদর্শনের ক্ষমতা চালু করা হোক (পরীক্ষামূলক)",
+       "tog-uselivepreview": "তাৎক্ষণিক প্রাকদর্শন ব্যবহার করো",
        "tog-forceeditsummary": "খালি সম্পাদনা সারাংশ প্রবেশ করানোর সময় আমাকে জানানো হোক",
        "tog-watchlisthideown": "আমার সম্পাদনাগুলি আমার নজরতালিকায় না দেখানো হোক",
        "tog-watchlisthidebots": "বটের করা সম্পাদনাগুলি নজরতালিকায় না দেখানো হোক",
        "login-userblocked": "এই ব্যবহারকারীকে বাধা দেওয়া হয়েছে। লগ-ইন সম্ভব নয়।",
        "wrongpassword": "আপনি ভুল পাসওয়ার্ড ব্যবহার করেছেন। অনুগ্রহ করে আবার চেষ্টা করুন।",
        "wrongpasswordempty": "পাসওয়ার্ড প্রবেশের ঘরটি খালি ছিল। দয়া করে আবার চেষ্টা করুন।",
-       "passwordtooshort": "পাসà¦\93য়ারà§\8dড à¦\85বশà§\8dযà¦\87 {{PLURAL:$1|১ à¦\85à¦\95à§\8dষরà§\87র|$1 à¦\85à¦\95à§\8dষরà§\87র}} à¦¹à¦¤à§\87 à¦¹à¦¬à§\87।",
+       "passwordtooshort": "পাসà¦\93য়ারà§\8dড à¦\95মপà¦\95à§\8dষà§\87 {{PLURAL:$1|১ à¦\85à¦\95à§\8dষরà§\87র|$1 à¦\85à¦\95à§\8dষরà§\87র}} à¦¹à¦¤à§\87 à¦¹à¦¬à§\87।",
        "password-name-match": "আপনার পাসওয়ার্ড আপনার ব্যবহারকারী নাম থেকে আলাদা হতে হবে।",
        "password-login-forbidden": "এই ব্যবহারকারীর নাম এবং পাসওয়ার্ডটি ব্যবহার নিষিদ্ধ করা হয়েছে।",
        "mailmypassword": "পাসওয়ার্ড রিসেট",
        "showhideselectedversions": "নির্বাচিত সংশোধনগুলো দেখাও/লুকাও",
        "editundo": "পূর্বাবস্থায় আনো",
        "diff-empty": "(কোন পার্থক্য নেই)",
+       "diff-multi-sameuser": "(একই ব্যবহারকারী দ্বারা সম্পাদিত {{PLURAL:$1|একটি মধ্যবর্তী সংশোধন|$1টি মধ্যবর্তী সংশোধন}} দেখানো হচ্ছে না)",
+       "diff-multi-otherusers": "({{PLURAL:$2|একজন|$2 জন}} ব্যবহারকারী দ্বারা সম্পাদিত {{PLURAL:$1|একটি|$1টি}} মধ্যবর্তী সংশোধন দেখানো হচ্ছে না)",
        "diff-multi-manyusers": "($2 জন {{PLURAL:$2|ব্যবহারাকারীর}} সম্পাদিত {{PLURAL:$1|একটি সাম্প্রতিক সংস্করণ|$1 টি সাম্প্রতিক সংস্করণ}} প্রদর্শিত হচ্ছে না)",
        "difference-missing-revision": "$1 পার্থক্যের {{PLURAL:$2|একটি সংস্করণ|$2টি সংস্করণসমূহ}} খুজে পাওয়া যাচ্ছে না।\n\nসাধারণত মুছে ফেলা হয়েছে এমন পাতার মেয়াদ উত্তীর্ণ ইতিহাস পাতার লিংক ওপেন করার কারণে এটি হতে পারে। \n[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} অপসারণ লগে] বিস্তারিত তথ্য জানা যাবে।",
        "searchresults": "অনুসন্ধানের ফলাফল",
        "action-viewmywatchlist": "আপনার নজরতালিকা দেখুন",
        "action-viewmyprivateinfo": "আপনার ব্যক্তিগত তথ্য দেখুন",
        "action-editmyprivateinfo": "আপনার ব্যক্তিগত তথ্য সম্পাদনা করুন",
-       "nchanges": "$1 {{PLURAL:$1|পরিবর্তন|পরিবর্তনসমূহ}}",
+       "nchanges": "$1টি {{PLURAL:$1|পরিবর্তন}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|সর্বশেষ প্রদর্শনের পর}}",
        "enhancedrc-history": "ইতিহাস",
        "recentchanges": "সাম্প্রতিক পরিবর্তনসমূহ",
        "activeusers-hidesysops": "প্রশাসক লুকাও",
        "activeusers-noresult": "কোনো ব্যবহারকারী পাওয়া যায়নি।",
        "listgrouprights": "দলগত ব্যবহারকারী অধিকার",
-       "listgrouprights-summary": "এই উইকির ব্যবহারকারীদের একটি গ্রুপগুলোর তালিকা দেখানো হচ্ছে, সাথে গ্রুপের কার্যপরিধিও উল্লেখ করা হয়েছে।\nনির্দিষ্ট গ্রুপের কার্যপরিধি সম্পর্কে জানতে দেখুন [[{{MediaWiki:Listgrouprights-helppage}}|additional information]]।",
+       "listgrouprights-summary": "এই উইকির ব্যবহারকারীদের একটি গ্রুপগুলোর তালিকা দেখানো হচ্ছে, সাথে গ্রুপের কার্যপরিধিও উল্লেখ করা হয়েছে।\nনির্দিষ্ট গ্রুপের কার্যপরিধি সম্পর্কে জানতে [[{{MediaWiki:Listgrouprights-helppage}}|অতিরিক্ত তথ্য]] দেখুন।",
        "listgrouprights-key": "লিজেন্ড:\n* <span class=\"listgrouprights-granted\">অনুমোদিত অধিকার</span>\n* <span class=\"listgrouprights-revoked\">বাধাপ্রাপ্ত অধিকার</span>",
        "listgrouprights-group": "দল",
        "listgrouprights-rights": "অধিকারসমূহ",
        "tags-active-yes": "হ্যাঁ",
        "tags-active-no": "না",
        "tags-edit": "সম্পাদনা",
-       "tags-hitcount": "$1 {{PLURAL:$1|পরিবর্তন|পরিবর্তনসমূহ}}",
+       "tags-hitcount": "$1টি {{PLURAL:$1|পরিবর্তন}}",
        "comparepages": "পাতার তুলনা",
        "compare-page1": "পাতা ১",
        "compare-page2": "পাতা ২",
index 69b38ea..7f11733 100644 (file)
@@ -45,7 +45,7 @@
        "tog-shownumberswatching": "Prikaži broj korisnika koji prate",
        "tog-oldsig": "Postojeći potpis:",
        "tog-fancysig": "Smatraj potpis kao wikitekst (bez automatskog linka)",
-       "tog-uselivepreview": "Koristite pregled uživo (eksperimentalno)",
+       "tog-uselivepreview": "Koristite pregled uživo",
        "tog-forceeditsummary": "Opomeni me pri unosu praznog sažetka",
        "tog-watchlisthideown": "Sakrij moje izmjene sa spiska praćenih članaka",
        "tog-watchlisthidebots": "Sakrij izmjene botova sa spiska praćenih članaka",
        "december-date": "$1. decembar",
        "pagecategories": "{{PLURAL:$1|Kategorija|Kategorije}}",
        "category_header": "Članci u kategoriji \"$1\"",
-       "subcategories": "Potkategorije",
+       "subcategories": "Podkategorije",
        "category-media-header": "Datoteke u kategoriji \"$1\"",
        "category-empty": "''Ova kategorija trenutno ne sadrži članke ni medije.''",
        "hidden-categories": "{{PLURAL:$1|Sakrivena kategorija|Sakrivene kategorije}}",
-       "hidden-category-category": "Sakrivene kategorije",
+       "hidden-category-category": "Skrivene kategorije",
        "category-subcat-count": "{{PLURAL:$2|Ova kategorija ima sljedeću podkategoriju.|Ova kategorija ima {{PLURAL:$1|sljedeću podkategoriju|sljedeće $1 podkategorije|sljedećih $1 podkategorija}}, od $2 ukupno.}}",
        "category-subcat-count-limited": "Ova kategorija sadrži {{PLURAL:$1|slijedeću $1 podkategoriju|slijedeće $1 podkategorije|slijedećih $1 podkategorija}}.",
        "category-article-count": "{{PLURAL:$2|U ovoj kategoriji nalazi se $1 članak.|{{PLURAL:$1|Prikazan je $1 članak|Prikazana su $1 članka|Prikazano je $1 članaka}} od ukupno $2 u ovoj kategoriji.}}",
        "otherlanguages": "Na drugim jezicima",
        "redirectedfrom": "(Preusmjereno sa $1)",
        "redirectpagesub": "Preusmjeri stranicu",
+       "redirectto": "Preusmjerenje na:",
        "lastmodifiedat": "Ova stranica je posljednji put izmijenjena $2, $1",
        "viewcount": "Ovoj stranici je pristupljeno {{PLURAL:$1|$1 put|$1 puta}}.",
        "protectedpage": "Zaštićena stranica",
        "filerenameerror": "Ne može se promjeniti ime datoteke \"$1\" u \"$2\".",
        "filedeleteerror": "Ne može se izbrisati datoteka \"$1\".",
        "directorycreateerror": "Nije moguće napraviti direktorijum \"$1\".",
+       "directorynotreadableerror": "Direktorij \"$1\" nije čitljiv.",
        "filenotfound": "Ne može se naći datoteka \"$1\".",
        "unexpected": "Neočekivana vrijednost: \"$1\"=\"$2\".",
        "formerror": "Greška: ne može se poslati upitnik",
        "createacct-imgcaptcha-ph": "Unesite tekst koji vidite iznad",
        "createacct-submit": "Napravite svoj korisnički račun",
        "createacct-another-submit": "Napravi još jedan korisnički račun",
-       "createacct-benefit-heading": "{{SITENAME}} je napravljen od strane ljudi kao što ste Vi.",
+       "createacct-benefit-heading": "{{SITENAME}} je napravljena od strane ljudi kao što ste Vi.",
        "createacct-benefit-body1": "{{PLURAL:$1|izmjena|izmjene}}",
        "createacct-benefit-body2": "{{PLURAL:$1|stranica|stranice|stranica}}",
-       "createacct-benefit-body3": "nedavni {{PLURAL:$1|doprinosa}}",
+       "createacct-benefit-body3": "nedavnih {{PLURAL:$1|doprinosa}}",
        "badretype": "Šifre koje ste unijeli se ne poklapaju.",
        "userexists": "Korisničko ime koje ste unijeli je već u upotrebi.\nMolimo Vas da izaberete drugo ime.",
        "loginerror": "Greška pri prijavljivanju",
        "accountcreated": "Korisnički račun je napravljen",
        "accountcreatedtext": "Korisnički račun za [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|razgovor]]) je napravljen.",
        "createaccount-title": "Pravljenje korisničkog računa za {{SITENAME}}",
-       "createaccount-text": "Neko je napravio korisnički račun za vašu e-mail adresu na {{SITENAME}} ($4) sa imenom \"$2\", i sa šifrom \"$3\".\nTrebali biste se prijaviti i promjeniti šifru.\n\nMožete ignorisati ovu poruku, ako je korisnički račun napravljen greškom.",
+       "createaccount-text": "Neko je napravio korisnički račun za vašu e-mail adresu na {{SITENAME}} ($4) sa imenom \"$2\", i sa šifrom \"$3\".\nTrebali biste se prijaviti i promijeniti šifru.\n\nMožete ignorisati ovu poruku, ako je korisnički račun napravljen greškom.",
        "login-throttled": "Previše puta ste se pokušali prijaviti.\nMolimo Vas da sačekate $1 prije nego što pokušate ponovo.",
        "login-abort-generic": "Vaša prijava nije bila uspješna – Prekinuto",
        "loginlanguagelabel": "Jezik: $1",
        "revdelete-hide-text": "Tekst revizije",
        "revdelete-hide-image": "Sakrij sadržaj datoteke",
        "revdelete-hide-name": "Sakrij akciju i cilj",
-       "revdelete-hide-comment": "Sakrij izmjene komentara",
+       "revdelete-hide-comment": "Uredi sažetak",
        "revdelete-hide-user": "Korisničko ime urednika/IP",
        "revdelete-hide-restricted": "Ograniči podatke za administratore kao i za druge korisnike",
        "revdelete-radio-same": "(ne mijenjaj)",
        "search-result-category-size": "{{PLURAL:$1|1 član|$1 člana|$1 članova}} ({{PLURAL:$2|1 podkategorija|$2 podkategorije|$2 podkategorija}}, {{PLURAL:$3|1 datoteka|$3 datoteke|$3 datoteka}})",
        "search-redirect": "(preusmjeravanje $1)",
        "search-section": "(sekcija $1)",
+       "search-category": "(kategorija $1)",
        "search-suggest": "Da li ste mislili: $1",
        "search-interwiki-caption": "Srodni projekti",
        "search-interwiki-default": "$1 rezultati:",
        "invalid-chunk-offset": "Neispravna polazna tačka",
        "img-auth-accessdenied": "Pristup onemogućen",
        "img-auth-nopathinfo": "Nedostaje PATH_INFO.\nVaš server nije postavljen da daje ovu informaciju.\nMožda je zasnovan na CGI koji ne podržava img_auth.\nPogledajte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
-       "img-auth-notindir": "Zahtjevana putanje nije u direktorijumu podešenom za postavljanje.",
+       "img-auth-notindir": "Zahtjevana putanja nije u direktoriju podešenom za postavljanje.",
        "img-auth-badtitle": "Ne mogu napraviti valjani naslov iz \"$1\".",
        "img-auth-nologinnWL": "Niste prijavljeni i \"$1\" nije na spisku dozvoljenih.",
        "img-auth-nofile": "Datoteka \"$1\" ne postoji.",
-       "img-auth-isdir": "Pokušavate pristupiti direktorijumu \"$1\".\nDozvoljen je samo pristup datotekama.",
+       "img-auth-isdir": "Pokušavate pristupiti direktoriju \"$1\".\nDozvoljen je samo pristup datotekama.",
        "img-auth-streaming": "Tok \"$1\".",
        "img-auth-public": "Funkcija img_auth.php služi za izlaz datoteka sa privatnih wikija.\nOva wiki je postavljena kao javna wiki.\nZa optimalnu sigurnost, img_auth.php je onemogućena.",
        "img-auth-noread": "Korisnik nema pristup za čitanje \"$1\".",
        "querypage-disabled": "Ova posebna stranica je onemogućena jer smanjuje performanse.",
        "booksources": "Štampani izvori",
        "booksources-search-legend": "Traži književne izvore",
+       "booksources-search": "Traži",
        "booksources-text": "Ispod se nalazi spisak vanjskih linkova na ostale stranice koje prodaju nove ili korištene knjige kao i stranice koje mogu da imaju važnije podatke o knjigama koje tražite:",
        "booksources-invalid-isbn": "Navedeni ISBN broj nije validan; molimo da provjerite da li je došlo do greške pri kopiranju iz prvobitnog izvora.",
        "specialloguserlabel": "Izvršilac:",
        "listgrouprights-addgroup-self-all": "Može dodati sve grupe na svoj račun",
        "listgrouprights-removegroup-self-all": "Može ukloniti sve grupe sa svog računa",
        "listgrouprights-namespaceprotection-namespace": "Imenski prostor",
+       "trackingcategories-name": "Ime poruke",
        "trackingcategories-nodesc": "Opis nije dostupan.",
        "mailnologin": "Nema adrese za slanje",
        "mailnologintext": "Morate biti [[Special:UserLogin|prijavljeni]]\ni imati ispravnu adresu e-pošte u vašim [[Special:Preferences|podešavanjima]]\nda biste slali e-poštu drugim korisnicima.",
        "tooltip-feed-atom": "Atom za ovu stranicu",
        "tooltip-t-contributions": "Pogledajte spisak doprinosa ovog korisnika",
        "tooltip-t-emailuser": "Pošaljite pismo ovom korisniku",
+       "tooltip-t-info": "Više informacija o ovoj stranici",
        "tooltip-t-upload": "Postavi slike i druge medije",
        "tooltip-t-specialpages": "Spisak svih posebnih stranica",
        "tooltip-t-print": "Verzija ove stranice za štampanje",
        "confirm-watch-top": "Dodajte ovu stranu na Vaš spisak praćenih članaka",
        "confirm-unwatch-button": "U redu",
        "confirm-unwatch-top": "Izbrišite ovu stranu sa Vašeg spiska praćenih članaka",
+       "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← prethodna stranica",
        "imgmultipagenext": "slijedeća stranica →",
        "imgmultigo": "Idi!",
        "imgmultigoto": "Idi na stranicu $1",
+       "img-lang-default": "(podrazumijevani jezik)",
+       "img-lang-info": "Prikaži ovu sliku u $1. $2",
        "img-lang-go": "Idi",
        "ascending_abbrev": "rast",
        "descending_abbrev": "opad",
        "autosumm-replace": "Zamjena stranice sa '$1'",
        "autoredircomment": "Preusmjereno na [[$1]]",
        "autosumm-new": "Napravljena stranica sa '$1'",
+       "autosumm-newblank": "Napravljena prazna stranica",
        "size-bytes": "$1 B",
        "size-kilobytes": "$1 KB",
        "size-megabytes": "$1 MB",
        "watchlistedit-raw-done": "Vaš spisak praćenja je ažuriran.",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 naslov je dodan|$1 naslova su dodana|$1 naslova je dodano}}:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 naslov je uklonjen|$1 naslova je uklonjeno}}:",
+       "watchlisttools-clear": "Očisti spisak nadgledanja",
        "watchlisttools-view": "Pregled promjena praćenih stranica",
        "watchlisttools-edit": "Pogledaj i uredi listu praćenih članaka.",
        "watchlisttools-raw": "Uređivanje praćenih stranica u okviru praćenja.",
        "version-version": "(Verzija $1)",
        "version-license": "Licenca",
        "version-ext-license": "Licenca",
+       "version-ext-colheader-name": "Proširenje",
+       "version-skin-colheader-name": "Izgled",
        "version-ext-colheader-version": "Verzija",
        "version-ext-colheader-license": "Licenca",
        "version-ext-colheader-description": "Opis",
        "specialpages-group-wiki": "Podaci i alati",
        "specialpages-group-redirects": "Preusmjeravanje posebnih stranica",
        "specialpages-group-spam": "Alati za spam",
+       "specialpages-group-developer": "Razvojni alati",
        "blankpage": "Prazna stranica",
        "intentionallyblankpage": "Ova stranica je namjerno ostavljena prazna",
        "external_image_whitelist": " #Ostavite ovu liniju onakva kakva je<pre>\n#Stavite obične fragmente opisa (samo dio koji ide između //) ispod\n#Ovi će biti spojeni sa URLovima sa vanjskih (eksternih) slika\n#One koji se spoje biće prikazane kao slike, u suprotnom će se prikazati samo link\n#Linije koje počinju sa # se tretiraju kao komentari\n#Ovo ne razlikuje velika i mala slova\n\n#Stavite sve regex fragmente iznad ove linije. Ostavite ovu liniju onakvu kakva je</pre>",
        "duration-centuries": "$1 {{PLURAL:$1|vijek|vijeka|vijekova}}",
        "duration-millennia": "$1 {{PLURAL:$1|milenij|milenija}}",
        "rotate-comment": "Slika rotirana za $1 {{PLURAL:$1|stepen|stepeni}} u smjeru kazaljke na satu",
+       "limitreport-walltime": "Korištenje u realnom vremenu",
        "limitreport-walltime-value": "$1 {{PLURAL:$1|sekunda|sekunde|sekundi}}",
        "expandtemplates": "Proširi šablone",
        "expand_templates_intro": "Ova posebna stranica uzima neki tekst i proširuje sve šablone u njemu rekurzivno.\nOna također proširuje parserske funkcije poput\n<nowiki>{{</nowiki>#language:…}} i varijable poput\n<nowiki>{{</nowiki>CURRENTDAY}}&mdash;u principu gotovo sve između dvostrukih zagrada.\nOvo se uradi putem poziva relevantnog parserskog nivoa iz same MediaWiki.",
        "expand_templates_preview": "Pregled",
        "pagelang-name": "Stranica",
        "pagelang-language": "Jezik",
-       "pagelang-select-lang": "Izaberi jezik"
+       "pagelang-select-lang": "Izaberi jezik",
+       "mediastatistics-header-unknown": "Nepoznato",
+       "json-error-syntax": "Sintaksna greška"
 }
index 133825c..882a312 100644 (file)
@@ -44,7 +44,8 @@
                        "Calak",
                        "F3RaN",
                        "ESM",
-                       "Loupeter"
+                       "Loupeter",
+                       "Macofe"
                ]
        },
        "tog-underline": "Subratlla els enllaços:",
@@ -72,7 +73,7 @@
        "tog-shownumberswatching": "Mostra el nombre d'usuaris que hi vigilen",
        "tog-oldsig": "Signatura actual:",
        "tog-fancysig": "Tractar la signatura com a text wiki (sense enllaç automàtic)",
-       "tog-uselivepreview": "Utilitza la previsualització automàtica (cal JavaScript) (experimental)",
+       "tog-uselivepreview": "Utilitza la previsualització automàtica",
        "tog-forceeditsummary": "Avisa'm en deixar el resum de la modificació en blanc",
        "tog-watchlisthideown": "Amaga les meues edicions de la llista de seguiment",
        "tog-watchlisthidebots": "Amaga de la llista de seguiment les edicions fetes per usuaris bots",
        "viewsourcetext": "Podeu visualitzar i copiar el codi font d’aquesta pàgina:",
        "viewyourtext": "Vostè pot veure i copiar la font de ' ' les modificacions ' ' d'aquesta pàgina:",
        "protectedinterface": "Aquesta pàgina proporciona el text de la interfície del software d'aquest wiki i està protegida per evitar els abusos.\nPer afegir o canviar les traduccions per a tots els wikis, feu servir [//translatewiki.net/ translatewiki.net], el projecte de localització de MediaWiki.",
-       "editinginterface": "'''Avís:''' Esteu editant una pàgina que conté cadenes de text per a la interfície d'aquest programari. Tingueu en compte que els canvis que es fan a aquesta pàgina afecten a l'aparença de la interfície d'altres usuaris. Per afegir o modificar traduccions a totes les wikis, plantegeu-vos utilitzar la [//translatewiki.net/ translatewiki.net], el projecte de localització de MediaWiki.",
+       "editinginterface": "'''Avís:''' esteu editant una pàgina que s'utilitza per proporcionar text d'interfície per al programari. Els canvis que es facin a la pàgina afectaran l'aparença de la interfície d'altres usuaris del wiki.",
        "translateinterface": "Per afegir o canviar traduccions per a tots els wikis, utilitzeu [//translatewiki.net/ translatewiki.net], el projecte de localització de MediaWiki.",
        "cascadeprotected": "Aquesta pàgina està protegida i no es pot modificar perquè està inclosa en {{PLURAL:$1|la següent pàgina, que té|les següents pàgines, que tenen}} activada l'opció de «protecció en cascada»:\n$2",
        "namespaceprotected": "No teniu permís per a modificar pàgines en l'espai de noms '''$1'''.",
index 91f08a2..3a9a46d 100644 (file)
@@ -15,7 +15,9 @@
        "tog-underline": "下劃綫鏈接",
        "tog-hideminor": "囥起最近改變其過幼修改",
        "tog-hidepatrolled": "囥起最近改變其巡邏修改",
+       "tog-newpageshidepatrolled": "共巡邏視頁趁新建頁列表𡅏囥起去",
        "tog-extendwatchlist": "敆擴展監視單單臺中顯示所有其更改,伓啻最近其更改",
+       "tog-usenewrc": "按頁顯示最近修改共監視列表臺中其群組改變",
        "tog-numberheadings": "自動編號其標題",
        "tog-showtoolbar": "顯示編輯工具欄",
        "tog-editondblclick": "雙擊就修改頁面",
        "tog-watchdefault": "添加我編輯其頁面共文件遘我其監視單",
        "tog-watchmoves": "添加我移動其頁面共文件遘我其監視單",
        "tog-watchdeletion": "添加我刪掉其頁面共文件遘我其監視單",
+       "tog-watchrollback": "敆我其監視列表臺中添加我做過回滚其頁面",
        "tog-minordefault": "默認共所有其編輯都當作過幼修改",
        "tog-previewontop": "敆編輯框以前顯示預覽",
        "tog-previewonfirst": "敆頭蜀回編輯時候看預覽",
        "tog-enotifwatchlistpages": "我其監視單有變時候,發電子郵件乞我",
        "tog-enotifusertalkpages": "我其討論頁有變時候,發電子郵件乞我",
        "tog-enotifminoredits": "就㑚講是過幼編輯,也着發電子郵件乞我",
+       "tog-enotifrevealaddr": "敆通知郵件臺中顯示我其電子郵件地址",
        "tog-shownumberswatching": "顯示監視用戶其數量",
        "tog-oldsig": "存在其簽名",
        "tog-fancysig": "共簽名當成維基文本(無自動鏈接)",
@@ -38,7 +42,7 @@
        "tog-watchlisthideown": "趁監視單𡅏囥起我其修改",
        "tog-watchlisthidebots": "囥起監視單其機器人其修改",
        "tog-watchlisthideminor": "囥起監視單其過幼修改",
-       "tog-watchlisthideliu": "共已經躒底其用戶其編輯趁監視單𡅏囥起咯",
+       "tog-watchlisthideliu": "共已經登錄其用戶其編輯趁監視單𡅏囥起咯",
        "tog-watchlisthideanons": "共匿名其用戶其編輯趁監視單𡅏囥起咯",
        "tog-watchlisthidepatrolled": "共巡查其編輯趁監視單𡅏囥起咯",
        "tog-ccmeonemails": "共我發乞其他用戶其電子郵件其備份發乞我。",
@@ -46,6 +50,7 @@
        "tog-showhiddencats": "㪗藏類別",
        "tog-norollbackdiff": "敆回滾其時候,無叕𣍐蜀様其地方",
        "tog-useeditwarning": "我編輯頁面其時候離開,起動警告我蜀下",
+       "tog-prefershttps": "登錄以後全程使用安全連接",
        "underline-always": "直頭",
        "underline-never": "頭𡅏無",
        "underline-default": "皮膚或者瀏覽器默認其",
        "mytalk": "我其討論",
        "anontalk": "茲隻IP其討論頁",
        "navigation": "引導",
-       "and": "&#32;and",
+       "and": "&#32;",
        "qbfind": "討",
        "qbbrowse": "覷蜀覷",
        "qbedit": "修改",
        "permalink": "永久鏈接",
        "print": "拍印",
        "view": "覷蜀覷",
+       "view-foreign": "敆$1𡅏看",
        "edit": "修改",
+       "edit-local": "編輯當地描述",
        "create": "創建",
+       "create-local": "添加當地描述",
        "editthispage": "修改茲頁",
        "create-this-page": "創建茲蜀頁",
        "delete": "刪除",
        "categorypage": "看分類頁",
        "viewtalkpage": "看討論",
        "otherlanguages": "其它其語言",
-       "redirectedfrom": "($1重定向過來)",
+       "redirectedfrom": "($1重定向過來)",
        "redirectpagesub": "重定向頁",
+       "redirectto": "重定向遘",
        "lastmodifiedat": "茲蜀頁是着$1 $2其辰候最後修改其。",
        "viewcount": "茲蜀頁已經乞訪問$1回了。{{PLURAL:$1}}",
        "protectedpage": "保護頁",
        "jumptonavigation": "引導:",
        "jumptosearch": "尋討",
        "view-pool-error": "對不住,服務器茲蜀萆時候已弳過載了。\n過価用戶敆𡅏覷茲蜀頁。\n起動等仂久再來覷茲蜀頁。\n\n$1",
+       "generic-pool-error": "對不住,現刻時服務器過載了。\n實在過価用戶敆𡅏訪問茲蜀萆資源。\n起動汝等蜀刻再訪問茲蜀萆資源。",
        "pool-timeout": "等待鎖定其時間遘了",
        "pool-queuefull": "隊列池已經滿了",
        "pool-errorunknown": "𣍐八什乇鄭咯",
        "aboutsite": "關於{{SITENAME}}",
        "aboutpage": "Project:關於",
-       "copyright": "å\85§å®¹æ\95\86$1ä¸\8båº\95æ\9c\83使ç\8d²å¾\97。",
+       "copyright": "å\85§å®¹æ\9c\83使æ\95\86$1ä¸\8båº\95æ\9c\83使ç\8d²å¾\97é\81\98ï¼\8cè\8b¥ç\84¡æ\9c\83給å\87ºå\85¶å®\83æ\8f\90示。",
        "copyrightpage": "{{ns:project}}:版權",
        "currentevents": "大樹下",
        "currentevents-url": "Project:大樹下",
        "youhavenewmessages": "汝有$1($2)。",
        "youhavenewmessagesfromusers": "汝有趁$3用戶($2)來其$1萆信息{{PLURAL:$3}}",
        "youhavenewmessagesmanyusers": "汝有趁雅価用戶($2)其$1信息",
-       "newmessageslinkplural": "$1條新其信息{{PLURAL:$1}}",
-       "newmessagesdifflinkplural": "最後其改變{{PLURAL:$1}}",
+       "newmessageslinkplural": "{{PLURAL:$1|蜀條新其消息|999=新其消息}}",
+       "newmessagesdifflinkplural": "最後{{PLURAL:$1|回改變|999=回改變}}",
        "youhavenewmessagesmulti": "汝有趁$1來其新信息",
        "editsection": "修改",
        "editold": "修改",
        "hidetoc": "囥起",
        "collapsible-collapse": "隱",
        "collapsible-expand": "現",
+       "confirmable-confirm": "汝會確定𣍐?",
+       "confirmable-yes": "是",
+       "confirmable-no": "伓是",
        "thisisdeleted": "卜看或者恢復$1?",
        "viewdeleted": "看$1?",
        "restorelink": "$1萆乞刪掉其修改{{PLURAL:$1}}",
        "nospecialpagetext": "<strong>汝請求蜀萆𣍐合法其特殊頁面。</strong>\n\n合法其特殊頁面清單會使敆[[Special:SpecialPages|{{int:特殊頁面}}]]頁面討著",
        "error": "鄭咯",
        "databaseerror": "數據庫有綻",
+       "databaseerror-text": "數據庫查詢發生錯誤。\n嚽可能是軟件底裡其程序缺陷。",
+       "databaseerror-textcl": "數據庫查詢發生錯誤。",
+       "databaseerror-query": "查詢語句:$1",
+       "databaseerror-function": "函數名:$1",
+       "databaseerror-error": "錯誤信息:$1",
        "laggedslavemode": "'''警告:'''頁面可能無最近其更新。",
        "readonly": "數據庫乞鎖起咯",
+       "enterlockreason": "拍底汝鎖定數據庫其原因,包括汝估計其釋放鎖其時間",
        "readonlytext": "Só-gé̤ṳ-kó cī-buàng ké̤ṳk nè̤ng sō̤ kī lāu, mâ̤-sāi siā sĭng dèu-mĕ̤k hĕ̤k có̤ siŭ-gāi, ô kō̤-nèng sê ôi-lāu nĭk-siòng mì-hô, cĭ-hâiu cêu â̤ ciáng-siòng.\n\nSō̤ kī só-gé̤ṳ-kó gì guāng-lī-uòng cūng-kuāng gāi-sék: $1",
+       "missing-article": "數據庫未討遘本身應當著討遘其名叫\"$1\"其頁面$2其文本。\n\n嚽可能是下底其過時其diff或者已經删除其歴史鏈接造成其。\n\n如果伓是茲兩種情況,汝可能發現著蜀萆服務器其缺陷。\n起動汝共茲蜀萆缺陷匯報乞[[Special:ListUsers/sysop|管理員]],附上網址。",
+       "missingarticle-rev": "(版本#:$1)",
        "missingarticle-diff": "(比並:$1、$2)",
+       "readonly_lag": "從數據庫跟上主數據庫其辰候,數據庫已經自動鎖定",
        "internalerror": "內部錯誤",
        "internalerror_info": "內部錯誤:$1",
        "filecopyerror": "𣍐使趁「$1」𡅏複製文件遘「$2」。",
        "filerenameerror": "𣍐使共「$1」其名字改去「$2」。",
        "filedeleteerror": "𣍐使刪掉文件「$1」。",
        "directorycreateerror": "𣍐使刪掉目錄「$1」。",
+       "directoryreadonlyerror": "目錄$1是只讀目錄。",
+       "directorynotreadableerror": "目錄$1是禁讀目錄。",
        "filenotfound": "討𣍐著文件「$1」。",
        "unexpected": "伓是卜挃其值:「$1」=「$2」。",
        "formerror": "賺:𣍐使提交表單。",
+       "badarticleerror": "不允許敆茲蜀萆做茲蜀種行為。",
        "cannotdelete": "無能耐刪掉頁面或者文件「$1」。\n可能茲已經共別儂刪掉咯了。",
        "cannotdelete-title": "無辦法刪掉頁面「$1」",
        "delete-hook-aborted": "刪除乞鉤子拍斷咯。\n無給出解釋。",
+       "no-null-revision": "𣍐使敆頁面$1𡅏新建空操作。",
        "badtitle": "獃其標題",
        "perfcached": "下底其數據乞緩存固加可能伓是最新其。{{PLURAL:$1|$1條結果}}會敆緩存臺中討著。",
        "perfcachedts": "下底其數據已經緩存過了,最後更新遘$1。{{PLURAL:$4|$4條結果}}會敆緩存臺中討著。",
        "protectedpagetext": "茲頁已經乞保護起咯,𣍐使修改或者其它行動。",
        "viewsourcetext": "汝會使看共複製茲蜀頁其源代碼:",
        "viewyourtext": "汝會使覷蜀覷或者複製茲頁'''汝其修改'''其源代碼:",
-       "editinginterface": "'''警告:'''汝敆𡅏修改其頁面廮𡅏提供茲蜀萆軟件其界面文本。\n茲蜀頁其改變會影響遘其它用戶其用戶界面其顯示。\n如果卜想修改維基其翻譯,起動遘MediaWiki本地化計劃[//translatewiki.net/wiki/Main_Page?setlang=en translatewiki.net]。",
+       "editinginterface": "<strong>警告:</strong>汝敆𡅏修改其頁面廮𡅏提供茲蜀萆軟件其界面文本。\n茲蜀頁其改變會影響遘其它用戶其用戶界面其顯示。",
+       "cascadeprotected": "茲蜀頁受保護,𣍐使編辑,因為茲蜀頁包含敆下底{{PLURAL:$1|頁|頁}}開起“級聯”選項其受保護頁面底裡。\n$2",
        "namespaceprotected": "汝𣍐使修改敆'''$1'''命名空間其頁面。",
        "customcssprotected": "汝𣍐使修改茲蜀萆CSS頁面,因為伊有別蜀隻用戶其設定。",
        "customjsprotected": "汝𣍐使修改茲蜀萆JavaScript頁面,因為伊有別蜀隻用戶其設定。",
        "mycustomcssprotected": "汝𣍐使修改茲蜀萆CSS頁面。",
        "mycustomjsprotected": "汝𣍐使修改茲蜀萆JavaScript頁面。",
+       "myprivateinfoprotected": "汝無權限编輯汝其私人信息。",
+       "mypreferencesprotected": "汝無權限編輯偏好。",
        "ns-specialprotected": "𣍐使修改特殊頁面。",
        "titleprotected": "茲蜀萆標題共[[User:$1|$1]]保護其咯。\n原因是「''$2''」。",
-       "exception-nologin": "未躒底其",
-       "exception-nologin-text": "茲蜀頁其行動卜挃汝躒底茲蜀萆維基百科。",
+       "exception-nologin": "未登錄",
+       "exception-nologin-text": "起動汝登錄以後再訪問茲蜀頁,或者做茲蜀萆操作。",
+       "exception-nologin-text-manual": "起動汝$1,以後才會使訪問茲蜀頁,或者做茲蜀萆行為。",
        "virus-badscanner": "獃其配置:𣍐八其病毒掃描器:''$1''",
        "virus-scanfailed": "掃描失敗(代碼$1)",
        "virus-unknownscanner": "𣍐八其反病毒:",
-       "logouttext": "'''汝現在躒出了。'''\n\n汝會使使無名方式繼續覷{{SITENAME}},或者汝會使蜀様或者𣍐蜀様其用戶<span class='plainlinks'>[$1 再躒底其]</span>。\n注意有其頁面可能繼續顯示真像汝應經躒底其了,除開汝清理汝其瀏覽器緩存。",
+       "logouttext": "<strong>汝現在退出了。</strong>\n\n注意有其頁面可能繼續顯示真像汝已經登錄了,除開汝清理瀏覽器緩存。",
        "welcomeuser": "歡迎,$1!",
        "welcomecreation-msg": "汝其賬戶已經開好了。\n伓嗵𣍐記改蜀改汝其[[Special:Preferences|{{SITENAME}}設定]]。",
        "yourname": "用戶名:",
        "userlogin-yourname": "用戶名",
        "userlogin-yourname-ph": "輸底汝其用戶名",
+       "createacct-another-username-ph": "輸底汝其用戶名",
        "yourpassword": "密碼:",
        "userlogin-yourpassword": "密碼",
        "userlogin-yourpassword-ph": "輸底汝其密碼",
        "yourdomainname": "汝其域名:",
        "password-change-forbidden": "汝𣍐使敆茲蜀萆維基百科𡅏修改密碼。",
        "externaldberror": "可能是驗證數據庫綻咯,或者是汝𣍐使升級汝其外部賬戶。",
-       "login": "躒底",
-       "nav-login-createaccount": "躒底/開賬戶",
-       "userlogin": "躒底/開賬戶",
-       "userloginnocreate": "躒底",
-       "logout": "出",
-       "userlogout": "出",
-       "notloggedin": "未躒底",
+       "login": "登錄",
+       "nav-login-createaccount": "登錄/開賬戶",
+       "userlogin": "登錄/開賬戶",
+       "userloginnocreate": "登錄",
+       "logout": "退出",
+       "userlogout": "退出",
+       "notloggedin": "未登錄",
        "userlogin-noaccount": "汝無賬戶?",
        "userlogin-joinproject": "共{{SITENAME}}加底其",
        "nologin": "汝無賬戶?$1",
        "nologinlink": "開蜀隻賬戶",
        "createaccount": "開賬戶",
        "gotaccount": "已經有賬戶了?'''$1'''。",
-       "gotaccountlink": "躒底",
-       "userlogin-resetlink": "躒底其資料𣍐記咯?",
+       "gotaccountlink": "登錄",
+       "userlogin-resetlink": "登錄其資料𣍐記咯?",
        "userlogin-resetpassword-link": "密码𣍐記?",
-       "userlogin-helplink2": "對手汝躒底",
+       "userlogin-helplink2": "對手汝登錄",
+       "userlogin-loggedin": "汝已經使$1登錄過了。\n卜想使其他用戶登錄,請使下底其表格來登錄。",
+       "userlogin-createanother": "新建另外蜀萆賬號",
        "createacct-emailrequired": "電子郵件地址",
        "createacct-emailoptional": "電子郵件地址(愛寫就寫)",
        "createacct-email-ph": "輸底汝其電子郵件地址",
+       "createacct-another-email-ph": "輸底電子郵件地址",
        "createaccountmail": "使臨時其隨機密碼,共伊送遘指定其電子郵件地址",
        "createacct-realname": "實際其名字(愛寫就寫)",
        "createaccountreason": "原因:",
        "createacct-captcha": "安全檢查",
        "createacct-imgcaptcha-ph": "輸底汝敆懸頂看見其文字",
        "createacct-submit": "開賬戶",
+       "createacct-another-submit": "新建另外蜀萆賬號",
        "createacct-benefit-heading": "{{SITENAME}}是共汝蜀様其儂做其。",
        "createacct-benefit-body1": "{{PLURAL:$1|修改}}",
        "createacct-benefit-body2": "{{PLURAL:$1|頁面}}",
        "loginerror": "躒底有鄭",
        "createacct-error": "賬戶開出毛病咯",
        "createaccounterror": "無能獃開賬戶:$1",
+       "nocookiesnew": "用戶賬號已經創建好了,但是汝未登錄。\n{{SITENAME}}使cookie來記錄已經登錄其用戶。\n但是汝禁用了cookie。\n起動汝開啟cookie,然後再使汝其新用戶共密碼來登錄。",
+       "nocookieslogin": "{{SITENAME}}使cookies來記錄已經登錄其用戶。\n但是汝禁用了cookie。\n起動汝開起cookie,然後再試蜀試。",
        "noname": "汝未指定蜀萆合法其用戶名。",
        "loginsuccesstitle": "躒底成功",
        "loginsuccess": "'''汝現在已經「$1」其成功躒底{{SITENAME}}了。'''",
        "passwordsent": "新密碼已經寄遘「$1」註冊其電子郵件地址了。\n收遘後,請再躒底蜀頭部。",
        "mailerror": "發電子郵件有賺:$1",
        "acct_creation_throttle_hit": "使汝其IP訪問茲蜀萆維基百科訪問者其已經敆最後蜀日創建{{PLURAL:$1|$1萆賬戶}}去了。茲蜀段時間最価若允許創建茲滿価萆賬戶。故此講使茲蜀萆IP訪問其儂敆現刻時𣍐使再開賬戶了。",
-       "emailauthenticated": "汝其電子郵件地址已經敆$2$3驗證過了。",
+       "emailauthenticated": "汝其電子郵件地址已經敆$2$3確定過了。",
+       "emailnotauthenticated": "汝其電子郵件固未確定過。\n下底其所有特性都𣍐發電子郵件乞汝。",
        "emailconfirmlink": "確認汝其電子郵件地址",
        "emaildisabled": "茲萆站點𣍐使發電子郵件。",
        "accountcreated": "賬戶創建了",
        "createaccount-title": "{{SITENAME}}其開賬戶",
        "login-abort-generic": "汝其躒底𣍐成功——放棄去了",
        "loginlanguagelabel": "語言:$1",
+       "pt-login": "登錄",
+       "pt-login-button": "登錄",
+       "pt-createaccount": "開新賬號",
+       "pt-userlogout": "退出",
        "php-mail-error-unknown": "PHP其mail()函數,𣍐八什乇賺去。",
        "changepassword": "改變密碼",
        "resetpass_header": "改變賬戶其密碼",
        "preview": "預覽",
        "showpreview": "顯示預覽",
        "showdiff": "看改變其部分",
-       "anoneditwarning": "'''警告:'''汝未躒底。\n汝其IP地址會乞記着茲頁面其修改歷史裏勢。",
+       "anoneditwarning": "<strong>警告:</strong>汝未登錄。\n如果汝做修改,汝其IP地址會敆編輯歷史底裡公開。如果你<strong>[$1登錄]</strong>或者<strong>[$2註册新賬號]</strong>,汝其修改記錄會顯示汝其用戶名,固有其它其好處。",
+       "anonpreviewwarning": "<em>汝未登錄。如果汝保存茲蜀頁其修改,汝其IP地址會記錄敆茲蜀頁其編輯歴史臺中。</em>",
        "missingcommenttext": "起動敆下底輸底蜀條評論。",
        "summary-preview": "總結預覽:",
        "blockedtitle": "用戶乞封鎖了",
        "loginreqlink": "躒底",
        "loginreqpagetext": "著$1才會使看其它頁面。",
        "accmailtitle": "密碼寄出了",
-       "accmailtext": "共[[User talk:$1|$1]]用戶其臨時產生其密碼已經發$2了。\n\n茲蜀萆新其賬戶其密碼會使敆用戶躒底以後著''[[Special:ChangePassword|改密碼]]''頁面𡅏改變。",
+       "accmailtext": "共[[User talk:$1|$1]]用戶隨機生成其密碼已經發遘$2了。汝登錄以後會使敆[[Special:ChangePassword|修改密碼]]頁面修改茲蜀萆密碼。",
        "newarticle": "(新)",
        "newarticletext": "汝已經跟鏈接跟遘無存在其頁面了。\n卜想創建頁面,敆下底其框框𡅏拍字(覷蜀覷[$1 幫助頁面]有無更更価其幫助)。\n如果汝是無注意來遘茲蜀萆頁面,篤囇汝其瀏覽器上其「返回」按鈕。",
        "anontalkpagetext": "''茲是未躒底其用戶討論頁面。''\n故此儂家著使數字IP來確定伊。\n總款其IP地址會乞雅価用戶共享。\n如果蜀隻未躒底其用戶見覺無關係其評論指向汝,起動[[Special:UserLogin/signup|開賬戶]]或者[[Special:UserLogin|躒底]]來避免以後共其它未躒底其用戶混蜀堆。",
        "noarticletext": "現在敆茲蜀頁𡅏無文字。汝會使敆其它其頁面𡅏[[Special:Search/{{PAGENAME}}|討蜀討茲蜀萆標題]],<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 討相關其記錄],或者[{{fullurl:{{FULLPAGENAME}}|action=edit}}編輯茲蜀頁]</span>。",
        "clearyourcache": "'''注意:'''保存以後,汝可能固著刷新汝其瀏覽器緩存來看遘變化。\n* '''火狐/Safari:'''擪下''Shift''篤蜀篤''重新載入'',或者擪蜀擪''Ctrl+F5''或者''Ctrl+R'' (''⌘-R''敆Mac懸頂)\n* '''Google Chrome:'''擪''Ctrl+Shift+R''(敆Mac𡅏使''⌘-Shift-R'')\n* '''Internet Explorer:'''擪''Ctrl''其時候篤蜀篤''刷新'',或者擪''Ctrl+F5''\n* '''Opera:'''敆''工具→首選項''𡅏清除緩存",
+       "note": "<strong>注意:</strong>",
        "previewnote": "'''記定茲若是蜀萆預覽。'''\n汝其改變固𡅏未保存!",
        "continue-editing": "行去編輯區",
        "editing": "修改 $1",
        "template-protected": "(保護)",
        "template-semiprotected": "(半保護)",
        "recreate-moveddeleted-warn": "'''注意:汝敆𡅏重新創建舊底已經乞刪唻其頁面。'''\n\n汝應該考慮蜀下繼續去編輯茲蜀頁到底是伓是合適其。茲蜀頁其刪除記錄共移動記錄都敆嚽塊:",
+       "edit-conflict": "編輯衝突",
+       "content-model-wikitext": "維基文本",
+       "content-model-text": "純文本",
+       "content-model-javascript": "JavaScript",
+       "content-model-css": "CSS",
        "undo-summary": "取消[[Special:Contributions/$2|$2]]([[User talk:$2|Tō̤-lâung]])其$1修改",
        "cantcreateaccounttitle": "無能獃開賬戶",
        "viewpagelogs": "看茲頁其歷史",
        "rclistfrom": "顯示由$3 $2開始其新其改變",
        "rcshowhideminor": "$1過幼修改",
        "rcshowhidebots": "$1機器人",
-       "rcshowhideliu": "$1躒底用戶",
+       "rcshowhideliu": "$1已註冊其用戶",
        "rcshowhideanons": "$1無名用戶",
        "rcshowhidemine": "$1我其修改",
        "rclinks": "顯示$2日以內產生其$1回改變<br />$3",
        "filesource": "來源:",
        "ignorewarning": "無視警告保存文件",
        "ignorewarnings": "無視警告",
-       "fileexists": "名字蜀樣其文件已經存在去了。如果𣍐確定汝是伓是卜想刪掉伊,起動檢查蜀下<strong>[[:$1]]</strong>。\n[[$1|thumb]]",
+       "fileexists": "名字蜀樣其文件已經存在去了。如果{{GENDER:|汝}}𣍐確定汝是伓是卜想刪掉伊,起動檢查蜀下<strong>[[:$1]]</strong>。\n[[$1|thumb]]",
        "uploadwarning": "上傳警告",
        "savefile": "保存文件",
        "uploadvirus": "茲文件有病毒!\n細底:$1",
        "watchthispage": "監視茲頁",
        "unwatch": "伓使監視",
        "unwatchthispage": "停止監視",
-       "watchlist-details": "{{PLURAL:$1}}$1頁敆汝其監視單𡅏,無算討論頁。",
+       "watchlist-details": "{{PLURAL:$1|$1頁|$1頁}}敆汝其監視單𡅏,無單獨算討論頁。",
        "wlshowlast": "顯示最$1點鐘$2日",
        "watchlist-options": "監視單選項",
        "watching": "監視...",
        "excontent": "乇是:「$1」",
        "excontentauthor": "乇是:「$1」(並且作者囇有「[[Special:Contributions/$2|$2]]」)",
        "exbeforeblank": "空白以前其乇是:「$1」",
-       "historywarning": "'''警告:'''汝卜想刪掉其頁面有蜀段大概$1隻{{PLURAL:$1|版本}}其它歷史:",
+       "historywarning": "<strong>警告:</strong>汝卜想刪掉其頁面有$1隻{{PLURAL:$1|版本|版本}}其蜀段歷史:",
        "confirmdeletetext": "汝準備全隻頁面共文章連伊敆蜀塊其歷史全部刪掉。\n請汝確認:汝當真卜想總款做,汝瞭解總款做其後果,並且汝總款做事符合[[{{MediaWiki:Policy-url}}]]其。",
        "actioncomplete": "行動成功",
        "actionfailed": "操作失敗",
        "whatlinkshere-hidelinks": "$1鏈接",
        "whatlinkshere-hideimages": "$1 文件鏈接",
        "whatlinkshere-filters": "過濾器",
-       "blockip": "封鎖用戶",
+       "blockip": "封鎖{{GENDER:$1|用戶}}",
        "blockiptext": "使下底其表單來封鎖趁指定IP地址或者用戶名其寫入訪問。茲囇使廮𡅏防止破壞,固加著符合[[{{MediaWiki:Policy-url}}|政策]]。敆下底填底指定其原因(比如講:引用乞破壞其頁面)。",
        "ipaddressorusername": "IP地址或者用戶名:",
        "ipbexpiry": "過期:",
index 7977fb6..180a185 100644 (file)
@@ -35,7 +35,7 @@
        "tog-enotifrevealaddr": "Гайта сан зlе оцу хаамаш барехь",
        "tog-shownumberswatching": "Гайта декъашхойн терахь, агӀо латийна болу шай тергаме могӀанан юкъа",
        "tog-oldsig": "Карара куьгтаӀорна:",
-       "tog-fancysig": "Шен Ð²Ð¸ÐºÐ¸-кÑ\8aаÑ\81Ñ\82аман ÐºÑ\83Ñ\8cгÑ\82аÓ\80даÑ\80 (Ñ\88а Ñ\88еÑ\85 Ñ\85Ñ\8cажоÑ\80аг Ð¹Ð¾Ñ\86Ñ\83Ñ\88)",
+       "tog-fancysig": "Шен вики-къастаман куьгтаӀдар (ша шех хьажорг йоцуш)",
        "tog-uselivepreview": "Лелайа чехка хьалха хьажа (JavaScript, муха ю хьажарна)",
        "tog-forceeditsummary": "Дага даийта, нагахь нисйарх лаьцна чохь язйина яцахь",
        "tog-watchlisthideown": "Къайлаяха ас нисйинарш тергаме могӀам чура",
        "anontalk": "Дийцаре хӀокху IP-адресна",
        "navigation": "Навигаци",
        "and": "&#32;а",
-       "qbfind": "Лаха",
+       "qbfind": "Лахар",
        "qbbrowse": "Хьажар",
        "qbedit": "Нисъе",
        "qbpageoptions": "Агlо нисйар",
        "returnto": "ЮхагӀо оцу агӀоне $1.",
        "tagline": "Гlирс хlокхуьна бу {{grammar:genitive|{{SITENAME}}}}",
        "help": "ГӀо",
-       "search": "Лаха",
+       "search": "Лахар",
        "searchbutton": "Лаха",
        "go": "Дехьа гӀо",
        "searcharticle": "Дехьа гӀо",
        "history_short": "Истори",
        "updatedmarker": "Керла яккхина сона гинчултӀаьхьа",
        "printableversion": "Зорба туху верси",
-       "permalink": "Ð\94аиман Ð¹Ð¾Ð»Ñ\83 Ñ\85Ñ\8cажоÑ\80аг",
+       "permalink": "Даиман йолу хьажорг",
        "print": "Зорба тоха",
        "view": "Хьажа",
        "view-foreign": "Сайтехь $1 хьажа",
        "readonly": "Блоктоьхна дӀайаздар хаамийн бухе",
        "enterlockreason": "Билгалде блоктохаран бахьна а и чекх йолу хан а.",
        "readonlytext": "АгӀонаш тӀетохар а кхин хийцамаш барна а блоктоьхна:\nБлокоьхначо биттина хаам: $1.",
-       "missing-article": "Ð¥Ó\80окÑ\85Ñ\83 Ñ\87оÑ\85Ñ\8c ÐºÐ°Ñ\80оезаÑ\88 Ð¹Ð¾Ð»Ñ\83 Ñ\85Ñ\8cан Ð´ÐµÑ\85аÑ\80Ñ\86а Ð¹Ð¾Ð·Ð°Ð½ Ð°Ð³Ó\80онаÑ\88 Ñ\86акаÑ\80ийна Â«$1» $2.\n\nÐ\98Ñ\88Ñ\82наÑ\80г Ð½Ð°Ð³Ð³Ð°Ñ\85Ñ\8c Ñ\85Ñ\83Ñ\8cлÑ\83 Ñ\85Ñ\8cажоÑ\80аг Ð´Ó\80аÑ\8fÑ\8cккÑ\85ина ÐµÐ»Ð°Ñ\85Ñ\8c Ñ\8f Ñ\85ийÑ\86ам Ð±Ð¸Ð½Ð° Ñ\82иÑ\88а Ñ\85Ñ\8cажоÑ\80агца дехьа гӀо гӀоьртича.\n\nНагахьсан гӀулкх цуьнах доьзна дацахь, хьуна карийна гӀирс латточехь гӀалат.\nДехар до, хаам бе оцуьнах [[Special:ListUsers/sysop|куьйгалхога]], гойтуш URL.",
+       "missing-article": "Ð¥Ó\80окÑ\85Ñ\83 Ñ\87оÑ\85Ñ\8c ÐºÐ°Ñ\80оезаÑ\88 Ð¹Ð¾Ð»Ñ\83 Ñ\85Ñ\8cан Ð´ÐµÑ\85аÑ\80Ñ\86а Ð¹Ð¾Ð·Ð°Ð½ Ð°Ð³Ó\80онаÑ\88 Ñ\86акаÑ\80ийна Â«$1» $2.\n\nÐ\98Ñ\88Ñ\82наÑ\80г Ð½Ð°Ð³Ð³Ð°Ñ\85Ñ\8c Ñ\85Ñ\83Ñ\8cлÑ\83 Ñ\85Ñ\8cажоÑ\80г Ð´Ó\80аÑ\8fÑ\8cккÑ\85ина ÐµÐ»Ð°Ñ\85Ñ\8c Ñ\8f Ñ\85ийÑ\86ам Ð±Ð¸Ð½Ð° Ñ\82иÑ\88а Ñ\85Ñ\8cажоÑ\80гца дехьа гӀо гӀоьртича.\n\nНагахьсан гӀулкх цуьнах доьзна дацахь, хьуна карийна гӀирс латточехь гӀалат.\nДехар до, хаам бе оцуьнах [[Special:ListUsers/sysop|куьйгалхога]], гойтуш URL.",
        "missingarticle-rev": "(верси № $1)",
        "missingarticle-diff": "(башхалла: $1, $2)",
        "readonly_lag": "Хаамашан базина цхьана хан блоктоьхна, хаамашан базан сервераш нисялца.",
        "italic_sample": "Сеттан до йоза",
        "italic_tip": "Сеттан до йоза",
        "link_sample": "Хьажориган коьрта могlа",
-       "link_tip": "ЧоÑ\8cÑ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80аг",
-       "extlink_sample": "http://www.example.com Ñ\85Ñ\8cажоÑ\80аг ÐºÐ¾Ñ\80Ñ\82а",
-       "extlink_tip": "Ð\90Ñ\80аÑ\85Ñ\8cаÑ\80а Ñ\85Ñ\8cажоÑ\80аг (йиÑ\86 Ð¼Ð° Ð¹Ðµ Ñ\85Ó\80оÑ\82Ñ\82алÑ\83Ñ\88еÑ\80г http://)",
+       "link_tip": "Чоьхьа хьажорг",
+       "extlink_sample": "http://www.example.com хьажорг корта",
+       "extlink_tip": "Арахьара хьажорг (йиц ма йе хӀотталушерг http://)",
        "headline_sample": "Йозан корта",
        "headline_tip": "Корта 2-гlа локхаллийца",
        "nowiki_sample": "Чудиллийша кхузе барамхlоттонза йоза.",
        "image_sample": "Example.jpg",
        "image_tip": "Чохь йолу файл",
        "media_sample": "Example.ogg",
-       "media_tip": "Ð¥Ñ\8cажоÑ\80аг Ð¼ÐµÐ´Ð¸Ð°-Ñ\84айлан Ñ\82Ó\80е",
+       "media_tip": "Хьажорг медиа-файлан тӀе",
        "sig_tip": "Хьан куьгтаlор аъ хlоттина хан",
        "hr_tip": "Ана сиз (сих сиха ма леладайша)",
        "summary": "Хийцамех лаьцна:",
        "note": "'''Билгалдаккхар:'''",
        "previewnote": "'''ХӀара хьлха хьажар ду, йоза хӀинца язданза ду!'''",
        "continue-editing": "Кхин дӀа тадар",
-       "session_fail_preview": "СеÑ\80веÑ\80 Ð»Ð°Ñ\80а Ñ\86а Ð¹Ð¸Ñ\80а Ð°Ñ\85Ñ\8cа Ð±Ð¸Ð½Ð° Ñ\85ийÑ\86амаÑ\88 Ð´Ó\80аÑ\8fзба. Ð\9aÑ\85иÑ\8a Ñ\86кÑ\8aа Ð° Ð³Ó\80оÑ\80Ñ\82аÑ\85Ñ\8c.\nÐ\9dагаÑ\85Ñ\8c Ñ\81анна Ñ\85Ó\80аÑ\80а Ð³Ó\80алаÑ\82 Ñ\8eÑ\85а Ð° Ð´Ð°Ð»Ð°Ñ\85Ñ\8c, [[Special:UserLogout|Ñ\81еанÑ\81 Ð´Ó\80а Ð° ÐºÑ\8aоÑ\8cвлин]], Ñ\8eÑ\85а Ð° Ñ\81иÑ\81Ñ\82емин Ñ\87Ñ\83вала/Ñ\8fла Ñ\85Ñ\8cажа.",
+       "session_fail_preview": "СеÑ\80веÑ\80 Ð»Ð°Ñ\80а Ñ\86а Ð¹Ð¸Ñ\80а Ð°Ñ\85Ñ\8cа Ð±Ð¸Ð½Ð° Ñ\85ийÑ\86амаÑ\88 Ð´Ó\80аÑ\8fзба. Ð\9aÑ\85иÑ\8a Ñ\86кÑ\8aа Ð° Ð³Ó\80оÑ\80Ñ\82аÑ\85Ñ\8c.\nÐ\9dагаÑ\85Ñ\8c Ñ\81анна Ñ\85Ó\80аÑ\80а Ð³Ó\80алаÑ\82 Ñ\8eÑ\85а Ð° Ð´Ð°Ð»Ð°Ñ\85Ñ\8c, [[Special:UserLogout|Ñ\81еанÑ\81 Ð´Ó\80а Ð° ÐºÑ\8aоÑ\8cвлин]], Ñ\8eÑ\85а Ð° Ñ\81иÑ\81Ñ\82емин Ñ\87Ñ\83гÓ\80о.",
        "edit_form_incomplete": "'''Цхьайолу тадаран формаш серверан тӀекхаьчча яц. Тидаме хьажа хьай нисдарш доьхна дуй, ТӀакха южу гӀорта.'''",
        "editing": "Тадар: $1",
        "creating": "АгӀо кхоллар «$1»",
        "diff-multi-sameuser": "(ца {{PLURAL:$1|гайтина юккъера цхьа верси|гайтина юккъера цхьа версеш}} оьцу декъашхочун)",
        "diff-multi-otherusers": "(ца {{PLURAL:$1|гайтина юккъера верси|гайтина юккъера версеш}} {{PLURAL:$2|кхин цхьан декъашхочун|$2 декъашхойн}})",
        "diff-multi-manyusers": "({{PLURAL:$1|гайтина яц $1 юккъера верси, йина|не показаны $1 юккъера версеш, йина}} {{PLURAL:$2|$2 декъашхочо|$2 декъашхоша}})",
-       "searchresults": "Ð\9bаÑ\85аÑ\80на Ñ\85илам",
-       "searchresults-title": "Лаха «$1»",
+       "searchresults": "Ð\9aаÑ\80ийнаÑ\80Ñ\88",
+       "searchresults-title": "Лахар «$1»",
        "titlematches": "АгӀонийн цӀераш цхьаьнанисялар",
        "textmatches": "АгӀонийн йоза цхьаьнанисдалар",
        "notextmatches": "АгӀонаш чура йозанашца цхьатера йогlуш яц",
        "searchall": "массо",
        "showingresults": "Лахахьа {{PLURAL:$1|гойту}} <strong>$1</strong> {{PLURAL:$1|хилам}}, дӀаболало кху № <strong>$2</strong>.",
        "showingresultsinrange": "Лахахь гайтина {{PLURAL:$1|<strong>1</strong> хилам}} диапазонехь <strong>$2</strong> тӀера <strong>$3</strong> кхаччалц.",
-       "search-showingresults": "{{PLURAL:$4|Хилам <strong>$1</strong> <strong>$3</strong> Ð½Ð°Ñ\85}}",
+       "search-showingresults": "{{PLURAL:$4|Ð\9aаÑ\80ийна <strong>$1</strong> â\80\94 Ñ\86Ñ\85Ñ\8cаÑ\8a Ð°Ð³Ó\80о|Ð\9aаÑ\80ийна <strong>$3</strong> Ð°Ð³Ó\80о, Ñ\86аÑ\80аÑ\85 Ð°Ð³Ó\80онгаÑ\85Ñ\8c Ð³Ð¾Ð¹Ñ\82Ñ\83 $2 Ð°Ð³Ó\80о}}",
        "search-nonefound": "Дехаре терра цхьа хӀума ца карийна.",
-       "powersearch-legend": "Шуьро лахар",
+       "powersearch-legend": "Шуьйра лахар",
        "powersearch-ns": "ЦӀерийн меттигашкахь лахар:",
        "powersearch-togglelabel": "Билгалдан:",
        "powersearch-toggleall": "Массо",
        "prefs-editing": "Тадар",
        "rows": "МогӀанаш:",
        "columns": "БӀогӀамаш:",
-       "searchresultshead": "Лаха",
+       "searchresultshead": "Лахар",
        "stub-threshold": "Кеч яран доза <a href=\"#\" class=\"stub\">коьртамогӀамна хьажоргаш</a> (байташках):",
        "stub-threshold-disabled": "ДӀадайина",
        "recentchangesdays": "Керла нисдар гайта динахь:",
        "recentchangeslinked-title": "Кхуьнца долу нисдарш $1",
        "recentchangeslinked-summary": "ХӀара хийцам биначу агӀонийн могӀам бу, тӀетовжар долуш хьагучу агӀон (я хьагойтуш йолучу категорена).\nАгӀонаш юькъа йогӀуш йолу хьан [[Special:Watchlist|тергаме могӀам чохь]] '''къастийна ю'''.",
        "recentchangeslinked-page": "АгӀон цӀе:",
-       "recentchangeslinked-to": "Ð\9aÑ\85еÑ\87Ñ\83 Ð°Ð³Ó\80оÑ\80, Ð³Ð°Ð¹Ñ\82а Ñ\85ийÑ\86амаÑ\88 Ð°Ð³Ó\80онаÑ\88Ñ\86а, Ñ\85Ó\80оÑ\82Ñ\82ийнаÑ\87Ñ\83 Ð°Ð³Ó\80онÑ\82Ó\80е Ñ\85Ñ\8cажоÑ\80аг Ð¹Ð¾Ð»Ñ\83Ñ\88",
+       "recentchangeslinked-to": "Кхечу агӀор, гайта хийцамаш агӀонашца, хӀоттийначу агӀонтӀе хьажорг йолуш",
        "upload": "Файл чуяккхар",
        "uploadbtn": "Файл чуяккхар",
        "reuploaddesc": "Юху гӀо файл чуйоккху агӀоне",
        "uploadnologintext": "Серверан чу файлаш яха хьо $1.",
        "uploaderror": "Файл чуяккхаран гӀалат",
        "upload-recreate-warning": "'''Тегам бе: иштта цӀе йолу файл дӀаяьккхина я цӀе хийцина.'''\n\nЛахахьа гойтуш ю хӀокху агӀона тептар:",
-       "uploadtext": "Ð\9bелайе Ñ\85Ó\80аÑ\80а Ð°Ð³Ó\80о Ñ\81еÑ\80веÑ\80 Ñ\87Ñ\83 Ñ\84айлаÑ\88 Ð¹Ð¾Ñ\85Ñ\83Ñ\88.\nÐ¥Ñ\8cалÑ\85о Ñ\87Ñ\83Ñ\8fÑ\8cÑ\85на Ñ\84айлаÑ\88 Ñ\85Ñ\8cажа,  [[Special:FileList|кÑ\85Ñ\83заÑ\85Ñ\8c]]. Ð\9aÑ\85ин Ñ\87Ñ\83Ñ\8fÑ\8cÑ\85на Ñ\84айлаÑ\88 Ð´Ó\80аÑ\8fзло [[Special:Log/upload|Ñ\87Ñ\83Ñ\8fÑ\85аÑ\80ан Ñ\82епÑ\82аÑ\80 Ñ\87оÑ\85Ñ\8c]], Ð´Ó\80аÑ\8fÑ\8cÑ\85на Ñ\84айлаÑ\88 ÐºÐ°Ñ\80о Ð¹Ð¸Ñ\88 Ñ\8e [[Special:Log/delete|кÑ\85Ñ\83заÑ\85Ñ\8c]].\n\nФайл Ð°Ð³Ó\80она Ñ\87Ñ\83йилла Ð»ÐµÐ»Ð°Ð±Ðµ Ð»Ð°Ñ\85аÑ\80а Ð¼Ð¾Ð³Ó\80анаÑ\88:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code>''' Ñ\84айла Ð¤Ð°Ð¹Ð»Ð°Ð½ Ñ\8eÑ\8cззина Ð²ÐµÑ\80Ñ\81и Ñ\87Ñ\83йиллÑ\83Ñ\88;\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|Ñ\86Ñ\83наÑ\85Ñ\8c Ð»Ð°Ñ\8cÑ\86на Ñ\85аам]]</nowiki></code>''' 200 Ð¿Ð¸ÐºÑ\81елÑ\8c Ð±Ð°Ñ\80амеÑ\85Ñ\8c Ñ\84айл Ñ\87Ñ\83йилаÑ\80 Ð±Ñ\83Ñ\85аÑ\85Ñ\8c Ñ\86Ñ\83наÑ\85Ñ\8c Ð»Ð°Ñ\8cÑ\86на Ð¼Ð¾Ð³Ó\80а Ð° Ð±Ð¾Ð»Ñ\83Ñ\88;\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>''' Ñ\84айлан Ñ\82Ó\80е Ñ\85Ñ\8cажоÑ\80аг Ñ\85Ó\80оÑ\82айо Ñ\84айл Ð°Ð³Ó\80онгаÑ\85Ñ\8c Ñ\86а Ð³Ñ\83Ñ\88.",
+       "uploadtext": "Лелайе хӀара агӀо сервер чу файлаш йохуш.\nХьалхо чуяьхна файлаш хьажа,  [[Special:FileList|кхузахь]]. Кхин чуяьхна файлаш дӀаязло [[Special:Log/upload|чуяхаран тептар чохь]], дӀаяьхна файлаш каро йиш ю [[Special:Log/delete|кхузахь]].\n\nФайл агӀона чуйилла лелабе лахара могӀанаш:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code>''' файла Файлан юьззина верси чуйиллуш;\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|цунахь лаьцна хаам]]</nowiki></code>''' 200 пиксель барамехь файл чуйилар бухахь цунахь лаьцна могӀа а болуш;\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>''' файлан тӀе хьажорг хӀотайо файл агӀонгахь ца гуш.",
        "upload-permitted": "Магийна файлийн тайпанаш: $1.",
        "upload-preferred": "Магийна файлийн тайпанаш: $1.",
        "upload-prohibited": "Магийна доцу файлийн тайпанаш: $1.",
        "randomredirect": "Цахууш нисделла дIасахьажор",
        "randomredirect-nopages": "«$1» цӀерийн меттиган чохь дӀасахьажораш яц.",
        "statistics": "Статистика",
-       "statistics-header-pages": "АгӀонийн жамӀ",
+       "statistics-header-pages": "АгӀонийн статистика",
        "statistics-header-edits": "Нисдарийн статистика",
        "statistics-header-users": "Декъашхойн статистика",
        "statistics-header-hooks": "Кхин статистика",
        "pageswithprop-legend": "АгӀонаш цхьадолу къастамашца",
        "pageswithprop-text": "Кхузахь гойтуш ю агӀонаш цхьадолу къастамаш куьйга юху билгал даьхнарш.",
        "pageswithprop-prop": "Къастаман цӀе:",
-       "pageswithprop-submit": "Ð\9bаÑ\85а",
+       "pageswithprop-submit": "Ð\9aаÑ\80о",
        "pageswithprop-prophidden-long": "деха йозан хӀуман маьӀна хьулйина ($1)",
        "pageswithprop-prophidden-binary": "шалха маьӀна долу хӀума хьулйина ($1)",
        "doubleredirects": "Шалха дIасахьажийнарш",
        "fewestrevisions": "ЧӀогӀа кӀезиг версеш йолу агӀонаш",
        "nbytes": "$1 {{PLURAL:$1|байт}}",
        "ncategories": "$1 {{PLURAL:$1|категори|категореш}}",
-       "ninterwikis": "$1 {{PLURAL:$1|1=Ñ\8eкÑ\8aаÑ\80вики-Ñ\85Ñ\8cажоÑ\80аг|Ñ\8eкÑ\8aаÑ\80вики-Ñ\85Ñ\8cажоÑ\80гаÑ\88}}",
+       "ninterwikis": "$1 {{PLURAL:$1|1=юкъарвики-хьажорг|юкъарвики-хьажоргаш}}",
        "nlinks": "$1 {{PLURAL:$1|хьажорг}}",
        "nmembers": "$1 {{PLURAL:$1|хӀума|хӀумнаш}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|хӀума|хӀумнаш}}",
        "listusers": "Декъашхойн могӀам",
        "listusers-editsonly": "Цхаъ мукъане а хийцам бина декъашхой гайта",
        "listusers-creationsort": "Кхоьллина хене хьаьжна нисъяр",
-       "listusers-desc": "Харжа къезиг хиларца",
+       "listusers-desc": "Харжа кӀезиг хиларца",
        "usereditcount": "$1 {{PLURAL:$1|нисдар|нисдарш}}",
        "usercreated": "{{GENDER:$3|дӀавазвелла|дӀаязелла}} $1 $2",
        "newpages": "Керла агӀонаш",
        "ancientpages": "ТӀехьара терахьца тадар дина яззамаш",
        "move": "ЦӀе хийца",
        "movethispage": "ХӀокху агӀон цӀе хийца",
-       "unusedimagestext": "Ð\94еÑ\85аÑ\80 Ð´Ð¾, Ñ\82идаме Ñ\8dÑ\86а, ÐºÑ\85ин Ð¹Ð¾Ð»Ñ\83 Ð´Ñ\83Ñ\8cнана Ð¼Ð°Ñ\88ан-меÑ\82Ñ\82игаÑ\88 Ð° Ð»ÐµÐ»Ð¾Ñ\88 Ñ\85ила Ð¼ÐµÐ³Ð° Ð½Ð¸Ð¹Ñ\81Ñ\81а Ð¹Ð¾Ð³Ó\80Ñ\83 Ñ\85Ñ\8cажоÑ\80аг (URL) Ñ\85Ó\80окÑ\85Ñ\83 Ñ\85Ó\80Ñ\83ман, Ñ\85Ó\80окÑ\85Ñ\83 Ð¼Ð¾Ð³Ó\80аме Ð¹Ð¾Ð³Ó\80Ñ\83Ñ\88 Ñ\8fлаÑ\85Ñ\8c Ñ\8fÑ\86аÑ\85Ñ\8c Ð° Ð¸Ð·Ð° Ñ\85ила Ð¼ÐµÐ³Ð° Ð¶Ð¸Ð³Ð°Ñ\80а Ð»ÐµÐ»Ð¾Ñ\88.",
+       "unusedimagestext": "Дехар до, тидаме эца, кхин йолу дуьнана машан-меттигаш а лелош хила мега нийсса йогӀу хьажорг (URL) хӀокху хӀуман, хӀокху могӀаме йогӀуш ялахь яцахь а иза хила мега жигара лелош.",
        "unusedcategoriestext": "ХӀокху категорешан чохь агӀонаш я кхин категореш яц.",
        "notargettitle": "Ӏалашо билгал йина яц",
        "notargettext": "И кхочушдан ахьа билгал йина яц Ӏалашонан агӀо я декъашхо.",
        "deletedcontributions": "Декъашхочун дӀабяккхина къинхьегам",
        "deletedcontributions-title": "ДӀабаьккхина къинхьегам",
        "sp-deletedcontributions-contribs": "къинхьегам",
-       "linksearch": "Ð\90Ñ\80аÑ\85Ñ\8cаÑ\80а Ñ\85Ñ\8cажоÑ\80аг",
-       "linksearch-pat": "Ð\9bаÑ\85а кеп:",
+       "linksearch": "Арахьара хьажорг",
+       "linksearch-pat": "Ð\9bеÑ\85аÑ\80на кеп:",
        "linksearch-ns": "ЦӀерийн ана:",
        "linksearch-ok": "Лаха",
        "linksearch-text": "Лело мега хӀоттош йолу символаш, масала, <code>*.wikipedia.org</code>.\nЛакхара даржан домен мукъа хила еза , масала<code>*.org</code><br />\nЛовш йолу {{PLURAL:$2|1=протокол|протоколаш}}: <code>$1</code> (Iад йитарца http://, протокол бакъалла язъен яцахь).",
-       "linksearch-line": "$2 â\80\94 Ñ\85Ñ\8cажоÑ\80аг ÐºÑ\85Ñ\83 $1",
+       "linksearch-line": "$2 — хьажорг кху $1",
        "listusersfrom": "Гучé баха декъашхой, болалуш болу тӀера:",
        "listusers-submit": "Гайта",
        "listusers-noresult": "Декъашхой цакарий.",
        "nolinkshere-ns": "Хаьржинчу анахь яц '''[[:$1]]''' цӀе йолу агӀонаш",
        "isredirect": "агӀо-дӀасахьажорг",
        "istemplate": "юкъаялийнарш",
-       "isimage": "Файлан Ñ\85Ñ\8cажоÑ\80аг",
+       "isimage": "Файлан хьажорг",
        "whatlinkshere-prev": "{{PLURAL:$1|1=хьалхайодарг|хьалхайодарш}} $1",
        "whatlinkshere-next": "{{PLURAL:$1|тӀаьхьайогӀург|тӀаьхьайогӀурш}} $1",
        "whatlinkshere-links": "← хьажоргаш",
        "blocklist-by": "Цунна блоктоьхана куьйгалхо",
        "blocklist-params": "Блоктохаран параметраш",
        "blocklist-reason": "Бахьна:",
-       "ipblocklist-submit": "Лаха",
+       "ipblocklist-submit": "Лахар",
        "ipblocklist-localblock": "Локальни блоктохар",
        "ipblocklist-otherblocks": "{{PLURAL:$1|Кхин блоктохар|Кхин блоктохарш}}",
        "infiniteblock": "хан чаккхе йоцуш",
        "lockedbyandtime": "($1 $2 $3)",
        "move-page": "$1 — цӀе хийцар",
        "move-page-legend": "ЦӀe хийца яр",
-       "movepagetext": "Ð\91Ñ\83Ñ\85аÑ\85Ñ\8c Ð¹Ð¾Ð»Ñ\83 Ñ\84оÑ\80манÑ\86а Ð°Ð³Ó\80он Ñ\86Ó\80е Ñ\85ийÑ\86ало. Ð¦Ñ\83л Ñ\81овнаÑ\85 Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аман Ñ\82епÑ\82аÑ\80 ÐºÑ\85оÑ\8cÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82е Ð´Ð¾ÐºÐºÑ\85а. Ð¥Ñ\8cалÑ\85алеÑ\80а Ñ\86Ó\80аÑ\80аÑ\85Ñ\8c Ñ\85иÑ\80Ñ\8aÑ\8e ÐºÐµÑ\80ла ÐºÑ\85оÑ\8cллина Ð°Ð³Ó\80онан Ñ\85Ñ\8cажоÑ\80аг.\n\nÐ¥Ñ\8cовÑ\81алаÑ\88 [[Special:DoubleRedirects|Ñ\88алÑ\85а]] Ð° [[Special:BrokenRedirects|йоÑ\85на Ñ\85Ñ\8cажоÑ\80гаÑ\88]] Ñ\8eй Ñ\82еÑ\85Ñ\8c Ð°Ñ\8cлла.\n\nШÑ\83 Ð¶Ð¾Ñ\8cпеÑ\85Ñ\8c Ð´Ñ\83 Ñ\85Ñ\8cажоÑ\80гаÑ\88 Ð½Ð¸Ð¹Ñ\81а Ð½ÐµÐºÑ\8a Ð³Ð¾Ð¹Ñ\82Ñ\83Ñ\88 Ñ\85илаÑ\80ан.\n\nТидам Ð±Ðµ Ñ\85Ñ\8cалÑ\85алеÑ\80а Ð°Ð³Ó\80он Ñ\86Ó\80е â\80\98â\80\99â\80\99Ñ\85ийÑ\86алÑ\83Ñ\80 Ñ\8fÑ\86â\80\99â\80\99â\80\99 Ð¸Ñ\88Ñ\82Ñ\82а Ñ\86Ó\80е Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80о Ð¹Ð¾Ð»Ñ\83Ñ\88 ÐµÐ»Ð°Ñ\85Ñ\8c. Ð®ÐºÑ\8aаÑ\80даккÑ\85аÑ\80: Ð¹Ð¾Ð»Ñ\83Ñ\88 Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80о ÐºÑ\85оÑ\8cÑ\87Ñ\83Ñ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80аг ÐµÐ»Ð°Ñ\85Ñ\8c, Ñ\8f ÐµÑ\81а ÐµÐ»Ð°Ñ\85Ñ\8c Ð°, Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аме Ð¸Ñ\81Ñ\82оÑ\80и Ñ\8fÑ\86аÑ\85Ñ\8c Ð°.\n\nÐ\98 Ð±Ð¾Ñ\85Ñ\83Ñ\80г Ð´Ñ\83 Ñ\88Ñ\83н Ð°Ð³Ó\80онан Ñ\86Ó\80е Ñ\8eÑ\85а Ð° Ñ\85Ñ\8cалÑ\85а Ñ\85иллаÑ\80гÑ\87Ñ\83нтӀе хийца йиш ю, амма йолуш йолу агӀо дӀаяккха йиш яц.\n\n'''ДӀАХЬЕДАР!'''\n\nЦӀе хийцар бахьнехь гӀаръяьлла агӀонашна дукха дагахь боцу хийцамаш хила тарло. Цундела цӀе хийцале шеш хила тарлучу тӀехьонашах кхета аьлла тешна хила.",
-       "movepagetext-noredirectfixer": "Ð\91Ñ\83Ñ\85аÑ\85Ñ\8c Ð¹Ð¾Ð»Ñ\83 Ñ\84оÑ\80манÑ\86а Ð°Ð³Ó\80он Ñ\86Ó\80е Ñ\85ийÑ\86ало. Ð¦Ñ\83л Ñ\81овнаÑ\85 Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аман Ñ\82епÑ\82аÑ\80 ÐºÑ\85оÑ\8cÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82е Ð´Ð¾ÐºÐºÑ\85а. Ð¥Ñ\8cалÑ\85алеÑ\80а Ñ\86Ó\80аÑ\80аÑ\85Ñ\8c Ñ\85иÑ\80Ñ\8aÑ\8e ÐºÐµÑ\80ла ÐºÑ\85оÑ\8cллина Ð°Ð³Ó\80онан Ñ\85Ñ\8cажоÑ\80аг.\n\nÐ¥Ñ\8cовÑ\81алаÑ\88 [[Special:DoubleRedirects|Ñ\88алÑ\85а]] Ð° [[Special:BrokenRedirects|йоÑ\85на Ñ\85Ñ\8cажоÑ\80гаÑ\88]] Ñ\8eй Ñ\82еÑ\85Ñ\8c Ð°Ñ\8cлла.\n\nШÑ\83 Ð¶Ð¾Ñ\8cпеÑ\85Ñ\8c Ð´Ñ\83 Ñ\85Ñ\8cажоÑ\80гаÑ\88 Ð½Ð¸Ð¹Ñ\81а Ð½ÐµÐºÑ\8a Ð³Ð¾Ð¹Ñ\82Ñ\83Ñ\88 Ñ\85илаÑ\80ан.\n\nТидам Ð±Ðµ Ñ\85Ñ\8cалÑ\85алеÑ\80а Ð°Ð³Ó\80он Ñ\86Ó\80е â\80\98â\80\99â\80\99Ñ\85ийÑ\86алÑ\83Ñ\80 Ñ\8fÑ\86â\80\99â\80\99â\80\99 Ð¸Ñ\88Ñ\82Ñ\82а Ñ\86Ó\80е Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80о Ð¹Ð¾Ð»Ñ\83Ñ\88 ÐµÐ»Ð°Ñ\85Ñ\8c. Ð®ÐºÑ\8aаÑ\80даккÑ\85аÑ\80: Ð¹Ð¾Ð»Ñ\83Ñ\88 Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80о ÐºÑ\85оÑ\8cÑ\87Ñ\83Ñ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80аг ÐµÐ»Ð°Ñ\85Ñ\8c, Ñ\8f ÐµÑ\81а ÐµÐ»Ð°Ñ\85Ñ\8c Ð°, Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аме Ð¸Ñ\81Ñ\82оÑ\80и Ñ\8fÑ\86аÑ\85Ñ\8c Ð°.\n\nÐ\98 Ð±Ð¾Ñ\85Ñ\83Ñ\80г Ð´Ñ\83 Ñ\88Ñ\83н Ð°Ð³Ó\80онан Ñ\86Ó\80е Ñ\8eÑ\85а Ð° Ñ\85Ñ\8cалÑ\85а Ñ\85иллаÑ\80гÑ\87Ñ\83нтӀе хийца йиш ю, амма йолуш йолу агӀо дӀаяккха йиш яц.\n\n'''ДӀАХЬЕДАР!'''\n\nЦӀе хийцар бахьнехь гӀаръяьлла агӀонашна дукха дагахь боцу хийцамаш хила тарло. Цундела цӀе хийцале шеш хила тарлучу тӀехьонашах кхета аьлла тешна хила.",
+       "movepagetext": "Ð\91Ñ\83Ñ\85аÑ\85Ñ\8c Ð¹Ð¾Ð»Ñ\83 Ñ\84оÑ\80манÑ\86а Ð°Ð³Ó\80он Ñ\86Ó\80е Ñ\85ийÑ\86ало. Ð¦Ñ\83л Ñ\81овнаÑ\85 Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аман Ñ\82епÑ\82аÑ\80 ÐºÑ\85оÑ\8cÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82е Ð´Ð¾ÐºÐºÑ\85а. Ð¥Ñ\8cалÑ\85алеÑ\80а Ñ\86Ó\80аÑ\80аÑ\85Ñ\8c Ñ\85иÑ\80Ñ\8aÑ\8e ÐºÐµÑ\80ла ÐºÑ\85оÑ\8cллина Ð°Ð³Ó\80онан Ñ\85Ñ\8cажоÑ\80г.\n\nÐ¥Ñ\8cовÑ\81алаÑ\88 [[Special:DoubleRedirects|Ñ\88алÑ\85а]] Ð° [[Special:BrokenRedirects|йоÑ\85на Ñ\85Ñ\8cажоÑ\80гаÑ\88]] Ñ\8eй Ñ\82еÑ\85Ñ\8c Ð°Ñ\8cлла.\n\nШÑ\83 Ð¶Ð¾Ñ\8cпеÑ\85Ñ\8c Ð´Ñ\83 Ñ\85Ñ\8cажоÑ\80гаÑ\88 Ð½Ð¸Ð¹Ñ\81а Ð½ÐµÐºÑ\8a Ð³Ð¾Ð¹Ñ\82Ñ\83Ñ\88 Ñ\85илаÑ\80ан.\n\nТидам Ð±Ðµ Ñ\85Ñ\8cалÑ\85алеÑ\80а Ð°Ð³Ó\80он Ñ\86Ó\80е â\80\98â\80\99â\80\99Ñ\85ийÑ\86алÑ\83Ñ\80 Ñ\8fÑ\86â\80\99â\80\99â\80\99 Ð¸Ñ\88Ñ\82Ñ\82а Ñ\86Ó\80е Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80о Ð¹Ð¾Ð»Ñ\83Ñ\88 ÐµÐ»Ð°Ñ\85Ñ\8c. Ð®ÐºÑ\8aаÑ\80даккÑ\85аÑ\80: Ð¹Ð¾Ð»Ñ\83Ñ\88 Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80о ÐºÑ\85оÑ\8cÑ\87Ñ\83Ñ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80г ÐµÐ»Ð°Ñ\85Ñ\8c, Ñ\8f ÐµÑ\81а ÐµÐ»Ð°Ñ\85Ñ\8c Ð°, Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аме Ð¸Ñ\81Ñ\82оÑ\80и Ñ\8fÑ\86аÑ\85Ñ\8c Ð°.\n\nÐ\98 Ð±Ð¾Ñ\85Ñ\83Ñ\80г Ð´Ñ\83 Ñ\88Ñ\83н Ð°Ð³Ó\80онан Ñ\86Ó\80е Ñ\8eÑ\85а Ð° Ñ\85Ñ\8cалÑ\85а Ñ\85иллаÑ\87Ñ\83н тӀе хийца йиш ю, амма йолуш йолу агӀо дӀаяккха йиш яц.\n\n'''ДӀАХЬЕДАР!'''\n\nЦӀе хийцар бахьнехь гӀаръяьлла агӀонашна дукха дагахь боцу хийцамаш хила тарло. Цундела цӀе хийцале шеш хила тарлучу тӀехьонашах кхета аьлла тешна хила.",
+       "movepagetext-noredirectfixer": "Ð\91Ñ\83Ñ\85аÑ\85Ñ\8c Ð¹Ð¾Ð»Ñ\83 Ñ\84оÑ\80манÑ\86а Ð°Ð³Ó\80он Ñ\86Ó\80е Ñ\85ийÑ\86ало. Ð¦Ñ\83л Ñ\81овнаÑ\85 Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аман Ñ\82епÑ\82аÑ\80 ÐºÑ\85оÑ\8cÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82е Ð´Ð¾ÐºÐºÑ\85а. Ð¥Ñ\8cалÑ\85алеÑ\80а Ñ\86Ó\80аÑ\80аÑ\85Ñ\8c Ñ\85иÑ\80Ñ\8aÑ\8e ÐºÐµÑ\80ла ÐºÑ\85оÑ\8cллина Ð°Ð³Ó\80онан Ñ\85Ñ\8cажоÑ\80г.\n\nÐ¥Ñ\8cовÑ\81алаÑ\88 [[Special:DoubleRedirects|Ñ\88алÑ\85а]] Ð° [[Special:BrokenRedirects|йоÑ\85на Ñ\85Ñ\8cажоÑ\80гаÑ\88]] Ñ\8eй Ñ\82еÑ\85Ñ\8c Ð°Ñ\8cлла.\n\nШÑ\83 Ð¶Ð¾Ñ\8cпеÑ\85Ñ\8c Ð´Ñ\83 Ñ\85Ñ\8cажоÑ\80гаÑ\88 Ð½Ð¸Ð¹Ñ\81а Ð½ÐµÐºÑ\8a Ð³Ð¾Ð¹Ñ\82Ñ\83Ñ\88 Ñ\85илаÑ\80ан.\n\nТидам Ð±Ðµ Ñ\85Ñ\8cалÑ\85алеÑ\80а Ð°Ð³Ó\80он Ñ\86Ó\80е â\80\98â\80\99â\80\99Ñ\85ийÑ\86алÑ\83Ñ\80 Ñ\8fÑ\86â\80\99â\80\99â\80\99 Ð¸Ñ\88Ñ\82Ñ\82а Ñ\86Ó\80е Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80о Ð¹Ð¾Ð»Ñ\83Ñ\88 ÐµÐ»Ð°Ñ\85Ñ\8c. Ð®ÐºÑ\8aаÑ\80даккÑ\85аÑ\80: Ð¹Ð¾Ð»Ñ\83Ñ\88 Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80о ÐºÑ\85оÑ\8cÑ\87Ñ\83Ñ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80г ÐµÐ»Ð°Ñ\85Ñ\8c, Ñ\8f ÐµÑ\81а ÐµÐ»Ð°Ñ\85Ñ\8c Ð°, Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аме Ð¸Ñ\81Ñ\82оÑ\80и Ñ\8fÑ\86аÑ\85Ñ\8c Ð°.\n\nÐ\98 Ð±Ð¾Ñ\85Ñ\83Ñ\80г Ð´Ñ\83 Ñ\88Ñ\83н Ð°Ð³Ó\80онан Ñ\86Ó\80е Ñ\8eÑ\85а Ð° Ñ\85Ñ\8cалÑ\85а Ñ\85иллаÑ\87Ñ\83н тӀе хийца йиш ю, амма йолуш йолу агӀо дӀаяккха йиш яц.\n\n'''ДӀАХЬЕДАР!'''\n\nЦӀе хийцар бахьнехь гӀаръяьлла агӀонашна дукха дагахь боцу хийцамаш хила тарло. Цундела цӀе хийцале шеш хила тарлучу тӀехьонашах кхета аьлла тешна хила.",
        "movepagetalktext": "ТӀе хӀоьттина йолу дийцаре агӀо ишта цӀе хийцина хира ю, '''цхьа йолу ханчохь, маца:'''\n\n*Йаьсса йоцу дийцаре агӀо йолуш ю оцу цӀарца йа\n*Ахьа къастаман харжам цабиняхь а къастам хӀотточехь.\n\nИшта чу ханчохь, ахьа дехьа яккха йезар ю йа куьйга хӀоттайар, нагахь иза хьашт йалахь.",
-       "movearticle": "ЦӀе хийца хӀокху агӀон",
+       "movearticle": "ЦӀе хийца агӀон",
        "moveuserpage-warning": "'''Тергам бе.''' Хьо декъашхочун агӀона цӀе хийца гӀерта. Дехар до, тергам бе, декъашхочун агӀона цӀе бен хийца лур яц, декъашхочун дӀаяздаран цӀе хийца лур яц.",
        "movecategorypage-warning": "<strong>ДӀахьедар:</strong> Хьо категорин агӀон цӀе хийца гӀерта. Дехар до, терго йе, хӀокху агӀона бен цӀе хуьйцур яц, шира чу категори чура массо агӀонаш керла категори чу йохур <em>яц</em>.",
        "movenologintext": "АгӀона цӀе хийца [[Special:UserLogin|системин чугӀо]].",
        "protectedpagemovewarning": "'''ДӀахьедар.''' ХӀара агӀо гӀаролла йина ю; цӀе хийца я нисйа а бакъо йолуш куьйгалхой бе бац.\nЛахахьа тептаро балийна тӀаьхьаралера дӀаязбина хаам:",
        "semiprotectedpagemovewarning": "'''ДӀахьедо.''' ХӀара агӀо гӀаролла йина ю; дӀабазбиначу декъашхошка бе цӀе хийцалуш яц.\nЛахахьа тептаро балийна тӀаьхьаралера дӀаязбина хаам:",
        "export": "АгӀонаш араяхар",
-       "exporttext": "ШÑ\83Ñ\8cга Ð´Ð°Ð»Ñ\83Ñ\80 Ð´Ñ\83 ÐºÑ\85еÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82еÑ\80а Ñ\87Ñ\83даÑ\85аÑ\80Ñ\88, Ð¹Ð¾Ð·Ð° Ð° Ñ\85ийÑ\86аме Ñ\82епÑ\82аÑ\80Ñ\88 Ð±Ð¸Ð»Ð³Ð°Ð»Ð»Ð° Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80онаÑ\88 Ð¹Ð° Ð³Ñ\83лдина Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80онаÑ\88 Ñ\85Ó\80окÑ\85 XML Ð±Ð°Ñ\80амÑ\86а, Ñ\8eÑ\85а Ñ\82Ó\80Ñ\8fÑ\85Ñ\8cа Ñ\87Ñ\83Ñ\80а [[Special:Import|Ñ\85Ñ\8cаÑ\8dÑ\86алÑ\83Ñ\80долÑ\88]] ÐºÑ\85еÑ\87Ñ\83 Ð²Ð¸ÐºÐ¸-Ñ\85Ñ\8cалÑ\85ен, Ð±Ð¾Ð»Ñ\85 Ð±ÐµÑ\88 Ð¹Ð¾Ð»Ñ\83 Ñ\85lокÑ\85Ñ\83 MediaWiki Ð³lиÑ\80Ñ\81аÑ\86а.\n\nÐ\9aÑ\85еÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82еÑ\80а Ñ\8fззамаÑ\88 Ñ\87Ñ\83йаÑ\85а, Ñ\87Ñ\83Ñ\8fзйе Ñ\86Ó\80е Ñ\82адеÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82е, Ñ\86Ó\80Ñ\85Ñ\8cа Ð¼Ð¾Ð³Ó\80ан Ñ\86Ó\80е Ð¼Ð¾Ð³Ó\80аÑ\80Ñ\88каÑ\85Ñ\8c, Ñ\8eÑ\85а Ñ\85аÑ\80жа Ð»Ð°Ñ\8cи Ñ\88Ñ\83на Ð\9aÑ\85еÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82еÑ\80 Ñ\87Ñ\83йаÑ\85а Ð¼Ð°Ñ\81Ñ\81о Ñ\8fззамаÑ\88на Ð¸Ñ\81Ñ\82оÑ\80и Ñ\85ийÑ\86амбаÑ\80Ñ\88 Ð¹Ð° Ñ\82Ó\80Ñ\8fÑ\85Ñ\8cаÑ\80алеÑ\80а Ñ\8fззамна Ð±Ð°Ñ\88Ñ\85о.\n\nШÑ\83Ñ\8cга ÐºÑ\85и Ð´Ð°Ð»Ð°Ð½Ð´ÐµÑ\80г, Ð»ÐµÐ»Ð°ÐµÑ\88 Ð¹Ð¾Ð»Ñ\83 Ð¼ÐµÑ\82Ñ\82иг ÐºÑ\8aаÑ\81Ñ\82аман Ð¼Ð°Ñ\88ан Ñ\85Ñ\8cажоÑ\80аг ÐºÑ\85еÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82еÑ\80 Ñ\87Ñ\83даÑ\85а Ñ\82Ó\80аÑ\8cÑ\85Ñ\8cаÑ\80леÑ\80аÑ\87Ñ\83 Ð±Ð°Ñ\88Ñ\85он Ñ\8fззамаÑ\88. Ð\9cаÑ\81ала Ð¾Ñ\86Ñ\83 Ñ\8fззамна [[{{MediaWiki:Mainpage}}]] Ñ\85Ó\80аÑ\80а Ñ\85иÑ\80а Ñ\8e Ñ\85Ñ\8cажоÑ\80аг [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]].",
+       "exporttext": "ШÑ\83Ñ\8cга Ð´Ð°Ð»Ñ\83Ñ\80 Ð´Ñ\83 ÐºÑ\85еÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82еÑ\80а Ñ\87Ñ\83даÑ\85аÑ\80Ñ\88, Ð¹Ð¾Ð·Ð° Ð° Ñ\85ийÑ\86аме Ñ\82епÑ\82аÑ\80Ñ\88 Ð±Ð¸Ð»Ð³Ð°Ð»Ð»Ð° Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80онаÑ\88 Ð¹Ð° Ð³Ñ\83лдина Ð¹Ð¾Ð»Ñ\83 Ð°Ð³Ó\80онаÑ\88 Ñ\85Ó\80окÑ\85 XML Ð±Ð°Ñ\80амÑ\86а, Ñ\8eÑ\85а Ñ\82Ó\80Ñ\8fÑ\85Ñ\8cа Ñ\87Ñ\83Ñ\80а [[Special:Import|Ñ\85Ñ\8cаÑ\8dÑ\86алÑ\83Ñ\80долÑ\88]] ÐºÑ\85еÑ\87Ñ\83 Ð²Ð¸ÐºÐ¸-Ñ\85Ñ\8cалÑ\85ен, Ð±Ð¾Ð»Ñ\85 Ð±ÐµÑ\88 Ð¹Ð¾Ð»Ñ\83 Ñ\85lокÑ\85Ñ\83 MediaWiki Ð³lиÑ\80Ñ\81аÑ\86а.\n\nÐ\9aÑ\85еÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82еÑ\80а Ñ\8fззамаÑ\88 Ñ\87Ñ\83йаÑ\85а, Ñ\87Ñ\83Ñ\8fзйе Ñ\86Ó\80е Ñ\82адеÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82е, Ñ\86Ó\80Ñ\85Ñ\8cа Ð¼Ð¾Ð³Ó\80ан Ñ\86Ó\80е Ð¼Ð¾Ð³Ó\80аÑ\80Ñ\88каÑ\85Ñ\8c, Ñ\8eÑ\85а Ñ\85аÑ\80жа Ð»Ð°Ñ\8cи Ñ\88Ñ\83на Ð\9aÑ\85еÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82еÑ\80 Ñ\87Ñ\83йаÑ\85а Ð¼Ð°Ñ\81Ñ\81о Ñ\8fззамаÑ\88на Ð¸Ñ\81Ñ\82оÑ\80и Ñ\85ийÑ\86амбаÑ\80Ñ\88 Ð¹Ð° Ñ\82Ó\80Ñ\8fÑ\85Ñ\8cаÑ\80алеÑ\80а Ñ\8fззамна Ð±Ð°Ñ\88Ñ\85о.\n\nШÑ\83Ñ\8cга ÐºÑ\85и Ð´Ð°Ð»Ð°Ð½Ð´ÐµÑ\80г, Ð»ÐµÐ»Ð°ÐµÑ\88 Ð¹Ð¾Ð»Ñ\83 Ð¼ÐµÑ\82Ñ\82иг ÐºÑ\8aаÑ\81Ñ\82аман Ð¼Ð°Ñ\88ан Ñ\85Ñ\8cажоÑ\80г ÐºÑ\85еÑ\87Ñ\83 Ð¼ÐµÑ\82Ñ\82еÑ\80 Ñ\87Ñ\83даÑ\85а Ñ\82Ó\80аÑ\8cÑ\85Ñ\8cаÑ\80леÑ\80аÑ\87Ñ\83 Ð±Ð°Ñ\88Ñ\85он Ñ\8fззамаÑ\88. Ð\9cаÑ\81ала Ð¾Ñ\86Ñ\83 Ñ\8fззамна [[{{MediaWiki:Mainpage}}]] Ñ\85Ó\80аÑ\80а Ñ\85иÑ\80а Ñ\8e Ñ\85Ñ\8cажоÑ\80г [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]].",
        "exportall": "Массо агӀонаш экспорт ян",
        "exportcuronly": "Карара верси бен юкъа ма тоха, юзийна хьалхалерра истори йоцуш",
        "export-submit": "Экспорт ян",
        "tooltip-t-upload": "Чуйаха файлаш",
        "tooltip-t-specialpages": "Белха агӀонанийн могӀам",
        "tooltip-t-print": "Хlокху агlонна зорба туху башхо",
-       "tooltip-t-permalink": "Ð\94аима Ð¹Ð¾Ð»Ñ\83 Ñ\85Ñ\8cажоÑ\80аг Ñ\85Ó\80окÑ\85Ñ\83 Ð±Ð°Ñ\88Ñ\85а Ð°Ð³Ó\80онна",
+       "tooltip-t-permalink": "Даима йолу хьажорг хӀокху башха агӀонна",
        "tooltip-ca-nstab-main": "Яззамна чулацам",
        "tooltip-ca-nstab-user": "ХӀора декъашхочун долахь йолу агӀо ю",
        "tooltip-ca-nstab-media": "Медиа-файл",
        "creditspage": "Баркаллаш",
        "nocredits": "Бац декъашхойн могӀам хӀокху яззамца",
        "spamprotectiontitle": "Совбиларна литтар",
-       "spamprotectiontext": "Ð¥Ñ\8cо Ð´Ó\80аÑ\8fзÑ\8aÑ\8fн Ð³Ó\80еÑ\80Ñ\82а Ð°Ð³Ó\80о Ñ\81пам-лиÑ\82Ñ\82аÑ\80о Ð´Ó\80акÑ\8aоÑ\8cвлина.\nЦÑ\83на Ð±Ð°Ñ\85Ñ\8cна Ñ\85ила Ñ\82ам Ð±Ñ\83 Ð°Ð³Ó\80она Ñ\87оÑ\85Ñ\8c Ð·Ñ\83лам Ð»Ð¸Ñ\82Ñ\82аÑ\80ан Ñ\87Ñ\83Ñ\82оÑ\8cÑ\85на Ð¹Ð¾Ð»Ñ\83 Ñ\85Ñ\8cажоÑ\80аг Ñ\85илаÑ\80.",
+       "spamprotectiontext": "Хьо дӀаязъян гӀерта агӀо спам-литтаро дӀакъоьвлина.\nЦуна бахьна хила там бу агӀона чохь зулам литтаран чутоьхна йолу хьажорг хилар.",
        "spambot_username": "Спам дӀацӀаняр",
        "pageinfo-title": "Хаамаш цу «$1»",
        "pageinfo-not-current": "Шира версийн оьцу хааме хьажа таро яц.",
        "newimages-legend": "Литтар",
        "newimages-showbots": "Гайта боташ чуяьхна файлаш",
        "noimages": "Суьрташ дац.",
-       "ilsubmit": "Лаха",
+       "ilsubmit": "Лахар",
        "bydate": "терахьашца",
        "sp-newimages-showfrom": "Гайта керла файлаш $2, $1 тӀера дуьйна",
        "seconds-abbrev": "$1 оцу",
        "saturday-at": "шот дийнахь $1",
        "sunday-at": "кӀиранан дийнахь $1",
        "yesterday-at": "селхана $1 даьлча",
-       "bad_image_list": "Ð\91аÑ\80ам Ñ\85ила Ð±ÐµÐ·Ð° Ð¸Ñ\88Ñ\82а:\n\nÐ\9bоÑ\80аÑ\88 Ñ\85иÑ\80а Ñ\8e Ð¼Ð¾Ð³Ó\80амÑ\8fÑ\85Ñ\8c Ð¹Ð¾Ð»Ñ\83 Ñ\85Ó\80Ñ\83мнаÑ\88 (могÓ\80ийн, Ð¹Ð¾Ð»Ð° Ð»Ñ\83Ñ\88 Ð¹Ð¾Ð»Ñ\83 Ñ\81имвол Ñ\82Ó\80иÑ\80а *).\nÐ\94Ñ\83Ñ\8cÑ\85Ñ\85Ñ\8cаÑ\80алеÑ\80а Ñ\85Ñ\8cажоÑ\80аг Ð¼Ð°Ð³Ó\80аÑ\80Ñ\88и Ñ\85ила Ð±ÐµÐ·Ð° Ñ\85Ñ\8cажоÑ\80аг ÐºÑ\85Ñ\83 Ñ\86амагдо Ñ\81Ñ\83Ñ\80Ñ\82 Ð´Ñ\83Ñ\8cлаÑ\87е.\nТÓ\80Ñ\8fÑ\85Ñ\8cа Ð¹Ð¾Ð³Ó\80Ñ\83Ñ\88 Ð¹Ð¾Ð»Ñ\83 Ñ\85Ñ\8cажоÑ\80аг оцу могӀарехь хира ю магóш, билгалла аьлча яззамаш долуче, сурт хьаллаточехь.",
+       "bad_image_list": "Ð\91аÑ\80ам Ñ\85ила Ð±ÐµÐ·Ð° Ð¸Ñ\88Ñ\82а:\n\nÐ\9bоÑ\80аÑ\88 Ñ\85иÑ\80а Ñ\8e Ð¼Ð¾Ð³Ó\80амÑ\8fÑ\85Ñ\8c Ð¹Ð¾Ð»Ñ\83 Ñ\85Ó\80Ñ\83мнаÑ\88 (могÓ\80ийн, Ð¹Ð¾Ð»Ð° Ð»Ñ\83Ñ\88 Ð¹Ð¾Ð»Ñ\83 Ñ\81имвол Ñ\82Ó\80иÑ\80а *).\nÐ\94Ñ\83Ñ\8cÑ\85Ñ\85Ñ\8cаÑ\80алеÑ\80а Ñ\85Ñ\8cажоÑ\80г Ð¼Ð°Ð³Ó\80анийн Ñ\85ила Ð±ÐµÐ·Ð° Ñ\85Ñ\8cажоÑ\80г ÐºÑ\85Ñ\83 Ñ\86амагдо Ñ\81Ñ\83Ñ\80Ñ\82 Ð´Ñ\83Ñ\8cлаÑ\87е.\nТÓ\80Ñ\8fÑ\85Ñ\8cа Ð¹Ð¾Ð³Ó\80Ñ\83Ñ\88 Ð¹Ð¾Ð»Ñ\83 Ñ\85Ñ\8cажоÑ\80г оцу могӀарехь хира ю магóш, билгалла аьлча яззамаш долуче, сурт хьаллаточехь.",
        "metadata": "Метахаамаш",
        "metadata-help": "ХӀокху файлаца кхин тӀе хаам бу, даиман чуйоккхуш йолу терахьца чоьнашца йа тӀейоккхучуьнца. Нагахь файлан тӀаьхьа хийцам биняхь, тӀаккха цӀхьаболу барам цӀхьаьна ца ба мега хӀинцалера суьртаца.",
        "metadata-expand": "Гайта кхин тlе болу хаам",
        "redirect-legend": "Файлан я агӀона тӀера дӀасхьажор",
        "redirect-summary": "ХӀара агӀо лело йиш ю файлан я агӀона тӀера дӀасхьажош.",
        "redirect-submit": "Дехьа гӀо",
-       "redirect-lookup": "Лаха:",
+       "redirect-lookup": "Лахар:",
        "redirect-value": "МаьӀна:",
        "redirect-user": "Декъашхочун ID",
        "redirect-page": "АгӀона ID",
        "fileduplicatesearch-summary": "Лаха цхьатера йолу файлаш хэш-кодаца.",
        "fileduplicatesearch-legend": "Цхьатера ерш лахар",
        "fileduplicatesearch-filename": "Файлан цӀе:",
-       "fileduplicatesearch-submit": "Лаха",
+       "fileduplicatesearch-submit": "Лахар",
        "fileduplicatesearch-info": "$1 × $2 пиксель<br />Файлан барам: $3<br />MIME-тайп: $4",
        "fileduplicatesearch-result-1": "«$1» файлах тера хӀума яц.",
        "fileduplicatesearch-noresults": "ЦӀе «$1» йолуш файл цакарий.",
index 4407ee3..7df6b42 100644 (file)
@@ -53,7 +53,7 @@
        "tog-shownumberswatching": "Zobrazovat počet sledujících uživatelů",
        "tog-oldsig": "Stávající podpis:",
        "tog-fancysig": "Používat v podpisu wikitext (bez automatického odkazu)",
-       "tog-uselivepreview": "Používat rychlý náhled (experimentální)",
+       "tog-uselivepreview": "Používat rychlý náhled",
        "tog-forceeditsummary": "Upozornit, když nevyplním shrnutí editace",
        "tog-watchlisthideown": "Na seznamu sledovaných stránek skrýt moje editace",
        "tog-watchlisthidebots": "Na seznamu sledovaných stránek skrýt editace botů",
        "anoneditwarning": "'''Varování:''' Nejste přihlášen(a). Pokud uložíte jakoukoli editaci, bude vaše IP adresa zveřejněna v historii této stránky. Pokud se <strong>[$1 přihlásíte]</strong> nebo si <strong>[$2 vytvoříte účet]</strong>, budou vaše editace připsány vašemu uživatelskému jménu a získáte i další výhody.",
        "anonpreviewwarning": "''Nejste přihlášen(a). Uložením zveřejníte svou IP adresu v historii této stránky.''",
        "missingsummary": "'''Připomenutí:''' Nezadali jste shrnutí editace. Pokud ještě jednou kliknete na Uložit změny, bude vaše editace zapsána bez shrnutí.",
+       "selfredirect": "<strong>Upozornění:</strong> Vytváříte přesměrování na týž článek. Pokud ještě jednou kliknete na „{{int:savearticle}}“, bude přesměrování vytvořeno.",
        "missingcommenttext": "Zadejte komentář",
        "missingcommentheader": "'''Připomenutí:''' Nezadali jste předmět/nadpis pro tento komentář.\nPokud ještě jednou kliknete na „{{int:savearticle}}“, bude vaše editace zapsána i bez toho.",
        "summary-preview": "Náhled shrnutí:",
        "log-name-pagelang": "Kniha změn jazyků",
        "log-description-pagelang": "Toto je protokol změn jazyků stránek.",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|změnil|změnila}} jazyk stránky $3 z $4 na $5.",
-       "default-skin-not-found": "Jejda! Výchozí vzhled vaší wiki, definovaný ve <code dir=\"ltr\">$wgDefaultSkin</code> jako <code>$1</code>, není dostupný.\n\nVaše instalace zřejmě obsahuje následující vzhledy. Informace o tom, jak je povolit a vybrat výchozí, najdete na stránce [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration/cs Manual:Skin configuration].\n\n$2\n\n; Pokud jste právě nainstalovali MediaWiki:\n: Zřejmě jste instalovali z gitu nebo nějakým jiným způsobem přímo ze zdrojového kódu. Tak to má fungovat. Zkuste nainstalovat některé vzhledy ze [https://www.mediawiki.org/wiki/Category:All_skins seznamu vzhledů na mediawiki.org] buď:\n:* Můžete si stáhnout [https://www.mediawiki.org/wiki/Download/cs instalace v tarballu], která zahrnuje několik vzhledů a rozšíření, a vykopírovat si z ní adresář <code dir=\"ltr\">skins/</code>, nebo\n:* Nebo si můžete gitem naklonovat jeden z repozitářů <code>mediawiki/skins/*</code> do adresáře <code>skins/</code> ve vaší instalaci MediaWiki.\n: Pokud jste vývojářem MediaWiki, nemělo by to nijak narušit váš gitový repozitář.\n\n; Pokud jste právě aktualizovali MediaWiki:\n: MediaWiki 1.24 a novější již automaticky nepovolují nainstalované vzhledy (vizte [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_autodiscovery/cs Manual:Skin autodiscovery]). Pro povolení všech právě nainstalovaných vzhledů vlepte následující řádky do <code>LocalSettings.php</code>:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Pokud jste právě upravili <code>LocalSettings.php</code>:\n: Překontrolujte případné překlepy v názvech vzhledů.",
-       "default-skin-not-found-no-skins": "Jejda! Výchozí vzhled vaší wiki, definovaný ve <code dir=\"ltr\">$wgDefaultSkin</code> jako <code>$1</code>, není dostupný.\n\nNemáte nainstalovány žádné vzhledy.\n\n; Pokud jste právě nainstalovali nebo aktualizovali MediaWiki:\n: Zřejmě jste instalovali z gitu nebo nějakým jiným způsobem přímo ze zdrojového kódu. Tak to má fungovat. MediaWiki 1.24 a novější již v hlavním repozitáři neobsahují žádné vzhledy. Zkuste nainstalovat některé vzhledy ze [https://www.mediawiki.org/wiki/Category:All_skins seznamu vzhledů na mediawiki.org] buď:\n:* Můžete si stáhnout [https://www.mediawiki.org/wiki/Download/cs instalace v tarballu], která zahrnuje několik vzhledů a rozšíření, a vykopírovat si z ní adresář <code>skins/</code>, nebo\n:* Nebo si můžete gitem naklonovat jeden z repozitářů <code>mediawiki/skins/*</code> do adresáře <code dir=\"ltr\">skins/</code> ve vaší instalaci MediaWiki.\n: Pokud jste vývojářem MediaWiki, nemělo by to nijak narušit váš gitový repozitář. Informace o tom, jak povolit vzhledy a vybrat výchozí, najdete na stránce [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration/cs Manual:Skin configuration].",
+       "default-skin-not-found": "Jejda! Výchozí vzhled vaší wiki, definovaný ve <code dir=\"ltr\">$wgDefaultSkin</code> jako <code>$1</code>, není dostupný.\n\nVaše instalace zřejmě obsahuje následující vzhledy. Informace o tom, jak je povolit a vybrat výchozí, najdete na stránce [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration/cs Manual:Skin configuration].\n\n$2\n\n; Pokud jste právě nainstalovali MediaWiki:\n: Zřejmě jste instalovali z gitu nebo nějakým jiným způsobem přímo ze zdrojového kódu. Tak to má fungovat. Zkuste nainstalovat některé vzhledy ze [https://www.mediawiki.org/wiki/Category:All_skins seznamu vzhledů na mediawiki.org] buď:\n:* Můžete si stáhnout [https://www.mediawiki.org/wiki/Download/cs instalaci v tarballu], která zahrnuje několik vzhledů a rozšíření, a vykopírovat si z ní adresář <code dir=\"ltr\">skins/</code>.\n:* Nebo si můžete stáhnout tarbally jednotlivých vzhledů z [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Nebo si můžete gitem naklonovat jeden z repozitářů <code>mediawiki/skins/*</code> do adresáře <code>skins/</code> ve vaší instalaci MediaWiki.\n: Pokud jste vývojářem MediaWiki, nemělo by to nijak narušit váš gitový repozitář.\n\n; Pokud jste právě aktualizovali MediaWiki:\n: MediaWiki 1.24 a novější již automaticky nepovolují nainstalované vzhledy (vizte [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_autodiscovery/cs Manual:Skin autodiscovery]). Pro povolení všech právě nainstalovaných vzhledů vlepte následující řádky do <code>LocalSettings.php</code>:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Pokud jste právě upravili <code>LocalSettings.php</code>:\n: Překontrolujte případné překlepy v názvech vzhledů.",
+       "default-skin-not-found-no-skins": "Jejda! Výchozí vzhled vaší wiki, definovaný ve <code dir=\"ltr\">$wgDefaultSkin</code> jako <code>$1</code>, není dostupný.\n\nNemáte nainstalovány žádné vzhledy.\n\n; Pokud jste právě nainstalovali nebo aktualizovali MediaWiki:\n: Zřejmě jste instalovali z gitu nebo nějakým jiným způsobem přímo ze zdrojového kódu. Tak to má fungovat. MediaWiki 1.24 a novější již v hlavním repozitáři neobsahují žádné vzhledy. Zkuste nainstalovat některé vzhledy ze [https://www.mediawiki.org/wiki/Category:All_skins seznamu vzhledů na mediawiki.org] buď:\n:* Můžete si stáhnout [https://www.mediawiki.org/wiki/Download/cs instalaci v tarballu], která zahrnuje několik vzhledů a rozšíření, a vykopírovat si z ní adresář <code>skins/</code>.\n:* Nebo si můžete stáhnout tarbally jednotlivých vzhledů z [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Nebo si můžete gitem naklonovat jeden z repozitářů <code>mediawiki/skins/*</code> do adresáře <code dir=\"ltr\">skins/</code> ve vaší instalaci MediaWiki.\n: Pokud jste vývojářem MediaWiki, nemělo by to nijak narušit váš gitový repozitář. Informace o tom, jak povolit vzhledy a vybrat výchozí, najdete na stránce [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration/cs Manual:Skin configuration].",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (povolený)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''zakázaný''')",
        "mediastatistics": "Statistika souborů",
index a670048..b0200ec 100644 (file)
        "tog-shownumberswatching": "Anzahl der beobachtenden Benutzer anzeigen",
        "tog-oldsig": "Vorhandene Signatur:",
        "tog-fancysig": "Signatur als Wikitext behandeln (ohne automatische Verlinkung)",
-       "tog-uselivepreview": "Vorschau sofort anzeigen (experimentell)",
+       "tog-uselivepreview": "Vorschau sofort anzeigen",
        "tog-forceeditsummary": "Warnen, sofern beim Speichern die Zusammenfassung fehlt",
        "tog-watchlisthideown": "Eigene Bearbeitungen in der Beobachtungsliste ausblenden",
        "tog-watchlisthidebots": "Bearbeitungen durch Bots in der Beobachtungsliste ausblenden",
        "anoneditwarning": "<strong>Warnung:</strong> Du bist nicht angemeldet. Deine IP-Adresse wird öffentlich sichtbar, falls du Bearbeitungen durchführst. Wenn du dich <strong>[$1 anmeldest]</strong> oder <strong>[$2 ein Benutzerkonto erstellst]</strong>, werden deine Bearbeitungen zusammen mit anderen Beiträgen deinem Benutzernamen zugeordnet.",
        "anonpreviewwarning": "''Du bist nicht angemeldet. Beim Speichern wird deine IP-Adresse in der Versionsgeschichte aufgezeichnet.''",
        "missingsummary": "'''Hinweis:''' Du hast keine Zusammenfassung angegeben. Wenn du erneut auf „{{int:savearticle}}“ klickst, wird deine Änderung ohne Zusammenfassung übernommen.",
+       "selfredirect": "<strong>Warnung:</strong> Du erstellst eine Weiterleitung auf den gleichen Artikel.\nWenn du erneut auf „{{int:savearticle}}“ klickst, wird die Weiterleitung erstellt.",
        "missingcommenttext": "Dein Abschnitt enthält keinen Text.",
        "missingcommentheader": "'''Achtung:''' Du hast kein Betreff/Überschrift eingegeben. Wenn du erneut auf „{{int:savearticle}}“ klickst, wird deine Bearbeitung ohne Überschrift gespeichert.",
        "summary-preview": "Vorschau der Zusammenfassungszeile:",
        "ninterwikis": "{{PLURAL:$1|Ein Interwikilink|$1 Interwikilinks}}",
        "nlinks": "{{PLURAL:$1|1 Link|$1 Links}}",
        "nmembers": "{{PLURAL:$1|1 Eintrag|$1 Einträge}}",
-       "nmemberschanged": "$1 → {{PLURAL:$2|Ein Mitglied|$2 Mitglieder}}",
+       "nmemberschanged": "$1 → $2 {{PLURAL:$2|Mitglied|Mitglieder}}",
        "nrevisions": "{{PLURAL:$1|1 Bearbeitung|$1 Bearbeitungen}}",
        "nviews": "{{PLURAL:$1|1 Abfrage|$1 Abfragen}}",
        "nimagelinks": "Verwendet auf {{PLURAL:$1|einer Seite|$1 Seiten}}",
index 0f4bca7..82e3fdf 100644 (file)
@@ -33,7 +33,7 @@
        "tog-shownumberswatching": "Fà vèder al nómer ed j utèint che gh'àn la pàgina sòta uservasiòun",
        "tog-oldsig": "La fîrma 'd adèsa",
        "tog-fancysig": "Trâta la fîrma cme wikitèst (sèinsa colegamèint avtomâtich)",
-       "tog-uselivepreview": "Permèt la funsiòun \"Live preview\" (guêrda préma 'd salvêr dal vîv - in sperimèint)",
+       "tog-uselivepreview": "Permèt la funsiòun \"Live preview\" (guêrda préma 'd salvêr in dirèta)",
        "tog-forceeditsummary": "Dmânda s'l'è vèira che al câmp argumèint l' é vōd",
        "tog-watchlisthideown": "Lōga al mé mudéfichi int i  tgnû 'd ôc specêl",
        "tog-watchlisthidebots": "Lōga al mudéfichi di bot int i tgnû 'd ôc specêl",
        "anoneditwarning": "<strong>Atèinti:</strong> An n'é mìa stê fât l'ingrès. S' ét farê dal mudéfichi al tó indirés IP al srà vést da tót. Se <strong>[$1 và dèinter]</strong> o <strong>[$2 fà 'n' utèinsa]</strong>, al tô mudéfichi a srân sgnêdi al tó nòm utèint, insèm a êter benefési.",
        "anonpreviewwarning": "\"An n'é mìa stê fât l'ingrès. Mèinter es sêlva la pàgina, l'indirés IP al srà sgnê int la stòria 'd la pàgina.\"",
        "missingsummary": "'''Atensiòun:''' an n'é mìa stê precişê al mutîv de sté mudéfica. S'es tōrna a clichêr insém a \"{{int:savearticle}}\" la mudéfica la gnirà salvêda cun al mutîv vōd.",
+       "selfredirect": "<strong>Ateinti:</strong>t'é drē fêr un rinvéi a l'istèsa vōş. S'ét fê cléch incòra in sém a \"{{int:savearticle}}\", al rinvéi al gnirà fât",
        "missingcommenttext": "Scréver un cumèint ché sòta.",
        "missingcommentheader": "'''Atensiòun:''' an n'é mìa stê precişê al mutîv/al tétol de sté mudéfica. S'es tōrna a clichêr insém a \"{{int:savearticle}}\" la mudéfica la gnirà salvêda sèinsa tétol.",
        "summary-preview": "Guêrda préma sûnt:",
        "right-protect": "Câmbia i livē 'd prutesiòun e mudéfica 'l pàgini prutèti in ripetisiòun",
        "right-editprotected": "Mudéfica 'l pàgini prutèti cun \"{{int:protect-level-sysop}}\"",
        "right-editsemiprotected": "Mudéfica 'l pàgini prutèti cun \"{{int:protect-level-autoconfirmed}}\"",
+       "right-editcontentmodel": "Mudéfica al mudèl ed còl ché dèinter int 'na pàgina.",
        "right-editinterface": "Mudéfica al colegamèint tra sistēma e utèint",
        "right-editusercssjs": "Mudéfica i file CSS e JS 'd êter utèint",
        "right-editusercss": "Mudéfica i file CSS 'd êter utèint",
        "right-editmyprivateinfo": "Câmbia 'l tō infurmasiòun personêli (per eşèimpi: indirés ed pôsta eletrônica, nòm vèira)",
        "right-editmyoptions": "Câmbia al tō preferèinsi",
        "right-rollback": "Scanşèla a la şvêlta al mudéfichi ed l'ûltèint ch'l'à mudifichê 'na pàgina pariculêra",
+       "right-markbotedits": "Sègna al mudéfichi da turnêr a mèter cme préma cme fâti da 'na mâchina in avtomâtich",
+       "right-noratelimit": "An n'é mìa ublighê al lémit 'd asiòun",
+       "right-import": "Côpia dal pàgini da 'd j êter wiki",
        "newuserlogpage": "Utèint nōv",
        "action-read": "lēzer cla pàgina ché",
        "action-edit": "Mudifichêr cla pàgina ché",
index 883dbd7..9b60639 100644 (file)
        "permalink": "Σταθερός σύνδεσμος",
        "print": "Εκτύπωση",
        "view": "Προβολή",
-       "view-foreign": "Î\94είÏ\84ε στο $1",
+       "view-foreign": "ΠÏ\81οβολή στο $1",
        "edit": "Επεξεργασία",
        "edit-local": "Επεξεργασία τοπικής περιγραφής",
        "create": "Δημιουργία",
-       "create-local": "ΠÏ\81οÏ\83θέÏ\83Ï\84ε Ï\84οÏ\80ική Ï\80εÏ\81ιγÏ\81αÏ\86ή",
+       "create-local": "ΠÏ\81οÏ\83θήκη Ï\84οÏ\80ικήÏ\82 Ï\80εÏ\81ιγÏ\81αÏ\86ήÏ\82",
        "editthispage": "Επεξεργασία αυτής της σελίδας",
        "create-this-page": "Δημιουργία αυτής της σελίδας",
        "delete": "Διαγραφή",
        "filepage-nofile-link": "Δεν υπάρχει τέτοιο αρχείο, αλλἀ μπορείτε να [$1 το επιφορτώσετε].",
        "uploadnewversion-linktext": "Φορτώστε μια νέα έκδοση αυτού του αρχείου",
        "shared-repo-from": "από το $1",
-       "shared-repo": "ένα ÎºÎ¿Î¹Î½Ï\8c ÎµÎ½Î±Ï\80οθεÏ\84ήÏ\81ιο",
+       "shared-repo": "κοινό εναποθετήριο",
        "shared-repo-name-wikimediacommons": "Wikimedia Commons",
        "upload-disallowed-here": "Δεν μπορείτε να αντικαταστήσετε αυτό το αρχείο.",
        "filerevert": "Επαναφορά $1",
index 75bdb11..52e3a78 100644 (file)
@@ -28,7 +28,7 @@
        "tog-shownumberswatching": "Show the number of watching users",
        "tog-oldsig": "Existing signature:",
        "tog-fancysig": "Treat signature as wikitext (without an automatic link)",
-       "tog-uselivepreview": "Use live preview (experimental)",
+       "tog-uselivepreview": "Use live preview",
        "tog-forceeditsummary": "Prompt me when entering a blank edit summary",
        "tog-watchlisthideown": "Hide my edits from the watchlist",
        "tog-watchlisthidebots": "Hide bot edits from the watchlist",
        "anoneditwarning": "<strong>Warning:</strong> You are not logged in. Your IP address will be publicly visible if you make any edits. If you <strong>[$1 log in]</strong> or <strong>[$2 create an account]</strong>, your edits will be attributed to your username, along with other benefits.",
        "anonpreviewwarning": "<em>You are not logged in. Saving will record your IP address in this page's edit history.</em>",
        "missingsummary": "<strong>Reminder:</strong> You have not provided an edit summary.\nIf you click \"{{int:savearticle}}\" again, your edit will be saved without one.",
+       "selfredirect": "<strong>Warning:</strong> You are creating redirect to the same article.\nIf you click \"{{int:savearticle}}\" again, the redirect will be created.",
        "missingcommenttext": "Please enter a comment below.",
        "missingcommentheader": "<strong>Reminder:</strong> You have not provided a subject/headline for this comment.\nIf you click \"{{int:savearticle}}\" again, your edit will be saved without one.",
        "summary-preview": "Summary preview:",
index b1a6743..4564aac 100644 (file)
        "tog-shownumberswatching": "Mostrar el número de usuarios que la vigilan",
        "tog-oldsig": "Firma actual:",
        "tog-fancysig": "Tratar la firma como wikitexto (sin un enlace automático)",
-       "tog-uselivepreview": "Usar previsualización dinámica (experimental)",
+       "tog-uselivepreview": "Usar previsualización dinámica",
        "tog-forceeditsummary": "Avisarme cuando grabe la página sin introducir un resumen de edición",
        "tog-watchlisthideown": "Ocultar mis ediciones en la lista de seguimiento",
        "tog-watchlisthidebots": "Ocultar las ediciones de bots en la lista de seguimiento",
        "right-protect": "Cambiar niveles de protección y editar páginas protegidas en cascada",
        "right-editprotected": "Editar páginas protegidas como «{{int:protect-level-sysop}}»",
        "right-editsemiprotected": "Editar páginas protegidas como «{{int:protect-level-autoconfirmed}}»",
+       "right-editcontentmodel": "Editar el modelo de contenido de una página",
        "right-editinterface": "Editar la interfaz de usuario",
        "right-editusercssjs": "Editar las páginas de CSS y JavaScript de otros usuarios",
        "right-editusercss": "Editar las páginas de CSS de otros usuarios",
        "action-viewmywatchlist": "Ver tu lista de seguimiento",
        "action-viewmyprivateinfo": "ver tu información privada",
        "action-editmyprivateinfo": "Editar tu información privada",
+       "action-editcontentmodel": "editar el modelo de contenido de una página",
        "nchanges": "$1 {{PLURAL:$1|cambio|cambios}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde la última visita}}",
        "enhancedrc-history": "historial",
        "unknown_extension_tag": "Etiqueta desconocida «$1»",
        "duplicate-defaultsort": "'''Atención:''' La clave de ordenamiento predeterminada «$2» anula la clave de ordenamiento anterior «$1».",
        "duplicate-displaytitle": "<strong>Advertencia:</strong> El título visualizado \"$2\" sobreescribe al anterior \"$1\".",
+       "invalid-indicator-name": "<strong>Error:</strong> el atributo <code>name</code> de los indicadores de estado de página no debe estar vacío.",
        "version": "Versión",
        "version-extensions": "Extensiones instaladas",
        "version-skins": "Temas instalados",
        "specialpages": "Páginas especiales",
        "specialpages-note-top": "Leyenda",
        "specialpages-note": "* Páginas especiales normales\n* <span class=\"mw-specialpagerestricted\">Páginas especiales restringidas.</span>\n* <span class=\"mw-specialpagecached\">Páginas especiales en caché (podrían ser obsoletas).</span>",
-       "specialpages-group-maintenance": "Reportes de mantenimiento",
+       "specialpages-group-maintenance": "Informes de mantenimiento",
        "specialpages-group-other": "Otras páginas especiales",
        "specialpages-group-login": "Acceder/crear cuenta",
        "specialpages-group-changes": "Cambios recientes y registros",
index fe227ff..7adc540 100644 (file)
        "virus-badscanner": "Viga konfiguratsioonis: tundmatu viirusetõrje: ''$1''",
        "virus-scanfailed": "skaneerimine ebaõnnestus (veakood $1)",
        "virus-unknownscanner": "tundmatu viirusetõrje:",
-       "logouttext": "'''Oled nüüd välja loginud.'''\n\nPane tähele, et seni kuni sa pole oma võrgulehitseja puhvrit tühjendanud, võidakse mõni lehekülg endiselt kuvada nii nagu oleksid ikka sisse logitud.",
+       "logouttext": "<strong>Oled nüüd välja loginud.</strong>\n\nPane tähele, et seni, kuni sa pole veebilehitseja puhvrit tühjendanud, võidakse mõni lehekülg endiselt kuvada nii nagu oleksid ikka sisse logitud.",
        "welcomeuser": "Tere tulemast, $1!",
        "welcomecreation-msg": "Sinu konto on loodud.\nÄra unusta seada oma {{GRAMMAR:genitive|{{SITENAME}}}} [[Special:Preferences|eelistusi]].",
        "yourname": "Kasutajanimi:",
        "userlogin": "Sisselogimine või kasutajakonto loomine",
        "userloginnocreate": "Sisselogimine",
        "logout": "Logi välja",
-       "userlogout": "Logi välja",
+       "userlogout": "Väljalogimine",
        "notloggedin": "Sisse logimata",
        "userlogin-noaccount": "Kas sul pole kontot?",
        "userlogin-joinproject": "Ühine projektiga {{SITENAME}}",
index 03ca92b..eaea3f6 100644 (file)
@@ -40,7 +40,9 @@
                        "Omid.koli",
                        "Alirezaaa",
                        "Mogoeilor",
-                       "Hosseinblue"
+                       "Hosseinblue",
+                       "فلورانس",
+                       "Saeidpourbabak"
                ]
        },
        "tog-underline": "خط کشیدن زیر پیوندها:",
        "filerenameerror": "نشد پروندهٔ «$1» به «$2» تغییر نام یابد.",
        "filedeleteerror": "نشد پروندهٔ «$1» حذف شود.",
        "directorycreateerror": "نشد مسیر $1 را ایجاد کرد.",
+       "directoryreadonlyerror": "دایرکتوری \"$1\" فقط خواندنی است.",
+       "directorynotreadableerror": "دایرکتوری \"$1\" قابل خواندن نیست.",
        "filenotfound": "پروندهٔ «$1» یافت نشد.",
        "unexpected": "مقدار غیرمنتظره: «$1»=«$2».",
        "formerror": "خطا: نمی‌توان فرم را فرستاد.",
        "right-protect": "تغییر میزان محافظت صفحات و ویرایش صفحات محافظت‌شده آبشاری",
        "right-editprotected": "ویرایش صفحه‌های محافظت‌شده به‌عنوان «{{int:protect-level-sysop}}»",
        "right-editsemiprotected": "ویرایش صفحه حفاظت‌شده به عنوان \"{{int:protect-level-autoconfirmed}}\"",
+       "right-editcontentmodel": "ویرایش مدل محتوای یک صفحه",
        "right-editinterface": "ویرایش واسط کاربری",
        "right-editusercssjs": "ویرایش صفحه‌های CSS و JS دیگر کاربرها",
        "right-editusercss": "ویرایش صفحه‌های CSS دیگر کاربرها",
        "action-viewmywatchlist": "فهرست پیگیری‌های خود را ببینید",
        "action-viewmyprivateinfo": "اطلاعات خصوصی خود را ببینید",
        "action-editmyprivateinfo": "اطلاعات خصوصی خود را ویرایش کنید",
+       "action-editcontentmodel": "ویرایش مدل محتوای یک صفحه",
        "nchanges": "$1 تغییر",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|از آخرین بازدید}}",
        "enhancedrc-history": "تاریخچه",
        "move-page": "انتقال $1",
        "move-page-legend": "انتقال صفحه",
        "movepagetext": "با استفاده از فرم زیر نام صفحه تغییر خواهد کرد، و تمام تاریخچه‌اش به نام جدید منتقل خواهد شد.\nعنوان قدیمی تبدیل به یک صفحهٔ تغییرمسیر به عنوان جدید خواهد شد.\nشما می‌توانید تغییرمسیرهایی که به عنوان اصلی اشاره دارند را به صورت خودکار به‌روزرسانی کنید.\nپیوندهای که به عنوان صفحهٔ قدیمی وجود دارند، تغییر نخواهند کرد؛ حتماً تغییرمسیرهای [[Special:DoubleRedirects|دوتایی]] یا [[Special:BrokenRedirects|خراب]] را بررسی کنید.\n'''شما''' مسئول اطمینان از این هستید که پیوندها هنوز به همان‌جایی که قرار است بروند.\n\nتوجه کنید که اگر از قبل صفحه‌ای در عنوان جدید وجود داشته باشد صفحه منتقل '''نخواهد شد'''،\nمگر این آخرین ویرایش تغییرمسیر باشد و در  تاریخچهٔ ویرایشی نداشته باشد.\nاین یعنی اگر اشتباه کردید می‌توانید صفحه را به همان جایی که از آن منتقل شده بود برگردانید، و این که نمی‌توانید روی صفحات موجود بنویسید.\n\n'''هشدار!'''\nانتقال صفحات به نام جدید ممکن است تغییر اساسی و غیرمنتظره‌ای برای صفحات محبوب باشد؛\nلطفاً مطمئن شوید که قبل از انتقال دادن صفحه، عواقب این کار را درک می‌کنید.",
-       "movepagetext-noredirectfixer": "استفاده از فرم زیر سبب تغییر نام یک صفحه و انتقال تمام تاریخچهٔ آن به نام جدید می‌شود.\nعنوان پیشین تغییرمسیری به عنوان جدید خواهد شد.\nبه خاطر داشته باشید که [[Special:DoubleRedirects|تغییرمسیرهای دوتایی]] یا [[Special:BrokenRedirects|تغییرمسیرهای خراب]] را بررسی کنید.\nشما مسئولید که مطمئن شوید پیوندها به جایی اشاره می‌کنند که قرار است بروند.\n\nتوجه کنید که اگر صفحه‌ای تحت عنوان جدید از قبل موجود باشد، انتقال انجام '''نخواهد شد'''، مگر اینکه صفحه خالی و یا تغییرمسیر باشد و تاریخچهٔ ویرایشی دیگری نداشته باشد.\nاین یعنی اگر صفحه را به نامی اشتباه منتقل کردید می‌توانید این تغییر را واگردانی کنید، اما نمی‌توانید به صفحه‌ای که از قبل موجود است انتقال دهید.\n\n'''هشدار!'''\nانتقال صفحه‌های پربیننده ممکن است عملی غیرمنتظره باشد؛\nلطفاً پیش از انتقال مطمئن شوید از نتیجهٔ کار آگاهید.",
+       "movepagetext-noredirectfixer": "استفاده از فرم زیر سبب تغییر نام یک صفحه و انتقال تمام تاریخچهٔ آن به نام جدید می‌شود.\nعنوان پیشین تغییرمسیری به عنوان جدید خواهد شد.\nبه خاطر داشته باشید که [[Special:DoubleRedirects|تغییرمسیرهای دوتایی]] یا [[Special:BrokenRedirects|تغییرمسیرهای خراب]] را بررسی کنید.\nشما مسئولید که مطمئن شوید پس از انتقال، پیوندها به عنوان پیشین به جایی منتهی می‌شوند که باید.\n\nتوجه کنید که اگر صفحه‌ای تحت عنوان جدید از قبل موجود باشد، انتقال انجام '''نخواهد شد'''، مگر اینکه صفحه خالی و یا تغییرمسیر باشد و تاریخچهٔ ویرایشی دیگری نداشته باشد.\nاین یعنی اگر صفحه را به نامی اشتباه منتقل کردید می‌توانید این تغییر را واگردانی کنید، اما نمی‌توانید یک صفحه را به صفحه‌ای که از قبل موجود است انتقال دهید.\n\n'''هشدار!'''\nانتقال صفحه‌های پربیننده ممکن است عملی غیرمنتظره باشد؛\nلطفاً پیش از انتقال مطمئن شوید از نتیجهٔ کار آگاهید.",
        "movepagetalktext": "صفحهٔ بحث مربوط، اگر وجود داشته باشد، بطور خودکار همراه با مقالهٔ اصلی منتقل خواهد شد '''مگر اینکه''' :\n* در حال انتقال صفحه از این فضای نام به فضای نام دیگری باشید،\n* یک صفحهٔ بحث غیرخالی تحت این نام جدید وجود داشته باشد، یا\n* جعبهٔ زیر را تیک نزده باشید.\n\nدر این حالات، باید صفحه را بطور دستی انتقال داده و یا محتویات دو صفحه را با ویرایش ادغام کنید.",
        "movearticle": "انتقال صفحه:",
        "moveuserpage-warning": "'''هشدار:''' شما در حال انتقال دادن یک صفحهٔ کاربر هستید. توجه داشته باشید که تنها صفحه منتقل می‌شود و نام کاربر تغییر '''نمی‌یابد'''.",
        "specialpages-group-wiki": "داده و ابزارها",
        "specialpages-group-redirects": "صفحه‌های ویژهٔ تغییرمسیر دهنده",
        "specialpages-group-spam": "ابزارهای هرزنگاری",
+       "specialpages-group-developer": "ابزارهای توسعه‌دهندگان",
        "blankpage": "صفحهٔ خالی",
        "intentionallyblankpage": "این صفحه به طور عمدی خالی گذاشته شده است.",
        "external_image_whitelist": " #این سطر را همان‌گونه که هست رها کنید<pre>\n#عبارت‌های باقاعده (regex) را در زیر قرار دهید (فقط بخشی که بین // قرار می‌گیرد)\n#آن‌ها با نشانی اینترنتی تصاویر خارجی پیوند داده شده تطبیق داده می‌شوند\n#مواردی که مطابق باشند به صورت تصویر نمایش می‌یابند، و در غیر این صورت تنها یک پیوند به تصویر نمایش می‌یابد\n#سطرهایی که با # آغاز شوند به عنوان توضیحات در نظر گرفته می‌شوند\n#این سطرها به کوچکی و بزرگی حروف حساس هستند\n\n#عبارت‌های باقاعده (regex)  را زیر این سطر قرار دهید. این سطر را همان‌گونه که هست رها کنید</pre>",
        "expand_templates_generate_xml": "نمایش درخت تجزیهٔ XML",
        "expand_templates_generate_rawhtml": "نمایش اچ‌تی‌ام‌ال خام",
        "expand_templates_preview": "پیش‌نمایش",
+       "expand_templates_preview_fail_html": "<em>زیرا {{SITENAME}} تا به HTML خام فعال و یک دست رفتن اطلاعات نشست وجود دارد، پیش نمایش به عنوان یک اقدام احتیاطی در برابر حملات جاوا اسکریپت پنهان است.</em>\n\n<strong>اگر این تلاش پیشنمایش مشروع است، لطفا دوباره سعی کنید. اگر هنوز کار نمی کند، سعی کنید [[Special:UserLogout|خروج از سیستم]] را کلیک نموده و دوباره وارد شوید.",
+       "expand_templates_preview_fail_html_anon": "<em>زیرا {{SITENAME}} تا به HTML خام فعال و یک دست رفتن اطلاعات نشست وجود دارد، پیش نمایش به عنوان یک اقدام احتیاطی در برابر حملات جاوا اسکریپت پنهان است.</em>\n\n<strong>اگر این تلاش پیشنمایش مشروع است، لطفا دوباره سعی کنید. اگر هنوز کار نمی کند، سعی کنید [[Special:UserLogout|خروج از سیستم]] را کلیک نموده و دوباره وارد شوید.",
        "pagelanguage": "صفحه انتخاب زبان",
        "pagelang-name": "صفحه",
        "pagelang-language": "زبان",
index 9a78cc6..79a45ea 100644 (file)
@@ -41,7 +41,8 @@
                        "아라",
                        "Syreeni",
                        "MrTapsa",
-                       "SMAUG"
+                       "SMAUG",
+                       "SuperPete"
                ]
        },
        "tog-underline": "Linkkien alleviivaus:",
@@ -69,7 +70,7 @@
        "tog-shownumberswatching": "Näytä sivua tarkkailevien käyttäjien määrä",
        "tog-oldsig": "Nykyinen allekirjoitus:",
        "tog-fancysig": "Muotoilematon allekirjoitus ilman automaattista linkkiä",
-       "tog-uselivepreview": "Käytä välitöntä esikatselua (kokeellinen)",
+       "tog-uselivepreview": "Käytä välitöntä esikatselua",
        "tog-forceeditsummary": "Huomauta minua, jos en ole kirjoittanut yhteenvetoa",
        "tog-watchlisthideown": "Piilota omat muokkaukset tarkkailulistalta",
        "tog-watchlisthidebots": "Piilota bottien muokkaukset tarkkailulistalta",
        "anoneditwarning": "<strong>Varoitus:</strong> Et ole kirjautunut sisään. IP-osoitteesi näkyy julkisesti kaikille, jos muokkaat. Jos <strong>[$1 kirjaudut sisään]</strong> tai <strong>[$2 luot tunnuksen]</strong>, muokkauksesi kirjataan käyttäjätunnuksesi tekemiksi ja samalla saat käyttöösi hyödyllisiä välineitä.",
        "anonpreviewwarning": "''Et ole kirjautunut sisään. Tallentaminen kirjaa IP-osoitteesi tämän sivun muutoshistoriaan.''",
        "missingsummary": "Et ole antanut yhteenvetoa. Jos valitset Tallenna uudelleen, niin muokkauksesi tallennetaan ilman yhteenvetoa.",
+       "selfredirect": "<strong>Varoitus:</strong> Olet tekemässä uudelleenohjausta samaan artikkeliin. Jos painat toimintoa \"{{int:savearticle}}\" uudestaan, tämä ohjaussivu luodaan.",
        "missingcommenttext": "Kirjoita viesti alle.",
        "missingcommentheader": "Et ole antanut otsikkoa kommentillesi. Napsauta ”{{int:savearticle}}”, jos et halua antaa otsikkoa.",
        "summary-preview": "Yhteenvedon esikatselu:",
        "content-model-javascript": "JavaScript",
        "content-model-css": "CSS",
        "duplicate-args-category": "Sivut, jotka käyttävät kaksinkertaisia argumentteja mallinekutsuissa",
+       "duplicate-args-category-desc": "Tämä sivu sisältää sellaisia mallinekutsuja, jotka käyttävät kaksi kertaa samaa argumenttia kuten <nowiki>{{foo|bar=1|bar=2}}</nowiki></code> taikka <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "expensive-parserfunction-warning": "Tällä sivulla on liian monta hitaiden laajennusfunktioiden kutsua.\nKutsuja pitäisi olla alle $2 {{PLURAL:$2|kappale|kappaletta}}, mutta nyt niitä on $1 {{PLURAL:$1|kappale|kappaletta}}.",
        "expensive-parserfunction-category": "Sivut, joissa on liian monta vaativaa jäsenninfunktiota",
        "post-expand-template-inclusion-warning": "'''Varoitus:''' Sisällytettyjen mallineiden koko on liian suuri.\nJoitakin mallineita ei ole sisällytetty.",
        "right-protect": "Muuttaa suojaustasoja ja muokata tarttuvasti suojattuja sivuja",
        "right-editprotected": "Muokata sivuja, jotka on suojattu tasolle \"{{int:protect-level-sysop}}\"",
        "right-editsemiprotected": "Muokata sivuja, jotka on suojattu tasolle \"{{int:protect-level-autoconfirmed}}\"",
+       "right-editcontentmodel": "Muokata sivun sisältömallia (content model)",
        "right-editinterface": "Muokata käyttöliittymätekstejä",
        "right-editusercssjs": "Muokata toisten käyttäjien CSS- ja JavaScript-tiedostoja",
        "right-editusercss": "Muokata toisten käyttäjien CSS-tiedostoja",
        "action-viewmywatchlist": "tarkastella tarkkailulistaasi",
        "action-viewmyprivateinfo": "katsoa omia yksityisiä tietojasi",
        "action-editmyprivateinfo": "muokata omia yksityisiä tietojasi",
+       "action-editcontentmodel": "muokata sivun sisältömallia",
        "nchanges": "$1 {{PLURAL:$1|muutos|muutosta}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|viimeisen käynnin jälkeen}}",
        "enhancedrc-history": "historia",
        "specialpages-group-wiki": "Tiedot ja työkalut",
        "specialpages-group-redirects": "Ohjaavat toimintosivut",
        "specialpages-group-spam": "Roskalinkkien (spam) työkalut",
+       "specialpages-group-developer": "Kehittäjien työkalut",
        "blankpage": "Tyhjä sivu",
        "intentionallyblankpage": "Tämä sivu on tarkoituksellisesti tyhjä.",
        "external_image_whitelist": " #Älä muuta tätä riviä lainkaan.<pre>\n#Laita säännöllisten lausekkeiden palaset (vain osa, joka menee //-merkkien väliin) alle\n#Niitä verrataan ulkoisten (suoralinkitettyjen) kuvien URLeihin\n#Ne jotka sopivat, näytetään kuvina, muutoin kuviin näytetään vain linkit\n#Rivit, jotka alkavat #-merkillä ovat kommentteja\n#Tämä on riippumaton kirjainkoosta\n\n#Laita kaikki säännöllisten lausekkeiden palaset tämän rivit yläpuolelle. Älä muuta tätä riviä lainkaan</pre>",
        "expand_templates_generate_xml": "Näytä XML-jäsennyspuu",
        "expand_templates_generate_rawhtml": "Näytä raaka HTML",
        "expand_templates_preview": "Esikatselu",
+       "expand_templates_preview_fail_html": "<em>Koska sivustolla {{SITENAME}} on käytössä puhdas HTML-koodi ja koska istunnon tiedot ovat kadonneet, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi.</em>\n\n<strong>Jos olet oikealla asialla, yritä uudestaan.</strong>\nJos esikatselu ei vieläkään toimi, kokeile [[Special:UserLogout|kirjautua ulos]] ja sen jälkeen kirjaudu uudestaan sisään.",
+       "expand_templates_preview_fail_html_anon": "<em>Koska sivustolla {{SITENAME}} on käytössä puhdas HTML-koodi ja koska et ole kirjautunut sisään, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi.</em>\n\n<strong>Jos olet oikealla asialla, [[Special:UserLogin|kirjaudu sisään]] ja yritä uudestaan.</strong>",
        "pagelanguage": "Sivun kielen valinta",
        "pagelang-name": "Sivu",
        "pagelang-language": "Kieli",
        "log-name-pagelang": "Kielenvaihtoloki",
        "log-description-pagelang": "Tämä on loki, johon merkitään muutokset sivujen kieliasetuksissa.",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|muutti}} sivun kieltä sivulla $3 kielestä $4 kieleksi $5.",
-       "default-skin-not-found": "Hupsista! Oletuksena tuleva ulkoasu sinun wikillesi, joka on määritelty koodissa <code dir=\"ltr\">$wgDefaultSkin</code> muotoon <code>$1</code>, ei ole saatavilla.\n\n\n<strong>Alla on ohjeita englanniksi:</strong>\n\n\nYour installation seems to include the following skins. See [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] for information how to enable them and choose the default.\n\n$2\n\n; If you have just installed MediaWiki: \n: You probably installed from git, or directly from the source code using some other method. This is expected. Try installing some skins from [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory], by: :* Downloading the [https://www.mediawiki.org/wiki/Download tarball installer], which comes with several skins and extensions. You can copy and paste the <code>skins/</code> directory from it. \n:* Cloning one of the <code>mediawiki/skins/*</code> repositories via git into the <code>skins/</code> directory of your MediaWiki installation. \n: Doing this should not interfere with your git repository if you're a MediaWiki developer.\n\n\n; If you have just upgraded MediaWiki: \n: MediaWiki 1.24 and newer no longer automatically enables installed skins (see [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). You can paste the following lines into <code>LocalSettings.php</code> to enable all currently installed skins:\n\n<pre>$3</pre>\n\n; If you have just modified <code>LocalSettings.php</code>: \n: Double-check the skin names for typos.",
-       "default-skin-not-found-no-skins": "Hupsista! Oletusulkoasua sinun wikillesi ei ole saatavilla. Se on määritelty ulkoasuksi <code>$1</code> kohteessa <code>$wgDefaultSkin</code>.\n\nSinulla ei ole lainkaan asennettuja ulkoasuja. (You have no installed skins.)\n\nAlla on lisäohjeita englanniksi:\n\n\n; If you have just installed or upgraded MediaWiki: \n\n: You probably installed from git, or directly from the source code using some other method. This is expected. MediaWiki 1.24 and newer doesn't include any skins in the main repository. Try installing some skins from [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory], by: \n\n:* Downloading the [https://www.mediawiki.org/wiki/Download tarball installer], which comes with several skins and extensions. You can copy and paste the <code>skins/</code> directory from it. \n\n:* Cloning one of the <code>mediawiki/skins/*</code> repositories via git into the <code dir=\"ltr\">skins/</code> directory of your MediaWiki installation. \n\n: Doing this should not interfere with your git repository if you're a MediaWiki developer. See [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] for information how to enable skins and choose the default.",
+       "default-skin-not-found": "Hupsista! Oletuksena tuleva ulkoasu sinun wikillesi, joka on määritelty koodissa <code dir=\"ltr\">$wgDefaultSkin</code> muotoon <code>$1</code>, ei ole saatavilla.\n\n\n<strong>Alla on ohjeita englanniksi:</strong>\n\n\nYour installation seems to include the following skins. See [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] for information how to enable them and choose the default.\n\n$2\n\n; If you have just installed MediaWiki: \n: You probably installed from git, or directly from the source code using some other method. This is expected. Try installing some skins from [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory], by: :* Downloading the [https://www.mediawiki.org/wiki/Download tarball installer], which comes with several skins and extensions. You can copy and paste the <code>skins/</code> directory from it. \n:* Downloading individual skin tarballs from [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Cloning one of the <code>mediawiki/skins/*</code> repositories via git into the <code>skins/</code> directory of your MediaWiki installation. \n: Doing this should not interfere with your git repository if you're a MediaWiki developer.\n\n\n; If you have just upgraded MediaWiki: \n: MediaWiki 1.24 and newer no longer automatically enables installed skins (see [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). You can paste the following lines into <code>LocalSettings.php</code> to enable all currently installed skins:\n\n<pre>$3</pre>\n\n; If you have just modified <code>LocalSettings.php</code>: \n: Double-check the skin names for typos.",
+       "default-skin-not-found-no-skins": "Hupsista! Oletusulkoasua sinun wikillesi ei ole saatavilla. Se on määritelty ulkoasuksi <code>$1</code> kohteessa <code>$wgDefaultSkin</code>.\n\nSinulla ei ole lainkaan asennettuja ulkoasuja. (You have no installed skins.)\n\nAlla on lisäohjeita englanniksi:\n\n\n; If you have just installed or upgraded MediaWiki: \n\n: You probably installed from git, or directly from the source code using some other method. This is expected. MediaWiki 1.24 and newer doesn't include any skins in the main repository. Try installing some skins from [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory], by: \n\n:* Downloading the [https://www.mediawiki.org/wiki/Download tarball installer], which comes with several skins and extensions. You can copy and paste the <code>skins/</code> directory from it. \n\n:* Downloading individual skin tarballs from [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n\n:* Cloning one of the <code>mediawiki/skins/*</code> repositories via git into the <code dir=\"ltr\">skins/</code> directory of your MediaWiki installation. \n\n: Doing this should not interfere with your git repository if you're a MediaWiki developer. See [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] for information how to enable skins and choose the default.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (käytössä)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''ei käytössä''')",
        "mediastatistics": "Median tilastotiedot",
index 3f65920..cf58229 100644 (file)
                        "SnowedEarth",
                        "Orikrin1998",
                        "Automatik",
-                       "Elodark"
+                       "Elodark",
+                       "Macofe"
                ]
        },
        "tog-underline": "Souligner les liens :",
        "tog-shownumberswatching": "Afficher le nombre d'utilisateurs qui suivent la page",
        "tog-oldsig": "Signature existante :",
        "tog-fancysig": "Traiter la signature comme du wikitexte (sans lien automatique)",
-       "tog-uselivepreview": "Utiliser l’aperçu rapide (expérimental)",
+       "tog-uselivepreview": "Utiliser l’aperçu rapide",
        "tog-forceeditsummary": "M'avertir lorsque je n'ai pas spécifié de résumé de modification",
        "tog-watchlisthideown": "Masquer mes propres modifications dans la liste de suivi",
        "tog-watchlisthidebots": "Masquer les modifications faites par des robots dans la liste de suivi",
        "anoneditwarning": "<strong>Attention :</strong> Vous n’êtes pas connecté. Votre adresse IP sera visible de tout le monde si vous faites des modifications. Si vous <strong>[$1 vous connectez]</strong> ou <strong>[$2 créez un compte]</strong>, vos modifications seront attribuées à votre nom d’utilisateur, entre autres avantages.",
        "anonpreviewwarning": "''Vous n’êtes pas identifié(e). Sauvegarder enregistrera votre adresse IP dans l’historique des modifications de la page.''",
        "missingsummary": "'''Rappel :''' vous n'avez pas encore fourni le résumé de votre modification.\nSi vous cliquez de nouveau sur le bouton « {{int:savearticle}} », la publication sera faite sans nouvel avertissement.",
+       "selfredirect": "<strong>Attention :</strong> Vous êtes en train de créer une redirection vers le même article.\nSi vous cliquez de nouveau sur « {{int:savearticle}} », la redirection sera créée.",
        "missingcommenttext": "Veuillez entrer un commentaire ci-dessous.",
        "missingcommentheader": "'''Rappel :''' vous n'avez pas fourni de sujet ou de titre à ce commentaire.\nSi vous cliquez de nouveau sur « {{int:Savearticle}} », votre modification sera enregistrée sans titre.",
        "summary-preview": "Aperçu du résumé :",
index fe11a5c..329f902 100644 (file)
        "wlheader-enotif": "Tha brathan-naidheachd air a' phost-d an comas.",
        "wlheader-showupdated": "Tha clò <strong>trom</strong> air duilleagan a chaidh atharrachadh on turas mu dheireadh a thadhail thu orra.",
        "wlnote": "Chì thu gu h-ìosal {{PLURAL:$1|a' $1 mhùthadh|an $1 mhùthadh|na $1 mùthaidhean|am $1 mùthadh}} mu dheireadh san {{PLURAL:$2|$2 uair a thìde|$2 uair a thìde|$2 uairean a thìde|$2 uair a thìde}} mu dheireadh, mar a bha e $3, $4.",
-       "wlshowlast": "Seall na $1 uairean a thìde mu dheireadh $2 làithean mu dheireadh",
+       "wlshowlast": "Seall na $1 uairean a thìde mu dheireadh $2 làithean mu dheireadh $3",
        "watchlist-options": "Roghainnean mo chlàir-faire",
        "watching": "'Ga chur air a' chlàr-fhaire...",
        "unwatching": "A' toirt far a' chlàir-fhaire...",
        "exif-gpsdifferential": "Ceartachadh diofarail GPS",
        "exif-coordinate-format": "$1° $2′ $3″ $4",
        "exif-jpegfilecomment": "Beachd faidhle JPEG",
-       "exif-keywords": "Facalan-luirg",
+       "exif-keywords": "Faclan-luirg",
        "exif-worldregioncreated": "An roinn-dùthcha san deach an dealbh a thogail",
        "exif-countrycreated": "An dùthaich san deach an dealbh a thogail",
        "exif-countrycodecreated": "Còd na dùthcha san deach an dealbh a thogail",
index d90b777..4754b14 100644 (file)
@@ -43,7 +43,7 @@
        "tog-shownumberswatching": "Mostrar o número de usuarios que están a vixiar",
        "tog-oldsig": "Sinatura actual:",
        "tog-fancysig": "Tratar a sinatura como se fose texto wiki (sen ligazón automática)",
-       "tog-uselivepreview": "Usar a vista previa en tempo real (experimental)",
+       "tog-uselivepreview": "Usar a vista previa en tempo real",
        "tog-forceeditsummary": "Avisádeme cando o campo resumo estea baleiro",
        "tog-watchlisthideown": "Agochar as edicións propias na lista de vixilancia",
        "tog-watchlisthidebots": "Agochar as edicións dos bots na lista de vixilancia",
        "anoneditwarning": "<strong>Aviso:</strong> Non accedeu ao sistema. O seu enderezo IP será rexistado no histórico de edicións desta páxina. Se <strong>[$1 accede ao sistema]</strong> ou <strong>[$2 crea unha conta]</strong>, as súas edicións serán rexistadas co seu nome de usuario, ademais doutros beneficios.",
        "anonpreviewwarning": "''Non accedeu ao sistema. Se garda a páxina, o seu enderezo IP quedará rexistrado no historial de edicións.''",
        "missingsummary": "'''Aviso:''' Esqueceu incluír o texto do campo resumo.\nSe preme en \"{{int:savearticle}}\" a súa edición gardarase sen ningunha descrición da edición.",
+       "selfredirect": "<strong>Atención:</strong> Está a crear unha redireción cara o mesmo artigo. Se preme \"{{int:savearticle}}\" de novo, crearase a redireción.",
        "missingcommenttext": "Por favor, escriba un comentario a continuación.",
        "missingcommentheader": "'''Aviso:''' Non escribiu ningún texto no asunto/título deste comentario.\nSe preme sobre \"{{int:savearticle}}\", a súa edición gardarase sen el.",
        "summary-preview": "Vista previa do resumo:",
index a19f7fd..0fc292d 100644 (file)
@@ -55,7 +55,7 @@
        "tog-shownumberswatching": "הצגת מספר המשתמשים העוקבים",
        "tog-oldsig": "החתימה הנוכחית:",
        "tog-fancysig": "התייחסות לחתימה כקוד ויקי (ללא קישור אוטומטי)",
-       "tog-uselivepreview": "שימוש בתצוגה מקדימה מהירה (ניסיוני)",
+       "tog-uselivepreview": "שימוש בתצוגה מקדימה מהירה",
        "tog-forceeditsummary": "הצגת אזהרה בעת הכנסת תקציר עריכה ריק",
        "tog-watchlisthideown": "הסתרת העריכות שלי ברשימת המעקב",
        "tog-watchlisthidebots": "הסתרת עריכות של בוטים ברשימת המעקב",
        "passwordreset-capture-help": "אם תסמנו תיבה זו, הדואר האלקטרוני (יחד עם הסיסמה הזמנית) יוצג לכם במקביל לשליחתו למשתמש.",
        "passwordreset-email": "כתובת דוא\"ל:",
        "passwordreset-emailtitle": "פרטי חשבון ב{{grammar:תחילית|{{SITENAME}}}}",
-       "passwordreset-emailtext-ip": "מישהו (ככל הנראה אתם, מכתובת ה־IP מספר $1) ביקש איפוס של\nהסיסמה שלכם ב{{grammar:תחילית|{{SITENAME}}}} ($4). {{PLURAL:$3|חשבון המשתמש הבא|חשבונות המשתמש הבאים}}\nשייכים לכתובת הדואר האלקטרוני הזו:\n\n$2\n\n{{PLURAL:$3|סיסמה זמנית זו|סיסמאות זמניות אלה}} יפקעו תוך {{PLURAL:$5|יום|יומיים|$5 ימים}}.\nעליכם להיכנס ולבחור סיסמה חדשה עכשיו. אם מישהו אחר ביצע בקשה זו, או שנזכרתם בסיסמתכם\nהמקורית ואינכם רוצים עוד לשנות אותה, באפשרותכם להתעלם מהודעה זו ולהמשיך להשתמש בסיסמה\nהישנה.",
-       "passwordreset-emailtext-user": "המשתמש $1 ב{{GRAMMAR:תחילית|{{SITENAME}}}} ביקש איפוס של הסיסמה שלכם ב{{GRAMMAR:תחילית|{{SITENAME}}}}\n($4). {{PLURAL:$3|חשבון המשתמש הבא|חשבונות המשתמש הבאים}} שייכים לכתובת הדואר האלקטרוני הזו:\n\n$2\n\n{{PLURAL:$3|סיסמה זמנית זו|סיסמאות זמניות אלה}} יפקעו תוך {{PLURAL:$5|יום|יומיים|$5 ימים}}.\nעליכם להיכנס ולבחור סיסמה חדשה עכשיו. אם מישהו אחר ביצע בקשה זו, או שנזכרתם בסיסמתכם\nהמקורית ואינכם רוצים עוד לשנות אותה, באפשרותכם להתעלם מהודעה זו ולהמשיך להשתמש בסיסמה\nהישנה.",
+       "passwordreset-emailtext-ip": "מישהו (ככל הנראה אתם, מכתובת ה־IP מספר $1) ביקש איפוס של\nהסיסמה שלכם ב{{grammar:תחילית|{{SITENAME}}}} ($4). {{PLURAL:$3|חשבון המשתמש הבא|חשבונות המשתמש הבאים}}\nשייכים לכתובת הדואר האלקטרוני הזו:\n\n$2\n\n{{PLURAL:$3|סיסמה זמנית זו תפקע|סיסמאות זמניות אלה יפקעו}} תוך {{PLURAL:$5|יום|יומיים|$5 ימים}}.\nעליכם להיכנס ולבחור סיסמה חדשה עכשיו. אם מישהו אחר ביצע בקשה זו, או שנזכרתם בסיסמתכם\nהמקורית ואינכם רוצים עוד לשנות אותה, באפשרותכם להתעלם מהודעה זו ולהמשיך להשתמש בסיסמה\nהישנה.",
+       "passwordreset-emailtext-user": "ה{{GENDER:$1|משתמש|משתמשת}} $1 ב{{GRAMMAR:תחילית|{{SITENAME}}}} {{GENDER:$1|ביקש|ביקשה}} איפוס של הסיסמה שלכם ב{{GRAMMAR:תחילית|{{SITENAME}}}}\n($4). {{PLURAL:$3|חשבון המשתמש הבא שייך|חשבונות המשתמש הבאים שייכים}} לכתובת הדואר האלקטרוני הזו:\n\n$2\n\n{{PLURAL:$3|סיסמה זמנית זו תפקע|סיסמאות זמניות אלה יפקעו}} תוך {{PLURAL:$5|יום|יומיים|$5 ימים}}.\nעליכם להיכנס ולבחור סיסמה חדשה עכשיו. אם מישהו אחר ביצע בקשה זו, או שנזכרתם בסיסמתכם\nהמקורית ואינכם רוצים עוד לשנות אותה, באפשרותכם להתעלם מהודעה זו ולהמשיך להשתמש בסיסמה\nהישנה.",
        "passwordreset-emailelement": "שם משתמש: $1\nסיסמה זמנית: $2",
        "passwordreset-emailsent": "נשלח דואר אלקטרוני לאיפוס הסיסמה.",
        "passwordreset-emailsent-capture": "נשלח דואר אלקטרוני לאיפוס הסיסמה, והוא מוצג להלן.",
        "anoneditwarning": "<strong>אזהרה:</strong> אינכם מחוברים לחשבון. כתובת ה־IP שלכם תוצג בפומבי אם תבצעו עריכות כלשהן. אם <strong>[$1 תיכנסו לחשבון]</strong> או <strong>[$2 תיצרו חשבון]</strong>, העריכות שלכם תיוחסנה לשם המשתמש שלכם ותקבלו גם יתרונות אחרים.",
        "anonpreviewwarning": "''אינכם מחוברים לחשבון. שמירה תגרום לכתובת ה־IP שלכם להירשם בהיסטוריית העריכות של הדף.''",
        "missingsummary": "<strong>תזכורת:</strong> לא הזנת תקציר עריכה.\nלחיצה חוזרת על הכפתור \"{{int:savearticle}}\" תגרום לעריכה שלך להישמר בלעדיו.",
+       "selfredirect": "<strong>אזהרה:</strong> ניסית ליצור הפניה מדף זה לעצמו.\nלחיצה חוזרת על הכפתור \"{{int:savearticle}}\" תגרום להפניה להיווצר.",
        "missingcommenttext": "יש להקליד את ההודעה למטה.",
        "missingcommentheader": "<strong>תזכורת:</strong> לא הזנת נושא/כותרת להודעה זו.\nלחיצה חוזרת על הכפתור \"{{int:savearticle}}\" תגרום לעריכה שלך להישמר ללא נושא/כותרת.",
        "summary-preview": "תצוגה מקדימה של התקציר:",
        "userinvalidcssjstitle": "'''אזהרה:''' העיצוב \"$1\" אינו קיים.\nדפי .css ו־.js מותאמים אישית משתמשים בכותרת עם אותיות קטנות – למשל, {{ns:user}}:דוגמה/vector.css ולא {{ns:user}}:דוגמה/Vector.css.",
        "updated": "(מעודכן)",
        "note": "'''הערה:'''",
-       "previewnote": "'''זכרו שזו רק תצוגה מקדימה.'''\nהשינויים שלכם טרם נשמרו!",
+       "previewnote": "<strong>זִכרו שזו רק תצוגה מקדימה.</strong>\nהשינויים שלכם טרם נשמרו!",
        "continue-editing": "מעבר לאזור העריכה",
        "previewconflict": "תצוגה מקדימה זו מציגה כיצד ייראה הטקסט בחלון העריכה העליון, אם תבחרו לשמור אותו.",
        "session_fail_preview": "'''לא ניתן לבצע את עריכתכם עקב אובדן מידע הכניסה.'''\nאנא נסו שוב.\nאם זה לא עוזר, נסו [[Special:UserLogout|לצאת מהחשבון]] ולהיכנס אליו שנית.",
index 23768c1..8564527 100644 (file)
        "protectedpagetext": "Ova stranica je zaključana da bi se onemogućile izmjene.",
        "viewsourcetext": "Možete pogledati i kopirati izvorni sadržaj ove stranice:",
        "viewyourtext": "Možete vidjeti i kopirati tekst '''vaših uređivanja''' na ovoj stranici:",
-       "protectedinterface": "Ova stranica je zaštićena od izmjena jer sadrži tekst MediaWiki softvera.\nAKo želite prevesti neprevedenu poruku ili popraviti prijevod neke druge poruke za sve MediaWiki wikije, posjetite [//translatewiki.net/  translatewiki.net], projekt za lokalizaciju MediaWiki softvera.",
+       "protectedinterface": "Ova stranica je zaštićena od izmjena jer sadrži tekst MediaWiki softvera.\nAko želite prevesti neprevedenu poruku ili popraviti prijevod neke druge poruke za sve MediaWiki wikije, posjetite [//translatewiki.net/  translatewiki.net], projekt za lokalizaciju MediaWiki softvera.",
        "editinginterface": "'''Upozorenje:''' Uređujete stranicu koja se rabi za prikaz teksta u sučelju softvera. Promjene učinjene na ovoj stranici će se odraziti na izgled korisničkog sučelja kod drugih suradnika. Za prijevod, razmotrite uporabu [//translatewiki.net/wiki/Main_Page?setlang=hr translatewiki.net], projekta lokalizacije MedijeWiki.",
+       "translateinterface": "Za dodavanje ili promjenu prijevoda za sve wikije koristite [//translatewiki.net/ translatewiki.net], projekt za lokalizaciju MediaWikija.",
        "cascadeprotected": "Ova je stranica zaključana za uređivanja jer je uključena u {{PLURAL:$1|slijedeću stranicu|slijedeće stranice}}, koje su zaštićene \"prenosivom zaštitom\":\n$2",
        "namespaceprotected": "Ne možete uređivati stranice u imenskom prostoru '''$1'''.",
        "customcssprotected": "Ne možete uređivati ovu CSS stranicu zato što ona sadrži osobne postavke drugog suradnika.",
        "revdelete-selected-file": "{{PLURAL:$1|Označena inačica|Označene inačice}} datoteke [[:$2]]:",
        "logdelete-selected": "{{PLURAL:$1|Odabrani zapis u evidenciji|Odabrani zapisi u evidenciji}}:",
        "revdelete-text-text": "Izbrisane izmjene će i dalje biti vidljive u povijesti stranice, ali dijelovi sadržaja neće biti vidljivi javno.",
-       "logdelete-text": "Izbrisane izmjene i dalje će biti vidljive u zapisnicima, ali dijelovi njihova sadržaja biti će nedostupni za javnost.",
+       "logdelete-text": "Izbrisane izmjene i dalje će biti vidljive u evidencijama, ali dijelovi njihova sadržaja biti će nedostupni za javnost.",
        "revdelete-text-others": "Ostali administratori na projektu {{SITENAME}} će moći vidjeti i vratiti izbrisani sadržaj na isti način, osim ako nisu postavljena dodatna ograničenja.",
        "revdelete-confirm": "Molimo potvrdite da namjeravate ovo učiniti, da razumijete posljedice i da to činite u skladu s [[{{MediaWiki:Policy-url}}|pravilima]].",
        "revdelete-suppress-text": "Sklanjanje uređivanja treba raditi '''iznimno''' u slijedećih par slučajeva:\n* Privatne informacije neprilične javnom mediju tipa\n*: ''kućna adresa i broj telefona, JMBG ili OIB, itd.''",
        "download": "skidanje",
        "unwatchedpages": "Nepraćene stranice",
        "listredirects": "Popis preusmjeravanja",
+       "listduplicatedfiles": "Popis kopija datoteka",
+       "listduplicatedfiles-summary": "Ovo je popis datoteka kojima je zadnja inačica kopija zadnje inačice druge datoteke. Na popisu su samo lokalno postavljene datoteke.",
        "unusedtemplates": "Nekorišteni predlošci",
        "unusedtemplatestext": "Slijedi popis svih stranica imenskog prostora {{ns:template}}, koje nisu umetnute na drugim stranicama. Pripazite da prije brisanja provjerite druge poveznice koje vode na te predloške.",
        "unusedtemplateswlh": "druge poveznice",
        "autoblocker": "Automatski ste blokirani jer je Vašu IP adresu nedavno koristio \"[[User:$1|$1]]\" koji je blokiran zbog: \"$2\".",
        "blocklogpage": "Evidencija blokiranja",
        "blocklog-showlog": "Ovaj suradnik je ranije blokiran.\nEvidencija blokiranja je prikazan ispod kao napomena:",
-       "blocklog-showsuppresslog": "Ovaj suradnik je ranije blokiran i skriven.\nZapisnik skrivanja je prikazan ispod kao napomena:",
+       "blocklog-showsuppresslog": "Ovaj suradnik je ranije blokiran i skriven.\nEvidencija skrivanja je prikazana ispod kao napomena:",
        "blocklogentry": "Blokiran je \"[[$1]]\" na rok $2 $3.",
        "reblock-logentry": "promijenjene postavke blokiranja za [[$1]] na rok od $2 $3",
        "blocklogtext": "Ovo je evidencija blokiranja i deblokiranja.\nNa popisu nema automatski blokiranih IP adresa.\nZa popis trenutačnih zabrana i blokiranja vidi [[Special:BlockList|popis blokiranja]].",
        "pageinfo-category-pages": "Broj stranica",
        "pageinfo-category-subcats": "Broj podkategorija",
        "pageinfo-category-files": "Broj datoteka",
-       "markaspatrolleddiff": "Označi za pregledano",
+       "markaspatrolleddiff": "Označi pregledanim",
        "markaspatrolledtext": "Označi ovaj članak pregledanim",
        "markedaspatrolled": "Pregledano",
        "markedaspatrolledtext": "Odabrana promjena [[:$1]] označena je pregledanom.",
        "expand_templates_remove_comments": "Ukloni komentare",
        "expand_templates_remove_nowiki": "Ukloni <nowiki> tagove u rezultatima.",
        "expand_templates_generate_xml": "Prikaži XML stablo",
-       "expand_templates_preview": "Vidi kako će izgledati"
+       "expand_templates_preview": "Vidi kako će izgledati",
+       "mediastatistics": "Statistika datoteka",
+       "mediastatistics-summary": "Slijede statistike postavljenih datoteka koje pokazuju zadnju inačicu datoteke. Starije ili izbrisane inačice nisu prikazane."
 }
index e81c941..b6703cb 100644 (file)
@@ -64,7 +64,7 @@
        "tog-shownumberswatching": "A lapot figyelő szerkesztők számának megjelenítése",
        "tog-oldsig": "A jelenlegi aláírás:",
        "tog-fancysig": "Az aláírás wikiszöveg (nem lesz automatikusan hivatkozásba rakva)",
-       "tog-uselivepreview": "Élő előnézet használata (kísérleti)",
+       "tog-uselivepreview": "Élő előnézet használata",
        "tog-forceeditsummary": "Figyelmeztessen, ha nem adok meg szerkesztési összefoglalót",
        "tog-watchlisthideown": "Saját szerkesztések elrejtése",
        "tog-watchlisthidebots": "Robotok szerkesztéseinek elrejtése",
        "viewsourcetext": "Megtekintheted és másolhatod a lap forrását:",
        "viewyourtext": "Megtekintheted és kimásolhatod a '''saját szerkesztéseidet''' az alábbi lapra:",
        "protectedinterface": "Ez a lap a szoftver felületéhez szolgáltat szöveget, és a visszaélések elkerülése miatt le van zárva.",
-       "editinginterface": "'''Vigyázat:''' egy olyan lapot szerkesztesz, ami a MediaWiki szoftver felületéhez tartozik. A lap megváltoztatása hatással lesz a kinézetre, ahogy más szerkesztők látják a lapot. Fordításra inkább használd a MediaWiki fordítására indított kezdeményezést, a [//translatewiki.net/wiki/Main_Page?setlang=hu translatewiki.net-et].",
+       "editinginterface": "<strong>Vigyázat:</strong> egy olyan lapot szerkesztesz, ami a MediaWiki szoftver felületéhez tartozik. A lap megváltoztatása hatással lesz a kinézetre, ahogy más szerkesztők látják a lapot.",
        "cascadeprotected": "Ez a lap szerkesztés elleni védelemmel lett ellátva, mert a következő {{PLURAL:$1|lapon|lapokon}} be van kapcsolva a „kaszkádolt” védelem:\n$2",
        "namespaceprotected": "Nincs jogosultságod a(z) '''$1''' névtérben található lapok szerkesztésére.",
        "customcssprotected": "Nem szerkesztheted ezt a CSS-lapot, mert egy másik felhasználó személyes beállításait tartalmazza.",
        "wlheader-enotif": "Az e-mailen keresztül történő értesítés engedélyezve.",
        "wlheader-showupdated": "Azok a lapok, amelyek megváltoztak, mióta utoljára megnézted őket, '''vastagítva''' láthatók.",
        "wlnote": "Alább {{PLURAL:$1|az utolsó változás|az utolsó <strong>$1</strong> változás}} látható az elmúlt {{PLURAL:$2|órában|<strong>$2</strong> órában}}, $3 $4-kor.",
-       "wlshowlast": "Az elmúlt $1 órában | $2 napon |  történt változtatások legyenek láthatóak",
+       "wlshowlast": "Az elmúlt $1 órában | $2 napon történt változtatások legyenek láthatóak",
        "watchlist-options": "A figyelőlista beállításai",
        "watching": "Figyelés...",
        "unwatching": "Figyelés befejezése...",
        "exbeforeblank": "az eltávolítás előtti tartalom: „$1”",
        "delete-confirm": "$1 törlése",
        "delete-legend": "Törlés",
-       "historywarning": "'''Figyelem:''' a lapnak, amit törölni készülsz, körülbelül $1 változattal rendelkező laptörténete van:",
+       "historywarning": "<strong>Figyelem:</strong> a lapnak, amit törölni készülsz, $1 változattal rendelkező laptörténete van:",
        "confirmdeletetext": "Egy lapot vagy fájlt készülsz törölni a teljes laptörténetével együtt.\nKérjük, erősítsd meg, hogy valóban ezt szeretnéd tenni, átlátod a következményeit, és hogy a műveletet a [[{{MediaWiki:Policy-url}}|törlési irányelvekkel]] összhangban végzed.",
        "actioncomplete": "Művelet végrehajtva",
        "actionfailed": "A művelet nem sikerült",
        "autoblockid": "$1. autoblokk",
        "block": "Felhasználó blokkolása",
        "unblock": "Felhasználó blokkolásának feloldása",
-       "blockip": "Blokkolás",
+       "blockip": "{{GENDER:$1|Felhasználó}} blokkolása",
        "blockip-legend": "Felhasználó blokkolása",
        "blockiptext": "Az alábbi űrlap segítségével megvonhatod egy szerkesztő vagy IP-cím szerkesztési jogait.\nÜgyelj rá, hogy az intézkedésed mindig legyen tekintettel a vonatkozó [[{{MediaWiki:Policy-url}}|irányelvekre]].\nAdd meg a blokkolás okát is (például idézd a blokkolandó személy által vandalizált lapokat).",
        "ipaddressorusername": "IP-cím vagy felhasználói név",
index 3cf8e3e..7aed2ff 100644 (file)
        "right-protect": "Agsukat kadagiti agpang ti salaknib ken agurnos kadagiti nasalakniban ti sariap a panid",
        "right-editprotected": "Agurnos kadagiti panid a nasalakniban a kas \"{{int:protect-level-sysop}}\"",
        "right-editsemiprotected": "Agurnos kadagiti panid a nasalakniban a kas \"{{int:protect-level-autoconfirmed}}\"",
+       "right-editcontentmodel": "Urnosen ti modelo ti linaon iti panid",
        "right-editinterface": "Agurnos iti interface ti agar-aramat",
        "right-editusercssjs": "Agurnos kadagiti papales ti CSS ken JavaScript dagiti sabali nga agar-aramat",
        "right-editusercss": "Agurnos kadagiti papeles ti CSS dagiti sabali nga agar-aramat",
        "action-viewmywatchlist": "agkita iti bukodmo a listaan ti bambantayan",
        "action-viewmyprivateinfo": "agkita iti bukodmo a pribado a pakaammo",
        "action-editmyprivateinfo": "agurnos iti bukodmo a pribado a pakaammo",
+       "action-editcontentmodel": "urnosen ti modelo ti linaon iti panid",
        "nchanges": "$1 {{PLURAL:$1|sinukatan|dagiti sinukatan}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|manipud ti naudi a panagsarungkar}}",
        "enhancedrc-history": "pakasaritaan",
        "specialpages-group-wiki": "Datos ken ramramit",
        "specialpages-group-redirects": "Panangibaw-ing kadagiti espesial a panid",
        "specialpages-group-spam": "Ramramit ti spam",
+       "specialpages-group-developer": "Ramramit dagiti agraramid",
        "blankpage": "Blanko a panid",
        "intentionallyblankpage": "Daytoy a panid  ket naigagara a blanko.",
        "external_image_whitelist": " #Baybayan daytoy a linia a kastoy<pre>\n#Ikabil ti \"regular expression fragments\" (idiay laeng paset nga ikabil ti tengnga ti  //) dita baba\n#Dagitoy ipada na ti URLs ti ruar (ti napudot a naikapet) imahen \n#Dagiti agpada ket agparang nga  imahen, ket no saan ti panilpo ti imahen ti agparang laeng\n#Dagiti linia nga umuna iti # ket maipabalin a komentario\n#Daytoy ket \"sensetibo ti kadakkel ti letra\"\n\n#Ikabil dagita \"regex fragment\" ti ngato daytoy a linia. Baybay-an a kastoy daytoy a linia</pre>",
index 3ed9f04..00faf9d 100644 (file)
@@ -76,7 +76,8 @@
                        "Taxandru",
                        "C.R.",
                        "Elitre",
-                       "Laurentius"
+                       "Laurentius",
+                       "Macofe"
                ]
        },
        "tog-underline": "Sottolinea i collegamenti:",
        "tog-shownumberswatching": "Mostra il numero di utenti che hanno la pagina in osservazione",
        "tog-oldsig": "Firma attuale:",
        "tog-fancysig": "Gestisci la firma come wikitesto (senza collegamento automatico)",
-       "tog-uselivepreview": "Abilita la funzione ''Live preview'' (anteprima in diretta - sperimentale)",
+       "tog-uselivepreview": "Abilita la funzione ''Live preview'' (anteprima in diretta)",
        "tog-forceeditsummary": "Chiedi conferma se il campo oggetto è vuoto",
        "tog-watchlisthideown": "Nascondi le mie modifiche negli osservati speciali",
        "tog-watchlisthidebots": "Nascondi le modifiche dei bot negli osservati speciali",
        "anoneditwarning": "<strong>Attenzione:</strong> Accesso non effettuato. Se effettuerai delle modifiche il tuo indirizzo IP sarà visibile pubblicamente. Se <strong>[$1 accedi]</strong> o <strong>[$2 crei un'utenza]</strong>, le tue modifiche saranno attribuite al tuo nome utente, insieme ad altri benefici.",
        "anonpreviewwarning": "''Non è stato eseguito il login. Salvando la pagina, il proprio indirizzo IP sarà registrato nella cronologia.''",
        "missingsummary": "'''Attenzione:''' non è stato specificato l'oggetto di questa modifica. Premendo di nuovo \"{{int:savearticle}}\" la modifica verrà salvata con l'oggetto vuoto.",
+       "selfredirect": "<strong>Attenzione:</strong> stai creando un redirect alla medesima voce.\nSe fai clic nuovamente su \"{{int:savearticle}}\", il redirect sarà creato.",
        "missingcommenttext": "Inserire un commento qui sotto.",
        "missingcommentheader": "'''Attenzione:''' non è stata specificato l'oggetto/l'intestazione di questo commento. Premendo di nuovo \"{{int:savearticle}}\" la modifica verrà salvata senza intestazione.",
        "summary-preview": "Anteprima dell'oggetto:",
index e95eeea..f6184c0 100644 (file)
        "nonunicodebrowser": "<strong>警告: ご使用中のブラウザーは Unicode に未対応です。</strong>\n安全にページを編集する回避策を表示しています: 編集ボックス内の非 ASCII 文字を 16 進数コードで表現しています。",
        "editingold": "<strong>警告: このページの古い版を編集しています。</strong>\n保存すると、この版以降になされた変更がすべて失われます。",
        "yourdiff": "差分",
-       "copyrightwarning": "{{SITENAME}}ã\81¸ã\81®æ\8a\95稿ã\81¯ã\80\81ã\81\99ã\81¹ã\81¦$2 (詳細ã\81¯$1ã\82\92å\8f\82ç\85§) ã\81®ã\82\82ã\81¨ã\81§å\85¬é\96\8bã\81\97ã\81\9fã\81¨è¦\8bã\81ªã\81\95ã\82\8cã\82\8bã\81\93ã\81¨ã\81«ã\81\94注æ\84\8fã\81\8fã\81 ã\81\95ã\81\84ã\80\82\nã\81\82ã\81ªã\81\9fã\81\8cæ\8a\95稿ã\81\97ã\81\9fã\82\82ã\81®ã\82\92ã\80\81ä»\96人ã\81«ã\82\88ã\81£ã\81¦é\81 æ\85®ã\81ªã\81\8fç·¨é\9b\86ã\81\97ã\80\81ã\81\9dã\82\8cã\82\92è\87ªç\94±ã\81«é\85\8då¸\83ã\81\99ã\82\8bã\81®ã\82\92æ\9c\9bã\81¾ã\81ªã\81\84å ´å\90\88ã\81¯ã\80\81ã\81\93ã\81\93ã\81«ã\81¯æ\8a\95稿ã\81\97ã\81ªã\81\84ã\81§ã\81\8fã\81 ã\81\95ã\81\84ã\80\82<br />\nã\81¾ã\81\9fã\80\81æ\8a\95稿ã\81\99ã\82\8bã\81®ã\81¯ã\80\81ã\81\82ã\81ªã\81\9fã\81\8cæ\9b¸ã\81\84ã\81\9fã\82\82ã\81®ã\81\8bã\80\81ã\83\91ã\83\96ã\83ªã\83\83ã\82¯ ã\83\89ã\83¡ã\82¤ã\83³ã\81¾ã\81\9fã\81¯ã\81\9dã\82\8cã\81«é¡\9eã\81\99ã\82\8bã\83\95ã\83ªã\83¼ã\81ªè³\87æ\96\99ã\81\8bã\82\89ã\81®è¤\87製ã\81§ã\81\82ã\82\8bã\81\93ã\81¨ã\82\92ç´\84æ\9d\9fã\81\97ã\81¦ã\81\8fã\81 ã\81\95ã\81\84ã\80\82\n<strong>è\91\97ä½\9c権ä¿\9dè­·ã\81\95ã\82\8cã\81¦ã\81\84ã\82\8bä½\9cå\93\81ã\82\92ã\80\81許諾ã\81ªã\81\97ã\81«æ\8a\95稿ã\81\97ã\81ªã\81\84ã\81§ã\81\8fã\81 ã\81\95ã\81\84!</strong>",
-       "copyrightwarning2": "{{SITENAME}}へのすべての投稿は、他の利用者によって編集、変更、除去される場合があります。\nあなたの投稿を、他人が遠慮なく編集するのを望まない場合は、ここには投稿しないでください。<br />\nまた、投稿するのは、あなたが書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください (詳細は$1を参照)。\n<strong>著作権保護されている作品を、許諾なしに投稿してはいけません!</strong>",
+       "copyrightwarning": "{{SITENAME}}ã\81¸ã\81®æ\8a\95稿ã\81¯ã\81\99ã\81¹ã\81¦ã\80\81$2 ï¼\88詳細ã\81¯$1ã\82\92å\8f\82ç\85§ï¼\89ã\81®ã\82\82ã\81¨ã\81§å\85¬é\96\8bã\81\97ã\81\9fã\81¨è¦\8bã\81ªã\81\95ã\82\8cã\82\8bã\81\93ã\81¨ã\81«ã\81\94注æ\84\8fã\81\8fã\81 ã\81\95ã\81\84ã\80\82\nè\87ªå\88\86ã\81\8cæ\9b¸ã\81\84ã\81\9fã\82\82ã\81®ã\81\8cä»\96ã\81®äººã\81«å®¹èµ¦ã\81ªã\81\8fç·¨é\9b\86ã\81\95ã\82\8cã\80\81è\87ªç\94±ã\81«é\85\8då¸\83ã\81\95ã\82\8cã\82\8bã\81®ã\82\92æ\9c\9bã\81¾ã\81ªã\81\84å ´å\90\88ã\81¯ã\80\81ã\81\93ã\81\93ã\81«æ\8a\95稿ã\81\97ã\81ªã\81\84ã\81§ã\81\8fã\81 ã\81\95ã\81\84ã\80\82<br />\nã\81¾ã\81\9fã\80\81æ\8a\95稿ã\81\99ã\82\8bã\81®ã\81¯ã\80\81è\87ªå\88\86ã\81§æ\9b¸ã\81\84ã\81\9fã\82\82ã\81®ã\81\8bã\80\81ã\83\91ã\83\96ã\83ªã\83\83ã\82¯ ã\83\89ã\83¡ã\82¤ã\83³ã\81¾ã\81\9fã\81¯ã\81\9dã\82\8cã\81«é¡\9eã\81\99ã\82\8bã\83\95ã\83ªã\83¼ã\81ªè³\87æ\96\99ã\81\8bã\82\89ã\81®è¤\87製ã\81§ã\81\82ã\82\8bã\81\93ã\81¨ã\82\92ç´\84æ\9d\9fã\81\97ã\81¦ã\81\8fã\81 ã\81\95ã\81\84ã\80\82\n<strong>è\91\97ä½\9c権ä¿\9dè­·ã\81\95ã\82\8cã\81¦ã\81\84ã\82\8bä½\9cå\93\81ã\81¯ã\80\81許諾ã\81ªã\81\97ã\81«æ\8a\95稿ã\81\97ã\81ªã\81\84ã\81§ã\81\8fã\81 ã\81\95ã\81\84ï¼\81</strong>",
+       "copyrightwarning2": "{{SITENAME}}への投稿はすべて、他の投稿者によって編集、変更、除去される場合があります。\n自分が書いたものが他の人に容赦なく編集されるのを望まない場合は、ここに投稿しないでください。<br />\nまた、投稿するのは、自分で書いたものか、パブリック ドメインまたはそれに類するフリーな資料からの複製であることを約束してください(詳細は$1を参照)。\n<strong>著作権保護されている作品は、許諾なしに投稿しないでください!</strong>",
        "longpageerror": "<strong>エラー: 投稿された文章は {{PLURAL:$1|$1 KB}} の長さがあります。これは投稿できる最大の長さ {{PLURAL:$2|$2 KB}} を超えています。</strong>\nこの編集内容は保存できません。",
        "readonlywarning": "<strong>警告: データベースがメンテナンスのためロックされており、現在は編集内容を保存できません。</strong>\n必要であれば文章をコピー&amp;ペーストしてテキストファイルとして保存し、後ほど保存をやり直してください。\n\nデータベースをロックした管理者による説明は以下の通りです: $1",
        "protectedpagewarning": "<strong>警告: このページは保護されているため、管理者権限を持つ利用者のみが編集できます。</strong>\n参考として以下に最後の記録を表示します:",
        "specialpages-group-wiki": "データとツール",
        "specialpages-group-redirects": "転送される特別ページ",
        "specialpages-group-spam": "スパム対策ツール",
+       "specialpages-group-developer": "開発者用ツール",
        "blankpage": "白紙ページ",
        "intentionallyblankpage": "このページは意図的に白紙にされています。",
        "external_image_whitelist": "  #この行はこのままにしておいてください<pre>\n#この下に正規表現 (//の間に入る記述) を置いてください\n#外部の (ホットリンクされている) 画像の URL と一致するか検査されます\n#一致する場合は画像として、一致しない場合は画像へのリンクとして表示されます\n#行の頭に # を付けるとコメントとして扱われます\n#大文字と小文字は区別されません\n\n#正規表現はすべてこの行の上に置いてください。この行はこのままにしておいてください</pre>",
index d70104e..9b54920 100644 (file)
@@ -48,7 +48,7 @@
        "tog-shownumberswatching": "მაკონტროლებელ მომხმარებელთა რიცხვის ჩვენება",
        "tog-oldsig": "არსებული ხელმოწერა:",
        "tog-fancysig": "საკუთარი ვიკიფორმატიანი ხელმოწერა (ავტომატური ბმულის გარეშე)",
-       "tog-uselivepreview": "გამოიყენეთ სწრაფი წინასწარი გადახედვა (ექსპერიმენტული)",
+       "tog-uselivepreview": "გამოიყენეთ სწრაფი წინასწარი გადახედვა",
        "tog-forceeditsummary": "გამაფრთხილე ცარიელი რედაქტირების რეზიუმეს შემთხვევაში",
        "tog-watchlisthideown": "დამალე ჩემი რედაქტირება კონტროლის სიაში",
        "tog-watchlisthidebots": "დამალე რობოტის რედაქტირება კონტროლის სიაში",
        "permalink": "მუდმივი ბმული",
        "print": "ამობეჭდე",
        "view": "იხილე",
+       "view-foreign": "იხილეთ $1-ზე",
        "edit": "რედაქტირება",
        "edit-local": "ლოკალური აღწერის რედაქტირება",
        "create": "შექმნა",
        "otherlanguages": "სხვა ენებზე",
        "redirectedfrom": "(გადმომისამართდა $1-დან)",
        "redirectpagesub": "გადამისამართება გვერდზე",
+       "redirectto": "გადამისამართება:",
        "lastmodifiedat": "ეს გვერდი ბოლოს განახლდა $2, $1.",
        "viewcount": "ეს გვერდი შემოწმდა {{PLURAL:$1|ერთხელ|$1-ჯერ}}.",
        "protectedpage": "დაბლოკილი გვერდი",
        "viewsourcetext": "თქვენ შეგიძლიათ ნახოთ ამ გვერდის საწყისი ფაილი და მისი ასლი შექმნათ:",
        "viewyourtext": "თქვენ შეგიძლიათ იხილოთ და დააკოპიროთ  '''თქვენი რედაქტირებების''' საწყისი ტექსტი ამ გვერდზე:",
        "protectedinterface": "ეს გვერდი წარმოადგენს ტექსტურ ინტერფეისს პროგრამული უზრუნველყოფისათვის და დაცულია ვანდალიზმის აღკვეთის მიზნით.",
-       "editinginterface": "'''á\83§á\83£á\83 á\83\90á\83\93á\83¦á\83\94á\83\91á\83\90:''' á\83\97á\83¥á\83\95á\83\94á\83\9c á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\9dá\83 á\83\9dá\83\91á\83\97 á\83\92á\83\95á\83\94á\83 á\83\93á\83¡, á\83 á\83\9dá\83\9bá\83\94á\83\9aá\83\98á\83ª á\83\9eá\83 á\83\9dá\83\92á\83 á\83\90á\83\9bá\83\98á\83¡ á\83\98á\83\9cá\83¢á\83\94á\83 á\83¤á\83\94á\83\98á\83¡á\83\98á\83¡ á\83¢á\83\94á\83¥á\83¡á\83¢á\83¡ á\83¨á\83\94á\83\98á\83ªá\83\90á\83\95á\83¡. \ná\83\90á\83\9b á\83\92á\83\95á\83\94á\83 á\83\93á\83\96á\83\94 á\83\92á\83\90á\83\9cá\83®á\83\9dá\83 á\83ªá\83\98á\83\94á\83\9aá\83\94á\83\91á\83£á\83\9aá\83\98 á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\94á\83\91á\83\90 á\83\92á\83\90á\83\9bá\83\9dá\83\98á\83¬á\83\95á\83\94á\83\95á\83¡ á\83\90á\83\9b á\83\95á\83\98á\83\99á\83\98á\83¡ á\83¡á\83®á\83\95á\83\90 á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\97á\83\90 á\83¡á\83\90á\83\9bá\83£á\83¨á\83\90á\83\9d á\83\98á\83\9cá\83¢á\83\94á\83 á\83¤á\83\94á\83\98á\83¡á\83\98á\83¡ á\83¨á\83\94á\83ªá\83\95á\83\9aá\83\90á\83¡á\83\90á\83ª. \ná\83\98á\83\9bá\83\98á\83¡á\83\90á\83\97á\83\95á\83\98á\83¡, á\83 á\83\9dá\83\9b á\83\93á\83\90á\83\90á\83\9bá\83\90á\83¢á\83\9dá\83\97 á\83\90á\83\9c á\83¨á\83\94á\83ªá\83\95á\83\90á\83\9aá\83\9dá\83\97 á\83\97á\83\90á\83 á\83\92á\83\9bá\83\90á\83\9cá\83\94á\83\91á\83\98 á\83§á\83\95á\83\94á\83\9aá\83\90 á\83\95á\83\98á\83\99á\83\98á\83¨á\83\98 გთხოვთ, გამოიყენოთ მედიავიკის ლოკალიზაციის პროექტი [//translatewiki.net/ translatewiki.net].",
+       "editinginterface": "'''á\83§á\83£á\83 á\83\90á\83\93á\83¦á\83\94á\83\91á\83\90:''' á\83\97á\83¥á\83\95á\83\94á\83\9c á\83\90á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\94á\83\91á\83\97 á\83\92á\83\95á\83\94á\83 á\83\93á\83¡, á\83 á\83\9dá\83\9bá\83\94á\83\9aá\83\98á\83ª á\83\9eá\83 á\83\9dá\83\92á\83 á\83\90á\83\9bá\83\98á\83¡ á\83\98á\83\9cá\83¢á\83\94á\83 á\83¤á\83\94á\83\98á\83¡á\83\98á\83¡ á\83¢á\83\94á\83¥á\83¡á\83¢á\83¡ á\83¨á\83\94á\83\98á\83ªá\83\90á\83\95á\83¡. \ná\83\90á\83\9b á\83\92á\83\95á\83\94á\83 á\83\93á\83\96á\83\94 á\83\92á\83\90á\83\9cá\83®á\83\9dá\83 á\83ªá\83\98á\83\94á\83\9aá\83\94á\83\91á\83£á\83\9aá\83\98 á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\94á\83\91á\83\90 á\83\92á\83\90á\83\9bá\83\9dá\83\98á\83¬á\83\95á\83\94á\83\95á\83¡ á\83\90á\83\9b á\83\95á\83\98á\83\99á\83\98á\83¡ á\83¡á\83®á\83\95á\83\90 á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\97á\83\90 á\83¡á\83\90á\83\9bá\83£á\83¨á\83\90á\83\9d á\83\98á\83\9cá\83¢á\83\94á\83 á\83¤á\83\94á\83\98á\83¡á\83\98á\83¡ á\83¨á\83\94á\83ªá\83\95á\83\9aá\83\90á\83¡á\83\90á\83ª. \ná\83\98á\83\9bá\83\98á\83¡á\83\90á\83\97á\83\95á\83\98á\83¡, á\83 á\83\9dá\83\9b á\83\93á\83\90á\83\90á\83\9bá\83\90á\83¢á\83\9dá\83\97 á\83\90á\83\9c á\83¨á\83\94á\83ªá\83\95á\83\90á\83\9aá\83\9dá\83\97 á\83\97á\83\90á\83 á\83\92á\83\9bá\83\90á\83\9cá\83\94á\83\91á\83\98 á\83§á\83\95á\83\94á\83\9aá\83\90 á\83\95á\83\98á\83\99á\83\98á\83¨á\83\98, გთხოვთ, გამოიყენოთ მედიავიკის ლოკალიზაციის პროექტი [//translatewiki.net/ translatewiki.net].",
        "cascadeprotected": "ეს გვერდი რედაქტირებისგან დაცულია, რადგან იგი ჩართულია შემდეგ {{PLURAL:$1|გვერდში, რომლის |გვერდებში, რომელთა}} დასაცავადაც ჩართულია პარამეტრი \"იერარქიული\":\n$2",
        "namespaceprotected": "თქვენ არ გაქვთ '''$1''' სახელთა სივრცეში გვერდების რედაქტირების უფლება.",
        "customcssprotected": "თქვენ არ გაქვთ ამ CSS გვერდის რედაქტირების უფლება, ვინაიდან ის სხვა მომხმარებლის პირად კონფიგურაციას შეიცავს.",
index 60b7594..8cb30ab 100644 (file)
        "pageinfo-header-edits": "편집 역사",
        "pageinfo-header-restrictions": "문서 보호",
        "pageinfo-header-properties": "문서 속성",
-       "pageinfo-display-title": "ë³´ì\97¬ì¤\84 ì\9d´ë¦\84",
+       "pageinfo-display-title": "ë³´ì\97¬ì¤\84 ì \9c목",
        "pageinfo-default-sort": "기본 정렬 키",
        "pageinfo-length": "문서 길이 (바이트)",
        "pageinfo-article-id": "문서 ID",
index fe9b550..282de51 100644 (file)
@@ -43,7 +43,7 @@
        "tog-shownumberswatching": "D'Zuel vun de Benotzer déi dës Säit iwwerwaache weisen",
        "tog-oldsig": "Aktuell Ënnerschrëft:",
        "tog-fancysig": "Ënnerschrëft als Wiki-Text behandelen (Ouni automatesche Link)",
-       "tog-uselivepreview": "Live-Preview benotzen (experimentell)",
+       "tog-uselivepreview": "Live-Preview benotzen",
        "tog-forceeditsummary": "Warnen, wa beim Späicheren de Resumé feelt",
        "tog-watchlisthideown": "Meng Ännerungen op menger Iwwerwaachungslëscht verstoppen",
        "tog-watchlisthidebots": "Ännerunge vu Botten op menger Iwwerwaachungslëscht verstoppen",
        "anoneditwarning": "<strong>Opgepasst:</strong> Dir sidd net ageloggt. Dowéinst gëtt amplaz vun engem Benotzernumm Är IP Adress ëffentlech gewise wann Dir Ännerunge maacht. Wann Dir <strong>[$1 Iech aloggt]</strong> oder <strong>[$2 e Bnotzerkont opmaachen]</strong>, Är Ännerunge ginn dann Ärem Benotzerkont zougedeelt, genee wéi aner Avantagen.",
        "anonpreviewwarning": "''Dir sidd net ageloggt. Wann Dir ofspäichert gëtt Är IP-Adress an der Lëscht vun de Versioune vun dëser Säit enregistréiert.''",
        "missingsummary": "'''Erënnerung:''' Dir hutt kee Resumé aginn.\nWann Dir nacheemol op \"{{int:savearticle}}\" klickt, gëtt Är Ännerung ouni Resumé ofgespäichert.",
+       "selfredirect": "<strong>Opgepasst:</strong> Dir maacht eng Viruleedung op deeselwechten Artikel.\nWann Dir nach eng Kéier op \"{{int:savearticle}}\" klickt, da gëtt d'Viruleedung ugeluecht.",
        "missingcommenttext": "Gitt w.e.g. eng Bemierkung an.",
        "missingcommentheader": "'''Denkt drun:''' Dir hutt keen Titel/Sujet fir dës Bemierkung aginn.\nWann Dir nach en Kéier op \"{{int:savearticle}}\" klickt da gëtt Är Ännerung ouni Titel gespäichert.",
        "summary-preview": "Resumé kucken ouni ofzespäicheren:",
index f4c1fc4..139f3c1 100644 (file)
@@ -43,7 +43,7 @@
        "tog-shownumberswatching": "Прикажи го бројот на корисници кои набљудуваат",
        "tog-oldsig": "Постоечки потпис:",
        "tog-fancysig": "Сметај го потписот за викитекст (без автоматска врска)",
-       "tog-uselivepreview": "Користи преглед во живо (експериментално)",
+       "tog-uselivepreview": "Користи преглед во живо",
        "tog-forceeditsummary": "Извести ме кога нема опис на промените",
        "tog-watchlisthideown": "Скриј мои уредувања од списокот на набљудувања",
        "tog-watchlisthidebots": "Скриј ботовски уредувања од списокот на набљудувања",
        "anoneditwarning": "<strong>Предупредување:</strong> Не сте најавени. Вашата IP-адреса ќе биде јавно видлива ако уредувате. Ако <strong>[$1 се најавите]</strong> или <strong>[$2 направите сметка]</strong>, тогаш уредувањата ќе се припишуваат на вашето корисничко име, покрај другите погодности.",
        "anonpreviewwarning": "''Не сте најавени. Ако ја зачувате, Вашата IP-адреса ќе биде заведена во историјата на уредување на страницата.''",
        "missingsummary": "'''Потсетник:''' Не внесовте опис на измените. Ако притиснете Зачувај повторно, вашите измени ќе се зачуваат без опис.",
+       "selfredirect": "<strong>Предупредување:</strong> Создавате пренасочување кон истата статија.\nАко стиснете на „{{int:savearticle}}“ повторно, тогаш пренасочувањето ќе се создаде.",
        "missingcommenttext": "Ве молиме внесете коментар подолу.",
        "missingcommentheader": "'''Потсетување:''' Не внесовте наслов за овој коментар.\nАко повторно стиснете на „{{int:savearticle}}“, уредувањето ќе биде зачувано без наслов.",
        "summary-preview": "Изглед на описот:",
        "pager-older-n": "{{PLURAL:$1|постара 1|постари $1}}",
        "suppress": "Скривање",
        "querypage-disabled": "Оваа службена страница е оневозможена за да не попречува на делотворноста.",
-       "apihelp": "Ð\9fомоÑ\88 Ñ\81о Ð¿Ñ\80илогот",
+       "apihelp": "Ð\9fомоÑ\88 Ñ\81о Ð¸Ð·Ð²Ñ\80Ñ\88никот",
        "apihelp-no-such-module": "Модулот „$1“ не е пронајден.",
        "booksources": "Печатени извори",
        "booksources-search-legend": "Пребарување на извори за книга",
        "hijri-calendar-m10": "Шавал",
        "hijri-calendar-m11": "Ду ел-Кида",
        "hijri-calendar-m12": "Ду ел-Хиџа",
-       "hebrew-calendar-m1": "Тишри",
-       "hebrew-calendar-m2": "Хешван",
-       "hebrew-calendar-m3": "Ð\9aислев",
-       "hebrew-calendar-m4": "Тебет",
-       "hebrew-calendar-m5": "Шебат",
-       "hebrew-calendar-m6": "Ð\90дар",
-       "hebrew-calendar-m6a": "Ð\90дар I",
-       "hebrew-calendar-m6b": "Ð\90дар II",
-       "hebrew-calendar-m7": "Ð\9dисан",
-       "hebrew-calendar-m8": "Ð\98јар",
-       "hebrew-calendar-m9": "Сиван",
-       "hebrew-calendar-m10": "Тамуз",
-       "hebrew-calendar-m11": "Ð\90в",
-       "hebrew-calendar-m12": "Ð\95лул",
-       "hebrew-calendar-m1-gen": "Тишри",
-       "hebrew-calendar-m2-gen": "Хешван",
-       "hebrew-calendar-m3-gen": "Ð\9aислев",
-       "hebrew-calendar-m4-gen": "Тебет",
-       "hebrew-calendar-m5-gen": "Шебат",
-       "hebrew-calendar-m6-gen": "Ð\90дар",
-       "hebrew-calendar-m6a-gen": "Ð\90дар I",
-       "hebrew-calendar-m6b-gen": "Ð\90дар II",
-       "hebrew-calendar-m7-gen": "Ð\9dисан",
-       "hebrew-calendar-m8-gen": "Ð\98јар",
-       "hebrew-calendar-m9-gen": "Сиван",
-       "hebrew-calendar-m10-gen": "Тамуз",
-       "hebrew-calendar-m11-gen": "Ð\90в",
-       "hebrew-calendar-m12-gen": "Ð\95лул",
+       "hebrew-calendar-m1": "тишри",
+       "hebrew-calendar-m2": "хешван",
+       "hebrew-calendar-m3": "кислев",
+       "hebrew-calendar-m4": "тевет",
+       "hebrew-calendar-m5": "шват",
+       "hebrew-calendar-m6": "адар",
+       "hebrew-calendar-m6a": "адар I",
+       "hebrew-calendar-m6b": "адар II",
+       "hebrew-calendar-m7": "нисан",
+       "hebrew-calendar-m8": "ијар",
+       "hebrew-calendar-m9": "сиван",
+       "hebrew-calendar-m10": "тамуз",
+       "hebrew-calendar-m11": "ав",
+       "hebrew-calendar-m12": "елул",
+       "hebrew-calendar-m1-gen": "тишри",
+       "hebrew-calendar-m2-gen": "хешван",
+       "hebrew-calendar-m3-gen": "кислев",
+       "hebrew-calendar-m4-gen": "тевет",
+       "hebrew-calendar-m5-gen": "шват",
+       "hebrew-calendar-m6-gen": "адар",
+       "hebrew-calendar-m6a-gen": "адар I",
+       "hebrew-calendar-m6b-gen": "адар II",
+       "hebrew-calendar-m7-gen": "нисан",
+       "hebrew-calendar-m8-gen": "ијар",
+       "hebrew-calendar-m9-gen": "сиван",
+       "hebrew-calendar-m10-gen": "тамуз",
+       "hebrew-calendar-m11-gen": "ав",
+       "hebrew-calendar-m12-gen": "елул",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|разговор]])",
        "unknown_extension_tag": "Непозната ознака на додатокот „$1“",
        "duplicate-defaultsort": "Предупредување: Основниот клуч за подредување „$2“ го поништува претходниот основен клуч за подредување „$1“.",
        "version-parserhooks": "Расчленувачки куки",
        "version-variables": "Променливи",
        "version-antispam": "Спречување на спам",
-       "version-api": "Ð\9fÑ\80илози",
+       "version-api": "Ð\98звÑ\80Ñ\88ниÑ\86и",
        "version-other": "Друго",
        "version-mediahandlers": "Ракувачи со мултимедијални содржини",
        "version-hooks": "Куки",
        "feedback-cancel": "Откажи",
        "feedback-submit": "Поднеси мислење",
        "feedback-adding": "Го додавам искажаното мислење во страницата...",
-       "feedback-error1": "Ð\93Ñ\80еÑ\88ка: Ð\9dепÑ\80епознаен Ñ\80езÑ\83лÑ\82аÑ\82 Ð¾Ð´ Ð¿Ñ\80илогот (API)",
+       "feedback-error1": "Ð\93Ñ\80еÑ\88ка: Ð\9dепÑ\80епознаен Ñ\80езÑ\83лÑ\82аÑ\82 Ð¾Ð´ Ð¸Ð·Ð²Ñ\80Ñ\88никот (API)",
        "feedback-error2": "Грешка: Уредувањето не успеа",
-       "feedback-error3": "Ð\93Ñ\80еÑ\88ка: Ð\9fÑ\80илогоÑ\82 (API) не одговара",
+       "feedback-error3": "Ð\93Ñ\80еÑ\88ка: Ð\98звÑ\80Ñ\88никоÑ\82 не одговара",
        "feedback-thanks": "Благодариме! Вашиот одѕив е објавен на страницата „[$2 $1]“.",
        "feedback-close": "Готово",
        "feedback-bugcheck": "Одлично! Само проверете да не е една од [$1 веќе познатите грешки].",
index 6fdd349..b7481e9 100644 (file)
@@ -55,7 +55,7 @@
        "tog-shownumberswatching": "ശ്രദ്ധിക്കുന്ന ഉപയോക്താക്കളുടെ എണ്ണം കാണിക്കുക",
        "tog-oldsig": "നിലവിലുള്ള ഒപ്പ്:",
        "tog-fancysig": "ഒപ്പ് ഒരു വിക്കി എഴുത്തായി പരിഗണിക്കുക (കണ്ണി സ്വയം ചേർക്കേണ്ടതില്ല)",
-       "tog-uselivepreview": "തത്സമയ പ്രിവ്യൂ ഉപയോഗപ്പെടുത്തുക (പരീക്ഷണാടിസ്ഥാനം)",
+       "tog-uselivepreview": "തത്സമയ പ്രിവ്യൂ ഉപയോഗപ്പെടുത്തുക",
        "tog-forceeditsummary": "തിരുത്തുകളുടെ ചുരുക്കം നൽകിയില്ലെങ്കിൽ എന്നെ ഓർമ്മിപ്പിക്കുക",
        "tog-watchlisthideown": "ഞാൻ ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടികയിൽനിന്ന് എന്റെ തിരുത്തുകൾ മറയ്ക്കുക",
        "tog-watchlisthidebots": "ഞാൻ ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടികയിൽനിന്ന് യന്ത്രങ്ങൾ വരുത്തിയ തിരുത്തുകൾ മറയ്ക്കുക",
        "anoneditwarning": "<strong>മുന്നറിയിപ്പ്:</strong> താങ്കൾ ലോഗിൻ ചെയ്തിട്ടില്ല. താങ്കൾ തിരുത്തുകളെന്തെങ്കിലും ചെയ്യുകയാണെങ്കിൽ താങ്കളുടെ ഐ.പി. വിലാസം എല്ലാവർക്കും ലഭ്യമായിരിക്കും. താങ്കൾ <strong>[$1 ലോഗിൻ ചെയ്യുകയോ]</strong>  <strong>[$2 അംഗത്വമെടുക്കുകയോ]</strong> ചെയ്യുന്നതുവഴി മറ്റ് ഗുണങ്ങളോടൊപ്പം താങ്കളുടെ തിരുത്തുകൾ ഉപയോക്തൃനാമത്തിലാവും അറിയപ്പെടുക.",
        "anonpreviewwarning": "''താങ്കൾ ലോഗിൻ ചെയ്തിട്ടില്ല. സേവ് ചെയ്യുമ്പോൾ താളിന്റെ തിരുത്തൽ ചരിത്രത്തിൽ താങ്കളുടെ ഐ.പി. വിലാസം ചേർത്തു സൂക്ഷിക്കപ്പെടും.''",
        "missingsummary": "'''ഓർമ്മക്കുറിപ്പ്:''' താങ്കൾ തിരുത്തലിന്റെ ചുരുക്കരൂപം നൽകിയിട്ടില്ല. ''സേവ് ചെയ്യുക'' ബട്ടൺ ഒരുവട്ടം കൂടി അമർത്തിയാൽ താങ്കൾ വരുത്തിയ മാറ്റം കാത്തുസൂക്ഷിക്കുന്നതാണ്.",
+       "selfredirect": "<strong>മുന്നറിയിപ്പ്:</strong> അതേ ലേഖനത്തിലേക്കുള്ള തിരിച്ചുവിടലാണ് താങ്കൾ സൃഷ്ടിക്കുന്നത്.\nവീണ്ടും \"{{int:savearticle}}\" അമർത്തിയാൽ, തിരിച്ചുവിടൽ സൃഷ്ടിക്കപ്പെടുന്നതാണ്.",
        "missingcommenttext": "താങ്കളുടെ അഭിപ്രായം ദയവായി താഴെ രേഖപ്പെടുത്തുക.",
        "missingcommentheader": "'''ഓർമ്മക്കുറിപ്പ്:''' ഈ കുറിപ്പിന് താങ്കൾ വിഷയം/തലക്കെട്ട് നൽകിയിട്ടില്ല. ''{{int:savearticle}}'' എന്ന ബട്ടൺ ഒരുവട്ടം കൂടി അമർത്തിയാൽ വിഷയം/തലക്കെട്ട് ഇല്ലാതെ തന്നെ കാത്തുസൂക്ഷിക്കുന്നതാവും.",
        "summary-preview": "ചുരുക്കരൂപം എങ്ങനെയുണ്ടെന്നു കാണുക:",
index d18c67e..bbe6a1c 100644 (file)
@@ -38,7 +38,7 @@
        "tog-shownumberswatching": "Fa' vedé 'o nummero d'utente che teneno 'a paggena cuntrullata",
        "tog-oldsig": "Firma 'e mmo:",
        "tog-fancysig": "Piglia 'a firma comme fosse nu wikitesto (senza fà link automatico)",
-       "tog-uselivepreview": "Abilita 'o \"Live preview\" (sperimentale)",
+       "tog-uselivepreview": "Abbìa 'o \"Live preview\"",
        "tog-forceeditsummary": "Chiere a mme quanno se sta azzeccanno nu campo oggetto abbacante",
        "tog-watchlisthideown": "Annascunne 'e cagnamiente d' 'a lista 'e cuntrollo mia",
        "tog-watchlisthidebots": "Annasconne 'e cagnamiènte d' 'e bot ncopp'a l'elenco 'e cuntrollo",
        "userlogin-createanother": "Cria n'at'account",
        "createacct-emailrequired": "Indirizzo email",
        "createacct-emailoptional": "Indirizzo 'e posta elettronica (ozzionale)",
-       "createacct-email-ph": "Scrive 'o nderizzo mail tuo",
-       "createacct-another-email-ph": "Scrive nderizzo mail",
+       "createacct-email-ph": "Scrivite 'o nderizzo mail vuosto",
+       "createacct-another-email-ph": "Scrivite nderizzo mail",
        "createaccountmail": "Usa na password qualunque temporanea e manna sta password a l'indirizzo 'e posta e-mail specificato",
        "createacct-realname": "Nomme riale (ozzionale)",
        "createaccountreason": "Mutivo:",
        "createacct-reason": "Mutivo",
        "createacct-reason-ph": "Pecché staje crianno n'at'utenza",
        "createacct-captcha": "Cuntrollo 'e sicurezza",
-       "createacct-imgcaptcha-ph": "Scrive 'o testo ca vire ncoppa",
+       "createacct-imgcaptcha-ph": "Scrivite 'o testo ca vedite ncoppa",
        "createacct-submit": "Cria 'a toja utenza",
        "createacct-another-submit": "Cria 'n atro account",
        "createacct-benefit-heading": "{{SITENAME}} è fatta 'e perzone comme te.",
        "emailnotauthenticated": "'O ndirizzo 'e posta elettronica nun è stat'ancora cunfermato.\nNun se mannarranno mmasciate e-mail p' ' funzione ccà abbascio.",
        "noemailprefs": "Avite 'a specificà nu ndirizzo e-mail pe ll'attivà sti funzione.",
        "emailconfirmlink": "Cunferma 'o nderizzo mail d' 'o tujo.",
-       "invalidemailaddress": "'O nderizzo e-mail scritto nun se può accettà pecché nun tene nu furmatto buono.\nScrive n'ata vota nu nderizzo bbuono o abbacanta 'a casella.",
+       "invalidemailaddress": "'O nderizzo e-mail scritto nun se può accettà pecché nun tene nu furmatto buono.\nScrivite n'ata vota nu nderizzo bbuono o abbacantate 'a casciulella.",
        "cannotchangeemail": "'E ccunte mail nun se ponno cagnà dint'a sta wiki.",
        "emaildisabled": "Chistu sito nun può mannà mmasciate e-mail.",
        "accountcreated": "Cunto criato",
        "anoneditwarning": "'''Attenzione:''' Nun avite fatto l'acciesso. 'A cronologgia d' 'a vosta sarrà visibbele pubbrecamente si facite cocche cagnamiento. Si <strong>[$1 tràse]</strong> o <strong>[$2 crìe nu cunto]</strong>, 'e cagnamiente vuoste ve sarranno attribbuite a vvuje, nzieme a n'ati migliuramente.",
        "anonpreviewwarning": "''Nun avite fatto 'o login. Sarvann' 'a paggena, l'indirizzo IP d' 'o vuosto sarrà riggistrato dint'a cronologgia.''",
        "missingsummary": "'''Attenziò:''' nun s'è specificato l'oggetto 'e stu cagnamiento. Clicann' 'a \"{{int:savearticle}}\" n'ata vota 'o cagnamiento sarrà sarvato cu l'oggetto abbacante.",
+       "selfredirect": "<strong>Attenziò:</strong> State crianno nu redirect a 'o stesso articolo.\nSi cliccate \"{{int:savearticle}}\" n'ata vota, si criarrà 'o redirect.",
        "missingcommenttext": "Pe' piacere scrivete nu commento ccà abbascio.",
        "missingcommentheader": "'''Attenziò:''' nun s'è specificato l'oggetto/titolo 'e stu commento. Clicann' 'a \"{{int:savearticle}}\" n'ata vota 'o cagnamiento sarrà sarvato c' 'o titolo abbacante.",
        "summary-preview": "Anteprimma'e l'oggetto:",
index 3f9f991..238ff58 100644 (file)
@@ -32,6 +32,7 @@
        "tog-watchdefault": "Spul wa'k bewarke op mien volglieste zetten",
        "tog-watchmoves": "Spul wa'k herneume op mien volglieste zetten",
        "tog-watchdeletion": "Spul wa'k vortdo op mien volglieste zetten",
+       "tog-watchrollback": "Ziejen waorvan ik bewarkingen weerummedreid hebbe automaties volgen",
        "tog-minordefault": "Markeer alle veraanderingen as 'kleine wieziging'",
        "tog-previewontop": "De naokiekzied boven t bewarkingsveld zetten",
        "tog-previewonfirst": "Naokieken bie eerste wieziging",
@@ -42,7 +43,7 @@
        "tog-shownumberswatching": "t Antal gebrukers bekieken die disse zied volgt",
        "tog-oldsig": "Bestaonde haandtekening:",
        "tog-fancysig": "Ondertekening zien as wikitekste (zonder automatiese verwiezing)",
-       "tog-uselivepreview": "Gebruuk \"rechtstreeks naokieken\" (experimenteel)",
+       "tog-uselivepreview": "Gebruuk \"rechtstreeks naokieken\"",
        "tog-forceeditsummary": "Geef n melding bie n lege samenvatting",
        "tog-watchlisthideown": "Verbarg mien eigen bewarkingen",
        "tog-watchlisthidebots": "Verbarg botgebrukers",
        "view": "Lezen",
        "view-foreign": "Bekieken op $1",
        "edit": "Bewarken",
+       "edit-local": "Lokale beschrieving bewarken",
        "create": "Anmaken",
+       "create-local": "Lokale beschrieving derbie doon",
        "editthispage": "Disse zied bewarken",
        "create-this-page": "Disse zied anmaken",
        "delete": "Vortdoon",
        "otherlanguages": "Aandere talen",
        "redirectedfrom": "(deurestuurd vanaof \"$1\")",
        "redirectpagesub": "Deurverwieszied",
+       "redirectto": "Deurverwiezen naor:",
        "lastmodifiedat": "Disse zied is t lest ewiezigd op $1 um $2.",
        "viewcount": "Disse zied is $1 {{PLURAL:$1|keer|keer}} bekeken.",
        "protectedpage": "Beveiligden zied",
        "jumptonavigation": "navigasie",
        "jumptosearch": "zeuk",
        "view-pool-error": "De servers bin op heden overbelast.\nTe veule gebrukers proberen disse zied te bekieken.\nWacht effen veurda'j opniej toegang proberen te kriegen tot disse zied.\n\n$1",
+       "generic-pool-error": "De servers bin op heden overbelast.\nTe veule gebrukers proberen disse zied te bekieken.\nWacht effen veurda'j opniej toegang proberen te kriegen tot disse zied.",
        "pool-timeout": "De maximumwachttied veur databankvergrendeling is verleupen.",
        "pool-queuefull": "De wachtrie van de poel is vol",
        "pool-errorunknown": "Onbekende fout",
+       "pool-servererror": "De dienst \"pool counter\" is niet beschikbaor ($1).",
        "aboutsite": "Over {{SITENAME}}",
        "aboutpage": "Project:Info",
        "copyright": "De inhoud is beschikbaor onder de $1 as der niks aanders an-egeven is.",
        "filerenameerror": "Bestaandsnaamwieziging \"$1\" naor \"$2\" niet meugelik.",
        "filedeleteerror": "Kon bestaand \"$1\" niet vortdoon.",
        "directorycreateerror": "Map \"$1\" kon niet an-emaakt wörden.",
+       "directoryreadonlyerror": "De map \"$1\" is allinnig-lezen.",
+       "directorynotreadableerror": "De map \"$1\" kan niet elezen wörden.",
        "filenotfound": "Kon bestaand \"$1\" niet vienen.",
        "unexpected": "Onverwachten weerde: \"$1\"=\"$2\".",
        "formerror": "Fout: kon formulier niet versturen",
        "viewsourcetext": "Je kunnen de brontekste van disse zied bewarken en bekieken:",
        "viewyourtext": "Je kunnen '''joew bewarkingen''' an de brontekste van disse zied bekieken en kopiëren:",
        "protectedinterface": "Op disse zied steet tekste die gebruukt wörden veur systeemteksten van disse wiki. Allinnig beheerders kunnen disse zied bewarken.\nUm vertalingen veur alle wiki's derbie te zetten of te wiezigen, gebruuk [//translatewiki.net/ translatewiki.net], t vertaalprojekt veur MediaWiki.",
-       "editinginterface": "'''Waorschuwing:''' je bewarken n zied die gebruukt wörden deur de programmatuur. Wa'j hier wiezigen, is van invleud op de hele wiki. Um vertalingen derbie te zetten of te wiezigen veur alle wiki's, gebruuk [//translatewiki.net/wiki/Main_Page?setlang=nds-nl translatewiki.net], t vertalingsprojekt veur MediaWiki.",
+       "editinginterface": "<strong>Waorschuwing:</strong> je bewarken n zied die gebruukt wörden deur de programmatuur. Wa'j hier wiezigen, is van invleud op de hele wiki. Um vertalingen derbie te zetten of te wiezigen veur alle wiki's, gebruuk [//translatewiki.net/wiki/Main_Page?setlang=nds-nl translatewiki.net], t vertalingsprojekt veur MediaWiki.",
        "cascadeprotected": "Disse zied is beveiligd umdat t veurkömp in de volgende {{PLURAL:$1|zied|ziejen}}, die beveiligd {{PLURAL:$1|is|bin}} mit de \"kaskade\"-opsie:\n$2",
        "namespaceprotected": "Je maggen gien ziejen in de '''$1'''-naamruumte bewarken.",
        "customcssprotected": "Je kunnen disse CSS-zied niet bewarken, umdat der persoonlike instellingen van n aandere gebruker in staon.",
        "import": "Ziejen invoeren",
        "importinterwiki": "Transwiki-invoer",
        "import-interwiki-text": "Kies n wiki en ziednaam um in te voeren.\nVersie- en auteursgegevens blieven hierbie beweerd.\nAlle transwiki-invoerhaandelingen wörden op-esleugen in t [[Special:Log/import|invoerlogboek]].",
+       "import-interwiki-sourcewiki": "Bronwiki:",
+       "import-interwiki-sourcepage": "Bronzied:",
        "import-interwiki-history": "Kopieer de hele geschiedenisse veur disse zied",
        "import-interwiki-templates": "Alle mallen opnemen",
        "import-interwiki-submit": "Invoeren",
        "version-hook-subscribedby": "In-eschreven deur",
        "version-version": "(Versie $1)",
        "version-license": "MediaWiki-lisensie",
+       "version-ext-colheader-version": "Versie",
+       "version-ext-colheader-license": "Lisensie",
+       "version-ext-colheader-description": "Beschrieving",
+       "version-ext-colheader-credits": "Auteurs",
        "version-poweredby-credits": "Disse wiki wörden an-estuurd deur '''[https://www.mediawiki.org/ MediaWiki]''', auteursrecht © 2001-$1 $2.",
        "version-poweredby-others": "aanderen",
        "version-poweredby-translators": "vertalers van translatewiki.net",
        "fileduplicatesearch-result-n": "Der {{PLURAL:$2|is één bestaand|bin $2 bestaanden}} die liek alleens bin as \"$1\".",
        "fileduplicatesearch-noresults": "Der is gien bestaand mit de naam \"$1\" evunnen.",
        "specialpages": "Spesiale ziejen",
+       "specialpages-note-top": "Legenda",
        "specialpages-note": "* Normale spesiale ziejen.\n* <span class=\"mw-specialpagerestricted\">Beparkt toegankelike spesiale ziejen.</span>",
        "specialpages-group-maintenance": "Onderhoudsliesten",
        "specialpages-group-other": "Aandere spesiale ziejen",
        "expand_templates_remove_comments": "Opmarking vorthaolen",
        "expand_templates_remove_nowiki": "Etiketten <nowiki> in resultaot onderdrokken",
        "expand_templates_generate_xml": "XML-parserboom bekieken",
-       "expand_templates_preview": "Naokieken"
+       "expand_templates_preview": "Naokieken",
+       "pagelang-language": "Taal",
+       "mediastatistics-header-audio": "Audio",
+       "mediastatistics-header-video": "Video's",
+       "mediastatistics-header-multimedia": "Interaktieve media"
 }
index a074da5..fa7a9d3 100644 (file)
@@ -60,7 +60,8 @@
                        "Calak",
                        "Arg",
                        "NCoppens",
-                       "Josse.Cottenier"
+                       "Josse.Cottenier",
+                       "Macofe"
                ]
        },
        "tog-underline": "Koppelingen onderstrepen:",
@@ -88,7 +89,7 @@
        "tog-shownumberswatching": "Het aantal gebruikers weergeven dat deze pagina volgt",
        "tog-oldsig": "Bestaande ondertekening:",
        "tog-fancysig": "Als wikitekst behandelen (zonder automatische koppeling)",
-       "tog-uselivepreview": "\"Live voorvertoning\" gebruiken (experimenteel)",
+       "tog-uselivepreview": "\"Live voorvertoning\" gebruiken",
        "tog-forceeditsummary": "Een melding geven bij een lege bewerkingssamenvatting",
        "tog-watchlisthideown": "Eigen bewerkingen op mijn volglijst verbergen",
        "tog-watchlisthidebots": "Botbewerkingen op mijn volglijst verbergen",
        "specialpages-group-wiki": "Gegevens en -hulpmiddelen",
        "specialpages-group-redirects": "Doorverwijzende speciale pagina's",
        "specialpages-group-spam": "Spamhulpmiddelen",
+       "specialpages-group-developer": "Hulpmiddelen voor ontwikkelaars",
        "blankpage": "Lege pagina",
        "intentionallyblankpage": "Deze pagina is bewust leeg gelaten en wordt gebruikt voor benchmarks, enzovoort.",
        "external_image_whitelist": " #Laat deze regel onveranderd<pre>\n#Zet hieronder reguliere expressiefragmenten (alleen het deel dat tussen de // staat)\n#Deze worden gehouden tegen de URL's van externe (gehotlinkte) afbeeldingen\n#Als de reguliere expressie van toegang is, wordt een afbeelding weergegeven, anders wordt alleen een koppeling weergegeven\n#Regels die beginnen met \"#\" worden als opmerking behandeld\n#Regels in de witte lijst zijn niet hoofdlettergevoelig.\n\n#Zet alle reguliere expressiefragmenten boven deze regel. Laat deze regel onveranderd</pre>",
index 23bb892..1a5e64e 100644 (file)
@@ -71,7 +71,8 @@
                        "Michał Sobkowski",
                        "Py64",
                        "Nanaki",
-                       "Alan ffm"
+                       "Alan ffm",
+                       "Macofe"
                ]
        },
        "tog-underline": "Podkreślenie linków:",
        "tog-shownumberswatching": "Pokaż liczbę użytkowników obserwujących stronę",
        "tog-oldsig": "Twój obecny podpis:",
        "tog-fancysig": "Traktuj podpis jako wikikod (nie linkuj automatycznie całości)",
-       "tog-uselivepreview": "Używaj dynamicznego podglądu (eksperymentalny)",
+       "tog-uselivepreview": "Używaj dynamicznego podglądu",
        "tog-forceeditsummary": "Informuj o niewypełnieniu opisu zmian",
        "tog-watchlisthideown": "Ukryj moje edycje na liście obserwowanych",
        "tog-watchlisthidebots": "Ukryj edycje botów na liście obserwowanych",
index 304c515..05afab3 100644 (file)
@@ -42,7 +42,7 @@
        "tog-shownumberswatching": "Smon-e ël nùmer d'utent che as ten-o la pàgina sot-euj",
        "tog-oldsig": "Firma esistenta:",
        "tog-fancysig": "Traté la firma com dël test wiki (sensa n'anliura automàtica)",
-       "tog-uselivepreview": "Dovré la fonsion ''Preuva dal viv'' (sperimental)",
+       "tog-uselivepreview": "Dovré la fonsion ''Preuva dal viv''",
        "tog-forceeditsummary": "Ciamé conferma se ël resumé dla modìfica a l'é veujd",
        "tog-watchlisthideown": "Stërmé mie modìfiche ant la ròba che im ten-o sot-euj",
        "tog-watchlisthidebots": "Stërmé le modìfiche fàite daj trigomiro ant la lista dle ròbe che im ten-o sot-euj",
        "anoneditwarning": "<strong>Atension:<strong> A l'é nen rintrà ant ël sistema. Soa adrëssa IP a së sc-iairërà s'a fà dle modìfiche. Si chiel a <strong>[$1 rintra ant ël sistema]</strong> o <strong>[$2 a crea an cont]</strong>, soe modìfiche a saran atribuìe a sò stranòm, ansema a d'àutri vantagg.",
        "anonpreviewwarning": "''A l'é nen rintrà ant ël sistema. An salvand a sarà memorisà soa adrëssa IP ant la stòria dle modìfiche ëd sa pàgina.''",
        "missingsummary": "'''Nòta:''' a l'ha butà gnun resumé dla modìfica. Se a sgnaca «{{int:savearticle}}» n'àutra vira, soa modìfica a resterà salvà sensa resumé.",
+       "selfredirect": "<strong>Atension:</strong> A l'é an camin ch'a crea na ridiriression a l'istess artìcol.\nS'a sgnaca torna ansima a «{{int:savearticle}}», la ridiression a sarà creà.",
        "missingcommenttext": "Për piasì, che a buta un coment sì-sota.",
        "missingcommentheader": "'''Ch'a arcòrda:''' A l'ha pa dàit ëd soget o d'intestassion për cost coment.\nSe a sgnaca torna «{{int:savearticle}}», soa modìfica a sarà salvà sensa gnun-a intestassion.",
        "summary-preview": "Preuva dël resumé:",
index fc640b9..21a976a 100644 (file)
@@ -91,7 +91,7 @@
        "tog-shownumberswatching": "Mostrar o número de utilizadores a vigiar",
        "tog-oldsig": "Assinatura atual:",
        "tog-fancysig": "Tratar assinatura como texto wiki (sem hiperligações automáticas)",
-       "tog-uselivepreview": "Usar a antevisão ao vivo (experimental)",
+       "tog-uselivepreview": "Usar a antevisão ao vivo",
        "tog-forceeditsummary": "Avisar-me se deixar o resumo da edição vazio",
        "tog-watchlisthideown": "Esconder as minhas edições ao listar mudanças às páginas vigiadas",
        "tog-watchlisthidebots": "Esconder edições de robôs ao listar mudanças às páginas vigiadas",
        "specialpages-group-wiki": "Dados e ferramentas",
        "specialpages-group-redirects": "Redirecionar páginas especiais",
        "specialpages-group-spam": "Ferramentas anti-spam",
+       "specialpages-group-developer": "Ferramentas de desenvolvimento",
        "blankpage": "Página em branco",
        "intentionallyblankpage": "Esta página foi intencionalmente deixada em branco",
        "external_image_whitelist": " # Deixe esta linha exatamente como ela está<pre>\n# Coloque fragmentos de expressões regulares (apenas a parte entre //) abaixo\n# Estas serão comparadas com as URL das imagens externas (com ligação direta)\n# As que corresponderem serão apresentadas como imagens, caso contrário apenas será apresentado um link para a imagem\n# As linhas que começam com um símbolo de cardinal (#) são tratadas como comentários\n# Esta lista não distingue maiúsculas de minúsculas\n\n# Coloque todos os fragmentos de expressões regulares (regex) acima desta linha. Deixe esta linha exatamente como ela está</pre>",
index 0a59925..2082104 100644 (file)
        "tog-shownumberswatching": "Toggle option used in [[Special:Preferences]], in the section for recent changes. When this option is activated, the entries in recent changes includes the number of users who watch pages. {{Gender}}",
        "tog-oldsig": "Used in [[Special:Preferences]], tab User profile. {{Gender}}",
        "tog-fancysig": "In user preferences under the signature box.  {{Gender}}",
-       "tog-uselivepreview": "{{Gender}}\nToggle option used in [[Special:Preferences]].\n\nLive preview is an experimental feature (unavailable by default) to use edit preview without loading the page again.",
+       "tog-uselivepreview": "{{Gender}}\nToggle option used in [[Special:Preferences]].\n\nLive preview is a feature to use edit preview without loading the page again.",
        "tog-forceeditsummary": "Toggle option used in [[Special:Preferences]] to force an edit ''{{msg-mw|summary}}''. {{Gender}}",
        "tog-watchlisthideown": "[[Special:Preferences]], tab 'Watchlist'. Offers user to hide own edits from watchlist. {{Gender}}",
        "tog-watchlisthidebots": "[[Special:Preferences]], tab 'Watchlist'. Offers user to hide bot edits from watchlist. {{Gender}}",
        "anoneditwarning": "Shown when editing a page anonymously.\n\nParameters:\n* $1 – A link to log in, <nowiki>{{fullurl:Special:UserLogin|returnto={{FULLPAGENAMEE}}}}</nowiki>\n* $2 – A link to sign up, <nowiki>{{fullurl:Special:UserLogin/signup|returnto={{FULLPAGENAMEE}}}}</nowiki>\n\nSee also:\n* {{msg-mw|mobile-frontend-editor-anoneditwarning}}",
        "anonpreviewwarning": "See also:\n* {{msg-mw|Anoneditwarning}}",
        "missingsummary": "The text \"edit summary\" is in {{msg-mw|Summary}}.\n\nSee also:\n* {{msg-mw|Missingcommentheader}}\n* {{msg-mw|Savearticle}}",
+       "selfredirect": "Notice displayed once after the user tries to create a redirect to the same article.",
        "missingcommenttext": "This message is shown, when the textbox by a new-section is empty.",
        "missingcommentheader": "Edit summary that is shown if you enable \"Prompt me when entering a blank summary\" and add a new section without headline to a talk page.\n\nSee also:\n* {{msg-mw|Missingsummary}}\n* {{msg-mw|Savearticle}}",
        "summary-preview": "Preview of the edit summary, shown under the edit summary itself.\nShould match: {{msg-mw|summary}}.",
index db6accf..ff387d9 100644 (file)
@@ -51,7 +51,7 @@
        "tog-shownumberswatching": "Arată numărul utilizatorilor care urmăresc",
        "tog-oldsig": "Semnătură actuală:",
        "tog-fancysig": "Tratează semnătura ca wikitext (fără o legătură automată)",
-       "tog-uselivepreview": "Folosește previzualizarea în timp real (experimental)",
+       "tog-uselivepreview": "Folosește previzualizarea în timp real",
        "tog-forceeditsummary": "Avertizează-mă când uit să descriu modificările",
        "tog-watchlisthideown": "Ascunde modificările mele la lista mea de urmărire",
        "tog-watchlisthidebots": "Ascunde modificările boților la lista mea de urmărire",
        "anoneditwarning": "<strong>Atenție:</strong> Nu v-ați autentificat. Adresa dumneavoastră IP va fi vizibilă în mod public dacă efectuați modificări. Dacă vă <strong>[$1 autentificați]</strong> sau vă <strong>[$2 creați un cont]</strong>, modificările dumneavoastră vor fi asociate numelui de utilizator, pe lângă alte beneficii.",
        "anonpreviewwarning": "''Nu v-ați autentificat. Dacă salvați pagina adresa dumneavoastră IP va fi înregistrată în istoric.''",
        "missingsummary": "'''Atenție:''' Nu ați completat caseta „descriere modificări”. Dacă apăsați din nou butonul „salvează pagina” modificările vor fi salvate fără descriere.",
+       "selfredirect": "<strong>Atenție:</strong> Sunteți pe cale să creați o redirecționare către același articol.\nDacă apăsați din nou pe „{{int:savearticle}}”, redirecționarea va fi creată.",
        "missingcommenttext": "Vă rugăm să introduceți un comentariu.",
        "missingcommentheader": "'''Atenție,''' nu ați pus titlu sau subiect la acest comentariu.\nDacă dați din nou clic pe „{{int:savearticle}}” modificarea va fi salvată fără titlu.",
        "summary-preview": "Previzualizare descriere:",
index 412fc0c..6f83e8e 100644 (file)
        "tog-shownumberswatching": "Показывать число участников, включивших страницу в свой список наблюдения",
        "tog-oldsig": "Текущая подпись:",
        "tog-fancysig": "Собственная вики-разметка подписи (без автоматической ссылки)",
-       "tog-uselivepreview": "Использовать быстрый предварительный просмотр (экспериментально)",
+       "tog-uselivepreview": "Использовать быстрый предварительный просмотр",
        "tog-forceeditsummary": "Предупреждать, когда не заполнено поле описания правки",
        "tog-watchlisthideown": "Скрывать мои правки из списка наблюдения",
        "tog-watchlisthidebots": "Скрывать правки ботов из списка наблюдения",
index 3bd9d93..ff5906d 100644 (file)
@@ -34,6 +34,7 @@
        "tog-watchdefault": "Eik pages n files that Ah eedit til ma watchleet",
        "tog-watchmoves": "Eik pages n files that Ah muiv til ma watchleet",
        "tog-watchdeletion": "Eik pages n files that Ah get rid o til ma watchleet",
+       "tog-watchrollback": "Eik pages whaur Ah'v performed ae rowback tae ma watchleet",
        "tog-minordefault": "Mairk aa eedits \"smaa\" bi defaut",
        "tog-previewontop": "Shaw luikower afore eedit kist n naw efter it",
        "tog-previewonfirst": "Shaw luikower oan firstwhile eidit",
@@ -63,6 +64,7 @@
        "underline-default": "Skin or brouser defaut",
        "editfont-style": "Eidit area font style:",
        "editfont-default": "Brouser defaut",
+       "editfont-monospace": "Monospaced font",
        "editfont-sansserif": "Sans-serif font",
        "editfont-serif": "Serif font",
        "sunday": "Sunday",
        "permalink": "Permanent airtin",
        "print": "Prent",
        "view": "See",
+       "view-foreign": "See oan $1",
        "edit": "Eedit",
        "edit-local": "Eedit local description",
        "create": "Ceaut",
+       "create-local": "Eik local descreeption",
        "editthispage": "Eedit this page",
        "create-this-page": "Creaut this page",
        "delete": "Delyte",
        "otherlanguages": "In ither leids",
        "redirectedfrom": "(Reguidit fae $1)",
        "redirectpagesub": "Reguidal page",
+       "redirectto": "Reguidit tae:",
        "lastmodifiedat": "This page wis hintmaist chynged oan $2, $1.",
        "viewcount": "This page haes been accesst $1 {{PLURAL:$1|yince|$1 times}}.",
        "protectedpage": "Protectit page",
        "hidetoc": "skauk",
        "collapsible-collapse": "Collapse.",
        "collapsible-expand": "Mak mair muckle",
+       "confirmable-confirm": "Ar {{GENDER:$1|ye}} sair?",
+       "confirmable-yes": "Ay",
+       "confirmable-no": "Na",
        "thisisdeleted": "See or restore $1?",
        "viewdeleted": "See $1?",
        "restorelink": "{{PLURAL:$1|yin delytit eidit|$1 delytit eidits}}",
        "filerenameerror": "Cuidna rename file \"$1\" til \"$2\".",
        "filedeleteerror": "Cuidna delyte file \"$1\".",
        "directorycreateerror": "Couldna creat directerie \"$1\".",
+       "directoryreadonlyerror": "Directerie \"$1\" is read-yinlie.",
+       "directorynotreadableerror": "Directerie \"$1\" is no readable.",
        "filenotfound": "Coudna fynd file \"$1\".",
        "unexpected": "Vailyie isnae expectit: \"$1\"=\"$2\".",
        "formerror": "Mistak: cuidna haun in form",
        "viewsourcetext": "Ye can leuk at n copie the soorce o this page:",
        "viewyourtext": "Ye can see n copie the soorce o <strong>yer eedits</strong> til this page:",
        "protectedinterface": "This page provides interface tex fer the saffware oan this wiki, n is protected fer tae hinder abuise.\nTae eik or chynge owersets fer aw wikis, please uise [//translatewiki.net/ translatewiki.net], the MediaWiki localisation waurk.",
-       "editinginterface": "<strong>Warnishment:</strong> Ye'r eeditin ae page that is uised tae provide interface tex fer the saffware.\nChynges til this page will affect the kithin o the uiser interface fer ither uisers oan this wiki.\nTae eik or chynge owersets fer aw wikis, please uise [//translatewiki.net/ translatewiki.net], the MediaWiki localisation waurk.",
+       "editinginterface": "<strong>Warnishment:</strong> Ye'r eeditin ae page that is uised tae provide interface tex fer the saffware.\nChynges til this page will affect the kithin o the uiser interface fer ither uisers oan this wiki.",
+       "translateinterface": "Tae eik or chynge owersets fer aw wikis, please uise [//translatewiki.net/ translatewiki.net], the MediaWiki localisation wairk.",
        "cascadeprotected": "This page haes been protectit fae eiditin, cause it is inclædit in the follaein {{PLURAL:$1|page|pages}}, that ar protectit wi the \"cascadin\" optie turnit oan:\n$2",
        "namespaceprotected": "Ye dinna hae permeession tae edit pages in the '''$1''' namespace.",
        "customcssprotected": "Ye dinna hae permeession tae eidit this CSS page cause it contains anither uiser's personal settings.",
        "createaccount-text": "Somebodie cræftit aen accoont fer yer wab-mail address oan {{SITENAME}} ($4) named \"$2\", wi passwaird \"$3\".\nYe shid log in n chynge yer passwaird nou.\n\nYe can ignore this message, gif this accoont wis cræftit bi mistak.",
        "login-throttled": "Ye'v makit ower monie recynt login attempts.\nPlease wait $1 afore giein it anither gae.",
        "login-abort-generic": "Yer login wisna successful - Aborted",
+       "login-migrated-generic": "Yer accoont's been migratit, n yer uisername nae langer exeests oan this wiki.",
        "loginlanguagelabel": "Leid: $1",
        "suspicious-userlogout": "Yer request tae log oot wis denied cause it luiks like it wis sent bi ae broken brouser or caching proxy.",
        "createacct-another-realname-tip": "Real name is aen optie.\nGif ye chuise tae provide it, this will be uised fer giein the uiser attreebution fer their wark.",
        "passwordreset-disabled": "Passwaird resets hae been disabled oan this wiki.",
        "passwordreset-emaildisabled": "Wab-mail features hae been disabled oan this wiki.",
        "passwordreset-username": "Uisername:",
+       "passwordreset-domain": "Domain:",
        "passwordreset-capture": "See the ootcomin e-mail?",
        "passwordreset-capture-help": "Gif ye check this kist, the e-mail (wi the temperie passwaird) will be shawn til ye n be sent til the uiser ava.",
        "passwordreset-email": "Wab-mail address:",
        "preview": "Luikower",
        "showpreview": "Shaw luikower",
        "showdiff": "Shaw chynges",
+       "blankarticle": "<strong>Wairnishment:</strong> The page that ye'r creautin is blank.\nGif ye clap \"{{int:savearticle}}\" again, the page will be creautit wioot oniething oan it.",
        "anoneditwarning": "<strong>Warnishment:</strong> Ye'r no loggit in. Yer IP address will be publeeclie veesible gif ye mak onie eedits. Gif ye <strong>[$1 log in]</strong> or <strong>[$2 creaute aen accoont]</strong>, yer eedits will be attreebutit tae yer uisername, aes weel aes ither benefits.",
        "anonpreviewwarning": "<em>Ye'r no loggit in. Hainin will record yer IP address in this page's eedit histerie.</em>",
        "missingsummary": "<strong>Mynd:</strong> Ye'v naw gien aen eedit owerview. Gif ye clap oan \"{{int:savearticle}}\" again, yer eedit will be haint wioot ane.",
        "edit-gone-missing": "Coudna update the page.\nIt appears tae hae been delytit.",
        "edit-conflict": "Eedit confleect.",
        "edit-no-change": "Yer eedit wis ignored cause nae chynge wis makit til the tex.",
+       "postedit-confirmation-created": "The page haes been creautit.",
+       "postedit-confirmation-restored": "The page haes been restored.",
        "postedit-confirmation-saved": "Yer eedit wis hained.",
        "edit-already-exists": "Coudna mak ae new page.\nIt awreadie exists.",
        "defaultmessagetext": "Defaut message tex",
        "editpage-notsupportedcontentformat-text": "The content format $1 isna supported bi the content model $2.",
        "content-model-wikitext": "wikitex",
        "content-model-text": "plain tex",
+       "content-model-javascript": "JavaScript",
+       "content-model-css": "CSS",
+       "duplicate-args-category": "Pages uisin dupleecate arguments in template caws",
+       "duplicate-args-category-desc": "The page contains template caws that uise dupleecates o arguments, lik <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> or <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "expensive-parserfunction-warning": "<strong>Warnishment:</strong> This page contains ower moni expensive parser function caws.\n\nIt shid hae less than $2 {{PLURAL:$2|caw|caws}}, thaur {{PLURAL:$1|is nou $1 caw|ar noo $1 caws}}.",
        "expensive-parserfunction-category": "Pages wi ower moni expensive parser function caws",
        "post-expand-template-inclusion-warning": "<strong>Warnishment Template incluid size is owermuckle. \nSome templates will na be incluidit.",
        "parser-template-recursion-depth-warning": "Template recursion depth limit owershote ($1)",
        "language-converter-depth-warning": "Leid converter depth limit owershote ($1)",
        "node-count-exceeded-category": "Pages whaur node-coont is owershote",
+       "node-count-exceeded-category-desc": "The page exceeds the mucklest node coont.",
        "node-count-exceeded-warning": "Page owershot the node coont",
        "expansion-depth-exceeded-category": "Pages whaur expansion depth is owershote",
+       "expansion-depth-exceeded-category-desc": "The page exceeds the mucklest expansion depth.",
        "expansion-depth-exceeded-warning": "Page owershote the expansion depth",
        "parser-unstrip-loop-warning": "Unstrip luip detected",
        "parser-unstrip-recursion-limit": "Unstrip recursion limit owershote ($1)",
        "rev-deleted-event": "(log action remuived)",
        "rev-deleted-user-contribs": "[uisername or IP address remuived - eidit skauk't fae contreebutions]",
        "rev-deleted-text-permission": "This page reveesion haes been <strong>delytit</strong>.\nDetails can be foond in the [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} delytion log].",
+       "rev-suppressed-text-permission": "This page reveesion haes been <strong>suppressed</strong>.\nTae fynd oot why the [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} suppression log].",
        "rev-deleted-text-unhide": "This page luikower haes been <strong>delytit</strong>.\nDetails can be foond in the [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} delytion log].\nYe can still [$1 see this luikower] gif ye wish tae proceed.",
        "rev-suppressed-text-unhide": "This page luikower haes been <strong>suppressed</strong>.\nDetails can be foond in the [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} suppression log].\nYe can still [$1 see this luikower] gif ye wish tae proceed.",
        "rev-deleted-text-view": "This page luikower haes been <strong>delytit</strong>.\nYe can see it; the details can be foond in the [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} delytion log].",
        "search-result-category-size": "{{PLURAL:$1|1 memmer|$1 memmers}} ({{PLURAL:$2|1 subcategerie|$2 subcategeries}}, {{PLURAL:$3|1 file|$3 files}})",
        "search-redirect": "(reguide $1)",
        "search-section": "(section $1)",
+       "search-category": "(categerie $1)",
        "search-file-match": "(matches file content.)",
        "search-suggest": "Did ye mean: $1",
        "search-interwiki-caption": "Sister projec's",
        "searchall": "aw",
        "showingresults": "Shawin ablo up tae {{PLURAL:$1|'''1''' ootcome|'''$1''' ootcomes}} stertin wi #'''$2'''.",
        "showingresultsinrange": "Shawin ablo up til {{PLURAL:$1|<strong>1</strong> ootcome|<strong>$1</strong> ootcome}} in range #<strong>$2</strong> til #<strong>$3</strong>.",
+       "search-showingresults": "{{PLURAL:$4|Ootcome <strong>$1</strong> o <strong>$3</strong>|Ootcomes <strong>$1 - $2</strong> o <strong>$3</strong>}}",
        "search-nonefound": "Thaur were naw ootcomes matchin the speiring.",
        "powersearch-legend": "Advanced rake",
        "powersearch-ns": "Rake in namespaces:",
        "restoreprefs": "Restore aw defaut settins (in aw sections)",
        "prefs-editing": "Eeditin",
        "rows": "Raws:",
+       "columns": "Columns:",
        "searchresultshead": "Rake ootcome settins",
        "stub-threshold": "Threeshaud fer <a href=\"#\" class=\"stub\">stub airtin</a> formattin (bytes):",
        "stub-threshold-disabled": "Disablt",
        "prefs-help-recentchangescount": "This includes recent chynges, page histories, n logs.",
        "prefs-help-watchlist-token2": "This is the hidlins key til the wab feed o yer watchleet. Onibodie wha kens this can read yer watchleet, sae dinna shair it. Gif ye need to, [[Special:ResetTokens|Ye can reset it]].",
        "savedprefs": "Yer preferences haes been hained.",
+       "timezonelegend": "Time zone:",
+       "localtime": "Local time:",
        "timezoneuseserverdefault": "Uise wiki defaut ($1)",
        "timezoneuseoffset": "Ither (speceefie affset)",
        "servertime": "Server time the nou",
        "timezoneregion-atlantic": "Atlaunteec Ocean",
        "timezoneregion-australia": "Australie",
        "timezoneregion-europe": "Europ",
+       "timezoneregion-indian": "Indian Ocean",
        "timezoneregion-pacific": "Paceefic Ocean",
        "allowemail": "Allou email fae ither uisers",
        "prefs-searchoptions": "Rake",
+       "prefs-namespaces": "Namespaces",
        "default": "defaut",
        "prefs-files": "Files",
        "prefs-custom-css": "Custom CSS",
        "gender-female": "She eedits wiki pages",
        "prefs-help-gender": "Settin this preference is aen optie.\nThe saffware uises its value tae address ye n tae mention ye til ithers uisin the appropriate grammatical gender.\nThis information will be publeec.",
        "email": "E-mail",
-       "prefs-help-realname": "Real name is aen optie.\nGif ye chuise tae provide it, this will be uised fer giein ye attreebution fer yer wark.",
+       "prefs-help-realname": "Real name is aen optie.\nGif ye chuise tae provide it, this will be uised fer giein ye attreebution fer yer wirk.",
        "prefs-help-email": "Wab-mail is optional, bit is needed fer passwaird resets, shid ye ferget yer passwaird.",
        "prefs-help-email-others": "Ye can chuise tae let ithers contact ye bi wab-mail through ae link oan yer uiser or tauk page.\nYer wab-mail address isna revealed whan ither uisers contact ye.",
        "prefs-help-email-required": "Yer e-mail address is needit.",
+       "prefs-info": "Baseec information",
        "prefs-i18n": "Internaitionalisation",
        "prefs-signature": "Signatur",
+       "prefs-dateformat": "Date format",
        "prefs-timeoffset": "Time affset",
        "prefs-advancedediting": "General opties",
        "prefs-editor": "Eediter",
        "prefs-advancedwatchlist": "Advanced opties",
        "prefs-displayrc": "Displey opties",
        "prefs-displaywatchlist": "Displey opties",
+       "prefs-tokenwatchlist": "Token",
        "prefs-diffs": "Diffs",
        "prefs-help-prefershttps": "This preeferance will tak effect oan yer nex login.",
+       "prefswarning-warning": "Ye'v makit chynges tae yer preferances that'v no been hained yet.\nGif ye leave this page wioot clapin \"$1\" than yer preferances 'll no be updatit.",
        "prefs-tabs-navigation-hint": "Tip: Ye can uise the cair n richt arrae keys tae naveegate atween the tabs in the tabs leet.",
        "email-address-validity-valid": "Wab-mail address appears tae be valid",
        "email-address-validity-invalid": "Enter ae valid wab-mail address",
        "group-autoconfirmed": "Autæconfirmed uisers",
        "group-bot": "Bots",
        "group-sysop": "Admeenistraters",
+       "group-bureaucrat": "Bureaucrats",
        "group-suppress": "Owersichts",
        "group-all": "(aw)",
        "group-user-member": "{{GENDER:$1|uiser}}",
        "group-autoconfirmed-member": "{{GENDER:$1|autæconfirmed uiser}}",
        "group-bot-member": "{{GENDER:$1|bot}}",
        "group-sysop-member": "{{GENDER:$1|admeenistrater}}",
+       "group-bureaucrat-member": "{{GENDER:$1|bureaucrat}}",
        "group-suppress-member": "{{GENDER:$1|owersicht}}",
        "grouppage-user": "{{ns:project}}:Uisers",
        "grouppage-autoconfirmed": "{{ns:project}}:Autæconfirmed uisers",
+       "grouppage-bot": "{{ns:project}}:Bots",
        "grouppage-sysop": "{{ns:project}}:Admeenistraters",
+       "grouppage-bureaucrat": "{{ns:project}}:Bureaucrats",
        "grouppage-suppress": "{{ns:project}}:Owersicht",
+       "right-read": "Read pages",
        "right-edit": "Eedit pages",
        "right-createpage": "Cræft pages (that arna tauk pages)",
        "right-createtalk": "Cræft discussion pages",
        "right-move": "Muiv pages",
        "right-move-subpages": "Muiv pages wi thair subpages",
        "right-move-rootuserpages": "Muiv ruit uiser pages",
+       "right-move-categorypages": "Muiv categerie pages",
        "right-movefile": "Muiv files",
        "right-suppressredirect": "Na cræft reguidals fae soorce pages whan muivin pages",
        "right-upload": "Uplaid files",
        "right-browsearchive": "Rake delytit pages",
        "right-undelete": "Ondelyte ae page",
        "right-suppressrevision": "See, skauk n onskauk speceefic reveesions o pages fae onie uiser",
+       "right-viewsuppressed": "See owerluiks that'r skaukt fae onie uiser",
        "right-suppressionlog": "see preevate logs",
        "right-block": "Block ither uisers fae eeditin",
        "right-blockemail": "Block ae uiser fae sendin wab-mail",
        "right-protect": "Chynge protection levels n eedit cascade-protected pages",
        "right-editprotected": "Eedit pages protected aes \"{{int:protect-level-sysop}}\"",
        "right-editsemiprotected": "Eedit pages protected aes \"{{int:protect-level-autoconfirmed}}\"",
+       "right-editcontentmodel": "Eedit the content model o ae page",
        "right-editinterface": "Eedit the uiser interface",
        "right-editusercssjs": "Eedit ither uisers' CSS n JavaScript files",
        "right-editusercss": "Eedit ither uisers' CSS files",
        "newuserlogpagetext": "This is ae log o uiser cræftins.",
        "rightslog": "Uiser richts log",
        "rightslogtext": "This is a log o chynges tae uiser richts.",
+       "action-read": "read this page",
        "action-edit": "eedit this page",
        "action-createpage": "cræft pages",
        "action-createtalk": "cræft discussion pages",
        "action-createaccount": "cræft this uiser accoont",
+       "action-history": "see the histerie o this page",
        "action-minoredit": "maurk this eedit aes smaa",
        "action-move": "muiv this page",
        "action-move-subpages": "mui this page, n its subpages",
        "action-move-rootuserpages": "muiv ruit uiser pages",
+       "action-move-categorypages": "muiv categerie pages",
        "action-movefile": "muiv this file",
        "action-upload": "uplaid this file",
        "action-reupload": "owerwrite this exeestin file",
        "action-viewmywatchlist": "see yer watchleet",
        "action-viewmyprivateinfo": "see yer preevate information",
        "action-editmyprivateinfo": "eedit yer preevate information",
+       "action-editcontentmodel": "eedit the content model o ae page",
        "nchanges": "$1 {{PLURAL:$1|chynge|chynges}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sin laist veesit}}",
        "enhancedrc-history": "histeri",
        "recentchanges-label-bot": "This eedit wis performed bi ae bot",
        "recentchanges-label-unpatrolled": "This eedit haes no bin patrolled yet",
        "recentchanges-label-plusminus": "The page size chynged bi this nummer o bytes",
+       "recentchanges-legend-heading": "'''Legend:'''",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (see [[Special:NewPages|leet o new pages]] n aw)",
        "rcnotefrom": "Ablo {{PLURAL:$5|is the chynge|ar the chynges}} sin <strong>$3, $4</strong> (up tae <strong>$1</strong> shawn).",
        "rclistfrom": "Shaw new chynges stertin fae $3 $2",
        "rc_categories": "Limit til categeries (separate wi \"|\")",
        "rc_categories_any": "Onie",
        "rc-change-size-new": "$1 {{PLURAL:$1|byte|bytes}} efter chynge",
+       "newsectionsummary": "/* $1 */ new section",
        "rc-enhanced-expand": "Shaw details",
        "rc-enhanced-hide": "Skauk details",
        "rc-old-title": "oreeginlie cræftit aes \"$1\"",
        "upload-recreate-warning": "'''Warnishment: Ae file bi that name haes been delytit or muived.'''\n\nThe delytion n muiv log fer this page ar gien here fer conveeneeance:",
        "uploadtext": "Uise the form ablo tae uplaid files.\nTae see or rake aforegaun uplaided files gang til the [[Special:FileList|leet o uplaided files]], (re)uplaids ar loggit in the [[Special:Log/upload|uplaid log]] aes weel, n delytions in the [[Special:Log/delete|delytion log]].\n\nTae incluid ae file in ae page, uise aen airtin in yin o the follaein forms:\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code></strong> tae uise the ful version o the file\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|alt tex]]</nowiki></code></strong> tae uise ae 200 pixel wide rendeetion in ae kist in the cair margin wi \"alt tex\" aes descreeption\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code></strong> fer linkin directlie til the file wioot displeyin the file.",
        "upload-permitted": "Permitit file types: $1.",
+       "upload-preferred": "Preferred file types: $1.",
        "upload-prohibited": "Proheebited file types: $1.",
        "uploadlogpage": "Uplaid log",
        "uploadlogpagetext": "Ablo is ae leet o the maist recynt file uplaids.\nSee the [[Special:NewFiles|gallerie o new files]] fer ae mair veesual luikower.",
+       "filename": "Filename",
        "filedesc": "Ootline",
        "fileuploadsummary": "Ootline:",
        "filereuploadsummary": "File chynges:",
        "license-nopreview": "(Luikower naw available)",
        "upload_source_url": "(yer chosen file fae ae valid, publeeclie accessible URL)",
        "upload_source_file": "(yer chosen file fae yer computer)",
+       "listfiles-delete": "delyte",
        "listfiles-summary": "This speecial page shaws aw uplaided files.",
        "listfiles_search_for": "Rake fer media name:",
        "imgfile": "file",
        "listfiles": "The file leet",
        "listfiles_thumb": "Thummnail",
+       "listfiles_date": "The Date",
        "listfiles_name": "Name",
        "listfiles_user": "Uiser",
        "listfiles_size": "Size",
        "listfiles_description": "Descreeption",
+       "listfiles_count": "Versions",
        "listfiles-show-all": "Incluide auld versions o eemages",
        "listfiles-latestversion": "The Nou version",
        "listfiles-latestversion-yes": "Ay",
        "filehist-nothumb": "Naw thummnail",
        "filehist-user": "Uiser",
        "filehist-dimensions": "Dimensions",
+       "filehist-filesize": "The File size",
        "filehist-comment": "Comment",
        "imagelinks": "File uisage",
        "linkstoimage": "The follaein {{PLURAL:$1|page airts|$1 pages airt}} tae this file:",
        "randomincategory": "Random page in categerie",
        "randomincategory-invalidcategory": "\"$1\" isna ae valid categerie name.",
        "randomincategory-nopages": "Thaur's naw pages in the [[:Category:$1|$1]] categerie.",
+       "randomincategory-category": "Categerie:",
+       "randomincategory-legend": "Random page in categerie",
        "randomredirect": "Random reguidal",
        "randomredirect-nopages": "Thaur's naw reguidals in the namespace \"$1\".",
        "statistics": "Stateestics",
        "statistics-header-edits": "Eidit stateestics",
        "statistics-header-users": "Uiser stateestics",
        "statistics-header-hooks": "Ither stateestics",
+       "statistics-articles": "Content pages",
        "statistics-pages": "Pages",
        "statistics-pages-desc": "Aw pages in the wiki, incluidin tauk pages, reguidals, etc.",
        "statistics-files": "Uplaided files",
        "fewestrevisions": "Pages wi the fewest reeveesions",
        "nbytes": "$1 {{PLURAL:$1|byte|bytes}}",
        "ncategories": "$1 {{PLURAL:$1|categerie|categeries}}",
+       "ninterwikis": "$1 {{PLURAL:$1|interwiki|interwikis}}",
        "nlinks": "$1 {{PLURAL:$1|airtin|airtins}}",
        "nmembers": "$1 {{PLURAL:$1|memmer|memmers}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|memmer|memmers}}",
        "wantedpages-badtitle": "Onvalid title in ootcome set: $1",
        "wantedfiles": "Wantit files",
        "wantedfiletext-cat": "The follaein files ar uised but dinna exeest. Files fae foreign repositeries micht be leetit despite exeestin. Onie sic false poseeteeves will be <del>struck oot</del>. Addeetionallie, pages that embed files that dinna exeest ar leetit in [[:$1]].",
+       "wantedfiletext-cat-noforeign": "The follaein files ar uised but dinna exeest. Mair than that, pages that embed files that dinna exeest ar leetit in [[:$1]].",
        "wantedfiletext-nocat": "The follaein files ar uised but dinna exeest. Files fae foreign repositeries micht be leetit despite exeestin. Onie sic false poseeteeves will be <del>struck oot</del>.",
+       "wantedfiletext-nocat-noforeign": "The folleain files ar uised but dinna exeest.",
        "wantedtemplates": "Wantit templates",
        "mostlinked": "Maist airtit-tae pages",
        "mostlinkedcategories": "Maist airtit-tae categeries",
        "prefixindex": "Aw pages wi prefix",
        "prefixindex-namespace": "Aw pages wi preefix ($1 namespace)",
        "prefixindex-strip": "Strip preefix in leet",
+       "shortpages": "Short pages",
        "longpages": "Lang pages",
        "deadendpages": "Deid-end pages",
        "deadendpagestext": "The follaein pages dinna link til ither pages in {{SITENAME}}.",
        "pager-older-n": "{{PLURAL:$1|aulder 1|aulder $1}}",
        "suppress": "Owersicht",
        "querypage-disabled": "This speecial page is disablit fer performance raisons.",
+       "apihelp": "API help",
+       "apihelp-no-such-module": "Module \"$1\" wis no foond.",
        "booksources": "Buik soorces",
        "booksources-search-legend": "Rake fer buik soorces",
+       "booksources-search": "Rake",
        "booksources-text": "Ablo is ae leet o airtins til ither steids that sell new n uised buiks, n micht hae further information aneat buiks that ye'r seekin ava:",
        "booksources-invalid-isbn": "The gien ISBN disna seem tae be valid; check fer mistaks copiein fae the oreeginal soorce.",
        "specialloguserlabel": "Performer:",
        "listgrouprights-removegroup-self": "Remuiv {{PLURAL:$2|groop|groops}} fae yer accoont: $1",
        "listgrouprights-addgroup-self-all": "Eik aw groops til yer accoont",
        "listgrouprights-removegroup-self-all": "Remuiv aw groops fae yer accoont",
+       "listgrouprights-namespaceprotection-header": "Namespace restreections",
+       "listgrouprights-namespaceprotection-namespace": "Namespace",
+       "listgrouprights-namespaceprotection-restrictedto": "Richt(s) allooing ae uiser tae eedit",
        "trackingcategories": "Keepin track o categeries",
        "trackingcategories-summary": "This page leets the trackin categeries that ar autæmateecallie populatit bi the MediaWiki saffware. Thair names can be chynged bi alterin the reelavant system messages in the {{ns:8}} namespace.",
        "trackingcategories-msg": "The Trackin Categerie",
        "emailto": "Til:",
        "emailsubject": "Aneat:",
        "emailmessage": "Message:",
+       "emailsend": "Send",
        "emailccme": "Wab-mail me ae copie o ma message.",
        "emailccsubject": "Copie o yer message til $1: $2",
        "emailsent": "Wab-mail sent",
        "watchnologin": "Nae loggit in",
        "addwatch": "Eik til watchleet",
        "addedwatchtext": "The page \"[[:$1]]\" haes been added til yer [[Special:Watchlist|watchleet]].\nFutur chynges til this page n its associated tauk page will be leeted thaur.",
+       "addedwatchtext-short": "The page \"$1\" haes been eikit tae yer watchleet.",
        "removewatch": "Remuiv fae watchleet",
        "removedwatchtext": "The page \"[[:$1]]\" haes been remuied fae [[Special:Watchlist|yer watchleet]].",
+       "removedwatchtext-short": "The page \"$1\" haes been remuived fae yer watchleet.",
        "watch": "Watch",
        "watchthispage": "Watch this page",
        "unwatch": "Onwatch",
        "wlheader-enotif": "Wab-mail annooncemant is enabled.",
        "wlheader-showupdated": "Pages that hae been chynged sin ye last veesitit thaim ar shawn in '''baud'''.",
        "wlnote": "Ablo {{PLURAL:$1|is the laist chynge|ae the laist <strong>$1</strong> chynges}} in the laist {{PLURAL:$2|hoor|<strong>$2</strong> hoors}}, aes o $3, $4.",
-       "wlshowlast": "Shaw hainmaist $1 hoors $2 days",
+       "wlshowlast": "Shaw the hainmaist $1 hoors $2 days",
        "watchlist-options": "Watchleet opties",
        "watching": "Watchin...",
        "unwatching": "Onwatchin...",
        "created": "cræftit",
        "changed": "chynged",
        "deletepage": "Delyte page",
+       "confirm": "Confirm",
        "excontent": "content wis: '$1'",
        "excontentauthor": "content wis: '$1' (n the ae contreebuter wis '[[Special:Contributions/$2|$2]]')",
        "exbeforeblank": "content afore blankin wis: '$1'",
        "delete-edit-reasonlist": "Eedit delytion raisons",
        "delete-toobig": "This page haes ae muckle eedit histerie, ower $1 {{PLURAL:$1|reveesion|reveesions}}.\nDelytion o sic pages haes been restrictit tae stap accidental disruption o {{SITENAME}}.",
        "delete-warning-toobig": "This page haes ae muckle eedit histerie, ower $1 {{PLURAL:$1|reveesion|reveesions}}.\nDelytin it micht disrupt database operations o {{SITENAME}};\nproceed wi caution.",
+       "deleteprotected": "Ye canna delyte this page cause it's been fended.",
        "deleting-backlinks-warning": "'''Warnishment:''' [[Special:WhatLinksHere/{{FULLPAGENAME}}|Ither pages]] airt til or transcluide the page ye'r aboot tae delyte.",
        "rollback": "Row back eedits",
        "rollback_short": "Rowback",
        "revertpage": "Reverted eidits bi [[Special:Contributions/$2|$2]] ([[User talk:$2|tauk]]) til laist reveesion bi [[User:$1|$1]]",
        "revertpage-nouser": "Reverted eedits bi ae skaukt uiser til laist revesion bi {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Reverted eedits b $1;\nchynged back til the laist reveesion bi $2.",
+       "sessionfailure-title": "Session failure",
        "sessionfailure": "Thaur seems tae be ae proablem wi yer login session;\nthis action haes been canceled aes ae precaution again session hijackin.\nGang back til the preeveeoos page, relaid that page n than gie it anither gae.",
        "protectlogpage": "Fend log",
        "protectlogtext": "Ablow is ae leet o chynges til page protections.\nSee the [[Special:ProtectedPages|protected pages leet]] fer the leet o currently operational page protections.",
        "protect-title": "Chynge protection level fer \"$1\"",
        "protect-title-notallowed": "See protection level o \"$1\"",
        "prot_1movedto2": "[[$1]] muivit tae [[$2]]",
+       "protect-badnamespace-title": "No-fendable namespace",
        "protect-badnamespace-text": "Pages in this namespace canna be protected.",
        "protect-norestrictiontypes-text": "This page canna be protected aes thaur's naw restreection types available.",
+       "protect-norestrictiontypes-title": "No-fendable page",
+       "protect-legend": "Confirm fendin",
        "protectcomment": "Raison:",
        "protectexpiry": "Expires:",
        "protect_expiry_invalid": "Expirie time is onvalit.",
        "protect-othertime": "Ither time:",
        "protect-othertime-op": "ither time",
        "protect-existing-expiry": "Exeestin expirie time: $3, $2",
+       "protect-existing-expiry-infinity": "Exeestin expirie time: infeenit",
        "protect-otherreason": "Ither/addeetional raison:",
        "protect-otherreason-op": "Ither raison",
        "protect-dropdown": "*Commyn protection raisons\n** Excesseeve vandaleesm\n** Excesseeve spammin\n** Coonter-producteeve eedit warrin\n** Hei traffeec page",
        "restriction-level": "Restreection level:",
        "minimum-size": "Smaaest size",
        "maximum-size": "Mucklest size:",
+       "pagesize": "(bytes)",
        "restriction-edit": "Eidit",
        "restriction-move": "Muiv",
        "restriction-create": "Creaut",
        "undelete-revision": "Deleted reveesion o $1 (aes o $4, at $5) bi $3:",
        "undeleterevision-missing": "Onvalid or missin reveesion.\nYe micht hae ae bad link, or the reveesion micht hae been restored or remuived fae the archive.",
        "undelete-nodiff": "Naw preeveeoos reveesion foond.",
+       "undeletebtn": "Restore",
        "undeletelink": "see/restore",
        "undeleteviewlink": "see",
+       "undeleteinvert": "Invert the selection",
        "undeletecomment": "Raison:",
        "undeletedrevisions": "{{PLURAL:$1|1 reveesion|$1 reveesions}} restored",
        "undeletedrevisions-files": "{{PLURAL:$1|1 reveesion|$1 reveesions}} n {{PLURAL:$2|1 file|$2 files}} restored",
+       "undeletedfiles": "{{PLURAL:$1|1 file|$1 files}} restored",
        "cannotundelete": "Ondelyte failed:\n$1",
        "undeletedpage": "<strong>$1 haes been restored</strong>\n\nConsult the [[Special:Log/delete|delytion log]] fer ae record o recynt delytions n restorations.",
        "undelete-header": "See [[Special:Log/delete|the delytion log]] fer the recentlie delytit pages.",
        "namespace": "Namespace:",
        "invert": "Invert selection",
        "tooltip-invert": "Check this kist tae skauk chynges til pages wiin the selectit namespace (n the associatit namespace gif checked)",
+       "namespace_association": "Associatit namespace",
        "tooltip-namespace_association": "Check this kist foreby tae incluid the tauk or subject namespace associatit wi the selectit namespace",
        "blanknamespace": "(Main)",
        "contributions": "{{GENDER:$1|Uiser}} contributions",
        "contributions-title": "Uiser contreebutions fer $1",
        "mycontris": "Ma contreebutions",
        "contribsub2": "Fer {{GENDER:$3|$1}} ($2)",
+       "contributions-userdoesnotexist": "Uiser accoont \"$1\" is no registerit.",
        "nocontribs": "Nae chynges wis funnd matchin thir criteria.",
        "uctop": "(current)",
        "month": "Fae month (n afore):",
        "ipbwatchuser": "Watch this uiser's uiser n tauk pages",
        "ipb-disableusertalk": "Stap this uiser fae eeditin thair ain tauk page while blockit",
        "ipb-change-block": "Re-block the uiser wi thir settins",
+       "ipb-confirm": "Confirm the block",
        "badipaddress": "That IP address is nae guid",
        "blockipsuccesssub": "Block succeedit",
        "blockipsuccesstext": "[[Special:Contributions/$1|$1]] haes been blockit.\n<br />See [[Special:BlockList|block leet]] tae review blocks.",
        "unblocked": "[[User:$1|$1]] haes been onblockit.",
        "unblocked-range": "$1 haes been onblockit.",
        "unblocked-id": "Block $1 haes been remuived.",
+       "unblocked-ip": "[[Special:Contributions/$1|$1]] haes been onblockt.",
        "blocklist": "Blockit uisers",
        "ipblocklist": "Blockit uisers",
        "ipblocklist-legend": "Fynd ae blockit uiser",
        "blocklist-tempblocks": "Skauk temparie blocks",
        "blocklist-addressblocks": "Skauk single IP blocks",
        "blocklist-rangeblocks": "Skauk range blocks",
+       "blocklist-timestamp": "Timestamp",
        "blocklist-target": "Tairget",
        "blocklist-expiry": "Dies",
        "blocklist-by": "Blockin admeen",
        "blocklist-params": "Block boonds",
        "blocklist-reason": "Raison",
        "ipblocklist-submit": "Rake",
+       "ipblocklist-localblock": "Local block",
        "ipblocklist-otherblocks": "Ither {{PLURAL:$1|block|blocks}}",
        "infiniteblock": "infeenite",
        "expiringblock": "dies oan $1 at $2",
        "cant-see-hidden-user": "The uiser that ye'r attemptin tae block haes awreadie been blockit n skaukt.\nAes ye dinna hae the skaukuiser richt, ye canna see or eedit the uiser's block.",
        "ipbblocked": "Ye canna block or onblock ither uisers cause ye yersel is blockit.",
        "ipbnounblockself": "Yer na permitit tae onblock yersel.",
+       "lockdb": "Lock database",
        "unlockdb": "Lowse database",
        "lockdbtext": "Lockin the database will suspend the abeelitie o aw uisers tae eedit pages, chynge thair preeferences, eedit thair watchleets, n ither things needin chynges in the database. Please confirm that this is whit ye'r etlin tae dae, n that ye'll lowse the database whan yer maintenance is dun.",
        "unlockdbtext": "Lowsin the database will gie back the abeelitie fer aa uisers tae eidit pages, chynge their preeferences, eidit their watchleets, an ither things needin chynges in the database. Please confirm that this is whit ye ettle tae dae.",
        "lockconfirm": "Ai, Ah reellie want tae lock the database.",
        "unlockconfirm": "Ai, Ah reellie want tae lowse the database.",
+       "lockbtn": "Lock database",
        "unlockbtn": "Lowse database",
        "locknoconfirm": "Ye didna tick the confirmation kist.",
        "lockdbsuccesssub": "Database lock fine",
        "movepagetalktext": "The associated tauk page will be autaematiclie muived alang wi it <strong>onless:</strong>\n*A no-tuim tauk page awreadie exeests unner the new name, or\n*Ye oncheck the kist ablo.\n\nIn thae cases, ye will hae tae muiv or merge the page manuallie gif ye sae desire.",
        "movearticle": "Muiv page:",
        "moveuserpage-warning": "<strong>Warnishment:</strong> Ye'r aboot tae muiv ae uiser page. Please tak tent that yinlie the page will be muivd n the uiser will <em>naw</em> be renamed.",
+       "movecategorypage-warning": "<strong>Wairnishment:</strong> Ye'r aboot tae muiv ae categerie page. Please mynd that yinlie the page'll be muived n onie pages in the auld categerie will <em>no</em> be recategerised intae the new categerie.",
        "movenologintext": "Ye maun be a registert uiser n [[Special:UserLogin|loggit in]] tae muiv ae page.",
        "movenotallowed": "Ye dinna hae permeession tae muiv pages.",
        "movenotallowedfile": "Ye dinna hae permeession tae muiv files.",
        "cant-move-user-page": "Ye dinna hae permeession tae muiv uiser pages (aside fae subpages).",
        "cant-move-to-user-page": "Ye dinna hae permeession tae muiv ae page til ae uiser page (except til ae uiser subpage).",
+       "cant-move-category-page": "Ye dinna hae permeession tae muiv categerie pages.",
+       "cant-move-to-category-page": "Ye dinna hae permeession tae muiv ae page tae ae categerie page.",
        "newtitle": "Til new teitle",
        "move-watch": "Watch soorce page n tairget page",
        "movepagebtn": "Muiv page",
        "movepage-max-pages": "The mmucklest o $1 {{PLURAL:$1|page|pages}} haes been muived n naw mair will be muived autæmateeclie.",
        "movelogpage": "Muiv log",
        "movelogpagetext": "Ae leet o aw page muives is ablo.",
+       "movesubpage": "{{PLURAL:$1|Subpage|Subpages}}",
        "movesubpagetext": "This page haes $1 {{PLURAL:$1|subpage|subpages}} shawn ablo.",
        "movenosubpage": "This page haes naw subpages.",
        "movereason": "Raison:",
        "exportcuronly": "Inclæde juist the nou reveesion, naw the ful histerie",
        "exportnohistory": "----\n<strong>Mynd:</strong> Exportin the ful histerie o pages throogh this form haes been disabled cause o performance raisons.",
        "exportlistauthors": "Incluid ae ful leet o contreebuters fer ilka page",
+       "export-submit": "Export",
        "export-addcattext": "Eik pages fae categerie:",
+       "export-addcat": "Eik",
        "export-addnstext": "Eik pages fae namespace:",
+       "export-addns": "Eik",
        "export-download": "Hain aes file",
        "export-templates": "Incluid templates",
        "export-pagelinks": "Incluid linkt pages til ae depth o:",
        "allmessagescurrent": "Message tex the nou",
        "allmessagestext": "This is ae leet o seestem messages available in the MediaWiki namespace.\nPlease veesit [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation MediaWiki Localisation] n [//translatewiki.net translatewiki.net] gif ye wish tae contreebute tae the generic MediaWiki localisation.",
        "allmessagesnotsupportedDB": "This page canna be uised cause <strong>$wgUseDatabaseMessages</strong> haes been disablt.",
+       "allmessages-filter-legend": "Filter",
        "allmessages-filter": "Filter b custymization state:",
        "allmessages-filter-unmodified": "Onmodified",
        "allmessages-filter-all": "Aw",
        "thumbnail_gd-library": "Oncompleate GD librie confeeguration: Missin function $1",
        "thumbnail_image-missing": "File seems tae be missin: $1",
        "thumbnail_image-failure-limit": "Thaur hae been ower monie recynt failed attempts ($1 or mair) tae render this thummnail. Please ettle again later.",
+       "import": "Import pages",
+       "importinterwiki": "Transwiki import",
        "import-interwiki-text": "Select ae wiki n page title tae import.\nReveesion dates n eediters' names will be preserved.\nAw transwiki import actions ar loggit at the [[Special:Log/import|import log]].",
+       "import-interwiki-sourcewiki": "The Soorce wiki:",
+       "import-interwiki-sourcepage": "The Soorce page:",
        "import-interwiki-history": "Copie aw histerie reveesions fer this page",
        "import-interwiki-templates": "Incluid aw templates",
+       "import-interwiki-submit": "Import",
        "import-interwiki-namespace": "Desteenation namespace:",
        "import-interwiki-rootpage": "Desteenation ruit page (aen optie):",
+       "import-upload-filename": "Filename:",
+       "import-comment": "Comment:",
        "importtext": "Please export the file fae the soorce wiki uising the [[Special:Export|export utilitie]].\nHain it til yer computer n uplaid it here.",
        "importstart": "Importin pages...",
        "import-revision-count": "$1 {{PLURAL:$1|reveesion|reveesions}}",
        "importnopages": "Naw pages tae import.",
        "imported-log-entries": "Imported $1 {{PLURAL:$1|log entrie|log entries}}.",
+       "importfailed": "The Import failed: <nowiki>$1</nowiki>",
        "importunknownsource": "Onkent import soorce type",
        "importcantopen": "Coudna apen import file",
+       "importbadinterwiki": "Bad interwiki airtin",
        "importsuccess": "Importit fine!",
        "importnosources": "Nae transwiki import soorces haes been defined n direct histerie uplaids is disabled.",
        "importnofile": "Naw import file wis uplaided.",
        "importuploaderrorsize": "Uplaid o import file failed.\nThe file is muckler than the permitit uplaid size.",
        "importuploaderrorpartial": "Uplaid o import file failed.\nThe file wis yinlie pairtlie uplaided.",
        "importuploaderrortemp": "Uplaid o import file failed.\nAe temparie fauder is missin.",
+       "import-parse-failure": "XML import parse failure",
        "import-noarticle": "Naw page tae import!",
        "import-nonewrevisions": "Nae reveesions imported (aw were either awreadie present, or skipt cause o mistaks).",
+       "xml-error-string": "$1 oan line $2, col $3 (byte $4): $5",
        "import-upload": "Uplaid XML data",
        "import-token-mismatch": "Loss o session data.\nPlease gie it anither gae.",
        "import-invalid-interwiki": "Canna import fae the speceefied wiki.",
        "import-options-wrong": "Wrang {{PLURAL:$2|optie|opties}}: <nowiki>$1</nowiki>",
        "import-rootpage-invalid": "Gien ruit page is aen onvalit title.",
        "import-rootpage-nosubpage": "Namespace \"$1\" o the ruit page disna permit subpages.",
+       "importlogpage": "The Import log",
        "importlogpagetext": "Admeenistrateeve imports o pages wi eedit histerie fae ither wikis.",
        "import-logentry-upload": "imported [[$1]] bi file uplaid",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|reveesion|reveesions}} importit",
+       "import-logentry-interwiki": "transwikied $1",
        "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|reveesion|reveesions}} importit fae $2",
        "javascripttest": "JavaScript testin",
        "javascripttest-title": "Rinnin $1 tests",
        "javascripttest-pagetext-frameworks": "Please chuise yin o the follaein testin framewairks: $1",
        "javascripttest-pagetext-skins": "Chuise ae skin tae rin the tests wi:",
        "javascripttest-qunit-intro": "See [$1 testin documentation] oan mediawiki.org.",
+       "javascripttest-qunit-heading": "MediaWiki JavaScript QUnit test suite",
        "tooltip-pt-userpage": "Yer uiser page",
        "tooltip-pt-anonuserpage": "The uiser page fer the IP address that ye'r eeditin aes",
        "tooltip-pt-mytalk": "Yer tauk page",
        "tooltip-pt-mycontris": "Leet o yer contreebutions",
        "tooltip-pt-login": "It's ae guid idea tae log in, but ye dinna hae tae.",
        "tooltip-pt-logout": "Log oot",
+       "tooltip-pt-createaccount": "We encoorage ye tae creaute aen accoont n log in; houever, it's no strictllie nesisair",
        "tooltip-ca-talk": "Discussion aneat the content page",
        "tooltip-ca-edit": "Ye can eedit this page. Please uise the luikower button afore hainin",
        "tooltip-ca-addsection": "Stairt ae new section",
        "tooltip-feed-atom": "Atom feed fer this page",
        "tooltip-t-contributions": "See ae leet o this uiser's contreebutions",
        "tooltip-t-emailuser": "Send ae wab-mail til this uiser",
+       "tooltip-t-info": "Mair information aneat this page",
        "tooltip-t-upload": "Uplaid files",
        "tooltip-t-specialpages": "Ae leet o aw byordinar pages",
        "tooltip-t-print": "Prentable version o this page",
        "anonusers": "{{SITENAME}} anonymoos {{PLURAL:$2|uiser|uisers}} $1",
        "creditspage": "Page creeedits",
        "nocredits": "Thaur's nae creedit info available fer this page.",
+       "spamprotectiontitle": "Spam protection filter",
        "spamprotectiontext": "The tex ye wished tae save wis blockit bi the spam filter.\nThis is maistlikly caused bi aen airtin til ae blaickleeted external site.",
        "spamprotectionmatch": "The follaein tex is whit triggered wir spam filter: $1",
+       "spambot_username": "MediaWiki spam cleanup",
        "spam_reverting": "Revertin til the laist reveesion na containin links til $1",
        "spam_blanking": "Aw reveesions contained links til $1, blankin",
        "spam_deleting": "Aw reveesions contained links til $1, delytin",
        "simpleantispam-label": "Anti-spam check.\nDiv <strong>NAW</strong> ful this in!",
        "pageinfo-title": "Information fer \"$1\"",
        "pageinfo-not-current": "Sairrie, it's na possible tae provide this information fer auld reveesions.",
+       "pageinfo-header-basic": "Baseec information",
        "pageinfo-header-edits": "Eedit histerie",
+       "pageinfo-header-restrictions": "Page fendin",
+       "pageinfo-header-properties": "Page properties",
        "pageinfo-display-title": "Displey title",
        "pageinfo-default-sort": "Defaut sort key",
+       "pageinfo-length": "Page langth (in bytes)",
+       "pageinfo-article-id": "The Page ID",
        "pageinfo-language": "Page content leid",
+       "pageinfo-content-model": "The Page content model",
        "pageinfo-robot-policy": "Indexin bi robots",
        "pageinfo-robot-index": "Permitit",
        "pageinfo-robot-noindex": "Na permitit",
        "pageinfo-hidden-categories": "Skaukt {{PLURAL:$1|categerie|categeries}} ($1)",
        "pageinfo-templates": "Transcluided {{PLURAL:$1|template|templates}} ($1)",
        "pageinfo-transclusions": "{{PLURAL:$1|Page|Pages}} transcluided oan ($1)",
+       "pageinfo-toolboxlink": "Page information",
        "pageinfo-redirectsto": "Reguidals til",
+       "pageinfo-redirectsto-info": "info",
        "pageinfo-contentpage": "Coonted aes ae content page",
        "pageinfo-contentpage-yes": "Ay",
        "pageinfo-protect-cascading": "Protections ar cascadin fae here",
        "mediawarning": "<strong>Warnishment:</strong> This file type micht contain maleecious code.\nBi executin it, yer system micht be compromised.",
        "imagemaxsize": "Eemage size leemit:<br /><em>(fer file descreeption pages)</em>",
        "thumbsize": "Thummnail size:",
+       "widthheightpage": "$1 × $2, $3 {{PLURAL:$3|page|pages}}",
+       "file-info": "file size: $1, MIME type: $2",
        "file-info-size": "$1 × $2 pixels, file size: $3, MIME type: $4",
+       "file-info-size-pages": "$1 × $2 pixels, file size: $3, MIME type: $4, $5 {{PLURAL:$5|page|pages}}",
        "file-nohires": "Nae heier resolution available.",
        "svg-long-desc": "SVG file, nominallie $1 × $2 pixels, file size: $3",
        "svg-long-desc-animated": "Animated SVG file, nominallie $1 × $2 pixels, file size: $3",
        "show-big-image": "Oreeginal file",
        "show-big-image-preview": "Size o this luikower: $1.",
        "show-big-image-other": "Ither {{PLURAL:$2|resolution|resolutions}}: $1.",
+       "show-big-image-size": "$1 × $2 pixels",
        "file-info-gif-looped": "luip't",
+       "file-info-gif-frames": "$1 {{PLURAL:$1|frame|frames}}",
        "file-info-png-looped": "luip't",
        "file-info-png-repeat": "pleyed $1 {{PLURAL:$1|time|times}}",
+       "file-info-png-frames": "$1 {{PLURAL:$1|frame|frames}}",
        "file-no-thumb-animation": "<strong>Mynd: Due til techneecal limitations, thummnails o this file will na be animated.</strong>",
        "file-no-thumb-animation-gif": "<strong>Mynd: Due til techneecal limitations, thummnails o hei resolution GIF eemages sic aes this will na be animated.</strong>",
        "newimages": "Gallerie o new files",
        "imagelisttext": "Ablo is a leet o $1 {{PLURAL:$1|eemage|eemages}} sortit $2.",
        "newimages-summary": "This byordinair page shaws the last uplaidit files.",
+       "newimages-legend": "Filter",
        "newimages-label": "Filename (or ae pairt o it):",
+       "newimages-showbots": "Shaw uplaids bi bots",
        "noimages": "Nawthing tae see.",
        "ilsubmit": "Rake",
        "bydate": "bi date",
        "sp-newimages-showfrom": "Shaw new files stairtin fae $2, $1",
        "seconds": "{{PLURAL:$1|$1 seicont|$1 seiconts}}",
+       "minutes": "{{PLURAL:$1|$1 minute|$1 minutes}}",
        "hours": "{{PLURAL:$1|$1 hoor|$1 hoors}}",
+       "days": "{{PLURAL:$1|$1 day|$1 days}}",
+       "weeks": "{{PLURAL:$1|$1 week|$1 weeks}}",
+       "months": "{{PLURAL:$1|$1 month|$1 months}}",
+       "years": "{{PLURAL:$1|$1 year|$1 years}}",
        "ago": "$1 sin",
        "just-now": "richt nou",
        "hours-ago": "$1 {{PLURAL:$1|hoor|hoors}} sin",
        "minutes-ago": "$1 {{PLURAL:$1|minute|minutes}} sin",
        "seconds-ago": "$1 {{PLURAL:$1|seicont|seiconts}} sin",
        "monday-at": "Monenday at $1",
+       "tuesday-at": "Tuesday at $1",
        "wednesday-at": "Wedensday at $1",
+       "thursday-at": "Thursday at $1",
        "friday-at": "Frisday at $1",
+       "saturday-at": "Saturday at $1",
+       "sunday-at": "Sunday at $1",
+       "yesterday-at": "Yesterday at $1",
        "bad_image_list": "The format is aes follaes:\n\nAinlie leet eetems (lines stairtin wi *) ar considered. The foremaist airtin oan ae line maun be aen airtin til aen ill file. Onie subsequent airtins oan the same line ar considered tae be exceptions, i,e., pages whaur the eemage can occur inline.",
        "metadata": "Metadata",
        "metadata-help": "This file contains addeetional information, likelie eikit fae the deegital camera or scanner uised tae cræft or deegitise it. \nGif the file haes bin modeefied fae its oreeginal state, some details micht na fullie reflect the modeefied file.",
        "metadata-expand": "Shaw extendit details",
        "metadata-collapse": "Skauk extendit details",
        "metadata-fields": "Eemage metadata fields leetit in this message will be incluidit oan eemage page displey whan the metadata buird is collaps't. Ithers will be skaukt bi defaut. \n* mak\n* model\n* datetimeoreeginal\n* exposuretime\n* fnummer\n* isospeedratins\n* focallength\n* airtist\n* copiericht\n* eemagedescreeption\n* gpslateetuid\n* gpslangeetuid\n* gpsalteetuid",
+       "exif-imagewidth": "Width",
        "exif-imagelength": "Heicht",
+       "exif-bitspersample": "Bits per component",
+       "exif-compression": "Compression scheme",
        "exif-photometricinterpretation": "Pixel composeetion",
+       "exif-orientation": "Orientation",
        "exif-samplesperpixel": "Nummer o components",
+       "exif-planarconfiguration": "Data arrangement",
        "exif-ycbcrsubsampling": "Subsamplin ratio o Y til C",
        "exif-ycbcrpositioning": "Y n C poseetionin",
+       "exif-xresolution": "Horizontal resolution",
        "exif-yresolution": "Verteecal resolution",
        "exif-stripoffsets": "Eemage data location",
        "exif-rowsperstrip": "Nummer o raws per streep",
        "exif-referenceblackwhite": "Pair o blaick n white referance values",
        "exif-datetime": "File chynge date n time",
        "exif-imagedescription": "Eemage title",
+       "exif-make": "Camera manufacturer",
+       "exif-model": "The Camera model",
        "exif-software": "Saffware uised",
        "exif-artist": "Writer",
        "exif-copyright": "Copiericht hauder",
+       "exif-exifversion": "Exif version",
        "exif-flashpixversion": "Supportit Flashpix version",
        "exif-colorspace": "Colour space",
        "exif-componentsconfiguration": "Meanin o ilka component",
        "exif-subsectime": "DateTime subseiconts",
        "exif-subsectimeoriginal": "DateTimeOreeginal subseiconts",
        "exif-subsectimedigitized": "DateTimeDeegeetized subseiconts",
+       "exif-exposuretime": "Exposure time",
+       "exif-exposuretime-format": "$1 sec ($2)",
        "exif-fnumber": "F Nummer",
+       "exif-exposureprogram": "Exposure Program",
        "exif-spectralsensitivity": "Spectral sensiteevitie",
        "exif-isospeedratings": "ISO speed ratin",
+       "exif-shutterspeedvalue": "APEX shutter speed",
+       "exif-aperturevalue": "APEX aperture",
        "exif-brightnessvalue": "APEX brichtness",
+       "exif-exposurebiasvalue": "APEX exposure bias",
        "exif-maxaperturevalue": "Mucklest launn aperture",
+       "exif-subjectdistance": "Subject distance",
        "exif-meteringmode": "Meterin mode",
        "exif-lightsource": "Licht soorce",
+       "exif-flash": "Flash",
+       "exif-focallength": "Lens focal langth",
        "exif-subjectarea": "Subject airt",
        "exif-flashenergy": "Flash energie",
+       "exif-focalplanexresolution": "Focal plane X resolution",
+       "exif-focalplaneyresolution": "Focal plane Y resolution",
+       "exif-focalplaneresolutionunit": "Focal plane resolution unit",
+       "exif-subjectlocation": "Subject location",
+       "exif-exposureindex": "Exposure index",
        "exif-sensingmethod": "Sensin methyd",
        "exif-filesource": "File soorce",
+       "exif-scenetype": "Scene type",
        "exif-customrendered": "Custym eemage processin",
+       "exif-exposuremode": "Exposure mode",
+       "exif-whitebalance": "White balance",
        "exif-digitalzoomratio": "Deegeetal zuim ratio",
+       "exif-focallengthin35mmfilm": "Focal length in 35 mm film",
+       "exif-scenecapturetype": "Scene captur type",
+       "exif-gaincontrol": "Scene control",
+       "exif-contrast": "Contrast",
+       "exif-saturation": "Saturation",
        "exif-sharpness": "Shairpness",
        "exif-devicesettingdescription": "Device settins descreeption",
        "exif-subjectdistancerange": "Subject deestance range",
        "exif-imageuniqueid": "Uníque eemage ID",
+       "exif-gpsversionid": "GPS tag version",
        "exif-gpslatituderef": "Nort or sooth lateetude",
        "exif-gpslatitude": "Lateetude",
        "exif-gpslongituderef": "Aest or west langeetude",
        "exif-gpstimestamp": "GPS time (atomeec clock)",
        "exif-gpssatellites": "Satellites uised fer measurement",
        "exif-gpsstatus": "Receever status",
+       "exif-gpsmeasuremode": "Measurement mode",
        "exif-gpsdop": "Measurement preeceesion",
+       "exif-gpsspeedref": "Speed unit",
        "exif-gpsspeed": "Speed o GPS receever",
        "exif-gpstrackref": "Referance fer direction o muivement",
        "exif-gpstrack": "Direction o muivement",
        "exif-gpsdestdistance": "Distance til destination",
        "exif-gpsprocessingmethod": "Name o GPS processin methyd",
        "exif-gpsareainformation": "Name o GPS airt",
+       "exif-gpsdatestamp": "GPS date",
        "exif-gpsdifferential": "GPS differantial correction",
+       "exif-jpegfilecomment": "JPEG file comment",
        "exif-keywords": "Keywairds",
        "exif-worldregioncreated": "Region o the Yird that the picture wis taen in",
        "exif-countrycreated": "Kintra that the picture wis taen in",
        "exif-provinceorstatedest": "Provínce or state shawn",
        "exif-citydest": "Ceetie shawn",
        "exif-sublocationdest": "Sublocation o ceetie shawn",
+       "exif-objectname": "Short title",
        "exif-specialinstructions": "Byordiair insructions",
        "exif-headline": "Heidline",
        "exif-credit": "Creedit/Provider",
        "exif-locationdest": "Location depeected",
        "exif-locationdestcode": "Code o location depeected",
        "exif-objectcycle": "Time o day that media is intended fer",
+       "exif-contact": "Contact information",
+       "exif-writer": "Writer",
        "exif-languagecode": "Leid",
+       "exif-iimversion": "IIM version",
        "exif-iimcategory": "Categerie",
        "exif-iimsupplementalcategory": "Supplemental categeries",
        "exif-datetimeexpires": "Dinna uise efter",
        "exif-lens": "Lens uised",
        "exif-serialnumber": "Serial nummer o camera",
        "exif-cameraownername": "Ainer o camera",
+       "exif-label": "Label",
        "exif-datetimemetadata": "Date metadata wis laist modeefied",
        "exif-nickname": "Informal name o eemage",
        "exif-rating": "Ratin (oot o 5)",
        "exif-morepermissionsurl": "Alternative licensin information",
        "exif-attributionurl": "Whan re-uisin this wairk, please link til",
        "exif-preferredattributionname": "Whan re-uisin this wairk, please creedit",
+       "exif-pngfilecomment": "PNG file comment",
+       "exif-disclaimer": "Disclaimer",
        "exif-contentwarning": "Content warnishment",
+       "exif-giffilecomment": "GIF file comment",
        "exif-intellectualgenre": "Type o eetem",
+       "exif-subjectnewscode": "Subject code",
+       "exif-scenecode": "IPTC scene code",
        "exif-event": "Event depected",
        "exif-organisationinimage": "Organization depected",
        "exif-personinimage": "Person depected",
        "exif-copyrighted-true": "Copierichted",
        "exif-copyrighted-false": "Copiericht status na set",
        "exif-unknowndate": "Onkent date",
+       "exif-orientation-1": "Ordinair",
        "exif-orientation-2": "Flipt horizontallie",
        "exif-orientation-3": "Rotatit 180°",
        "exif-orientation-4": "Flipt verticlie",
        "exif-orientation-7": "Rotatit 90° CW n flipt verticlie",
        "exif-orientation-8": "Rotatit 90° CW",
        "exif-planarconfiguration-1": "chunkie format",
+       "exif-planarconfiguration-2": "planar format",
        "exif-colorspace-65535": "Oncalibratit",
        "exif-componentsconfiguration-0": "disna exeest",
        "exif-exposureprogram-0": "Na defined",
+       "exif-exposureprogram-1": "Manual",
+       "exif-exposureprogram-2": "Ordinair program",
        "exif-exposureprogram-3": "Apertur prioritie",
        "exif-exposureprogram-4": "Shutter prioritie",
        "exif-exposureprogram-5": "Cræftie program (biased thewaird the depth o field)",
        "exif-exposureprogram-6": "Action program (biased thewaird fast shutter speed)",
        "exif-exposureprogram-7": "Portrait mode (fer closeup photæs wi the backgroond oot o focus)",
        "exif-exposureprogram-8": "Launnscape mode (fer launnscape photæs wi the backgroonn in focus)",
+       "exif-subjectdistance-value": "$1 meters",
        "exif-meteringmode-0": "Onkent",
+       "exif-meteringmode-1": "Average",
        "exif-meteringmode-2": "Center weichtit average",
+       "exif-meteringmode-3": "Spot",
        "exif-meteringmode-4": "Multí-Spot",
+       "exif-meteringmode-5": "Pattern",
        "exif-meteringmode-6": "Pairtial",
        "exif-meteringmode-255": "Ither",
        "exif-lightsource-0": "Onkent",
        "exif-lightsource-1": "Daylicht",
        "exif-lightsource-2": "Fluorescant",
        "exif-lightsource-3": "Tungsten (incandescant licht)",
+       "exif-lightsource-4": "Flash",
+       "exif-lightsource-9": "Fine weather",
        "exif-lightsource-10": "Cloodie weather",
+       "exif-lightsource-11": "Gloam",
        "exif-lightsource-12": "Daylicht fluorescant (D 5700 – 7100K)",
        "exif-lightsource-13": "Day white fluorescant (N 4600 – 5400K)",
        "exif-lightsource-14": "Cuil white fluorescant (W 3900 – 4500K)",
        "exif-lightsource-17": "Staunart licht A",
        "exif-lightsource-18": "Staunart licht B",
        "exif-lightsource-19": "Staunart licht C",
+       "exif-lightsource-24": "ISO studio tungsten",
        "exif-lightsource-255": "Ither licht soorce",
        "exif-flash-fired-0": "Flash didna fire",
+       "exif-flash-fired-1": "Flash fired",
        "exif-flash-return-0": "naw flash return detection function",
        "exif-flash-return-2": "flash return licht na detectit",
        "exif-flash-return-3": "flash return licht detectit",
        "exif-flash-mode-3": "autæ mode",
        "exif-flash-function-1": "Naw flash function",
        "exif-flash-redeye-1": "reid-ee reduction mode",
+       "exif-focalplaneresolutionunit-2": "inches",
        "exif-sensingmethod-1": "Ondefined",
        "exif-sensingmethod-2": "Yin-chip colour airt senser",
        "exif-sensingmethod-3": "Twa-chip colour airt senser",
        "exif-sensingmethod-8": "Colour sequential linear senser",
        "exif-filesource-3": "Deegeetal still camera",
        "exif-scenetype-1": "Ae directlie photægraphed eemage",
+       "exif-customrendered-0": "Ordinair process",
        "exif-customrendered-1": "Custym process",
        "exif-exposuremode-0": "Autæ exposure",
+       "exif-exposuremode-1": "Manual exposure",
        "exif-exposuremode-2": "Autæ bracket",
        "exif-whitebalance-0": "Autæ white balance",
+       "exif-whitebalance-1": "Manual white balance",
        "exif-scenecapturetype-0": "Staunart",
        "exif-scenecapturetype-1": "Launscape",
+       "exif-scenecapturetype-2": "Portrait",
        "exif-scenecapturetype-3": "Nicht scene",
        "exif-gaincontrol-0": "Nane",
        "exif-gaincontrol-1": "Law gain up",
        "exif-gaincontrol-2": "Hei gain up",
        "exif-gaincontrol-3": "Law gain doon",
        "exif-gaincontrol-4": "Hei gain doon",
+       "exif-contrast-0": "Ordinair",
        "exif-contrast-1": "Saft",
        "exif-contrast-2": "Haurd",
+       "exif-saturation-0": "Ordinair",
        "exif-saturation-1": "Law saturation",
        "exif-saturation-2": "Hei saturation",
+       "exif-sharpness-0": "Ordinair",
        "exif-sharpness-1": "Saff",
        "exif-sharpness-2": "Haurd",
        "exif-subjectdistancerange-0": "Onkent",
+       "exif-subjectdistancerange-1": "Macro",
        "exif-subjectdistancerange-2": "Claise luik at",
        "exif-subjectdistancerange-3": "Distance sechtline",
        "exif-gpslatitude-n": "Nort lateetude",
        "exif-gpslongitude-w": "West langeetude",
        "exif-gpsaltitude-above-sealevel": "$1 {{PLURAL:$1|meter|meters}} abuin sea level",
        "exif-gpsaltitude-below-sealevel": "$1 {{PLURAL:$1|meter|meters}} ablo sea level",
+       "exif-gpsstatus-a": "Measurement in progress",
        "exif-gpsstatus-v": "Measurement interoperabeelitie",
+       "exif-gpsmeasuremode-2": "2-dimensional measurement",
+       "exif-gpsmeasuremode-3": "3-dimensional measurement",
        "exif-gpsspeed-k": "Kilometers aen hoor",
        "exif-gpsspeed-m": "Miles aen hoor",
+       "exif-gpsspeed-n": "Knots",
+       "exif-gpsdestdistance-k": "Kilometers",
+       "exif-gpsdestdistance-m": "Miles",
        "exif-gpsdestdistance-n": "Nauteecal miles",
        "exif-gpsdop-excellent": "Excellant ($1)",
        "exif-gpsdop-good": "Guid ($1)",
+       "exif-gpsdop-moderate": "Moderate ($1)",
+       "exif-gpsdop-fair": "Fair ($1)",
        "exif-gpsdop-poor": "Puir ($1)",
        "exif-objectcycle-a": "Mornin yinlie",
        "exif-objectcycle-p": "Evenin yinlie",
        "exif-objectcycle-b": "Baith mornin n evenin",
+       "exif-gpsdirection-t": "True direction",
        "exif-gpsdirection-m": "Magneteec direction",
+       "exif-ycbcrpositioning-1": "Centerit",
+       "exif-ycbcrpositioning-2": "Co-steidit",
        "exif-dc-contributor": "Contreebuters:",
        "exif-dc-coverage": "Spatial or tempral scope o media",
+       "exif-dc-date": "Date(s)",
+       "exif-dc-publisher": "Publisher",
        "exif-dc-relation": "Relatit media",
        "exif-dc-rights": "Richts",
        "exif-dc-source": "Soorce media",
        "exif-iimcategory-clj": "Crime n law",
        "exif-iimcategory-dis": "Disasters n accidants",
        "exif-iimcategory-fin": "Economie n business",
+       "exif-iimcategory-edu": "Education",
+       "exif-iimcategory-evn": "Environment",
        "exif-iimcategory-hth": "The Heal",
        "exif-iimcategory-hum": "Fawk interest",
        "exif-iimcategory-lab": "Laber",
        "exif-iimcategory-rel": "Releegion n truent",
        "exif-iimcategory-sci": "Sciance n technologie",
        "exif-iimcategory-soi": "Social eessues",
+       "exif-iimcategory-spo": "Sports",
        "exif-iimcategory-war": "War, conflict n onrest",
+       "exif-iimcategory-wea": "Weather",
+       "exif-urgency-normal": "Ordinair ($1)",
        "exif-urgency-low": "Law ($1)",
        "exif-urgency-high": "Hei ($1)",
        "exif-urgency-other": "Uiser-defined prioritie ($1)",
        "confirm_purge_button": "OK",
        "confirm-purge-top": "Clair the cache o this page?",
        "confirm-purge-bottom": "Purgin ae page clears the cache n forces the maist recynt reveesion tae appear.",
+       "confirm-watch-button": "OK",
        "confirm-watch-top": "Eik this page til yer watchleet?",
+       "confirm-unwatch-button": "OK",
        "confirm-unwatch-top": "Remuiv this page fae yer watchleet?",
+       "quotation-marks": "\"$1\"",
        "imgmultipageprev": "← preeveeoos page",
        "imgmultipagenext": "nex page →",
        "imgmultigo": "Gang!",
        "img-lang-default": "(defaut leid)",
        "img-lang-info": "Render this eemage in $1. $2",
        "img-lang-go": "Gang",
+       "ascending_abbrev": "asc",
+       "descending_abbrev": "desc",
        "table_pager_next": "Page aifter",
        "table_pager_prev": "Page afore",
+       "table_pager_first": "First page",
        "table_pager_last": "Laist page",
        "table_pager_limit": "Shaw $1 eetems per page",
        "table_pager_limit_label": "Eetems per page:",
        "autosumm-replace": "Replacin page wi '$1'",
        "autoredircomment": "Reguidin til [[$1]]",
        "autosumm-new": "Cræftit page wi \"$1\"",
+       "autosumm-newblank": "Creautit blank page",
        "lag-warn-normal": "Chynges newer than $1 {{PLURAL:$1|seicont|seiconts}} micht na be shawn in this leet.",
        "lag-warn-high": "Cause o hei database server lag, chynges newer than $1 {{PLURAL:$1|seicont|seiconts}} micht na be shawn in this leet.",
        "watchlistedit-normal-title": "Eedit watchleet",
        "watchlistedit-raw-title": "Eedit raw watchleet",
        "watchlistedit-raw-legend": "Eedit raw watchleet",
        "watchlistedit-raw-explain": "Titles oan yer watchleet ar shawn ablo, n can be eeditit bi eikin til n remuivin fae the leet;\nyin title per line.\nWhan dun, clap \"{{int:Watchlistedit-raw-submit}}\".\nYe can [[Special:EditWatchlist|uise the staundairt eediter]] n aw.",
+       "watchlistedit-raw-titles": "Titles:",
        "watchlistedit-raw-submit": "Update watchleet",
        "watchlistedit-raw-done": "Yer watchleet haes been updated.",
        "watchlistedit-raw-added": "{{PLURAL:$1|1 title wis|$1 titles were}} added:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 title wis|$1 titles were}} remuived:",
+       "watchlistedit-clear-title": "Cleared watchleet",
+       "watchlistedit-clear-legend": "Clear watchleet",
+       "watchlistedit-clear-explain": "Aw o the titles will be remuived fae yer watchleet",
+       "watchlistedit-clear-titles": "Titles:",
+       "watchlistedit-clear-submit": "Clear the watchleet (This is fer aye!)",
+       "watchlistedit-clear-done": "Yer watchleet's been cleared.",
+       "watchlistedit-clear-removed": "{{PLURAL:$1|1 title wis|$1 titles were}} remuived:",
+       "watchlistedit-too-many": "Thaur's ower monie pages tae displey here.",
+       "watchlisttools-clear": "Clear the watchleet",
        "watchlisttools-view": "See reelavant chynges",
        "watchlisttools-edit": "See n eedit watchleet",
        "watchlisttools-raw": "Eedit raw watchleet",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|tauk]])",
        "unknown_extension_tag": "Onkent extension tag \"$1\"",
        "duplicate-defaultsort": "<strong>Warnishment:</strong> Defaut sort key \"$2\" owerrides earlier defaut sort key \"$1\".",
+       "duplicate-displaytitle": "<strong>Warnishment:</strong> Displey title \"$2\" owerrides the earlier displey title \"$1\".",
+       "invalid-indicator-name": "<strong>Mistak:</strong> Page status indicaters' <code>name</code> attreebute maunna be tuim.",
+       "version": "Version",
        "version-extensions": "Instawed extensions",
+       "version-skins": "Instawed skins",
        "version-specialpages": "Byordinar pages",
        "version-parserhooks": "Parser huiks",
        "version-variables": "Vareeables",
+       "version-antispam": "Spam hinderance",
        "version-other": "Ither",
        "version-mediahandlers": "Media haunnlers",
        "version-hooks": "Huiks",
+       "version-parser-extensiontags": "Parser extension tags",
        "version-parser-function-hooks": "Parser function huiks",
        "version-hook-name": "Huik name",
        "version-hook-subscribedby": "Subscribed bi",
        "version-no-ext-name": "[no name]",
+       "version-license": "MediaWiki License",
+       "version-ext-license": "License",
+       "version-ext-colheader-name": "Extension",
+       "version-skin-colheader-name": "Skin",
+       "version-ext-colheader-version": "Version",
+       "version-ext-colheader-license": "License",
        "version-ext-colheader-description": "Descreeption",
        "version-ext-colheader-credits": "Writers",
        "version-license-title": "License fer $1",
        "version-credits-summary": "We'd like tae recognize the follaein fawk fer thair contreebution til [[Special:Version|MediaWiki]].",
        "version-license-info": "MediaWiki is free saffware; ye can reedistreebute it n/or modifie it unner the terms o the GNU General Public License aes publeesht bi the Free Software Foundation; either version 2 o the License, or (bi yer optie) onie later version.\n\nMediaWiki is distreebuted in the hope that it will be uissfu, bit WIOOT ONIE WARRANTIE; wioot even the implied warrantie o MERCHANTABILITIE or FITNESS FER AE PARTEECULAR PURPYSS. See the GNU General Public License fer mair details.\n\nYe shid hae receeved [{{SERVER}}{{SCRIPTPATH}}/COPIEIN ae copie o the GNU General Public License] alang wi this program; gif na, write til the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA or [//www.gnu.org/licenses/old-licenses/gpl-2.0.html read it online].",
        "version-software": "Instawed saffware",
+       "version-software-product": "Product",
+       "version-software-version": "Version",
        "version-entrypoints": "Entrie point URLs",
        "version-entrypoints-header-entrypoint": "Entrie point",
+       "version-entrypoints-header-url": "URL",
        "redirect": "Reguidal bi file, uiser, page or reveesion ID",
        "redirect-legend": "Reguidal til ae file or page",
        "redirect-summary": "This byordiair page reguides til ae file (gien the file name), ae page (gien ae reveesion ID or page ID), or ae uiser page (gien ae numereec uiser ID). Uissage: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/page/64308]], [[{{#Special:Redirect}}/reveesion/328429]], or [[{{#Special:Redirect}}/uiser/101]].",
        "redirect-submit": "Gang",
        "redirect-lookup": "Luikup:",
+       "redirect-value": "Value:",
        "redirect-user": "Uiser ID",
+       "redirect-page": "Page ID",
        "redirect-revision": "Page reveesion",
+       "redirect-file": "File name",
        "redirect-not-exists": "Value na foond",
        "fileduplicatesearch": "Rake fer dupleecate files",
        "fileduplicatesearch-summary": "Rake fer dupleecate files based oan hash values.",
        "fileduplicatesearch-legend": "Rake fer ae dupleecate",
        "fileduplicatesearch-filename": "Filename:",
        "fileduplicatesearch-submit": "Rake",
+       "fileduplicatesearch-info": "$1 × $2 pixel<br />File size: $3<br />MIME type: $4",
        "fileduplicatesearch-result-1": "The file \"$1\" haes naw identeecal dupleecation.",
        "fileduplicatesearch-result-n": "The file \"$1\" haes {{PLURAL:$2|1 identeecal dupleecation|$2 identeecal dupleecations}}.",
        "fileduplicatesearch-noresults": "Naw file named \"$1\" foond.",
        "specialpages": "Byordinar pages",
+       "specialpages-note-top": "The Legend",
        "specialpages-note": "* Normal byordinair pages.\n* <span class=\"mw-specialpagerestricted\">Restreected byordinair pages.</span>",
+       "specialpages-group-maintenance": "Maintenance reports",
        "specialpages-group-other": "Ither byordinair pages",
        "specialpages-group-login": "Login / cræft accoont",
        "specialpages-group-changes": "Recynt chynges n logs",
        "specialpages-group-wiki": "Data n tuils",
        "specialpages-group-redirects": "Reguidin byordinair pages",
        "specialpages-group-spam": "Spam tuils",
+       "specialpages-group-developer": "Deveeloper tuils",
+       "blankpage": "Blank page",
        "intentionallyblankpage": "This page is intentionlie left blank.",
        "external_image_whitelist": " #Lea this line exactlie aes it is<pre>\n#Put regulair expression fragments (jist the pairt that gaes atween the //) ablo\n#Thir will be matched wi the URLs o ootby (hotairtit) eemages\n#Thae that match will be displeyed aes eemages, itherwise yinlie aen airtin til the eemage will be shawn\n#Lines beginnin wi # ar treated aes comments\n#This is case-onsensiteeve\n\n#Put aw regex fragments abuin this line. Lea this line exactlie aes it is</pre>",
        "tags": "Valit chynge tags",
        "tag-filter": "[[Special:Tags|Tag]] filter:",
        "tag-filter-submit": "Filter",
+       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag|Tags}}]]: $2)",
+       "tags-title": "Tags",
        "tags-intro": "This page leets the tags that the saffware can maurk aen eedit wi, n thair meanin.",
+       "tags-tag": "Tag name",
        "tags-display-header": "Appearance oan chynge leets",
        "tags-description-header": "Ful descreeption o meanin",
        "tags-active-header": "Acteeve?",
        "tags-active-no": "Naw",
        "tags-edit": "eedit",
        "tags-hitcount": "$1 {{PLURAL:$1|chynge|chynges}}",
+       "comparepages": "Compare pages",
+       "compare-page1": "Page 1",
+       "compare-page2": "Page 2",
        "compare-rev1": "Reveesion 1",
        "compare-rev2": "Reveesion 2",
+       "compare-submit": "Compare",
        "compare-invalid-title": "The title that ye speceefied is onvalit.",
        "compare-title-not-exists": "The title that ye speceefied disna exeest.",
        "compare-revision-not-exists": "The reveesion that ye speceefied disna exeest.",
        "htmlform-no": "Naw",
        "htmlform-yes": "Ay",
        "htmlform-chosen-placeholder": "Select aen optie",
+       "htmlform-cloner-create": "Eik mair",
+       "htmlform-cloner-delete": "Remuiv",
+       "htmlform-cloner-required": "At least the ae value is needit.",
        "sqlite-has-fts": "$1 wi ful-tex rake support",
        "sqlite-no-fts": "$1 wioot ful-tex rake support",
        "logentry-delete-delete": "$1 {{GENDER:$2|delytit}} page $3",
+       "logentry-delete-restore": "$1 {{GENDER:$2|restored}} page $3",
        "logentry-delete-event": "$1 {{GENDER:$2|chynged}} veesibeelitie o {{PLURAL:$5|ae log event|$5 log events}} oan $3: $4",
        "logentry-delete-revision": "$1 {{GENDER:$2|chynged}} veesibeelitie o {{PLURAL:$5|ae reveesion|$5 reveesions}} oan page $3: $4",
        "logentry-delete-event-legacy": "$1 {{GENDER:$2|chynged}} veesibeelitie o log events oan $3",
        "logentry-delete-revision-legacy": "$1 {{GENDER:$2|chynged}} veesibeelitie o reveesions oan page $3",
+       "logentry-suppress-delete": "$1 {{GENDER:$2|suppressed}} page $3",
        "logentry-suppress-event": "$1 hidlinswise {{GENDER:$2|chynged}} veesibeelitie o {{PLURAL:$5|ae log event|$5 log events}} oan $3: $4",
        "logentry-suppress-revision": "$1 hidlinswise {{GENDER:$2|chynged}} veesibeelity o {{PLURAL:$5|ae reveesion|$5 reveesions}} oan page $3: $4",
        "logentry-suppress-event-legacy": "$1 hidlinswise {{GENDER:$2|chynged}} veesibeelitie o log events oan $3",
        "revdelete-uname-unhid": "uisername onskaukt",
        "revdelete-restricted": "applied restreections til admeenistraters",
        "revdelete-unrestricted": "remuived restreections fer admeenistraters",
+       "logentry-merge-merge": "$1 {{GENDER:$2|merged}} $3 intae $4 (reveesions up tae $5)",
        "logentry-move-move": "$1 {{GENDER:$2|muived}} page $3 til $4",
        "logentry-move-move-noredirect": "$1 {{GENDER:$2|muived}} page $3 til $4 wioot leain ae reguidal",
        "logentry-move-move_redir": "$1 {{GENDER:$2|muived}} page $3 til $4 ower reguidal",
        "logentry-rights-rights": "$1 {{GENDER:$2|chynged}} groop memmership fer $3 fae $4 til $5",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|chynged}} groop memmership fer $3",
        "logentry-rights-autopromote": "$1 wis autæmateeclie {{GENDER:$2|promoted}} fae $4 til $5",
+       "logentry-upload-upload": "$1 {{GENDER:$2|uplaidit}} $3",
+       "logentry-upload-overwrite": "$1 {{GENDER:$2|uplaidit}} ae new version o $3",
+       "logentry-upload-revert": "$1 {{GENDER:$2|uplaidit}} $3",
        "rightsnone": "(nane)",
+       "revdelete-summary": "eedit the ootline",
        "feedback-bugornote": "Gif yer readie tae describe ae techneecal proablem in detail please [$1 report ae bug].\nItherwise, ye can uiss the easie form ablo. Yer comment will be eikit til the page \"[$3 $2]\", alang wi yer uisername.",
+       "feedback-subject": "Aneat:",
+       "feedback-message": "Message:",
+       "feedback-cancel": "Cancel",
+       "feedback-submit": "Haund Feedback In",
        "feedback-adding": "Eikin feedback til page...",
        "feedback-error1": "Mistak: Onrecognised ootcome fae API",
        "feedback-error2": "Mistak: Eedit failed",
        "searchsuggest-search": "Rake",
        "searchsuggest-containing": "containin...",
        "api-error-badaccess-groups": "Ye'r na permittit tae uplaid files til this wiki.",
+       "api-error-badtoken": "Inby mistak: Bad token.",
        "api-error-copyuploaddisabled": "Uplaidin bi URL is disabled oan this server.",
        "api-error-duplicate": "Thaur {{PLURAL:$1|is [$2 anither file]|ar [$2 some ither files]}} awreadie oan the site wi the same content.",
        "api-error-duplicate-archive": "Thaur {{PLURAL:$1|wis [$2 anither file]|were [$2 some ither files]}} awreadie oan the site wi the same content, but {{PLURAL:$1|it wis|thay were}} delytit.",
        "api-error-stashfailed": "Internal mistak: Server failed tae store temparie file.",
        "api-error-publishfailed": "Internal mistak: Server failed tae publeesh temparie file.",
        "api-error-stasherror": "Thaur wis ae mistak while uplaidin the file tae stash.",
+       "api-error-stashedfilenotfound": "The stashed file wis no foond whan attemptin tae uplaid it fae the stash.",
+       "api-error-stashpathinvalid": "The path that the stashed file shid hae been foond at wis no valid.",
+       "api-error-stashfilestorage": "Thaur wis ae mistak in storin the file in the stash.",
+       "api-error-stashzerolength": "The server coudna stash the file, cause it haed zero langth.",
+       "api-error-stashnotloggedin": "Ye maun be loggit in tae hain files in the uplaid stash.",
+       "api-error-stashwrongowner": "The file that ye were attemptin tae access in the stash disna belang tae ye.",
+       "api-error-stashnosuchfilekey": "The file key that ye were attemptin tae access in the stash disna exeest.",
        "api-error-timeout": "The server didna respond wiin the expectit time.",
        "api-error-unclassified": "Aen onkent mistake occurred.",
+       "api-error-unknown-code": "Onknawn mistak: \"$1\".",
        "api-error-unknown-error": "Internal mistak: Sommit went wrang whan uplaidin yer file.",
+       "api-error-unknown-warning": "Onknawn warnishment: \"$1\".",
+       "api-error-unknownerror": "Onknawn mistak: \"$1\".",
        "api-error-uploaddisabled": "Uplaidin is disabled oan this wiki.",
        "api-error-verification-error": "This file micht be rotten, or hae the wrang extension.",
        "duration-seconds": "$1 {{PLURAL:$1|seicont|seiconts}}",
+       "duration-minutes": "$1 {{PLURAL:$1|minute|minutes}}",
        "duration-hours": "$1 {{PLURAL:$1|hoor|hoors}}",
+       "duration-days": "$1 {{PLURAL:$1|day|days}}",
+       "duration-weeks": "$1 {{PLURAL:$1|week|weeks}}",
+       "duration-years": "$1 {{PLURAL:$1|year|years}}",
+       "duration-decades": "$1 {{PLURAL:$1|decade|decades}}",
        "duration-centuries": "$1 {{PLURAL:$1|centuair|centuairs}}",
+       "duration-millennia": "$1 {{PLURAL:$1|millennium|millennia}}",
        "rotate-comment": "Eemage rotated bi $1 {{PLURAL:$1|degree|degrees}} clockwise",
        "limitreport-title": "Parser profilin data:",
        "limitreport-cputime": "CPU time uissage",
        "limitreport-ppvisitednodes": "Preprocessor veesitit node coont",
        "limitreport-ppgeneratednodes": "Preprocessor generated node coont",
        "limitreport-postexpandincludesize": "Post-expand incluid size",
+       "limitreport-postexpandincludesize-value": "$1/$2 {{PLURAL:$2|byte|bytes}}",
+       "limitreport-templateargumentsize": "Template argument size",
+       "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|byte|bytes}}",
        "limitreport-expansiondepth": "Heiest expansion depth",
        "limitreport-expensivefunctioncount": "Expensive parser function coont",
+       "expandtemplates": "Mak templates muckler",
        "expand_templates_intro": "This byordiair page taks tex n expauns aw templates in it recurseevelie.\nIt foreby expaunds supported parser functions like\n<code><nowiki>{{</nowiki>#language:…}}</code> n vareeables like\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nIn fact, it expauns just aboot awthings in dooble-braces.",
        "expand_templates_title": "Contex title, fer {{FULLPAGENAME}}, etc.:",
+       "expand_templates_input": "The Input tex:",
        "expand_templates_output": "Ootcome",
        "expand_templates_xml_output": "XML ootpit",
        "expand_templates_html_output": "Raw HTML ootpit",
+       "expand_templates_ok": "OK",
+       "expand_templates_remove_comments": "Remuiv comments",
        "expand_templates_remove_nowiki": "Suppress <nowiki> tags in ootcome",
        "expand_templates_generate_xml": "Shaw XML parse tree",
        "expand_templates_generate_rawhtml": "Shaw raw HTML",
-       "expand_templates_preview": "Luikower"
+       "expand_templates_preview": "Luikower",
+       "expand_templates_preview_fail_html": "<em>Cause {{SITENAME}} haes raw HTML enabled n thaur wis ae loss o session data, the luikower haes been skaukt tae help defend again JavaScript attacks.</em>\n\n<strong>Gif this is a legeetimate luikower attempt, please gie it anither shot.</strong>\nGif ye still haae nae joy, than gie [[Special:UserLogout|loggin oot]] n loggin back in ae shot.",
+       "expand_templates_preview_fail_html_anon": "<em>Cause {{SITENAME}} haes raw HTML enabled n ye'r no loggit in, the luikower haes been skaukt tae fend again JavaScript attacks.</em>\n\n<strong>Gif this is ae legeetimate luikower attempt, than please [[Special:UserLogin|log in]] n gie it anither shot.</strong>",
+       "pagelanguage": "Page leid selecter",
+       "pagelang-name": "Page",
+       "pagelang-language": "Leid",
+       "pagelang-use-default": "Uise the defaut leid",
+       "pagelang-select-lang": "Pick yer leid",
+       "right-pagelang": "Chynge page leid",
+       "action-pagelang": "chynge the page leid",
+       "log-name-pagelang": "Chynge leid log",
+       "log-description-pagelang": "This is ae log o chynges in page leids.",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|chynged}} page leid fer $3 fae $4 tae $5.",
+       "default-skin-not-found": "Whoops! The defaut skin fer yer wiki, defined in <code dir=\"ltr\">$wgDefaultSkin</code> aes <code>$1</code>, is no available.\n\nYer instawation seems tae incluid the follaein skins. See [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] fer information oan hou tae enable thaim n chuise the defaut.\n\n$2\n\n; Gif ye'v juist instawed MediaWiki:\n: Ye proabablie instawed it fae git, or directlie fae the soorce code uisin some ither method. This is expectie. Gie instawin some skins fae [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory] ae shot, bi:\n:* Dounlaidin the [https://www.mediawiki.org/wiki/Download tarball installer], this comes wi several skins n extensions. Ye can than capie n paste the <code>skins/</code> directerie fae this.\n:* Dounlaidin indiveedual skin tarballs frae [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Clonin one of the <code>mediawiki/skins/*</code> repositries bi wa o git intae the <code dir=\"ltr\">skins/</code> directerie o yer MediaWiki instawation.\n: Daein this shoudna interfere wi yer git repositrie gif ye'r ae MediaWiki deveeloper.\n\n; Gif ye,v juist upgradit MediaWiki:\n: MediaWiki 1.24 n newer nae langer enables instawed skins autæmateeclie (see [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). Ye can paste the follaein lines intae <code>LocalSettings.php</code> tae enable aw nou installed skins:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Gif ye'v juist modified <code>LocalSettings.php</code>:\n: Double-check the skin names fer typos.",
+       "default-skin-not-found-no-skins": "Whoops! The defaut skin fer yer wiki, defined in <code>$wgDefaultSkin</code> aes <code>$1</code>, is no available.\n\nYe'v nae instawed skins.\n\n; Gif ye'v juist instawed or upgradit MediaWiki:\n: Ye probably instawed fae git, or directlie fae the soorce code uisin some ither method. This is expectit. MediaWiki 1.24 n newer disna incluid onie skins in the main repositrie. Gie instawin some skins fae [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org's skin directory] ae shot, bi:\n:* Dounlaidin the [https://www.mediawiki.org/wiki/Download tarball installer], this comes wi several skins n extensions. Ye can than capie n paste the <code>skins/</code> directerie fae it.\n:* Dounlaidin individual skin tarballs fae [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Cloning yin o the <code>mediawiki/skins/*</code> repositries bi wa o git intae the <code dir=\"ltr\">skins/</code> directerie o yer MediaWiki instawation.\n: Daein this shoudna interfere wi yer git repositrie gif ye'r ae MediaWiki deveeloper. See [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] fer information oan hou tae enable skins n chuise the defaut.",
+       "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (enabled)",
+       "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''disablt''')",
+       "mediastatistics": "Media stateestics",
+       "mediastatistics-summary": "Stateestics aneat uplaided file types. This yinlie incluids the maist recent version o ae file. Auld or delytit versions o files ar excluidit.",
+       "mediastatistics-nbytes": "{{PLURAL:$1|$1 byte|$1 bytes}} ($2; $3%)",
+       "mediastatistics-table-mimetype": "MIME type",
+       "mediastatistics-table-extensions": "Possible extensions",
+       "mediastatistics-table-count": "Nummer o files",
+       "mediastatistics-table-totalbytes": "Combined size",
+       "mediastatistics-header-unknown": "Onknawn",
+       "mediastatistics-header-bitmap": "Bitmap eemages",
+       "mediastatistics-header-drawing": "Drawins (vecter eemages)",
+       "mediastatistics-header-audio": "Audio",
+       "mediastatistics-header-video": "Videos",
+       "mediastatistics-header-multimedia": "Rich media",
+       "mediastatistics-header-office": "Affice",
+       "mediastatistics-header-text": "Texual",
+       "mediastatistics-header-executable": "Executables",
+       "mediastatistics-header-archive": "Compressed formats",
+       "json-warn-trailing-comma": "$1 trailin {{PLURAL:$1|comma wis|commas were}} remuived fae JSON",
+       "json-error-unknown": "Thaur wis ae proablem wi the JSON. Mistak: $1",
+       "json-error-depth": "The mucklest stack depth haes been exceedit",
+       "json-error-state-mismatch": "Onvalit or malformed JSON",
+       "json-error-ctrl-char": "Control chairacter mistak, possiblie wranglie encoded",
+       "json-error-syntax": "Syntax mistak",
+       "json-error-utf8": "Malformed UTF-8 chairacters, possiblie wranglie encoded",
+       "json-error-recursion": "Yin or mair recurseeve references in the value tae be encoded",
+       "json-error-inf-or-nan": "Yin or mair NAN or INF values in the value tae be encoded",
+       "json-error-unsupported-type": "Ae value o ae type that canna be encoded wis gien"
 }
index 47267a0..a965ded 100644 (file)
@@ -37,7 +37,7 @@
        "tog-shownumberswatching": "Prikaži število uporabnikov, ki spremljajo temo",
        "tog-oldsig": "Trenutni podpis:",
        "tog-fancysig": "Obravnavaj podpis kot wikibesedilo (brez samodejne povezave)",
-       "tog-uselivepreview": "Uporabi hitri predogled (preizkusno)",
+       "tog-uselivepreview": "Uporabi hitri predogled",
        "tog-forceeditsummary": "Ob vpisu praznega povzetka urejanja me opozori",
        "tog-watchlisthideown": "Na spisku nadzorov skrij moja urejanja",
        "tog-watchlisthidebots": "Na spisku nadzorov skrij urejanja botov",
        "anoneditwarning": "<strong>Opozorilo:</strong> Niste prijavljeni. Vaš IP-naslov bo javno viden, če naredite kakršno koli urejanje. Če se <strong>[$1 prijavite]</strong> ali <strong>[$2 ustvarite račun]</strong>, bodo vaša urejanja pripisana vašemu uporabniškemu imenu skupaj z drugimi prednostmi.",
        "anonpreviewwarning": "Niste prijavljeni. Ob spremembi strani se bo vaš IP-naslov zapisal v zgodovini urejanja te strani.",
        "missingsummary": "'''Opozorilo:''' Niste napisali povzetka urejanja. Ob ponovnem kliku gumba ''Shrani'' se bo vaše urejanje shranilo brez njega.",
+       "selfredirect": "<strong>Opozorilo:</strong> Ustvarjate preusmeritev na isti članek.\nČe ponovno kliknete »{{int:savearticle}}«, bomo preusmeritev ustvarili.",
        "missingcommenttext": "Prosimo, vpišite v spodnje polje komentar.",
        "missingcommentheader": "'''Opozorilo:''' Niste vnesli zadeve/naslova za ta komentar.\nČe boste ponovno kliknili »{{int:savearticle}}«, bo vaše urejanje shranjeno brez le-tega.",
        "summary-preview": "Predogled povzetka",
index c56f06a..6f52692 100644 (file)
@@ -88,7 +88,7 @@
        "tog-shownumberswatching": "Visa antalet användare som bevakar",
        "tog-oldsig": "Nuvarande signatur:",
        "tog-fancysig": "Behandla signatur som wikitext (utan en automatisk länk)",
-       "tog-uselivepreview": "Använd direktuppdaterad förhandsgranskning (experimentell)",
+       "tog-uselivepreview": "Använd direktuppdaterad förhandsgranskning",
        "tog-forceeditsummary": "Påminn mig om jag inte fyller i en redigeringskommentar",
        "tog-watchlisthideown": "Dölj mina redigeringar i bevakningslistan",
        "tog-watchlisthidebots": "Visa inte robotredigeringar i bevakningslistan",
        "anoneditwarning": "<strong>Varning:</strong> Du är inte inloggad. Din IP-adress kommer att vara publikt synlig om du gör några redigeringar. Om du <strong>[$1 loggar in]</strong> eller <strong>[$2 skapar ett konto]</strong> kommer dina redigeringar att tillskrivas ditt användarnamn, tillsammans med andra fördelar.",
        "anonpreviewwarning": "''Du är inte inloggad. Om du sparar kommer din IP-adress registreras på denna sidas redigeringshistorik.''",
        "missingsummary": "<strong>Påminnelse:</strong> Du har inte skrivit någon redigeringskommentar.\nOm du klickar på \"{{int:savearticle}}\" igen kommer din redigering att sparas utan en sådan.",
+       "selfredirect": "<strong>Varning:</strong> Du omdirigerar till samma artikel.\nOm du klickar på \"{{int:savearticle}}\" igen kommer omdirigeringen att skapas.",
        "missingcommenttext": "Var god och skriv in en kommentar nedan.",
        "missingcommentheader": "<strong>Påminnelse:</strong> Du har inte skrivit något ämne/rubrik för den här kommentaren.\nOm du trycker på \"{{int:savearticle}}\" igen kommer din redigering sparas utan rubrik.",
        "summary-preview": "Förhandsgranskning av sammanfattning:",
        "right-protect": "Ändra skyddsnivåer och redigera kaskadskyddade sidor",
        "right-editprotected": "Redigera skyddade sidor som \"{{int:protect-level-sysop}}\"",
        "right-editsemiprotected": "Redigera skyddade sidor som \"{{int:protect-level-autoconfirmed}}\"",
+       "right-editcontentmodel": "Ändra innehållsmodellen för en sida",
        "right-editinterface": "Redigera användargränssnittet",
        "right-editusercssjs": "Redigera andra användares CSS- och JS-filer",
        "right-editusercss": "Redigera andra användares CSS-filer",
        "action-viewmywatchlist": "visa din bevakningslista",
        "action-viewmyprivateinfo": "visa din privata information",
        "action-editmyprivateinfo": "redigera din privata information",
+       "action-editcontentmodel": "ändra innehållsmodellen för en sida",
        "nchanges": "$1 {{PLURAL:$1|ändring|ändringar}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|sedan senaste besöket}}",
        "enhancedrc-history": "historik",
        "expand_templates_generate_xml": "Visa parseträd som XML",
        "expand_templates_generate_rawhtml": "Visa rå HTML",
        "expand_templates_preview": "Förhandsvisning",
+       "expand_templates_preview_fail_html": "<em>Eftersom {{SITENAME}} har rå HTML aktiverat och det uppstod en förlust av sessionsdata har förhandsgranskningen dolts som en försiktighetsåtgärd för att skydda mot JavaScript-attacker.</em>\n\n<strong>Om detta är ett äkta försök att förhandsgranska sidan, vänligen försök igen.</strong>\nOm det fortfarande inte fungerar, försök att [[Special:UserLogout|logga ut]] och sedan logga in igen.",
+       "expand_templates_preview_fail_html_anon": "<em>Eftersom {{SITENAME}} har rå HTML aktiverat och du inte är inloggad har förhandsgranskningen dolts som en försiktighetsåtgärd för att skydda mot JavaScript-attacker.</em>\n\n<strong>Om detta är ett äkta försök att förhandsgranska sidan, vänligen [[Special:UserLogin|logga in]] och försök igen.</strong>",
        "pagelanguage": "Sidspråksväljare",
        "pagelang-name": "Sida",
        "pagelang-language": "Språk",
        "log-description-pagelang": "Detta är en logg över ändringar i sidspråken.",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|ändrade}} sidspråket för $3 från $4 till $5.",
        "default-skin-not-found": "Ojsan! Standardutseendet för din wiki, definierad i <code dir=\"ltr\">$wgDefaultSkin</code> som <code>$1</code>, är inte tillgängligt.\n\nDin installation verkar innehålla följande utseenden. Se [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manualen: Utseendeinställningar] för information om hur du aktiverar dem och hur standard väljs.\n\n$2\n\n; Om du precis installerat MediaWiki:\n: Du installerade troligen från git, eller direkt från källkoden via någon annan metod. Detta är normalt. Försök att installera några utseenden från [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org:s utseendekatalog], genom att:\n:* Ladda ner [https://www.mediawiki.org/wiki/Download tarball-installeraren], som kommer med flera utseenden och tillägg. Du kan klippa och klistra in <code>skins/</code>-katalogen från den.\n:* Ladda ner individuella tarballs med utseenden från [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Klona ett av <code>mediawiki/skins/*</code>-centralförvaren in i <code dir=\"ltr\">skins/</code>-arkiven i din MediaWiki-installation.\n: Att göra detta borde inte påverka ditt git-centralförvar om du är en MediaWiki-utvecklare. \n\n; Om du precis har uppgraderat MediaWiki:\n: MediaWiki 1.24 och nyare aktiverar ej längre automatiskt installerade utseenden (se [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Automatisk identifiering av utseenden]). Du kan klistra in följande rader i <code>LocalSettings.php</code> för att aktivera alla för närvarande installerade utseenden:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Om du precis har modifierat <code>LocalSettings.php</code>:\n: Dubbelkolla namnen för utseendena för att identifiera stavfel.",
-       "default-skin-not-found-no-skins": "Ojsan! Standardutseendet för din wiki, definierad i <code>$wgDefaultSkin</code> som <code>$1</code>, är inte tillgängligt.\n\nDu har inga installerade utseenden.\n\n; Om du precis installerat eller uppdaterat MediaWiki:\n: Du installerade troligen från git, eller direkt från källkoden via någon annan metod. Detta är att förvänta. MediaWiki 1.24 och nyare inkluderar inte några utseenden i det huvudsakliga centralförvaret. Försök att installera några utseenden från [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org:s utseendekatalog], genom att:\n:* Ladda ner [https://www.mediawiki.org/wiki/Download tarball-installeraren], som kommer med flera utseenden och tillägg. Du kan klipp-och-klistra in <code dir=\"ltr\">skins/</code>-katalogen från den.\n* Klona ett av <code>mediawiki/skins/*</code>-centralförvaren in i <code>skins/</code>-katalogen i din MediaWiki-installation.\n: Att göra detta borde inte påverka ditt git-centralförvar om du är en MediaWiki-utvecklare. Se [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manualen: Utseendeinställningar] för information om hur utseenden aktiveras och hur standardutseendet väljs.",
+       "default-skin-not-found-no-skins": "Ojsan! Standardutseendet för din wiki, definierad i <code>$wgDefaultSkin</code> som <code>$1</code>, är inte tillgängligt.\n\nDu har inga installerade utseenden.\n\n; Om du precis installerat eller uppdaterat MediaWiki:\n: Du installerade troligen från git, eller direkt från källkoden via någon annan metod. Detta är att förvänta. MediaWiki 1.24 och nyare inkluderar inte några utseenden i det huvudsakliga centralförvaret. Försök att installera några utseenden från [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org:s utseendekatalog], genom att:\n:* Ladda ner [https://www.mediawiki.org/wiki/Download tarball-installeraren], som kommer med flera utseenden och tillägg. Du kan klipp-och-klistra in <code dir=\"ltr\">skins/</code>-katalogen från den.\n:* Ladda ner individuella tarballs med utseende från [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Klona ett av <code>mediawiki/skins/*</code>-centralförvaren in i <code>skins/</code>-katalogen i din MediaWiki-installation.\n: Att göra detta borde inte påverka ditt git-centralförvar om du är en MediaWiki-utvecklare. Se [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manualen: Utseendeinställningar] för information om hur utseenden aktiveras och hur standardutseendet väljs.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (aktiverad)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''inaktiverad''')",
        "mediastatistics": "Mediastatistik",
index 14ebeaf..67346b3 100644 (file)
@@ -47,7 +47,7 @@
        "tog-shownumberswatching": "వీక్షకుల సంఖ్యను చూపు",
        "tog-oldsig": "ప్రస్తుత సంతకం:",
        "tog-fancysig": "సంతకాన్ని వికీపాఠ్యంగా తీసుకో (ఆటోమెటిక్‌ లింకు లేకుండా)",
-       "tog-uselivepreview": "à°µà±\86à°¨à±\81à°µà±\86à°\82à°\9f à°®à±\81à°¨à±\81à°\9cà±\82à°ªà±\81à°¨à±\81 à°µà°¾à°¡à±\81 (à°ªà±\8dà°°à°¯à±\8bà°\97ాతà±\8dà°®à°\95à°\82)",
+       "tog-uselivepreview": "తాà°\9cà°¾ à°®à±\81à°¨à±\81à°\9cà±\82à°ªà±\81à°¨à±\81 à°µà°¾à°¡à±\81",
        "tog-forceeditsummary": "దిద్దుబాటు సారాంశం ఖాళీగా ఉంటే ఆ విషయాన్ని నాకు సూచించు",
        "tog-watchlisthideown": "నా మార్పులను వీక్షణా జాబితాలో చూపించొద్దు",
        "tog-watchlisthidebots": "బాట్లు చేసిన మార్పులను నా వీక్షణా జాబితాలో చూపించొద్దు",
        "hidetoc": "దాచు",
        "collapsible-collapse": "కుదించు",
        "collapsible-expand": "విస్తరించు",
+       "confirmable-yes": "అవును",
+       "confirmable-no": "కాదు",
        "thisisdeleted": "$1ను చూస్తారా, పునఃస్థాపిస్తారా?",
        "viewdeleted": "$1 చూస్తారా?",
        "restorelink": "{{PLURAL:$1|ఒక తొలగించిన మార్పు|$1 తొలగించిన మార్పులు}}",
        "search-result-category-size": "{{PLURAL:$1|1 సభ్యుడు|$1 సభ్యులు}} ({{PLURAL:$2|1 ఉవవర్గం|$2 ఉపవర్గాలు}}, {{PLURAL:$3|1 దస్త్రం|$3 దస్త్రాలు}})",
        "search-redirect": "(దారిమార్పు $1)",
        "search-section": "(విభాగం $1)",
+       "search-category": "(వర్గం $1)",
        "search-file-match": "(ఫైలు విషయంతో సరిపోలుతోంది)",
        "search-suggest": "మీరు అంటున్నది ఇదా: $1",
        "search-interwiki-caption": "సోదర ప్రాజెక్టులు",
        "license-nopreview": "(మునుజూపు అందుబాటులో లేదు)",
        "upload_source_url": " (సార్వజనికంగా అందుబాటులో ఉన్న, సరైన URL)",
        "upload_source_file": " (మీ కంప్యూటర్లో ఒక ఫైలు)",
+       "listfiles-delete": "తొలగించు",
        "listfiles-summary": "ఈ ప్రత్యేక పేజీ, ఎక్కించిన ఫైళ్ళన్నిటినీ చూపిస్తుంది.",
        "listfiles_search_for": "మీడియా పేరుకై వెతుకు:",
        "imgfile": "దస్త్రం",
        "randomincategory": "వర్గంలోని యాదృచ్చిక పేజీ",
        "randomincategory-invalidcategory": "\"$1\" అనేది సరైన పర్గం పేరు కాదు.",
        "randomincategory-nopages": "[[:Category:$1|$1]] వర్గంలో పేజీలేమీ లేవు.",
+       "randomincategory-category": "వర్గం:",
        "randomredirect": "యాదృచ్చిక దారిమార్పు",
        "randomredirect-nopages": "\"$1\" పేరుబరిలో దారిమార్పులేమీ లేవు.",
        "statistics": "గణాంకాలు",
        "querypage-disabled": "పనితీరు కారణాల వలన, ఈ ప్రత్యేకపేజీని అశక్తం చేసాం.",
        "booksources": "పుస్తక మూలాలు",
        "booksources-search-legend": "పుస్తక మూలాల కోసం వెతుకు",
+       "booksources-search": "వెతుకు",
        "booksources-text": "కొత్త, పాత పుస్తకాలు అమ్మే ఇతర సైట్లకు లింకులు కింద ఇచ్చాం. మీరు వెతికే పుస్తకాలకు సంబంధించిన మరింత సమాచారం కూడా అక్కడ దొరకొచ్చు:",
        "booksources-invalid-isbn": "మీరిచ్చిన ISBN సరైనదిగా అనిపించుటలేదు; అసలు మూలాన్నుండి కాపీ చేయడంలో పొరపాట్లున్నాయేమో చూసుకోండి.",
        "specialloguserlabel": "కర్త:",
        "confirm-watch-top": "ఈ పుటను మీ వీక్షణ జాబితాలో చేర్చాలా?",
        "confirm-unwatch-button": "సరే",
        "confirm-unwatch-top": "ఈ పుటను మీ వీక్షణ జాబితా నుండి తొలగించాలా?",
+       "quotation-marks": "“$1”",
        "imgmultipageprev": "← మునుపటి పేజీ",
        "imgmultipagenext": "తరువాతి పేజీ →",
        "imgmultigo": "వెళ్ళు!",
        "autosumm-replace": "పేజీని '$1' తో మారుస్తున్నాం",
        "autoredircomment": "[[$1]]కు దారిమళ్ళించారు",
        "autosumm-new": "'$1' తో కొత్త పేజీని సృష్టించారు",
+       "autosumm-newblank": "ఖాళీ పేజీని సృష్టించారు",
        "lag-warn-normal": "$1 {{PLURAL:$1|క్షణం|క్షణాల}} లోపు జరిగిన మార్పులు ఈ జాబితాలో కనిపించకపోవచ్చు.",
        "lag-warn-high": "అధిక వత్తిడి వలన డేటాబేసు సర్వరు వెనుకబడింది, $1 {{PLURAL:$1|క్షణం|క్షణాల}} కంటే కొత్తవైన మార్పులు ఈ జాబితాలో కనిపించకపోవచ్చు.",
        "watchlistedit-normal-title": "వీక్షణ జాబితాను మార్చు",
        "duplicate-defaultsort": "హెచ్చరిక: డిఫాల్టు పేర్చు కీ \"$2\", గత డిఫాల్టు పేర్చు కీ \"$1\" ని అతిక్రమిస్తుంది.",
        "version": "సంచిక",
        "version-extensions": "స్థాపించిన పొడగింతలు",
-       "version-skins": "అలంకారాలు",
+       "version-skins": "à°¸à±\8dథాపిà°\82à°\9aà°¿à°¨ à°\85à°²à°\82à°\95ారాలà±\81",
        "version-specialpages": "ప్రత్యేక పేజీలు",
        "version-parserhooks": "పార్సరు కొక్కాలు",
        "version-variables": "చరరాశులు",
        "version-hook-name": "కొక్కెం పేరు",
        "version-hook-subscribedby": "ఉపయోగిస్తున్నవి",
        "version-version": "(కూర్పు $1)",
+       "version-no-ext-name": "[పేరు లేదు]",
        "version-license": "MediaWiki లైసెన్సు",
        "version-ext-license": "లైసెన్సు",
        "version-ext-colheader-name": "పొడిగింత",
+       "version-skin-colheader-name": "అలంకారం",
        "version-ext-colheader-version": "కూర్పు",
        "version-ext-colheader-license": "లైసెన్సు",
        "version-ext-colheader-description": "వివరణ",
        "specialpages-group-wiki": "డాటా మరియు పనిముట్లు",
        "specialpages-group-redirects": "ప్రత్యేక పేజీల దారిమార్పులు",
        "specialpages-group-spam": "స్పామ్ పనిముట్లు",
+       "specialpages-group-developer": "వికాసకుల పనిముట్లు",
        "blankpage": "ఖాళీ పేజీ",
        "intentionallyblankpage": "బెంచిమార్కింగు, మొదలగు వాటికై ఈ పేజీని కావాలనే ఖాళీగా వదిలాము.",
        "external_image_whitelist": " #ఈ లైనును ఎలా ఉన్నదో అలాగే వదిలెయ్యండి<pre>\n#regular expression తునకలను (// ల మధ్య ఉండే భాగం)కింద పెట్టండి\n#వీటిని బయటి బొమ్మల URLలతో సరిపోల్చుతాము\n#సరిపోలిన బొమ్మలను చూపిస్తాము, మిగిలినవాటి లింకులను మాత్రమే చూపిస్తాము\n##తో మొదలయ్యే లైనులు వ్యాఖ్యానాలుగా భావించబడతాయి\n#ఇది కేస్-సెన్సిటివ్\n\n#అన్ని తునకలను ఈ లైనుకు పైన ఉంచండి.  ఈ లైనును ఎలా ఉన్నదో అలాగే వదిలెయ్యండి</pre>",
        "expand_templates_remove_nowiki": "ఫలితంలో <nowiki> ట్యాగులను అణచిపెట్టు",
        "expand_templates_generate_xml": "XML పార్స్ ట్రీని చూపించు",
        "expand_templates_generate_rawhtml": "ముడి HTML ను చూపించు",
-       "expand_templates_preview": "మునుజూపు"
+       "expand_templates_preview": "మునుజూపు",
+       "pagelang-name": "పేజీ",
+       "pagelang-language": "భాష",
+       "pagelang-use-default": "అప్రమేయ భాషను వాడు"
 }
index 88defd0..87b513c 100644 (file)
@@ -48,7 +48,7 @@
        "tog-shownumberswatching": "แสดงจำนวนผู้ใช้ที่เฝ้าดู",
        "tog-oldsig": "ลายเซ็นที่ใช้อยู่:",
        "tog-fancysig": "ถือลายเซ็นเป็นข้อความวิกิ (โดยไม่มีลิงก์อัตโนมัติ)",
-       "tog-uselivepreview": "à¹\83à¸\8aà¹\89à¸\95ัวอยà¹\88าà¸\87à¸\97ัà¸\99à¸\97ี (à¸\97à¸\94ลอà¸\87)",
+       "tog-uselivepreview": "à¹\83à¸\8aà¹\89à¸\81ารà¹\81สà¸\94à¸\87à¸\95ัวอยà¹\88าà¸\87à¹\81à¸\9aà¸\9aสà¸\94",
        "tog-forceeditsummary": "เตือนเมื่อช่องคำอธิบายอย่างย่อว่าง",
        "tog-watchlisthideown": "ซ่อนการแก้ไขของฉันจากรายการเฝ้าดู",
        "tog-watchlisthidebots": "ซ่อนการแก้ไขของบอตจากรายการเฝ้าดู",
        "anoneditwarning": "<strong>คำเตือน:</strong> คุณมิได้ล็อกอิน สาธารณะจะเห็นเลขที่อยู่ไอพีของคุณหากคุณแก้ไข หากคุณ<strong>[$1 ล็อกอิน]</strong>หรือ<strong>[$2 สร้างบัญชี]</strong> การแก้ไขของคุณจะถือว่าเป็นของชื่อผู้ใช้ของคุณ ร่วมกับประโยชน์อื่น",
        "anonpreviewwarning": "<em>คุณมิได้ล็อกอิน การบันทึกจะเก็บเลขที่อยู่ไอพีของคุณในประวัติการแก้ไขของหน้านี้</em>",
        "missingsummary": "<strong>อย่าลืม:</strong> คุณยังไม่ได้ให้คำอธิบายการแก้ไข \nถ้าคุณคลิก \"{{int:savearticle}}\" อีก จะบันทึกการแก้ไขของคุณโดยไม่มีคำอธิบายการแก้ไข",
+       "selfredirect": "<strong>คำเตือน:</strong> คุณกำลังสร้างการเปลี่ยนทางไปบทความเดียวกัน หากคุณคลิก \"{{int:savearticle}}\" อีกครั้ง จะสร้างการเปลี่ยนทาง",
        "missingcommenttext": "กรุณากรอกความเห็นด้านล่าง",
        "missingcommentheader": "<strong>อย่าลืม:</strong> คุณยังไม่ได้ใส่หัวข้อ/พาดหัวสำหรับความเห็นนี้ \nถ้าคุณคลิก \"{{int:savearticle}}\" อีก จะบันทึกการแก้ไขของคุณโดยไม่มีหัวข้อ/พาดหัว",
        "summary-preview": "ตัวอย่างคำอธิบาย:",
index 8dd9504..336f588 100644 (file)
@@ -83,7 +83,7 @@
        "tog-shownumberswatching": "Показувати число користувачів, які додали сторінку до свого списку спостереження",
        "tog-oldsig": "Існуючий підпис:",
        "tog-fancysig": "Сприймати підпис як вікі-текст (без автоматичного посилання)",
-       "tog-uselivepreview": "Використовувати швидкий попередній перегляд (експериментально)",
+       "tog-uselivepreview": "Використовувати швидкий попередній перегляд",
        "tog-forceeditsummary": "Попереджати, коли не зазначений короткий опис редагування",
        "tog-watchlisthideown": "Приховати мої редагування у списку спостереження",
        "tog-watchlisthidebots": "Приховати редагування ботів у списку спостереження",
        "anoneditwarning": "<strong>Увага!</strong> Ви не авторизувалися на сайті. Ваша IP-адреса буде публічно видима, якщо ви будете вносити будь-які правки. Якщо ви <strong>[$1 увійдете]</strong> або <strong>[$2 створите обліковий запис]</strong>, правки замість цього будуть пов'язані з вашим ім'ям користувача, а також у вас з'являться інші переваги.",
        "anonpreviewwarning": "''Ви не увійшли в систему. Якщо ви виконаєте збереження, то в історію сторінки буде записана ваша IP-адреса.''",
        "missingsummary": "'''Нагадування''': Ви не дали короткого опису змін.\nНатиснувши кнопку «Зберегти» ще раз, ви збережете зміни без коментаря.",
+       "selfredirect": "<strong>Попередження:</strong> Ви створюєте перенаправлення на цю ж сторінку.\nЯкщо Ви натиснете \"{{int:savearticle}}\" ще раз, перенаправлення буде створено.",
        "missingcommenttext": "Будь ласка, введіть нижче ваше повідомлення.",
        "missingcommentheader": "'''Нагадування''': ви не вказали тему/заголовок для цього коментаря.\nНатиснувши кнопку «{{int:savearticle}}» ще раз, ви збережете редагування без заголовка.",
        "summary-preview": "Опис буде:",
index 54b5846..968a02d 100644 (file)
        "exif-iimcategory-wea": "Ob-havo",
        "namespacesall": "Barchasi",
        "monthsall": "barchasi",
+       "confirmrecreate": "Ushbu sahifa siz tahrir qilayotganingizda foydalanuvchi [[User:$1|$1]] ([[User talk:$1|munozara]]) tomonidan quyidagi sababga binoan yoʻqotilgan:\n: <em>$2</em>\nIltimos, sahifani qaytadan yaratmoqchi ekanligingizni tasdiqlang.",
+       "confirmrecreate-noreason": "Ushbu sahifa siz tahrir qilayotganingizda foydalanuvchi [[User:$1|$1]] ([[User talk:$1|munozara]]) tomonidan yoʻqotilgan. Iltimos, sahifani qaytadan yaratmoqchi ekanligingizni tasdiqlang.",
        "unit-pixel": " piksel",
        "imgmultipageprev": "← oldingi sahifa",
        "imgmultipagenext": "keyingi sahifa →",
index fbff85d..c862c3c 100644 (file)
@@ -21,9 +21,9 @@
        "tog-newpageshidepatrolled": "באַהאַלטן פאַטראלירטע בלעטער פון דער ליסטע פון נײַע בלעטער",
        "tog-extendwatchlist": "פארברייטערן די אויפפאסן ליסטע צו צייגן אלע פאסנדע ענדערונגען (אנדערשט: בלויז די לעצטע ענדערונג פון יעדן בלאט)",
        "tog-usenewrc": "גרופירן ענדערונגען לויטן בלאט אין \"לעצטע ענדערונגען\" און אויפֿפאסן ליסטע",
-       "tog-numberheadings": "נומערירן קעפלעך אויטאמאטיש",
+       "tog-numberheadings": "נומערירן קעפּלעך אויטאָמאַטיש",
        "tog-showtoolbar": "ווײַזן רעדאקטירן געצייג-שטאנג",
-       "tog-editondblclick": "רעדאקטירן בלעטער דורך טאפל קליק",
+       "tog-editondblclick": "רעדאַקטירן בלעטער דורך טאָפּל־קליק",
        "tog-editsectiononrightclick": "באמעגלעכן אפטייל רעדאקטירן דורכן רעכטס־קליקן אויף אפטייל קעפלעך",
        "tog-watchcreations": "צולייגן בלעטער וואס איך באשאף און טעקעס וואס איך לאד ארויף צו מיין אכטונג ליסטע",
        "tog-watchdefault": "צולייגן בלעטער וואס איך רעדאקטיר צו מיין אכטונג ליסטע",
index 5c703d6..742f39d 100644 (file)
        "tog-shownumberswatching": "显示监视用户数",
        "tog-oldsig": "当前签名:",
        "tog-fancysig": "将签名视为维基文本(不自动生成链接)",
-       "tog-uselivepreview": "使用实时预览(试验中)",
+       "tog-uselivepreview": "使用实时预览",
        "tog-forceeditsummary": "未输入编辑摘要时提醒我",
        "tog-watchlisthideown": "隐藏监视列表中的我的编辑",
        "tog-watchlisthidebots": "隐藏监视列表中的机器人编辑",
        "anoneditwarning": "<strong>警告:</strong>您没有登录。您做出任何编辑后您的IP地址会公开可见。如果您<strong>[$1 登陆]</strong>或<strong>[$2 注册]</strong>一个账户,您的编辑将归属于您的用户名,以及有其他好处。",
        "anonpreviewwarning": "<em>你没有登录。保存会记录你的IP地址于该页面的编辑历史中。</em>",
        "missingsummary": "'''提示:'''你没有提供编辑摘要。如果你再次点击“{{int:savearticle}}”,你的编辑将不带编辑摘要保存。",
+       "selfredirect": "<strong>警告:</strong>您正在创建重定向到同一条目的重定向。\n如果您再次点击“{{int:savearticle}}”,重定向将被创建。",
        "missingcommenttext": "请在下面输入评论。",
        "missingcommentheader": "'''提示:''' 您还没有为此评论提供一个标题。如果您再次点击“{{int:savearticle}}”,您的编辑将不带标题保存。",
        "summary-preview": "摘要预览:",
        "protectlogtext": "下面是页面保护更改的列表。请见[[Special:ProtectedPages|受保护页面列表]]查看目前正在进行的页面保护的列表。",
        "protectedarticle": "保护“[[$1]]”",
        "modifiedarticleprotection": "更改“[[$1]]”的保护等级",
-       "unprotectedarticle": "移除保护自“[[$1]]”",
+       "unprotectedarticle": "移除页面“[[$1]]”的保护",
        "movedarticleprotection": "移动保护设置自“[[$2]]”至“[[$1]]”",
        "protect-title": "更改“$1”的保护等级",
        "protect-title-notallowed": "查看“$1”的保护等级",
        "file-no-thumb-animation": "'''注意:由于技术限制,该文件的缩略图无法进行动画处理。'''",
        "file-no-thumb-animation-gif": "'''注意:由于技术限制,高分辨率GIF图像的缩略图无法进行动画处理。'''",
        "newimages": "新文件图库",
-       "imagelisttext": "以下是按$2排列的'''$1'''个文件列表。",
+       "imagelisttext": "以下是按$2排列的<strong>$1</strong>个文件列表。",
        "newimages-summary": "本特殊页面展示最后上传的文件。",
        "newimages-legend": "过滤",
        "newimages-label": "文件名(或它的一部份):",
        "confirm-purge-top": "要清除此页面的缓存吗?",
        "confirm-purge-bottom": "清除页面数据会清除缓存并强制显示最近的版本。",
        "confirm-watch-button": "确定",
-       "confirm-watch-top": "将此页添加到您的监视吗?",
+       "confirm-watch-top": "å°\86此页添å\8a å\88°æ\82¨ç\9a\84ç\9b\91è§\86å\88\97表å\90\97ï¼\9f",
        "confirm-unwatch-button": "确定",
        "confirm-unwatch-top": "从监视列表中删除此页吗?",
        "semicolon-separator": ";",
        "api-error-stashnosuchfilekey": "您试图在藏匿处访问的文件密钥不存在。",
        "api-error-timeout": "服务器没有在预期内响应。",
        "api-error-unclassified": "出现未知错误。",
-       "api-error-unknown-code": "未知错误:$1",
+       "api-error-unknown-code": "未知错误:“$1”。",
        "api-error-unknown-error": "内部错误:尝试上传文件时出错。",
        "api-error-unknown-warning": "未知的警告:“$1”。",
        "api-error-unknownerror": "未知错误:$1。",
index 8b3a491..fe1f3e6 100644 (file)
@@ -86,7 +86,7 @@
        "tog-shownumberswatching": "顯示正在監視的使用者數",
        "tog-oldsig": "現有簽名:",
        "tog-fancysig": "將簽名視為 Wikitext 語言 (不自動產生連結)",
-       "tog-uselivepreview": "使用即時預覽 (實驗中)",
+       "tog-uselivepreview": "使用即時預覽",
        "tog-forceeditsummary": "未填寫編輯摘要時提示我",
        "tog-watchlisthideown": "隱藏監視清單中我的編輯",
        "tog-watchlisthidebots": "隱藏監視清單中機器人的編輯",
        "generic-pool-error": "抱歉,太多使用者正嘗試檢視此資源,伺服器超出負荷。\n請稍候片刻再嘗試。",
        "pool-timeout": "正在等待取消鎖定",
        "pool-queuefull": "程序序列已滿",
-       "pool-errorunknown": "未知錯誤",
+       "pool-errorunknown": "不明錯誤",
        "pool-servererror": "無法使用程序計數服務 ($1)。",
        "aboutsite": "關於 {{SITENAME}}",
        "aboutpage": "Project:About",
        "anoneditwarning": "<strong>警告:</strong>您尚未登入。 若您進行任何的編輯您的 IP 位置將會被公開。 若您 <strong>[$1 登入]</strong> 或 <strong>[$2 建立帳號]</strong>,您的編輯將會以您的使用者名稱標示,擁有其他優點。",
        "anonpreviewwarning": "<em>您尚未登入。儲存頁面會將您的 IP 位址記錄在此頁面的編輯歷史中。</em>",
        "missingsummary": "<strong>提醒:</strong>您未填寫編輯摘要。\n若您再點選 \"{{int:savearticle}}\" 一次,將略過摘要直接儲存您的編輯。",
+       "selfredirect": "<strong>警告:</strong> 您正建立連結至自己的重新導向。\n若您再點選 \"{{int:savearticle}}\" 一次,將會繼續建立重新導向。",
        "missingcommenttext": "請在下方輸入評論。",
        "missingcommentheader": "<strong>提醒:</strong>您未填寫此評論的主旨/標題。\n若您再點選 \"{{int:savearticle}}\" 一次,將略過主旨/標題直接儲存您的評論。",
        "summary-preview": "摘要預覽:",
        "semiprotectedpagewarning": "<strong>注意:</strong>本頁已經被保護,只有已註冊的使用者才可編輯。\n以下提供最近的日誌以便參考:",
        "cascadeprotectedwarning": "<strong>警告:</strong>本頁已經被保護,只有擁有管理員權限的使用者才可編輯,此頁面被下列頁面引用因此連鎖保護:",
        "titleprotectedwarning": "<strong>警告:本頁面已被保護,需要 [[Special:ListGroupRights|特殊權限]] 方可建立。</strong>\n以下提供最近的日誌以便參考:",
-       "templatesused": "此頁面使用了以下{{PLURAL:$1|樣}}:",
+       "templatesused": "此頁面使用了以下{{PLURAL:$1|樣}}:",
        "templatesusedpreview": "此預覽使用了以下{{PLURAL:$1|樣板}}:",
-       "templatesusedsection": "此頁面使用了以下{{PLURAL:$1|樣}}:",
+       "templatesusedsection": "此頁面使用了以下{{PLURAL:$1|樣}}:",
        "template-protected": "(受保護)",
        "template-semiprotected": "(受半保護)",
        "hiddencategories": "此頁面屬於 {{PLURAL:$1|1 個隱藏分類|$1 個隱藏分類}}的成員:",
        "content-model-text": "純文字",
        "content-model-javascript": "JavaScript",
        "content-model-css": "CSS",
-       "duplicate-args-category": "樣呼叫時使用重複的參數的頁面",
-       "duplicate-args-category-desc": "該頁面包含重複使用參數的樣呼叫,如 <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> 或 <code><nowiki>{{foo|bar|1=baz}}</nowiki>。",
+       "duplicate-args-category": "樣呼叫時使用重複的參數的頁面",
+       "duplicate-args-category-desc": "該頁面包含重複使用參數的樣呼叫,如 <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> 或 <code><nowiki>{{foo|bar|1=baz}}</nowiki>。",
        "expensive-parserfunction-warning": "<strong>警告:</strong>此頁面使用了太多消耗系統資源的解析函數。\n\n使用次數應小於 $2 次,但目前使用了 $1 次。",
        "expensive-parserfunction-category": "使用了太多消耗系統資源的分析函數的頁面",
        "post-expand-template-inclusion-warning": "<strong>警告:</strong>引用樣板後大小超出限制。\n部份樣板內容將不會被使用。",
        "post-expand-template-inclusion-category": "引用樣板後大小超出限制的頁面",
-       "post-expand-template-argument-warning": "<strong>警告:</strong>此頁面有一個以上的樣參數過長。\n過長的參數會被直接忽略。",
+       "post-expand-template-argument-warning": "<strong>警告:</strong>此頁面有一個以上的樣參數過長。\n過長的參數會被直接忽略。",
        "post-expand-template-argument-category": "樣板參數有部份被忽略的頁面",
        "parser-template-loop-warning": "偵測到樣板遞迴:[[$1]]",
-       "parser-template-recursion-depth-warning": "超出樣遞迴深度限制 ($1)",
+       "parser-template-recursion-depth-warning": "超出樣遞迴深度限制 ($1)",
        "language-converter-depth-warning": "已超出語言轉換器深度限制 ($1)",
        "node-count-exceeded-category": "節點數量超出限制的頁面",
        "node-count-exceeded-category-desc": "超出節點數量限制的頁面。",
        "history-feed-empty": "請求的頁面不存在,\n可能已被刪除或重新命名。\n請嘗試 [[Special:Search|搜尋本站]] 取得其他相關的新頁面。",
        "rev-deleted-comment": "(已移除編輯摘要)",
        "rev-deleted-user": " (已移除使用者名稱)",
-       "rev-deleted-event": "(已移除日誌)",
+       "rev-deleted-event": "(已移除日誌操作)",
        "rev-deleted-user-contribs": "[使用者名稱或 IP 位址已移除 - 已隱藏貢獻清單中的編輯]",
        "rev-deleted-text-permission": "此頁面修訂已被 <strong>刪除</strong>。\n可至 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪除日誌] 取得詳細資訊。",
        "rev-suppressed-text-permission": "此頁面修訂已被 <strong>禁止顯示</strong>。\n可至 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 禁止顯示日誌] 取得詳細資訊。",
        "searchprofile-advanced-tooltip": "搜尋自訂命名空間",
        "search-result-size": "$1 ($2 個字)",
        "search-result-category-size": "$1 位成員 ($2 個子分類,$3 個檔案)",
-       "search-redirect": "(重新導向自 $1 )",
+       "search-redirect": "(重新導向自 $1)",
        "search-section": "(章節 $1)",
        "search-category": "(分類 $1)",
        "search-file-match": "(符合檔案內容)",
        "right-protect": "更改保護層級及編輯被連鎖保護的頁面",
        "right-editprotected": "編輯保護層級為 \"{{int:protect-level-sysop}}\" 的頁面",
        "right-editsemiprotected": "編輯保護層級為 \"{{int:protect-level-autoconfirmed}}\" 的頁面",
+       "right-editcontentmodel": "編輯頁面的內容模型",
        "right-editinterface": "編輯使用者介面",
        "right-editusercssjs": "編輯其他使用者的 CSS 和 JavaScript 檔案",
        "right-editusercss": "編輯其他使用者的 CSS 檔案",
        "action-viewmywatchlist": "檢視您的監視清單",
        "action-viewmyprivateinfo": "檢視您的個人資訊",
        "action-editmyprivateinfo": "編輯您的個人資訊",
+       "action-editcontentmodel": "編輯頁面的內容模型",
        "nchanges": "$1 次變更",
        "enhancedrc-since-last-visit": "自上次訪問已有 $1",
        "enhancedrc-history": "歷史",
        "listduplicatedfiles-summary": "此清單中包含最新版本的檔案與其他檔案重複的清單,本清單只顯示本地檔案。",
        "listduplicatedfiles-entry": "[[:File:$1|$1]] 有[[$3|其他 $2 個重複檔案]]。",
        "unusedtemplates": "未使用的樣板",
-       "unusedtemplatestext": "此頁面列出所有於 {{ns:template}} 命名空間下未被其他頁面引用的樣版。\n在刪除前,仍需檢查是否有連結這些樣版的其他頁面。",
+       "unusedtemplatestext": "此頁面列出所有於 {{ns:template}} 命名空間下未被其他頁面引用的樣板。\n在刪除前,仍需檢查是否有連結這些樣板的其他頁面。",
        "unusedtemplateswlh": "其他連結",
        "randompage": "隨機頁面",
        "randompage-nopages": "在{{PLURAL:$2|命名空間}}中沒有任何頁面:$1。",
        "uncategorizedpages": "未分類的頁面",
        "uncategorizedcategories": "未分類的分類",
        "uncategorizedimages": "未分類的檔案",
-       "uncategorizedtemplates": "待分類樣",
+       "uncategorizedtemplates": "待分類樣",
        "unusedcategories": "未使用的分類",
        "unusedimages": "未使用的檔案",
        "wantedcategories": "需要的分類",
        "wantedfiletext-cat-noforeign": "下列檔案已被使用但不存在。 除此之外,頁面已內嵌但不存在的檔案列於 [[:$1]]。",
        "wantedfiletext-nocat": "下列檔案被時用,但檔案不存在。 外部儲存庫的檔案儘管存在,但此清單仍會列出。 這類誤報的項目會以 <del>刪除線</del> 標示。",
        "wantedfiletext-nocat-noforeign": "下列檔案已被使用但不存在。",
-       "wantedtemplates": "需要的樣",
+       "wantedtemplates": "需要的樣",
        "mostlinked": "被連結最多的頁面",
        "mostlinkedcategories": "被連結最多的分類",
        "mostlinkedtemplates": "被引用最多的頁面",
        "trackingcategories-desc": "分類收錄標準",
        "noindex-category-desc": "命名空間允許,且含有魔術字 <code><nowiki>__NOINDEX__</nowiki></code> 未被機器人列入索引的頁面。",
        "index-category-desc": "命名空間允許,且含有魔術字 <code><nowiki>__INDEX__</nowiki></code> 被機器人列入索引的頁面。",
-       "post-expand-template-inclusion-category-desc": "展開樣版後大小超過 <code>$wgMaxArticleSize</code> 導致部份樣版未正常展開的頁面。",
-       "post-expand-template-argument-category-desc": "展開樣參數後大小超過 <code>$wgMaxArticleSize</code> 的頁面 (有些於三括號中,如 <code>{{{Foo}}}</code>)。",
+       "post-expand-template-inclusion-category-desc": "展開樣板後大小超過 <code>$wgMaxArticleSize</code> 導致部份樣板未正常展開的頁面。",
+       "post-expand-template-argument-category-desc": "展開樣參數後大小超過 <code>$wgMaxArticleSize</code> 的頁面 (有些於三括號中,如 <code>{{{Foo}}}</code>)。",
        "expensive-parserfunction-category-desc": "頁面使用太多消耗系統資源的解析器函數 (如 <code>#ifexist</code>)。\n請參考 [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit]。",
        "broken-file-category-desc": "含有損壞檔案連結的頁面 (內嵌檔案連結的檔案不存在)。",
        "hidden-category-category-desc": "內容中使用 <code><nowiki>__HIDDENCAT__</nowiki></code> 的分類,可隱藏預設在頁面上顯示的分類連結方塊。",
        "whatlinkshere-prev": "前 $1 筆",
        "whatlinkshere-next": "後 $1 筆",
        "whatlinkshere-links": "← 連結",
-       "whatlinkshere-hideredirs": "$1重新導向頁面",
+       "whatlinkshere-hideredirs": "$1 重新導向頁面",
        "whatlinkshere-hidetrans": "$1 引用",
        "whatlinkshere-hidelinks": "$1 連結",
        "whatlinkshere-hideimages": "$1 檔案連結",
        "tooltip-search": "搜尋 {{SITENAME}}",
        "tooltip-search-go": "若與此名稱相符的頁面存在,前往該頁面",
        "tooltip-search-fulltext": "搜尋使用此文字的頁面",
-       "tooltip-p-logo": "前往主頁",
-       "tooltip-n-mainpage": "前往主頁",
-       "tooltip-n-mainpage-description": "前往主頁",
-       "tooltip-n-portal": "關於本專案,您可以做什麼、哪裡可以找到事情",
-       "tooltip-n-currentevents": "尋找新聞中最新動態的背景資訊",
+       "tooltip-p-logo": "前往主頁",
+       "tooltip-n-mainpage": "前往主頁",
+       "tooltip-n-mainpage-description": "前往主頁",
+       "tooltip-n-portal": "關於本專案、您可以做什麼、哪裡可以找到您需要的事物",
+       "tooltip-n-currentevents": "於最新動態中尋找背景資訊",
        "tooltip-n-recentchanges": "列出此 Wiki 中的近期變更清單",
        "tooltip-n-randompage": "隨機進入一個頁面",
        "tooltip-n-help": "尋求協助的地方",
        "pageinfo-recent-authors": "最近作者數",
        "pageinfo-magic-words": "魔術{{PLURAL:$1|字}} ($1)",
        "pageinfo-hidden-categories": "隱藏分類 ($1)",
-       "pageinfo-templates": "引用樣 ($1)",
+       "pageinfo-templates": "引用樣 ($1)",
        "pageinfo-transclusions": "頁面被引用於 ($1)",
        "pageinfo-toolboxlink": "頁面資訊",
        "pageinfo-redirectsto": "重新導向至",
        "exif-datetimemetadata": "資料定義最後修改日期",
        "exif-nickname": "非正式的影像名稱",
        "exif-rating": "評分 (共 5 分)",
-       "exif-rightscertificate": "版權管理證書",
+       "exif-rightscertificate": "版權管理憑證",
        "exif-copyrighted": "版權狀態",
        "exif-copyrightowner": "版權所有人",
        "exif-usageterms": "使用條款",
        "tag-filter-submit": "搜尋",
        "tag-list-wrapper": "([[Special:Tags|標籤]]:$2)",
        "tags-title": "標籤",
-       "tags-intro": "此頁面列出所有可用來標示編輯的標籤,以及這些標籤的含意。",
+       "tags-intro": "此頁面列出所有可用來標示編輯內容的標籤以及這些標籤所代表的意思。",
        "tags-tag": "標籤名稱",
-       "tags-display-header": "在更改清單中的出現方式",
-       "tags-description-header": "完整含意說明",
+       "tags-display-header": "在變更日誌中顯示的方式",
+       "tags-description-header": "意義完整的說明",
        "tags-active-header": "開啟?",
-       "tags-hitcount-header": "已加上標籤的更改",
+       "tags-hitcount-header": "已標記的變更",
        "tags-active-yes": "是",
        "tags-active-no": "否",
        "tags-edit": "編輯",
        "api-error-overwrite": "不允許覆蓋已存在的檔案。",
        "api-error-stashfailed": "內部錯誤:伺服器儲存暫存檔案失敗。",
        "api-error-publishfailed": "內部錯誤:伺服器發佈暫存檔案失敗。",
-       "api-error-stasherror": "上傳檔案至儲庫時發生錯誤。",
-       "api-error-stashedfilenotfound": "嘗試從藏匿處上傳時找不到藏匿的檔案。",
-       "api-error-stashpathinvalid": "æ\89¾å\88°ç\9a\84è\97\8få\8c¿æª\94æ¡\88ç\9a\84è·¯å¾\91æ\98¯ç\84¡æ\95\88ç\9a\84。",
-       "api-error-stashfilestorage": "儲存檔案至藏匿處時出錯。",
-       "api-error-stashzerolength": "伺服器不能藏匿檔案,因爲它已經沒有藏匿空間了。",
-       "api-error-stashnotloggedin": "您必須登入以儲存檔案至上傳藏匿處。",
-       "api-error-stashwrongowner": "您嘗試在藏匿處存取的檔案不屬於您。",
-       "api-error-stashnosuchfilekey": "您嘗試在藏匿處存取的檔案金鑰不存在。",
+       "api-error-stasherror": "上傳檔案至儲庫時發生錯誤。",
+       "api-error-stashedfilenotfound": "嘗試從儲藏庫上傳檔案時查無該檔案。",
+       "api-error-stashpathinvalid": "æ\87\89該å­\98å\9c¨å\84²è\97\8fæª\94æ¡\88ç\9a\84è·¯å¾\91ç\84¡æ\95\88。",
+       "api-error-stashfilestorage": "儲存檔案至儲藏庫時發生錯誤。",
+       "api-error-stashzerolength": "伺服器無法儲藏該檔案,因為該檔案大小為 0。",
+       "api-error-stashnotloggedin": "您必須登入以儲存檔案於上傳儲藏庫。",
+       "api-error-stashwrongowner": "您嘗試在儲藏庫存取的檔案不屬於您的。",
+       "api-error-stashnosuchfilekey": "您嘗試在儲藏庫存取的檔案金鑰不存在。",
        "api-error-timeout": "伺服器沒有在預期的時間內回應。",
        "api-error-unclassified": "發生不明錯誤。",
        "api-error-unknown-code": "不明錯誤:\"$1\"。",
        "limitreport-expansiondepth": "最高展開深度",
        "limitreport-expensivefunctioncount": "高消耗解析器函數次數",
        "expandtemplates": "展開樣板",
-       "expand_templates_intro": "本特殊頁面會將文字中的樣展開,可以包含支援的解析器語法,如 <code><nowiki>{{</nowiki>#language:…}}</code> 與變數如 <code><nowiki>{{</nowiki>CURRENTDAY}}</code>。\n實際上,絕大部分在雙括號中的內容都會被展開。",
+       "expand_templates_intro": "本特殊頁面會將文字中的樣展開,可以包含支援的解析器語法,如 <code><nowiki>{{</nowiki>#language:…}}</code> 與變數如 <code><nowiki>{{</nowiki>CURRENTDAY}}</code>。\n實際上,絕大部分在雙括號中的內容都會被展開。",
        "expand_templates_title": "上下文標題,用於 {{FULLPAGENAME}} 等:",
        "expand_templates_input": "輸入文字:",
        "expand_templates_output": "結果",
        "expand_templates_generate_xml": "顯示 XML 解析樹",
        "expand_templates_generate_rawhtml": "顯示原始 HTML",
        "expand_templates_preview": "預覽",
+       "expand_templates_preview_fail_html": "<em>因連線階段的資料遺失且 {{SITENAME}} 已開啟顯示原始 HTML 功能,為預防 JavaScript 攻擊已隱藏預覽內容。</em>\n\n<strong>若您目前的預覽動作並無非法,請再試一次。</strong>\n若仍然無效,請嘗試[[Special:UserLogout|登出]]並再登入一次。",
+       "expand_templates_preview_fail_html_anon": "<em>因您尚未登入且 {{SITENAME}} 已開啟顯示原始 HTML 功能,為預防 JavaScript 攻擊已隱藏預覽內容。</em>\n\n<strong>若您目前的預覽動作並無非法,請[[Special:UserLogin|登入]]後再試一次。</strong>",
        "pagelanguage": "頁面語言選擇器",
        "pagelang-name": "頁面",
        "pagelang-language": "語言",
        "log-name-pagelang": "更改語言日誌",
        "log-description-pagelang": "此頁為頁面語言的變更日誌。",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|已更改}}頁面 $3 的語言從 $4 到 $5。",
-       "default-skin-not-found": "哎呀!您於 <code dir=\"ltr\">$wgDefaultSkin</code> 設定的 Wiki 預設外觀 <code>$1</code> 無法使用。\n\n您的安裝程序應包含以下外觀。 請參考 [https://www.mediawiki.org/wiki/Manual:Skin_configuration 操作手冊:外觀設定] 以取得如何開啟外觀並設為預設值的資訊。\n\n$2\n\n; 若您才剛安裝完 MediaWiki:\n: 您大概是使用 git 或直接透過原始碼使用其他方法安裝,這種情況是正常的。請嘗試安裝 [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org 的外觀目錄] 中的部份外觀使用以下方式:\n:* 下載 [https://www.mediawiki.org/wiki/Special:MyLanguage/Download tarball 安裝程式],該程式包含數個外觀與擴充套件。 您可以複製並貼上至 <code>skins/</code> 目錄。\n:* 透過 git 複製 <code>mediawiki/skins/*</code> 儲存庫中其中一個外觀到您安裝的 MediaWiki <code dir=\"ltr\">skins/</code> 目錄中。\n: 若您是 MediaWiki 的開發人員,這麼做應該不會影響到您的 git 儲存庫。\n\n; 若您才剛升級 MediaWiki:\n: MediaWiki 1.24 與較新的版本不再自動開啟已安裝的外觀 (請參考 [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery 操作手冊:外觀自動搜尋])。 您可以將下列行貼上至 <code>LocalSettings.php</code> 來開啟所有目前已經安裝的外觀:\n\n<pre dir=\"ltr\">$3</pre>\n\n; 若您才剛修改 <code>LocalSettings.php</code>:\n: 請再次確認您輸入的外觀名稱是否有誤。",
-       "default-skin-not-found-no-skins": "哎呀!您於 <code>$wgDefaultSkin</code> 設定的 Wiki 預設外觀 <code>$1</code> 無法使用。\n\n您未安裝任何的外觀。\n\n; 若您才剛安裝完或升級完 MediaWiki:\n: 您大概是使用 git 或直接透過原始碼使用其他方法安裝,這種情況是正常的。 MediaWiki 1.24 或較新的版本在主要儲存庫中不再包含任何的外觀。 請嘗試安裝 [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org 的外觀目錄] 中的部份外觀使用以下方式:\n:* 下載 [https://www.mediawiki.org/wiki/Special:MyLanguage/Download tarball 安裝程式],該程式包含數個外觀與擴充套件。 您可以複製並貼上至 <code>skins/</code> 目錄。\n:* 透過 git 複製 <code>mediawiki/skins/*</code> 儲存庫中其中一個外觀到您安裝的 MediaWiki <code dir=\"ltr\">skins/</code> 目錄中。\n: 若您是 MediaWiki 的開發人員,這麼做應該不會影響到您的 git 儲存庫。 請參考 [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration 操作手冊:外觀設定] 以取得如何開啟外觀並設為預設值的資訊。",
+       "default-skin-not-found": "哎呀!您於 <code dir=\"ltr\">$wgDefaultSkin</code> 設定的 Wiki 預設外觀 <code>$1</code> 無法使用。\n\n您的安裝程序應包含以下外觀。 請參考 [https://www.mediawiki.org/wiki/Manual:Skin_configuration 操作手冊:外觀設定] 以取得如何開啟外觀並設為預設值的資訊。\n\n$2\n\n; 若您才剛安裝完 MediaWiki:\n: 您大概是使用 git 或直接透過原始碼使用其他方法安裝,這種情況是正常的。請嘗試安裝 [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org 的外觀目錄] 中的部份外觀使用以下方式:\n:* 下載 [https://www.mediawiki.org/wiki/Special:MyLanguage/Download tarball 安裝程式],該程式包含數個外觀與擴充套件。 您可以複製並貼上至 <code>skins/</code> 目錄。\n:* 自 [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org] 下載個別外觀 tarball。\n:* 透過 git 複製 <code>mediawiki/skins/*</code> 儲存庫中其中一個外觀到您安裝的 MediaWiki <code dir=\"ltr\">skins/</code> 目錄中。\n: 若您是 MediaWiki 的開發人員,這麼做應該不會影響到您的 git 儲存庫。\n\n; 若您才剛升級 MediaWiki:\n: MediaWiki 1.24 與較新的版本不再自動開啟已安裝的外觀 (請參考 [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery 操作手冊:外觀自動搜尋])。 您可以將下列行貼上至 <code>LocalSettings.php</code> 來開啟所有目前已經安裝的外觀:\n\n<pre dir=\"ltr\">$3</pre>\n\n; 若您才剛修改 <code>LocalSettings.php</code>:\n: 請再次確認您輸入的外觀名稱是否有誤。",
+       "default-skin-not-found-no-skins": "哎呀!您於 <code>$wgDefaultSkin</code> 設定的 Wiki 預設外觀 <code>$1</code> 無法使用。\n\n您未安裝任何的外觀。\n\n; 若您才剛安裝完或升級完 MediaWiki:\n: 您大概是使用 git 或直接透過原始碼使用其他方法安裝,這種情況是正常的。 MediaWiki 1.24 或較新的版本在主要儲存庫中不再包含任何的外觀。 請嘗試安裝 [https://www.mediawiki.org/wiki/Category:All_skins mediawiki.org 的外觀目錄] 中的部份外觀使用以下方式:\n:* 下載 [https://www.mediawiki.org/wiki/Special:MyLanguage/Download tarball 安裝程式],該程式包含數個外觀與擴充套件。 您可以複製並貼上至 <code>skins/</code> 目錄。\n:* 自 [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org] 下載個別外觀 tarball。\n:* 透過 git 複製 <code>mediawiki/skins/*</code> 儲存庫中其中一個外觀到您安裝的 MediaWiki <code dir=\"ltr\">skins/</code> 目錄中。\n: 若您是 MediaWiki 的開發人員,這麼做應該不會影響到您的 git 儲存庫。 請參考 [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration 操作手冊:外觀設定] 以取得如何開啟外觀並設為預設值的資訊。",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (已開啟)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''已停用''')",
        "mediastatistics": "媒體統計資訊",
index 0852f44..3c99df0 100644 (file)
@@ -80,6 +80,7 @@ $specialPageAliases = array(
        'Listgrouprights'           => array( 'רשימת_הרשאות_לקבוצה' ),
        'Listredirects'             => array( 'רשימת_הפניות', 'הפניות' ),
        'Listusers'                 => array( 'רשימת_משתמשים', 'משתמשים' ),
+       'ListDuplicatedFiles'       => array( 'רשימת_קבצים_כפולים' ),
        'Lockdb'                    => array( 'נעילת_בסיס_הנתונים' ),
        'Log'                       => array( 'יומנים' ),
        'Lonelypages'               => array( 'דפים_יתומים' ),
@@ -122,6 +123,7 @@ $specialPageAliases = array(
        'Specialpages'              => array( 'דפים_מיוחדים' ),
        'Statistics'                => array( 'סטטיסטיקות' ),
        'Tags'                      => array( 'תגיות' ),
+       'TrackingCategories'        => array( 'קטגוריות_מעקב' ),
        'Unblock'                   => array( 'שחרור_חסימה' ),
        'Uncategorizedcategories'   => array( 'קטגוריות_חסרות_קטגוריה' ),
        'Uncategorizedimages'       => array( 'קבצים_חסרי_קטגוריה', 'תמונות_חסרות_קטגוריה' ),
index 1d558d2..108fe9f 100644 (file)
@@ -102,7 +102,7 @@ abstract class Maintenance {
        private $mDependantParameters = array();
 
        /**
-        * Used by getDD() / setDB()
+        * Used by getDB() / setDB()
         * @var DatabaseBase
         */
        private $mDb = null;
@@ -944,8 +944,8 @@ abstract class Maintenance {
 
                $wgShowSQLErrors = true;
 
-               // @codingStandardsIgnoreStart Allow error supppression. wfSuppressWarnings()
-               // is not avaiable.
+               // @codingStandardsIgnoreStart Allow error suppression. wfSuppressWarnings()
+               // is not available.
                @set_time_limit( 0 );
                // @codingStandardsIgnoreStart
 
@@ -1184,7 +1184,7 @@ abstract class Maintenance {
         * We default as considering stdin a tty (for nice readline methods)
         * but treating stout as not a tty to avoid color codes
         *
-        * @param int $fd File descriptor
+        * @param mixed $fd File descriptor
         * @return bool
         */
        public static function posix_isatty( $fd ) {
index f13cb44..85ebd51 100644 (file)
@@ -895,10 +895,10 @@ class TextPassDumper extends BackupDumper {
                                $this->thisPage .= $data;
                        }
                }
-               elseif ( $this->lastName == "model"  ) {
+               elseif ( $this->lastName == "model" ) {
                        $this->thisRevModel .= $data;
                }
-               elseif ( $this->lastName == "format"  ) {
+               elseif ( $this->lastName == "format" ) {
                        $this->thisRevFormat .= $data;
                }
 
index b97e1b0..2f533cf 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 require_once __DIR__ . '/Maintenance.php';
-require_once 'PHPUnit/Autoload.php';
 
 /**
  * @ingroup Maintenance
@@ -43,6 +42,17 @@ class CheckLess extends Maintenance {
                // require it here.
                require_once __DIR__ . '/../tests/TestsAutoLoader.php';
 
+               // If phpunit isn't available by autoloader try pulling it in
+               if ( !class_exists( 'PHPUnit_Framework_TestCase' ) ) {
+                       require_once 'PHPUnit/Autoload.php';
+               }
+
+               // RequestContext::resetMain() will print warnings unless this
+               // is defined.
+               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+                       define( 'MW_PHPUNIT_TEST', true );
+               }
+
                $textUICommand = new PHPUnit_TextUI_Command();
                $argv = array(
                        "$IP/tests/phpunit/phpunit.php",
index ad8b004..c6281fd 100644 (file)
@@ -4514,7 +4514,7 @@ what
 whatlinkshere
 whatwg
 wheely
-wheter
+whether
 whitelist
 whitelisted
 whitelistedittext
index 66e8da0..d17b06d 100644 (file)
@@ -91,6 +91,7 @@ class FindHooks extends Maintenance {
                        $IP . '/includes/jobqueue/',
                        $IP . '/includes/json/',
                        $IP . '/includes/logging/',
+                       $IP . '/includes/mail/',
                        $IP . '/includes/media/',
                        $IP . '/includes/page/',
                        $IP . '/includes/parser/',
index 31ce702..257fe14 100644 (file)
@@ -23,7 +23,7 @@
  * @author Antoine Musso <hashar at free dot fr>
  */
 
-/** A general output object. Need to be overriden */
+/** A general output object. Need to be overridden */
 class StatsOutput {
        function formatPercent( $subset, $total, $revert = false, $accuracy = 2 ) {
                wfSuppressWarnings();
index 638d7c5..7b05cb7 100644 (file)
@@ -3,7 +3,7 @@
  * Parse some wikitext.
  *
  * Wikitext can be given by stdin or using a file. The wikitext will be parsed
- * using 'CLIParser' as a title. This can be overriden with --title option.
+ * using 'CLIParser' as a title. This can be overridden with --title option.
  *
  * Example1:
  * @code
@@ -110,7 +110,7 @@ class CLIParser extends Maintenance {
 
        /**
         * Title object to use for CLI parsing.
-        * Default title is 'CLIParser', it can be overriden with the option
+        * Default title is 'CLIParser', it can be overridden with the option
         * --title <Your:Title>
         *
         * @return Title
index 910f56b..45cc339 100644 (file)
@@ -471,7 +471,7 @@ class RecompressTracked {
         * @param int $pageId
         */
        function doPage( $pageId ) {
-               $title = Title::newFromId( $pageId );
+               $title = Title::newFromID( $pageId );
                if ( $title ) {
                        $titleText = $title->getPrefixedText();
                } else {
index 470647a..55f535d 100644 (file)
@@ -37,12 +37,18 @@ class UpdateArticleCount extends Maintenance {
                parent::__construct();
                $this->mDescription = "Count of the number of articles and update the site statistics table";
                $this->addOption( 'update', 'Update the site_stats table with the new count' );
+               $this->addOption( 'use-master', 'Count using the master database' );
        }
 
        public function execute() {
                $this->output( "Counting articles..." );
 
-               $counter = new SiteStatsInit( false );
+               if ( $this->hasOption( 'use-master' ) ) {
+                       $dbr = wfGetDB( DB_MASTER );
+               } else {
+                       $dbr = wfGetDB( DB_SLAVE, 'vslow' );
+               }
+               $counter = new SiteStatsInit( $dbr );
                $result = $counter->articles();
 
                $this->output( "found {$result}.\n" );
index d6a3181..e5332df 100644 (file)
@@ -44,6 +44,7 @@ return array(
        'user.cssprefs' => array( 'class' => 'ResourceLoaderUserCSSPrefsModule' ),
 
        // Populate mediawiki.user placeholders with information about the current user
+       'user.defaults' => array( 'class' => 'ResourceLoaderUserDefaultsModule' ),
        'user.options' => array( 'class' => 'ResourceLoaderUserOptionsModule' ),
        'user.tokens' => array( 'class' => 'ResourceLoaderUserTokensModule' ),
 
@@ -757,6 +758,7 @@ return array(
                        'zh-cn' => 'resources/lib/moment/locale/zh-cn.js',
                        'zh-tw' => 'resources/lib/moment/locale/zh-tw.js',
                ),
+               'targets' => array( 'desktop', 'mobile' ),
        ),
 
        /* MediaWiki */
@@ -1042,7 +1044,16 @@ return array(
                'dependencies' => array(
                        'jquery.form',
                        'jquery.spinner',
+                       'mediawiki.api',
                        'mediawiki.action.history.diff',
+                       'mediawiki.util',
+                       'mediawiki.jqueryMsg',
+               ),
+               'messages' => array(
+                       'otherlanguages',
+                       'tooltip-p-lang',
+                       'summary-preview',
+                       'parentheses',
                ),
        ),
        'mediawiki.action.edit.stash' => array(
@@ -1617,12 +1628,12 @@ return array(
                        'resources/lib/oojs-ui/oojs-ui.js',
                ),
                'skinScripts' => array(
-                       'default' => 'resources/lib/oojs-ui/oojs-ui-apex.js',
-                       'minerva' => 'resources/lib/oojs-ui/oojs-ui-mediawiki.js',
+                       'default' => 'resources/lib/oojs-ui/oojs-ui-mediawiki.js',
                ),
-               'skinStyles' => array(
-                       'default' => 'resources/lib/oojs-ui/oojs-ui-apex.svg.css',
-                       'minerva' => 'resources/lib/oojs-ui/oojs-ui-mediawiki.svg.css',
+               'dependencies' => array(
+                       'es5-shim',
+                       'oojs',
+                       'oojs-ui.styles',
                ),
                'messages' => array(
                        'ooui-dialog-message-accept',
@@ -1638,9 +1649,13 @@ return array(
                        'ooui-toolgroup-collapse',
                        'ooui-toolgroup-expand',
                ),
-               'dependencies' => array(
-                       'es5-shim',
-                       'oojs',
+               'targets' => array( 'desktop', 'mobile' ),
+       ),
+
+       'oojs-ui.styles' => array(
+               'position' => 'top',
+               'skinStyles' => array(
+                       'default' => 'resources/lib/oojs-ui/oojs-ui-mediawiki.svg.css',
                ),
                'targets' => array( 'desktop', 'mobile' ),
        ),
index f1c6ea3..ce3afa4 100644 (file)
@@ -9,14 +9,20 @@
                        "SMP",
                        "Vriullop",
                        "Toniher",
-                       "Edustus"
+                       "Edustus",
+                       "Davidpar"
                ]
        },
-       "ooui-outline-control-move-down": "Baixa element",
-       "ooui-outline-control-move-up": "Puja element",
+       "ooui-outline-control-move-down": "Baixa l'element",
+       "ooui-outline-control-move-up": "Puja l'element",
+       "ooui-outline-control-remove": "Esborra l'ítem",
        "ooui-toolbar-more": "Més",
        "ooui-toolgroup-expand": "Més",
        "ooui-toolgroup-collapse": "Menys",
+       "ooui-dialog-message-accept": "D'acord",
+       "ooui-dialog-message-reject": "Cancel·la",
+       "ooui-dialog-process-error": "Alguna cosa no ha funcionat",
        "ooui-dialog-process-dismiss": "Descarta",
-       "ooui-dialog-process-retry": "Torneu-ho a provar"
+       "ooui-dialog-process-retry": "Torneu-ho a provar",
+       "ooui-dialog-process-continue": "Continua"
 }
index d6034f0..f4d4a5c 100644 (file)
                        "SteveR",
                        "Tel'et",
                        "Tifinaghes",
-                       "Ата"
+                       "Ата",
+                       "Piramidion"
                ]
        },
        "ooui-outline-control-move-down": "Перемістити елемент униз",
        "ooui-outline-control-move-up": "Перемістити елемент вгору",
        "ooui-outline-control-remove": "Видалити елемент",
        "ooui-toolbar-more": "Більше",
+       "ooui-toolgroup-expand": "Більше",
+       "ooui-toolgroup-collapse": "Менше",
        "ooui-dialog-message-accept": "Готово",
        "ooui-dialog-message-reject": "Скасувати",
        "ooui-dialog-process-error": "Щось пішло не так",
diff --git a/resources/lib/oojs-ui/images/grab.cur b/resources/lib/oojs-ui/images/grab.cur
new file mode 100644 (file)
index 0000000..fba3ddc
Binary files /dev/null and b/resources/lib/oojs-ui/images/grab.cur differ
diff --git a/resources/lib/oojs-ui/images/grabbing.cur b/resources/lib/oojs-ui/images/grabbing.cur
new file mode 100644 (file)
index 0000000..41aaa62
Binary files /dev/null and b/resources/lib/oojs-ui/images/grabbing.cur differ
index 2756079..4c4512b 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.2.4
+ * OOjs UI v0.5.0
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-12-02T18:45:30Z
+ * Date: 2014-12-12T20:13:21Z
  */
 .oo-ui-progressBarWidget-slide-frames from {
        margin-left: -40%;
 .oo-ui-buttonElement-frameless.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        margin-left: 0.25em;
 }
-.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        color: #087ecc;
 }
 .oo-ui-buttonElement-frameless.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        outline: none;
 }
 .oo-ui-buttonElement-framed > input.oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        line-height: 1.9em;
 }
 .oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
        margin-left: -0.5em;
        margin-right: 0.3em;
 }
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
        border: solid 1px #a6cee1;
        background: #cde7f4;
        filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#eaf4fa', endColorstr='#b0d9ee');
        background-image:      -o-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
        background-image:         linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
 }
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:focus {
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
        border-color: #9dc2d4;
 }
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
        border: solid 1px #a6cee1;
        background: #cde7f4;
        filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#b0d9ee', endColorstr='#eaf4fa');
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
+.oo-ui-draggableElement {
+       cursor: -webkit-grab -moz-grab, url(images/grab.cur), move;
+       /*
+        * HACK: In order to style horizontally, we must override
+        * OO.ui.OptionWidget's display rule that is currently set
+        * to be 'block'
+        */
+}
+.oo-ui-draggableElement-dragging {
+       cursor: -webkit-grabbing -moz-grabbing, url(images/grabbing.cur), move;
+       background: rgba(0, 0, 0, 0.2);
+       opacity: 0.4;
+}
+.oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement.oo-ui-optionWidget {
+       display: inline-block;
+}
+.oo-ui-draggableGroupElement-placeholder {
+       position: absolute;
+       display: block;
+       background: rgba(0, 0, 0, 0.4);
+}
 .oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
        overflow-y: hidden;
 }
 .oo-ui-fieldLayout:after {
        clear: both;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
-       display: block;
-       float: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        display: block;
        float: left;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        text-align: right;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
-       display: inline-block;
-       vertical-align: middle;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body {
+       display: table;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
-       display: inline-block;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+       display: table-cell;
        vertical-align: middle;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-labelElement.oo-ui-fieldLayout-align-top > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        display: inline-block;
 }
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
-       z-index: 1;
-}
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help {
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help {
        float: right;
 }
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help-content {
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+       z-index: 1;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help .oo-ui-fieldLayout-help-content {
        padding: 0.5em 0.75em;
        line-height: 1.5em;
 }
 .oo-ui-fieldLayout:last-child {
        margin-bottom: 0;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        padding-top: 0.5em;
        margin-right: 5%;
        width: 35%;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        width: 60%;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
-       padding: 0.75em 0.5em 0.5em 0.5em;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+       padding: 0.5em;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        padding: 0.5em 0;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        padding: 0.5em 0;
 }
 .oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
 .oo-ui-popupWidget-head .oo-ui-labelElement-label {
        margin: 0.75em 1em;
 }
-.oo-ui-popupWidget-body {
-       box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
-}
 .oo-ui-popupWidget-body-padded {
        padding: 0 1em;
 }
 }
 .oo-ui-textInputWidget {
        position: relative;
+       vertical-align: middle;
        -webkit-box-sizing: border-box;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 .oo-ui-outlineControlsWidget-items,
 .oo-ui-outlineControlsWidget-movers {
        height: 2em;
-       margin: 0.5em;
+       margin: 0.5em 0.5em 0.5em 0;
        padding: 0;
 }
 .oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
        margin: 0.5em 0 0.5em 0.5em;
        opacity: 0.2;
 }
-.oo-ui-outlineControlsWidget-items {
-       margin-left: 0;
-}
 .oo-ui-comboBoxWidget {
        display: inline-block;
        position: relative;
 .oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
        background-color: rgba(0, 0, 0, 0.1);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
        background-color: rgba(8, 126, 204, 0.05);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
        background-color: rgba(8, 126, 204, 0.1);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
        font-weight: bold;
 }
 .oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
        /* Adjust for border so text aligns with title */
        margin: -1px;
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
        background-color: rgba(8, 126, 204, 0.05);
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
        background-color: rgba(8, 126, 204, 0.1);
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
        font-weight: bold;
 }
 .oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover,
index bf7e39f..eefc652 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.2.4
+ * OOjs UI v0.5.0
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-12-02T18:45:19Z
+ * Date: 2014-12-12T20:13:09Z
  */
 /* Instantiation */
 
index 7d4acb5..1236d0b 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.2.4
+ * OOjs UI v0.5.0
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-12-02T18:45:30Z
+ * Date: 2014-12-12T20:13:21Z
  */
 .oo-ui-progressBarWidget-slide-frames from {
        margin-left: -40%;
 .oo-ui-buttonElement-frameless.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        margin-left: 0.25em;
 }
-.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        color: #087ecc;
 }
 .oo-ui-buttonElement-frameless.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        outline: none;
 }
 .oo-ui-buttonElement-framed > input.oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        line-height: 1.9em;
 }
 .oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
        margin-left: -0.5em;
        margin-right: 0.3em;
 }
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
        border: solid 1px #a6cee1;
        background: #cde7f4;
        filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#eaf4fa', endColorstr='#b0d9ee');
        background-image:      -o-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
        background-image:         linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
 }
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:focus {
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
        border-color: #9dc2d4;
 }
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
        border: solid 1px #a6cee1;
        background: #cde7f4;
        filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#b0d9ee', endColorstr='#eaf4fa');
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
+.oo-ui-draggableElement {
+       cursor: -webkit-grab -moz-grab, url(images/grab.cur), move;
+       /*
+        * HACK: In order to style horizontally, we must override
+        * OO.ui.OptionWidget's display rule that is currently set
+        * to be 'block'
+        */
+}
+.oo-ui-draggableElement-dragging {
+       cursor: -webkit-grabbing -moz-grabbing, url(images/grabbing.cur), move;
+       background: rgba(0, 0, 0, 0.2);
+       opacity: 0.4;
+}
+.oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement.oo-ui-optionWidget {
+       display: inline-block;
+}
+.oo-ui-draggableGroupElement-placeholder {
+       position: absolute;
+       display: block;
+       background: rgba(0, 0, 0, 0.4);
+}
 .oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
        overflow-y: hidden;
 }
 .oo-ui-fieldLayout:after {
        clear: both;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
-       display: block;
-       float: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        display: block;
        float: left;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        text-align: right;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
-       display: inline-block;
-       vertical-align: middle;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body {
+       display: table;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
-       display: inline-block;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+       display: table-cell;
        vertical-align: middle;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-labelElement.oo-ui-fieldLayout-align-top > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        display: inline-block;
 }
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
-       z-index: 1;
-}
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help {
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help {
        float: right;
 }
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help-content {
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+       z-index: 1;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help .oo-ui-fieldLayout-help-content {
        padding: 0.5em 0.75em;
        line-height: 1.5em;
 }
 .oo-ui-fieldLayout:last-child {
        margin-bottom: 0;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        padding-top: 0.5em;
        margin-right: 5%;
        width: 35%;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        width: 60%;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
-       padding: 0.75em 0.5em 0.5em 0.5em;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+       padding: 0.5em;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        padding: 0.5em 0;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        padding: 0.5em 0;
 }
 .oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
 .oo-ui-popupWidget-head .oo-ui-labelElement-label {
        margin: 0.75em 1em;
 }
-.oo-ui-popupWidget-body {
-       box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
-}
 .oo-ui-popupWidget-body-padded {
        padding: 0 1em;
 }
 }
 .oo-ui-textInputWidget {
        position: relative;
+       vertical-align: middle;
        -webkit-box-sizing: border-box;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 .oo-ui-outlineControlsWidget-items,
 .oo-ui-outlineControlsWidget-movers {
        height: 2em;
-       margin: 0.5em;
+       margin: 0.5em 0.5em 0.5em 0;
        padding: 0;
 }
 .oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
        margin: 0.5em 0 0.5em 0.5em;
        opacity: 0.2;
 }
-.oo-ui-outlineControlsWidget-items {
-       margin-left: 0;
-}
 .oo-ui-comboBoxWidget {
        display: inline-block;
        position: relative;
 .oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
        background-color: rgba(0, 0, 0, 0.1);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
        background-color: rgba(8, 126, 204, 0.05);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
        background-color: rgba(8, 126, 204, 0.1);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
        font-weight: bold;
 }
 .oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
        /* Adjust for border so text aligns with title */
        margin: -1px;
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
        background-color: rgba(8, 126, 204, 0.05);
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
        background-color: rgba(8, 126, 204, 0.1);
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
        font-weight: bold;
 }
 .oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover,
index e360991..2d1060c 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.2.4
+ * OOjs UI v0.5.0
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-12-02T18:45:30Z
+ * Date: 2014-12-12T20:13:21Z
  */
 .oo-ui-progressBarWidget-slide-frames from {
        margin-left: -40%;
 }
 .oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
 .oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
-       width: 2.2em;
-       height: 2.2em;
+       width: 1.9em;
+       height: 1.9em;
 }
 .oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon,
 .oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
 .oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        color: #444444;
 }
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
        color: #598ad1;
 }
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        color: #777777;
 }
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button > .oo-ui-labelElement-label,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        color: #015ccc;
 }
 .oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
 }
 .oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
        margin: 0.1em 0;
-       padding: 0.3em 1.2em;
-       border-radius: 0.3em;
+       padding: 0.2em 0.8em;
+       border-radius: 2px;
        -webkit-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
           -moz-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
            -ms-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
        outline: none;
 }
 .oo-ui-buttonElement-framed > input.oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
-       line-height: 2.2em;
+.oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+       line-height: 1.9em;
 }
 .oo-ui-buttonElement-framed.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
        margin-left: -0.5em;
        background-color: #d0d0d0;
        border-color: #d0d0d0;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
+       color: #0274ff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
+       box-shadow: inset 0 -0.2em 0 0 #015ccc, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
+       border-bottom-color: #015ccc;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
+       color: #00af89;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
+       box-shadow: inset 0 -0.2em 0 0 #008c6d, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
+       border-bottom-color: #008c6d;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
+       color: #d11d13;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
+       box-shadow: inset 0 -0.2em 0 0 #a7170f, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
+       border-bottom-color: #a7170f;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
        text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2);
        color: #ffffff;
        background-color: #0274ff;
        border-color: #0274ff;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:focus {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
        box-shadow: inset 0 -0.2em 0 0 #015ccc, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
        border-bottom-color: #015ccc;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
        background-color: #015ccc;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
        text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2);
        color: #ffffff;
        background-color: #00af89;
        border-color: #00af89;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
        box-shadow: inset 0 -0.2em 0 0 #008c6d, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
        border-bottom-color: #008c6d;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
        background-color: #008c6d;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
        text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2);
        color: #ffffff;
        background-color: #d11d13;
        border-color: #d11d13;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
        box-shadow: inset 0 -0.2em 0 0 #a7170f, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
        border-bottom-color: #a7170f;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
        background-color: #a7170f;
 }
 .oo-ui-clippableElement-clippable {
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
+.oo-ui-draggableElement {
+       cursor: -webkit-grab -moz-grab, url(images/grab.cur), move;
+       /*
+        * HACK: In order to style horizontally, we must override
+        * OO.ui.OptionWidget's display rule that is currently set
+        * to be 'block'
+        */
+}
+.oo-ui-draggableElement-dragging {
+       cursor: -webkit-grabbing -moz-grabbing, url(images/grabbing.cur), move;
+       background: rgba(0, 0, 0, 0.2);
+       opacity: 0.4;
+}
+.oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement.oo-ui-optionWidget {
+       display: inline-block;
+}
+.oo-ui-draggableGroupElement-placeholder {
+       position: absolute;
+       display: block;
+       background: rgba(0, 0, 0, 0.4);
+}
 .oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
        overflow-y: hidden;
 }
 .oo-ui-fieldLayout:after {
        clear: both;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        display: block;
        float: left;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
-       display: block;
-       float: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        text-align: right;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
-       display: inline-block;
-       vertical-align: middle;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body {
+       display: table;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
-       display: inline-block;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+       display: table-cell;
        vertical-align: middle;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-labelElement.oo-ui-fieldLayout-align-top > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        display: inline-block;
 }
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
-       z-index: 1;
-}
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help {
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help {
        float: right;
 }
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help-content {
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+       z-index: 1;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help .oo-ui-fieldLayout-help-content {
        padding: 0.5em 0.75em;
        line-height: 1.5em;
 }
 .oo-ui-fieldLayout:last-child {
        margin-bottom: 0;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        padding-top: 0.5em;
        margin-right: 5%;
        width: 35%;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        width: 60%;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
-       padding: 0.75em 0.5em 0.5em 0.5em;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+       padding: 0.5em;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        padding: 0.5em 0;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        padding: 0.5em 0;
 }
 .oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
 .oo-ui-listToolGroup .oo-ui-tool-link {
        padding-right: 0.5em;
 }
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
        background-color: #eeeeee;
 }
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled,
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
+       background-color: #d0d0d0;
+}
 .oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
        color: #cccccc;
 }
        background-image: /* @embed */ url(themes/mediawiki/images/icons/check.svg);
 }
 .oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
-       background-color: #e1f3ff;
+       background-color: #eeeeee;
 }
 .oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
        color: #cccccc;
        pointer-events: none;
 }
 .oo-ui-toolbar-bar {
-       border-bottom: solid 1px #cccccc;
+       border-bottom: solid 4px rgba(0, 0, 0, 0.15);
        background: #ffffff;
 }
 .oo-ui-toolbar-bar .oo-ui-toolbar-bar {
        display: none;
 }
 .oo-ui-selectWidget {
-       border-radius: 0.3em;
+       border-radius: 2px;
 }
 .oo-ui-selectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
        border-radius: 0;
        margin-left: -1px;
 }
 .oo-ui-selectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonElement-button {
-       border-bottom-left-radius: 0.3em;
-       border-top-left-radius: 0.3em;
+       border-bottom-left-radius: 2px;
+       border-top-left-radius: 2px;
        margin-left: 0;
 }
 .oo-ui-selectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonElement-button {
-       border-bottom-right-radius: 0.3em;
-       border-top-right-radius: 0.3em;
+       border-bottom-right-radius: 2px;
+       border-top-right-radius: 2px;
 }
 .oo-ui-optionWidget {
        position: relative;
 }
 .oo-ui-selectWidget-depressed .oo-ui-optionWidget-selected,
 .oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed {
-       background-color: #a7dcff;
+       background-color: #d0d0d0;
 }
 .oo-ui-optionWidget.oo-ui-widget-disabled {
        color: #cccccc;
 .oo-ui-buttonSelectWidget {
        display: inline-block;
        white-space: nowrap;
-       border-radius: 0.3em;
+       border-radius: 2px;
 }
 .oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
        border-radius: 0;
        margin-left: -1px;
 }
 .oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonElement-button {
-       border-bottom-left-radius: 0.3em;
-       border-top-left-radius: 0.3em;
+       border-bottom-left-radius: 2px;
+       border-top-left-radius: 2px;
        margin-left: 0;
 }
 .oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonElement-button {
-       border-bottom-right-radius: 0.3em;
-       border-top-right-radius: 0.3em;
+       border-bottom-right-radius: 2px;
+       border-top-right-radius: 2px;
 }
 .oo-ui-radioSelectWidget {
        padding: 0.75em 0 0.5em 0;
        vertical-align: middle;
 }
 .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
-       height: 2.2em;
+       height: 1.9em;
 }
 .oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
 .oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
-       height: 2.2em;
+       height: 1.9em;
        margin-top: 0;
 }
 .oo-ui-buttonOptionWidget.oo-ui-optionWidget-selected,
        background-position: center center;
        background-repeat: no-repeat;
        line-height: 2.5em;
-       height: 2.2em;
-       width: 2.2em;
+       height: 1.9em;
+       width: 1.9em;
 }
 .oo-ui-iconWidget.oo-ui-widget-disabled {
        opacity: 0.2;
        background-position: center center;
        background-repeat: no-repeat;
        line-height: 2.5em;
-       height: 2.2em;
-       width: 2.2em;
+       height: 1.9em;
+       width: 1.9em;
 }
 .oo-ui-indicatorWidget.oo-ui-widget-disabled {
        opacity: 0.2;
 .oo-ui-buttonGroupWidget {
        display: inline-block;
        white-space: nowrap;
-       border-radius: 0.3em;
+       border-radius: 2px;
 }
 .oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
        border-radius: 0;
        margin-left: -1px;
 }
 .oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:first-child .oo-ui-buttonElement-button {
-       border-bottom-left-radius: 0.3em;
-       border-top-left-radius: 0.3em;
+       border-bottom-left-radius: 2px;
+       border-top-left-radius: 2px;
        margin-left: 0;
 }
 .oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:last-child .oo-ui-buttonElement-button {
-       border-bottom-right-radius: 0.3em;
-       border-top-right-radius: 0.3em;
+       border-bottom-right-radius: 2px;
+       border-top-right-radius: 2px;
 }
 .oo-ui-toggleSwitchWidget {
        position: relative;
 .oo-ui-popupWidget-head .oo-ui-labelElement-label {
        margin: 0.75em 1em;
 }
-.oo-ui-popupWidget-body {
-       box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
-}
 .oo-ui-popupWidget-body-padded {
        padding: 0 1em;
 }
 }
 .oo-ui-checkboxInputWidget {
        position: relative;
-       line-height: 1.6em;
+       line-height: 2em;
+       white-space: nowrap;
 }
 .oo-ui-checkboxInputWidget * {
+       font: inherit;
        vertical-align: middle;
 }
 .oo-ui-checkboxInputWidget input[type="checkbox"] {
        opacity: 0;
-       width: 1.6em;
-       height: 1.6em;
+       margin: 0;
+       width: 2em;
+       height: 2em;
        max-width: none;
 }
 .oo-ui-checkboxInputWidget input[type="checkbox"] + span {
 }
 .oo-ui-checkboxInputWidget input[type="checkbox"] + span::before {
        content: "";
+       -webkit-box-sizing: border-box;
+          -moz-box-sizing: border-box;
+               box-sizing: border-box;
        position: absolute;
        left: 0;
-       border-radius: 0.3em;
-       width: 1.6em;
-       height: 1.6em;
-       background-color: #ffffff;
-       border: 1px solid grey;
+       border-radius: 2px;
+       width: 2em;
+       height: 2em;
+       background-color: white;
+       border: 1px solid #777777;
 }
 .oo-ui-checkboxInputWidget input[type="checkbox"]:checked + span::before {
        background-image: /* @embed */ url(themes/mediawiki/images/icons/check-constructive.svg);
-       background-size: 1.6em, 1.6em;
+       background-size: 2em, 2em;
        background-repeat: no-repeat;
-       background-position: center top;
+       background-position: center center;
+       background-origin: border-box;
 }
-.oo-ui-checkboxInputWidget input[type="checkbox"]:active + span::after,
-.oo-ui-checkboxInputWidget input[type="checkbox"]:focus + span::after {
+.oo-ui-checkboxInputWidget input[type="checkbox"]:active + span::before {
+       background-color: #dddddd;
+       border-color: #dddddd;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:focus + span::before {
+       border-width: 2px;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:focus:hover + span::before,
+.oo-ui-checkboxInputWidget input[type="checkbox"]:hover + span::before {
+       border-bottom-width: 3px;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled + span::before {
+       cursor: default;
+       background-color: #eeeeee;
+       border-color: #eeeeee;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled:checked + span::before {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/check-invert.svg);
+}
+.oo-ui-radioInputWidget {
+       position: relative;
+       line-height: 2em;
+}
+.oo-ui-radioInputWidget * {
+       font: inherit;
+       vertical-align: middle;
+}
+.oo-ui-radioInputWidget input[type="radio"] {
+       opacity: 0;
+       margin: 0;
+       width: 2em;
+       height: 2em;
+       max-width: none;
+}
+.oo-ui-radioInputWidget input[type="radio"] + span {
+       cursor: pointer;
+       margin: 0 0.4em;
+}
+.oo-ui-radioInputWidget input[type="radio"] + span::before {
+               transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+          -moz-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+           -ms-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+            -o-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+       -webkit-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
        content: "";
+       -webkit-box-sizing: border-box;
+          -moz-box-sizing: border-box;
+               box-sizing: border-box;
        position: absolute;
-       width: 1.6em;
-       height: 1.5em;
-       left: 1px;
-       border-bottom: solid 0.2em #d3d3d3;
+       left: 0;
+       border-radius: 100%;
+       width: 2em;
+       height: 2em;
+       background: white;
+       border: 1px solid #777777;
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle-constructive.svg);
+       background-repeat: no-repeat;
+       background-position: center center;
+       background-origin: border-box;
+       background-size: 0 0;
+}
+.oo-ui-radioInputWidget input[type="radio"]:checked + span::before {
+       background-size: 100% 100%;
 }
-.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled + span {
+.oo-ui-radioInputWidget input[type="radio"]:active + span::before {
+       background-color: #dddddd;
+       border-color: #dddddd;
+}
+.oo-ui-radioInputWidget input[type="radio"]:focus + span::before {
+       border-width: 2px;
+}
+.oo-ui-radioInputWidget input[type="radio"]:focus:hover + span::before,
+.oo-ui-radioInputWidget input[type="radio"]:hover + span::before {
+       border-bottom-width: 3px;
+}
+.oo-ui-radioInputWidget input[type="radio"]:disabled + span::before {
        cursor: default;
+       background-color: #eeeeee;
+       border-color: #eeeeee;
 }
-.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled + span::before {
-       background-color: lightgrey;
+.oo-ui-radioInputWidget input[type="radio"]:disabled:checked + span::before {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle-invert.svg);
 }
 .oo-ui-textInputWidget {
        position: relative;
+       vertical-align: middle;
        -webkit-box-sizing: border-box;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
 .oo-ui-textInputWidget.oo-ui-indicatorElement input,
 .oo-ui-textInputWidget.oo-ui-indicatorElement textarea {
-       padding-right: 2.2em;
+       padding-right: 1.9em;
 }
 .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
        width: 1.6em;
           -moz-user-select: none;
            -ms-user-select: none;
                user-select: none;
+       font-size: 1.1em;
+       padding: 0.75em;
+}
+.oo-ui-outlineOptionWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
+       padding-right: 1.5em;
+}
+.oo-ui-outlineOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+       opacity: 0.5;
+}
+.oo-ui-outlineOptionWidget-level-0 {
+       padding-left: 3.5em;
+}
+.oo-ui-outlineOptionWidget-level-0 .oo-ui-iconElement-icon {
+       left: 1em;
+}
+.oo-ui-outlineOptionWidget-level-1 {
+       padding-left: 5em;
+}
+.oo-ui-outlineOptionWidget-level-1 .oo-ui-iconElement-icon {
+       left: 2.5em;
+}
+.oo-ui-outlineOptionWidget-level-2 {
+       padding-left: 6.5em;
+}
+.oo-ui-outlineOptionWidget-level-2 .oo-ui-iconElement-icon {
+       left: 4em;
+}
+.oo-ui-selectWidget-depressed .oo-ui-outlineOptionWidget.oo-ui-optionWidget-selected {
+       background-color: #d0d0d0;
+       text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-important {
+       font-weight: bold;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-placeholder {
+       font-style: italic;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-empty .oo-ui-iconElement-icon {
+       opacity: 0.5;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-empty .oo-ui-labelElement-label {
+       color: #777777;
+}
+.oo-ui-outlineControlsWidget {
+       height: 3em;
+       background-color: #ffffff;
 }
 .oo-ui-outlineControlsWidget-items,
 .oo-ui-outlineControlsWidget-movers {
 .oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
        float: right;
 }
+.oo-ui-outlineControlsWidget-items,
+.oo-ui-outlineControlsWidget-movers {
+       height: 2em;
+       margin: 0.5em 0.5em 0.5em 0;
+       padding: 0;
+}
+.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
+       width: 1.5em;
+       height: 2em;
+       margin: 0.5em 0 0.5em 0.5em;
+       opacity: 0.2;
+}
 .oo-ui-comboBoxWidget {
        display: inline-block;
        position: relative;
        height: 2.35em;
 }
 .oo-ui-comboBoxWidget .oo-ui-textInputWidget.oo-ui-indicatorElement {
-       padding-right: 2.2em;
+       padding-right: 1.9em;
 }
 .oo-ui-comboBoxWidget .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
-       width: 2.2em;
+       width: 1.9em;
        background-position: center center;
        border: solid 1px #cccccc;
        border-left: none;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
+.oo-ui-searchWidget {
+       border: solid 1px #cccccc;
+}
 .oo-ui-searchWidget-query {
        position: absolute;
        top: 0;
        overflow-y: auto;
 }
 .oo-ui-searchWidget-query {
-       height: 2.4em;
-       top: 1px;
+       height: 4em;
+       padding: 0 1em;
+       border-bottom: solid 1px #cccccc;
 }
-.oo-ui-searchWidget-query .oo-ui-textInputWidget input {
-       border-width: 1px 0;
+.oo-ui-searchWidget-query .oo-ui-textInputWidget {
+       margin: 0.75em 0;
 }
 .oo-ui-searchWidget-results {
-       top: 2.2em;
-       bottom: 0.2em;
+       top: 4em;
+       padding: 1em;
        line-height: 0;
 }
 .oo-ui-window {
 .oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
        background-color: rgba(0, 0, 0, 0.1);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
        background-color: rgba(8, 126, 204, 0.05);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
        background-color: rgba(8, 126, 204, 0.1);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
        font-weight: bold;
 }
 .oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
        /* Adjust for border so text aligns with title */
        margin: -1px;
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
        background-color: rgba(8, 126, 204, 0.05);
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
        background-color: rgba(8, 126, 204, 0.1);
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
        font-weight: bold;
 }
 .oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover,
 .oo-ui-image-invert.oo-ui-icon-previous {
        background-image: /* @embed */ url(themes/mediawiki/images/icons/move-rtl-invert.png);
 }
+.oo-ui-icon-circle {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle.png);
+}
+.oo-ui-image-constructive .oo-ui-icon-circle,
+.oo-ui-image-constructive.oo-ui-icon-circle {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle-constructive.png);
+}
+.oo-ui-image-invert .oo-ui-icon-circle,
+.oo-ui-image-invert.oo-ui-icon-circle {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle-invert.png);
+}
 .oo-ui-icon-redo {
        background-image: /* @embed */ url(themes/mediawiki/images/icons/arched-arrow-ltr.png);
 }
index 875dab4..b590c97 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.2.4
+ * OOjs UI v0.5.0
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-12-02T18:45:19Z
+ * Date: 2014-12-12T20:13:09Z
  */
 /**
  * @class
@@ -33,7 +33,7 @@ OO.ui.MediaWikiTheme.prototype.getElementClasses = function ( element ) {
        var variant,
                variants = {
                        invert: false,
-                       primary: false,
+                       progressive: false,
                        constructive: false,
                        destructive: false
                },
@@ -41,16 +41,10 @@ OO.ui.MediaWikiTheme.prototype.getElementClasses = function ( element ) {
                classes = OO.ui.MediaWikiTheme.super.prototype.getElementClasses.call( this, element );
 
        if ( element.supports( [ 'isFramed', 'isDisabled', 'hasFlag' ] ) ) {
-               if ( element.isFramed() && !element.isDisabled() ) {
-                       if (
-                               element.hasFlag( 'primary' ) ||
-                               element.hasFlag( 'constructive' ) ||
-                               element.hasFlag( 'destructive' )
-                       ) {
-                               variants.invert = true;
-                       }
+               if ( !element.isDisabled() && element.isFramed() && element.hasFlag( 'primary' ) ) {
+                       variants.invert = true;
                } else {
-                       variants.primary = element.hasFlag( 'primary' );
+                       variants.progressive = element.hasFlag( 'progressive' );
                        variants.constructive = element.hasFlag( 'constructive' );
                        variants.destructive = element.hasFlag( 'destructive' );
                }
index 644eadc..0713084 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.2.4
+ * OOjs UI v0.5.0
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-12-02T18:45:30Z
+ * Date: 2014-12-12T20:13:21Z
  */
 .oo-ui-progressBarWidget-slide-frames from {
        margin-left: -40%;
 }
 .oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
 .oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
-       width: 2.2em;
-       height: 2.2em;
+       width: 1.9em;
+       height: 1.9em;
 }
 .oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon,
 .oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
 .oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        color: #444444;
 }
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
        color: #598ad1;
 }
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        color: #777777;
 }
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button > .oo-ui-labelElement-label,
-.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
        color: #015ccc;
 }
 .oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
 }
 .oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
        margin: 0.1em 0;
-       padding: 0.3em 1.2em;
-       border-radius: 0.3em;
+       padding: 0.2em 0.8em;
+       border-radius: 2px;
        -webkit-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
           -moz-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
            -ms-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
        outline: none;
 }
 .oo-ui-buttonElement-framed > input.oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
-       line-height: 2.2em;
+.oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+       line-height: 1.9em;
 }
 .oo-ui-buttonElement-framed.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
        margin-left: -0.5em;
        background-color: #d0d0d0;
        border-color: #d0d0d0;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
+       color: #0274ff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
+       box-shadow: inset 0 -0.2em 0 0 #015ccc, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
+       border-bottom-color: #015ccc;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
+       color: #00af89;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
+       box-shadow: inset 0 -0.2em 0 0 #008c6d, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
+       border-bottom-color: #008c6d;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
+       color: #d11d13;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
+       box-shadow: inset 0 -0.2em 0 0 #a7170f, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
+       border-bottom-color: #a7170f;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
        text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2);
        color: #ffffff;
        background-color: #0274ff;
        border-color: #0274ff;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:focus {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
        box-shadow: inset 0 -0.2em 0 0 #015ccc, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
        border-bottom-color: #015ccc;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
        background-color: #015ccc;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
        text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2);
        color: #ffffff;
        background-color: #00af89;
        border-color: #00af89;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
        box-shadow: inset 0 -0.2em 0 0 #008c6d, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
        border-bottom-color: #008c6d;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
        background-color: #008c6d;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
        text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2);
        color: #ffffff;
        background-color: #d11d13;
        border-color: #d11d13;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
        box-shadow: inset 0 -0.2em 0 0 #a7170f, 0 0.1em 0 0 rgba(0, 0, 0, 0.1);
        border-bottom-color: #a7170f;
 }
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
        background-color: #a7170f;
 }
 .oo-ui-clippableElement-clippable {
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
+.oo-ui-draggableElement {
+       cursor: -webkit-grab -moz-grab, url(images/grab.cur), move;
+       /*
+        * HACK: In order to style horizontally, we must override
+        * OO.ui.OptionWidget's display rule that is currently set
+        * to be 'block'
+        */
+}
+.oo-ui-draggableElement-dragging {
+       cursor: -webkit-grabbing -moz-grabbing, url(images/grabbing.cur), move;
+       background: rgba(0, 0, 0, 0.2);
+       opacity: 0.4;
+}
+.oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement.oo-ui-optionWidget {
+       display: inline-block;
+}
+.oo-ui-draggableGroupElement-placeholder {
+       position: absolute;
+       display: block;
+       background: rgba(0, 0, 0, 0.4);
+}
 .oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
        overflow-y: hidden;
 }
 .oo-ui-fieldLayout:after {
        clear: both;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        display: block;
        float: left;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
-       display: block;
-       float: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        text-align: right;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
-       display: inline-block;
-       vertical-align: middle;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body {
+       display: table;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
-       display: inline-block;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+       display: table-cell;
        vertical-align: middle;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-labelElement.oo-ui-fieldLayout-align-top > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        display: inline-block;
 }
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
-       z-index: 1;
-}
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help {
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help {
        float: right;
 }
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help-content {
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+       z-index: 1;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help .oo-ui-fieldLayout-help-content {
        padding: 0.5em 0.75em;
        line-height: 1.5em;
 }
 .oo-ui-fieldLayout:last-child {
        margin-bottom: 0;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        padding-top: 0.5em;
        margin-right: 5%;
        width: 35%;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        width: 60%;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
-       padding: 0.75em 0.5em 0.5em 0.5em;
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+       padding: 0.5em;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
        padding: 0.5em 0;
 }
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
        padding: 0.5em 0;
 }
 .oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
 .oo-ui-listToolGroup .oo-ui-tool-link {
        padding-right: 0.5em;
 }
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
        background-color: #eeeeee;
 }
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled,
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
+       background-color: #d0d0d0;
+}
 .oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
        color: #cccccc;
 }
        background-image: /* @embed */ url(themes/mediawiki/images/icons/check.svg);
 }
 .oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
-       background-color: #e1f3ff;
+       background-color: #eeeeee;
 }
 .oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
        color: #cccccc;
        pointer-events: none;
 }
 .oo-ui-toolbar-bar {
-       border-bottom: solid 1px #cccccc;
+       border-bottom: solid 4px rgba(0, 0, 0, 0.15);
        background: #ffffff;
 }
 .oo-ui-toolbar-bar .oo-ui-toolbar-bar {
        display: none;
 }
 .oo-ui-selectWidget {
-       border-radius: 0.3em;
+       border-radius: 2px;
 }
 .oo-ui-selectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
        border-radius: 0;
        margin-left: -1px;
 }
 .oo-ui-selectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonElement-button {
-       border-bottom-left-radius: 0.3em;
-       border-top-left-radius: 0.3em;
+       border-bottom-left-radius: 2px;
+       border-top-left-radius: 2px;
        margin-left: 0;
 }
 .oo-ui-selectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonElement-button {
-       border-bottom-right-radius: 0.3em;
-       border-top-right-radius: 0.3em;
+       border-bottom-right-radius: 2px;
+       border-top-right-radius: 2px;
 }
 .oo-ui-optionWidget {
        position: relative;
 }
 .oo-ui-selectWidget-depressed .oo-ui-optionWidget-selected,
 .oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed {
-       background-color: #a7dcff;
+       background-color: #d0d0d0;
 }
 .oo-ui-optionWidget.oo-ui-widget-disabled {
        color: #cccccc;
 .oo-ui-buttonSelectWidget {
        display: inline-block;
        white-space: nowrap;
-       border-radius: 0.3em;
+       border-radius: 2px;
 }
 .oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
        border-radius: 0;
        margin-left: -1px;
 }
 .oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonElement-button {
-       border-bottom-left-radius: 0.3em;
-       border-top-left-radius: 0.3em;
+       border-bottom-left-radius: 2px;
+       border-top-left-radius: 2px;
        margin-left: 0;
 }
 .oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonElement-button {
-       border-bottom-right-radius: 0.3em;
-       border-top-right-radius: 0.3em;
+       border-bottom-right-radius: 2px;
+       border-top-right-radius: 2px;
 }
 .oo-ui-radioSelectWidget {
        padding: 0.75em 0 0.5em 0;
        vertical-align: middle;
 }
 .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
-       height: 2.2em;
+       height: 1.9em;
 }
 .oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
 .oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
-       height: 2.2em;
+       height: 1.9em;
        margin-top: 0;
 }
 .oo-ui-buttonOptionWidget.oo-ui-optionWidget-selected,
        background-position: center center;
        background-repeat: no-repeat;
        line-height: 2.5em;
-       height: 2.2em;
-       width: 2.2em;
+       height: 1.9em;
+       width: 1.9em;
 }
 .oo-ui-iconWidget.oo-ui-widget-disabled {
        opacity: 0.2;
        background-position: center center;
        background-repeat: no-repeat;
        line-height: 2.5em;
-       height: 2.2em;
-       width: 2.2em;
+       height: 1.9em;
+       width: 1.9em;
 }
 .oo-ui-indicatorWidget.oo-ui-widget-disabled {
        opacity: 0.2;
 .oo-ui-buttonGroupWidget {
        display: inline-block;
        white-space: nowrap;
-       border-radius: 0.3em;
+       border-radius: 2px;
 }
 .oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
        border-radius: 0;
        margin-left: -1px;
 }
 .oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:first-child .oo-ui-buttonElement-button {
-       border-bottom-left-radius: 0.3em;
-       border-top-left-radius: 0.3em;
+       border-bottom-left-radius: 2px;
+       border-top-left-radius: 2px;
        margin-left: 0;
 }
 .oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:last-child .oo-ui-buttonElement-button {
-       border-bottom-right-radius: 0.3em;
-       border-top-right-radius: 0.3em;
+       border-bottom-right-radius: 2px;
+       border-top-right-radius: 2px;
 }
 .oo-ui-toggleSwitchWidget {
        position: relative;
 .oo-ui-popupWidget-head .oo-ui-labelElement-label {
        margin: 0.75em 1em;
 }
-.oo-ui-popupWidget-body {
-       box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
-}
 .oo-ui-popupWidget-body-padded {
        padding: 0 1em;
 }
 }
 .oo-ui-checkboxInputWidget {
        position: relative;
-       line-height: 1.6em;
+       line-height: 2em;
+       white-space: nowrap;
 }
 .oo-ui-checkboxInputWidget * {
+       font: inherit;
        vertical-align: middle;
 }
 .oo-ui-checkboxInputWidget input[type="checkbox"] {
        opacity: 0;
-       width: 1.6em;
-       height: 1.6em;
+       margin: 0;
+       width: 2em;
+       height: 2em;
        max-width: none;
 }
 .oo-ui-checkboxInputWidget input[type="checkbox"] + span {
 }
 .oo-ui-checkboxInputWidget input[type="checkbox"] + span::before {
        content: "";
+       -webkit-box-sizing: border-box;
+          -moz-box-sizing: border-box;
+               box-sizing: border-box;
        position: absolute;
        left: 0;
-       border-radius: 0.3em;
-       width: 1.6em;
-       height: 1.6em;
-       background-color: #ffffff;
-       border: 1px solid grey;
+       border-radius: 2px;
+       width: 2em;
+       height: 2em;
+       background-color: white;
+       border: 1px solid #777777;
 }
 .oo-ui-checkboxInputWidget input[type="checkbox"]:checked + span::before {
        background-image: /* @embed */ url(themes/mediawiki/images/icons/check-constructive.svg);
-       background-size: 1.6em, 1.6em;
+       background-size: 2em, 2em;
        background-repeat: no-repeat;
-       background-position: center top;
+       background-position: center center;
+       background-origin: border-box;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:active + span::before {
+       background-color: #dddddd;
+       border-color: #dddddd;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:focus + span::before {
+       border-width: 2px;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:focus:hover + span::before,
+.oo-ui-checkboxInputWidget input[type="checkbox"]:hover + span::before {
+       border-bottom-width: 3px;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled + span::before {
+       cursor: default;
+       background-color: #eeeeee;
+       border-color: #eeeeee;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled:checked + span::before {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/check-invert.svg);
+}
+.oo-ui-radioInputWidget {
+       position: relative;
+       line-height: 2em;
+}
+.oo-ui-radioInputWidget * {
+       font: inherit;
+       vertical-align: middle;
 }
-.oo-ui-checkboxInputWidget input[type="checkbox"]:active + span::after,
-.oo-ui-checkboxInputWidget input[type="checkbox"]:focus + span::after {
+.oo-ui-radioInputWidget input[type="radio"] {
+       opacity: 0;
+       margin: 0;
+       width: 2em;
+       height: 2em;
+       max-width: none;
+}
+.oo-ui-radioInputWidget input[type="radio"] + span {
+       cursor: pointer;
+       margin: 0 0.4em;
+}
+.oo-ui-radioInputWidget input[type="radio"] + span::before {
+               transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+          -moz-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+           -ms-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+            -o-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+       -webkit-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
        content: "";
+       -webkit-box-sizing: border-box;
+          -moz-box-sizing: border-box;
+               box-sizing: border-box;
        position: absolute;
-       width: 1.6em;
-       height: 1.5em;
-       left: 1px;
-       border-bottom: solid 0.2em #d3d3d3;
+       left: 0;
+       border-radius: 100%;
+       width: 2em;
+       height: 2em;
+       background: white;
+       border: 1px solid #777777;
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle-constructive.svg);
+       background-repeat: no-repeat;
+       background-position: center center;
+       background-origin: border-box;
+       background-size: 0 0;
+}
+.oo-ui-radioInputWidget input[type="radio"]:checked + span::before {
+       background-size: 100% 100%;
 }
-.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled + span {
+.oo-ui-radioInputWidget input[type="radio"]:active + span::before {
+       background-color: #dddddd;
+       border-color: #dddddd;
+}
+.oo-ui-radioInputWidget input[type="radio"]:focus + span::before {
+       border-width: 2px;
+}
+.oo-ui-radioInputWidget input[type="radio"]:focus:hover + span::before,
+.oo-ui-radioInputWidget input[type="radio"]:hover + span::before {
+       border-bottom-width: 3px;
+}
+.oo-ui-radioInputWidget input[type="radio"]:disabled + span::before {
        cursor: default;
+       background-color: #eeeeee;
+       border-color: #eeeeee;
 }
-.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled + span::before {
-       background-color: lightgrey;
+.oo-ui-radioInputWidget input[type="radio"]:disabled:checked + span::before {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle-invert.svg);
 }
 .oo-ui-textInputWidget {
        position: relative;
+       vertical-align: middle;
        -webkit-box-sizing: border-box;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
 .oo-ui-textInputWidget.oo-ui-indicatorElement input,
 .oo-ui-textInputWidget.oo-ui-indicatorElement textarea {
-       padding-right: 2.2em;
+       padding-right: 1.9em;
 }
 .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
        width: 1.6em;
           -moz-user-select: none;
            -ms-user-select: none;
                user-select: none;
+       font-size: 1.1em;
+       padding: 0.75em;
+}
+.oo-ui-outlineOptionWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
+       padding-right: 1.5em;
+}
+.oo-ui-outlineOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+       opacity: 0.5;
+}
+.oo-ui-outlineOptionWidget-level-0 {
+       padding-left: 3.5em;
+}
+.oo-ui-outlineOptionWidget-level-0 .oo-ui-iconElement-icon {
+       left: 1em;
+}
+.oo-ui-outlineOptionWidget-level-1 {
+       padding-left: 5em;
+}
+.oo-ui-outlineOptionWidget-level-1 .oo-ui-iconElement-icon {
+       left: 2.5em;
+}
+.oo-ui-outlineOptionWidget-level-2 {
+       padding-left: 6.5em;
+}
+.oo-ui-outlineOptionWidget-level-2 .oo-ui-iconElement-icon {
+       left: 4em;
+}
+.oo-ui-selectWidget-depressed .oo-ui-outlineOptionWidget.oo-ui-optionWidget-selected {
+       background-color: #d0d0d0;
+       text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-important {
+       font-weight: bold;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-placeholder {
+       font-style: italic;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-empty .oo-ui-iconElement-icon {
+       opacity: 0.5;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-empty .oo-ui-labelElement-label {
+       color: #777777;
+}
+.oo-ui-outlineControlsWidget {
+       height: 3em;
+       background-color: #ffffff;
 }
 .oo-ui-outlineControlsWidget-items,
 .oo-ui-outlineControlsWidget-movers {
 .oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
        float: right;
 }
+.oo-ui-outlineControlsWidget-items,
+.oo-ui-outlineControlsWidget-movers {
+       height: 2em;
+       margin: 0.5em 0.5em 0.5em 0;
+       padding: 0;
+}
+.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
+       width: 1.5em;
+       height: 2em;
+       margin: 0.5em 0 0.5em 0.5em;
+       opacity: 0.2;
+}
 .oo-ui-comboBoxWidget {
        display: inline-block;
        position: relative;
        height: 2.35em;
 }
 .oo-ui-comboBoxWidget .oo-ui-textInputWidget.oo-ui-indicatorElement {
-       padding-right: 2.2em;
+       padding-right: 1.9em;
 }
 .oo-ui-comboBoxWidget .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
-       width: 2.2em;
+       width: 1.9em;
        background-position: center center;
        border: solid 1px #cccccc;
        border-left: none;
           -moz-box-sizing: border-box;
                box-sizing: border-box;
 }
+.oo-ui-searchWidget {
+       border: solid 1px #cccccc;
+}
 .oo-ui-searchWidget-query {
        position: absolute;
        top: 0;
        overflow-y: auto;
 }
 .oo-ui-searchWidget-query {
-       height: 2.4em;
-       top: 1px;
+       height: 4em;
+       padding: 0 1em;
+       border-bottom: solid 1px #cccccc;
 }
-.oo-ui-searchWidget-query .oo-ui-textInputWidget input {
-       border-width: 1px 0;
+.oo-ui-searchWidget-query .oo-ui-textInputWidget {
+       margin: 0.75em 0;
 }
 .oo-ui-searchWidget-results {
-       top: 2.2em;
-       bottom: 0.2em;
+       top: 4em;
+       padding: 1em;
        line-height: 0;
 }
 .oo-ui-window {
 .oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
        background-color: rgba(0, 0, 0, 0.1);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
        background-color: rgba(8, 126, 204, 0.05);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
        background-color: rgba(8, 126, 204, 0.1);
 }
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
        font-weight: bold;
 }
 .oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
        /* Adjust for border so text aligns with title */
        margin: -1px;
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
        background-color: rgba(8, 126, 204, 0.05);
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
        background-color: rgba(8, 126, 204, 0.1);
 }
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
        font-weight: bold;
 }
 .oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover,
 .oo-ui-image-invert.oo-ui-icon-previous {
        background-image: /* @embed */ url(themes/mediawiki/images/icons/move-rtl-invert.svg);
 }
+.oo-ui-icon-circle {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle.svg);
+}
+.oo-ui-image-constructive .oo-ui-icon-circle,
+.oo-ui-image-constructive.oo-ui-icon-circle {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle-constructive.svg);
+}
+.oo-ui-image-invert .oo-ui-icon-circle,
+.oo-ui-image-invert.oo-ui-icon-circle {
+       background-image: /* @embed */ url(themes/mediawiki/images/icons/circle-invert.svg);
+}
 .oo-ui-icon-redo {
        background-image: /* @embed */ url(themes/mediawiki/images/icons/arched-arrow-ltr.svg);
 }
index 1209434..7f519a6 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * OOjs UI v0.2.4
+ * OOjs UI v0.5.0
  * https://www.mediawiki.org/wiki/OOjs_UI
  *
  * Copyright 2011–2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: 2014-12-02T18:45:19Z
+ * Date: 2014-12-12T20:13:09Z
  */
 ( function ( OO ) {
 
@@ -730,7 +730,7 @@ OO.ui.Element = function OoUiElement( config ) {
        config = config || {};
 
        // Properties
-       this.$ = config.$ || OO.ui.Element.getJQuery( document );
+       this.$ = config.$ || OO.ui.Element.static.getJQuery( document );
        this.data = config.data;
        this.$element = this.$( this.$.context.createElement( this.getTagName() ) );
        this.elementGroup = null;
@@ -777,7 +777,7 @@ OO.ui.Element.static.tagName = 'div';
  *   not in an iframe
  * @return {Function} Bound jQuery function
  */
-OO.ui.Element.getJQuery = function ( context, $iframe ) {
+OO.ui.Element.static.getJQuery = function ( context, $iframe ) {
        function wrapper( selector ) {
                return $( selector, wrapper.context );
        }
@@ -798,7 +798,7 @@ OO.ui.Element.getJQuery = function ( context, $iframe ) {
  * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Object to get the document for
  * @return {HTMLDocument|null} Document object
  */
-OO.ui.Element.getDocument = function ( obj ) {
+OO.ui.Element.static.getDocument = function ( obj ) {
        // jQuery - selections created "offscreen" won't have a context, so .context isn't reliable
        return ( obj[0] && obj[0].ownerDocument ) ||
                // Empty jQuery selections might have a context
@@ -819,7 +819,7 @@ OO.ui.Element.getDocument = function ( obj ) {
  * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the window for
  * @return {Window} Window object
  */
-OO.ui.Element.getWindow = function ( obj ) {
+OO.ui.Element.static.getWindow = function ( obj ) {
        var doc = this.getDocument( obj );
        return doc.parentWindow || doc.defaultView;
 };
@@ -831,7 +831,7 @@ OO.ui.Element.getWindow = function ( obj ) {
  * @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the direction for
  * @return {string} Text direction, either 'ltr' or 'rtl'
  */
-OO.ui.Element.getDir = function ( obj ) {
+OO.ui.Element.static.getDir = function ( obj ) {
        var isDoc, isWin;
 
        if ( obj instanceof jQuery ) {
@@ -859,7 +859,7 @@ OO.ui.Element.getDir = function ( obj ) {
  * @param {Object} [offset] Offset to start with, used internally
  * @return {Object} Offset object, containing left and top properties
  */
-OO.ui.Element.getFrameOffset = function ( from, to, offset ) {
+OO.ui.Element.static.getFrameOffset = function ( from, to, offset ) {
        var i, len, frames, frame, rect;
 
        if ( !to ) {
@@ -904,7 +904,7 @@ OO.ui.Element.getFrameOffset = function ( from, to, offset ) {
  * @param {jQuery} $anchor Element to get $element's position relative to
  * @return {Object} Translated position coordinates, containing top and left properties
  */
-OO.ui.Element.getRelativePosition = function ( $element, $anchor ) {
+OO.ui.Element.static.getRelativePosition = function ( $element, $anchor ) {
        var iframe, iframePos,
                pos = $element.offset(),
                anchorPos = $anchor.offset(),
@@ -934,7 +934,7 @@ OO.ui.Element.getRelativePosition = function ( $element, $anchor ) {
  * @param {HTMLElement} el Element to measure
  * @return {Object} Dimensions object with `top`, `left`, `bottom` and `right` properties
  */
-OO.ui.Element.getBorders = function ( el ) {
+OO.ui.Element.static.getBorders = function ( el ) {
        var doc = el.ownerDocument,
                win = doc.parentWindow || doc.defaultView,
                style = win && win.getComputedStyle ?
@@ -961,7 +961,7 @@ OO.ui.Element.getBorders = function ( el ) {
  * @param {HTMLElement|Window} el Element to measure
  * @return {Object} Dimensions object with `borders`, `scroll`, `scrollbar` and `rect` properties
  */
-OO.ui.Element.getDimensions = function ( el ) {
+OO.ui.Element.static.getDimensions = function ( el ) {
        var $el, $win,
                doc = el.ownerDocument || el.document,
                win = doc.parentWindow || doc.defaultView;
@@ -999,6 +999,38 @@ OO.ui.Element.getDimensions = function ( el ) {
        }
 };
 
+/**
+ * Get scrollable object parent
+ *
+ * documentElement can't be used to get or set the scrollTop
+ * property on Blink. Changing and testing its value lets us
+ * use 'body' or 'documentElement' based on what is working.
+ *
+ * https://code.google.com/p/chromium/issues/detail?id=303131
+ *
+ * @static
+ * @param {HTMLElement} el Element to find scrollable parent for
+ * @return {HTMLElement} Scrollable parent
+ */
+OO.ui.Element.static.getRootScrollableElement = function ( el ) {
+       var scrollTop, body;
+
+       if ( OO.ui.scrollableElement === undefined ) {
+               body = el.ownerDocument.body;
+               scrollTop = body.scrollTop;
+               body.scrollTop = 1;
+
+               if ( body.scrollTop === 1 ) {
+                       body.scrollTop = scrollTop;
+                       OO.ui.scrollableElement = 'body';
+               } else {
+                       OO.ui.scrollableElement = 'documentElement';
+               }
+       }
+
+       return el.ownerDocument[ OO.ui.scrollableElement ];
+};
+
 /**
  * Get closest scrollable container.
  *
@@ -1010,7 +1042,7 @@ OO.ui.Element.getDimensions = function ( el ) {
  * @param {string} [dimension] Dimension of scrolling to look for; `x`, `y` or omit for either
  * @return {HTMLElement} Closest scrollable container
  */
-OO.ui.Element.getClosestScrollableContainer = function ( el, dimension ) {
+OO.ui.Element.static.getClosestScrollableContainer = function ( el, dimension ) {
        var i, val,
                props = [ 'overflow' ],
                $parent = $( el ).parent();
@@ -1020,7 +1052,7 @@ OO.ui.Element.getClosestScrollableContainer = function ( el, dimension ) {
        }
 
        while ( $parent.length ) {
-               if ( $parent[0] === el.ownerDocument.body ) {
+               if ( $parent[0] === this.getRootScrollableElement( el ) ) {
                        return $parent[0];
                }
                i = props.length;
@@ -1046,7 +1078,7 @@ OO.ui.Element.getClosestScrollableContainer = function ( el, dimension ) {
  *  to scroll in both directions
  * @param {Function} [config.complete] Function to call when scrolling completes
  */
-OO.ui.Element.scrollIntoView = function ( el, config ) {
+OO.ui.Element.static.scrollIntoView = function ( el, config ) {
        // Configuration initialization
        config = config || {};
 
@@ -1059,8 +1091,8 @@ OO.ui.Element.scrollIntoView = function ( el, config ) {
                $win = $( this.getWindow( el ) );
 
        // Compute the distances between the edges of el and the edges of the scroll viewport
-       if ( $sc.is( 'body' ) ) {
-               // If the scrollable container is the <body> this is easy
+       if ( $sc.is( 'html, body' ) ) {
+               // If the scrollable container is the root, this is easy
                rel = {
                        top: eld.rect.top,
                        bottom: $win.innerHeight() - eld.rect.bottom,
@@ -1106,35 +1138,6 @@ OO.ui.Element.scrollIntoView = function ( el, config ) {
        }
 };
 
-/**
- * Bind a handler for an event on a DOM element.
- *
- * Used to be for working around a jQuery bug (jqbug.com/14180),
- * but obsolete as of jQuery 1.11.0.
- *
- * @static
- * @deprecated Use jQuery#on instead.
- * @param {HTMLElement|jQuery} el DOM element
- * @param {string} event Event to bind
- * @param {Function} callback Callback to call when the event fires
- */
-OO.ui.Element.onDOMEvent = function ( el, event, callback ) {
-       $( el ).on( event, callback );
-};
-
-/**
- * Unbind a handler bound with #static-method-onDOMEvent.
- *
- * @deprecated Use jQuery#off instead.
- * @static
- * @param {HTMLElement|jQuery} el DOM element
- * @param {string} event Event to unbind
- * @param {Function} [callback] Callback to unbind
- */
-OO.ui.Element.offDOMEvent = function ( el, event, callback ) {
-       $( el ).off( event, callback );
-};
-
 /* Methods */
 
 /**
@@ -1224,7 +1227,9 @@ OO.ui.Element.prototype.isElementAttached = function () {
  * @return {HTMLDocument} Document object
  */
 OO.ui.Element.prototype.getElementDocument = function () {
-       return OO.ui.Element.getDocument( this.$element );
+       // Don't use this.$.context because subclasses can rebind this.$
+       // Don't cache this in other ways either because subclasses could can change this.$element
+       return OO.ui.Element.static.getDocument( this.$element );
 };
 
 /**
@@ -1233,14 +1238,14 @@ OO.ui.Element.prototype.getElementDocument = function () {
  * @return {Window} Window object
  */
 OO.ui.Element.prototype.getElementWindow = function () {
-       return OO.ui.Element.getWindow( this.$element );
+       return OO.ui.Element.static.getWindow( this.$element );
 };
 
 /**
  * Get closest scrollable container.
  */
 OO.ui.Element.prototype.getClosestScrollableElementContainer = function () {
-       return OO.ui.Element.getClosestScrollableContainer( this.$element[0] );
+       return OO.ui.Element.static.getClosestScrollableContainer( this.$element[0] );
 };
 
 /**
@@ -1269,29 +1274,7 @@ OO.ui.Element.prototype.setElementGroup = function ( group ) {
  * @param {Object} [config] Configuration options
  */
 OO.ui.Element.prototype.scrollElementIntoView = function ( config ) {
-       return OO.ui.Element.scrollIntoView( this.$element[0], config );
-};
-
-/**
- * Bind a handler for an event on this.$element
- *
- * @deprecated Use jQuery#on instead.
- * @param {string} event
- * @param {Function} callback
- */
-OO.ui.Element.prototype.onDOMEvent = function ( event, callback ) {
-       OO.ui.Element.onDOMEvent( this.$element, event, callback );
-};
-
-/**
- * Unbind a handler bound with #offDOMEvent
- *
- * @deprecated Use jQuery#off instead.
- * @param {string} event
- * @param {Function} callback
- */
-OO.ui.Element.prototype.offDOMEvent = function ( event, callback ) {
-       OO.ui.Element.offDOMEvent( this.$element, event, callback );
+       return OO.ui.Element.static.scrollIntoView( this.$element[0], config );
 };
 
 /**
@@ -1781,15 +1764,19 @@ OO.ui.Window.prototype.withoutSizeTransitions = function ( callback ) {
 OO.ui.Window.prototype.getContentHeight = function () {
        var bodyHeight,
                win = this,
-               styleObj = this.$frame[0].style;
+               bodyStyleObj = this.$body[0].style,
+               frameStyleObj = this.$frame[0].style;
 
        // Temporarily resize the frame so getBodyHeight() can use scrollHeight measurements.
        // Disable transitions first, otherwise we'll get values from when the window was animating.
        this.withoutSizeTransitions( function () {
-               var oldHeight = styleObj.height;
-               styleObj.height = '1px';
+               var oldHeight = frameStyleObj.height, oldPosition = bodyStyleObj.position;
+               frameStyleObj.height = '1px';
+               // Force body to resize to new width
+               bodyStyleObj.position = 'relative';
                bodyHeight = win.getBodyHeight();
-               styleObj.height = oldHeight;
+               frameStyleObj.height = oldHeight;
+               bodyStyleObj.position = oldPosition;
        } );
 
        return Math.round(
@@ -1948,13 +1935,13 @@ OO.ui.Window.prototype.setManager = function ( manager ) {
        } else {
                this.$content = this.$( '<div>' );
                this.$document = $( this.getElementDocument() );
-               this.$content.addClass( 'oo-ui-window-content' );
+               this.$content.addClass( 'oo-ui-window-content' ).attr( 'tabIndex', 0 );
                this.$frame.append( this.$content );
        }
        this.toggle( false );
 
        // Figure out directionality:
-       this.dir = OO.ui.Element.getDir( this.$iframe || this.$content ) || 'ltr';
+       this.dir = OO.ui.Element.static.getDir( this.$iframe || this.$content ) || 'ltr';
 
        return this;
 };
@@ -2140,7 +2127,7 @@ OO.ui.Window.prototype.hold = function ( data ) {
 
        this.getHoldProcess( data ).execute().done( function () {
                // Get the focused element within the window's content
-               var $focus = win.$content.find( OO.ui.Element.getDocument( win.$content ).activeElement );
+               var $focus = win.$content.find( OO.ui.Element.static.getDocument( win.$content ).activeElement );
 
                // Blur the focused element
                if ( $focus.length ) {
@@ -2255,7 +2242,7 @@ OO.ui.Window.prototype.load = function () {
        doc.close();
 
        // Properties
-       this.$ = OO.ui.Element.getJQuery( doc, this.$iframe );
+       this.$ = OO.ui.Element.static.getJQuery( doc, this.$iframe );
        this.$content = this.$( '.oo-ui-window-content' ).attr( 'tabIndex', 0 );
        this.$document = this.$( doc );
 
@@ -2390,7 +2377,8 @@ OO.ui.Dialog.static.escapable = true;
 OO.ui.Dialog.prototype.onDocumentKeyDown = function ( e ) {
        if ( e.which === OO.ui.Keys.ESCAPE ) {
                this.close();
-               return false;
+               e.preventDefault();
+               e.stopPropagation();
        }
 };
 
@@ -3109,7 +3097,7 @@ OO.ui.WindowManager.prototype.addWindows = function ( windows ) {
  * @throws {Error} If windows being removed are not being managed
  */
 OO.ui.WindowManager.prototype.removeWindows = function ( names ) {
-       var i, len, win, name,
+       var i, len, win, name, cleanupWindow,
                manager = this,
                promises = [],
                cleanup = function ( name, win ) {
@@ -3123,7 +3111,8 @@ OO.ui.WindowManager.prototype.removeWindows = function ( names ) {
                if ( !win ) {
                        throw new Error( 'Cannot remove window' );
                }
-               promises.push( this.closeWindow( name ).then( cleanup.bind( null, name, win ) ) );
+               cleanupWindow = cleanup.bind( null, name, win );
+               promises.push( this.closeWindow( name ).then( cleanupWindow, cleanupWindow ) );
        }
 
        return $.when.apply( $, promises );
@@ -3153,7 +3142,7 @@ OO.ui.WindowManager.prototype.updateWindowSize = function ( win ) {
                return;
        }
 
-       var viewport = OO.ui.Element.getDimensions( win.getElementWindow() ),
+       var viewport = OO.ui.Element.static.getDimensions( win.getElementWindow() ),
                sizes = this.constructor.static.sizes,
                size = win.getSize();
 
@@ -3750,7 +3739,7 @@ OO.ui.ButtonElement.prototype.setButtonElement = function ( $button ) {
                this.$button
                        .removeClass( 'oo-ui-buttonElement-button' )
                        .removeAttr( 'role accesskey tabindex' )
-                       .off( this.onMouseDownHandler );
+                       .off( 'mousedown', this.onMouseDownHandler );
        }
 
        this.$button = $button
@@ -4155,6 +4144,371 @@ OO.ui.GroupElement.prototype.clearItems = function () {
        return this;
 };
 
+/**
+ * A mixin for an element that can be dragged and dropped.
+ * Use in conjunction with DragGroupWidget
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ */
+OO.ui.DraggableElement = function OoUiDraggableElement() {
+       // Properties
+       this.index = null;
+
+       // Initialize and events
+       this.$element
+               .attr( 'draggable', true )
+               .addClass( 'oo-ui-draggableElement' )
+               .on( {
+                       dragstart: this.onDragStart.bind( this ),
+                       dragover: this.onDragOver.bind( this ),
+                       dragend: this.onDragEnd.bind( this ),
+                       drop: this.onDrop.bind( this )
+               } );
+};
+
+/* Events */
+
+/**
+ * @event dragstart
+ * @param {OO.ui.DraggableElement} item Dragging item
+ */
+
+/**
+ * @event dragend
+ */
+
+/**
+ * @event drop
+ */
+
+/* Methods */
+
+/**
+ * Respond to dragstart event.
+ * @param {jQuery.Event} event jQuery event
+ * @fires dragstart
+ */
+OO.ui.DraggableElement.prototype.onDragStart = function ( e ) {
+       var dataTransfer = e.originalEvent.dataTransfer;
+       // Define drop effect
+       dataTransfer.dropEffect = 'none';
+       dataTransfer.effectAllowed = 'move';
+       // We must set up a dataTransfer data property or Firefox seems to
+       // ignore the fact the element is draggable.
+       try {
+               dataTransfer.setData( 'application-x/OOjs-UI-draggable', this.getIndex() );
+       } catch ( err ) {
+               // The above is only for firefox. No need to set a catch clause
+               // if it fails, move on.
+       }
+       // Add dragging class
+       this.$element.addClass( 'oo-ui-draggableElement-dragging' );
+       // Emit event
+       this.emit( 'dragstart', this );
+       return true;
+};
+
+/**
+ * Respond to dragend event.
+ * @fires dragend
+ */
+OO.ui.DraggableElement.prototype.onDragEnd = function () {
+       this.$element.removeClass( 'oo-ui-draggableElement-dragging' );
+       this.emit( 'dragend' );
+};
+
+/**
+ * Handle drop event.
+ * @param {jQuery.Event} event jQuery event
+ * @fires drop
+ */
+OO.ui.DraggableElement.prototype.onDrop = function ( e ) {
+       e.preventDefault();
+       this.emit( 'drop', e );
+};
+
+/**
+ * In order for drag/drop to work, the dragover event must
+ * return false and stop propogation.
+ */
+OO.ui.DraggableElement.prototype.onDragOver = function ( e ) {
+       e.preventDefault();
+};
+
+/**
+ * Set item index.
+ * Store it in the DOM so we can access from the widget drag event
+ * @param {number} Item index
+ */
+OO.ui.DraggableElement.prototype.setIndex = function ( index ) {
+       if ( this.index !== index ) {
+               this.index = index;
+               this.$element.data( 'index', index );
+       }
+};
+
+/**
+ * Get item index
+ * @return {number} Item index
+ */
+OO.ui.DraggableElement.prototype.getIndex = function () {
+       return this.index;
+};
+
+/**
+ * Element containing a sequence of child elements that can be dragged
+ * and dropped.
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$group] Container node, assigned to #$group, omit to use a generated `<div>`
+ * @cfg {string} [orientation] Item orientation, 'horizontal' or 'vertical'. Defaults to 'vertical'
+ */
+OO.ui.DraggableGroupElement = function OoUiDraggableGroupElement( config ) {
+       // Configuration initialization
+       config = config || {};
+
+       // Parent constructor
+       OO.ui.GroupElement.call( this, config );
+
+       // Properties
+       this.orientation = config.orientation || 'vertical';
+       this.dragItem = null;
+       this.itemDragOver = null;
+       this.itemKeys = {};
+       this.sideInsertion = '';
+
+       // Events
+       this.aggregate( {
+               dragstart: 'itemDragStart',
+               dragend: 'itemDragEnd',
+               drop: 'itemDrop'
+       } );
+       this.connect( this, {
+               itemDragStart: 'onItemDragStart',
+               itemDrop: 'onItemDrop',
+               itemDragEnd: 'onItemDragEnd'
+       } );
+       this.$element.on( {
+               dragover: $.proxy( this.onDragOver, this ),
+               dragleave: $.proxy( this.onDragLeave, this )
+       } );
+
+       // Initialize
+       if ( $.isArray( config.items ) ) {
+               this.addItems( config.items );
+       }
+       this.$placeholder = $( '<div>' )
+               .addClass( 'oo-ui-draggableGroupElement-placeholder' );
+       this.$element
+               .addClass( 'oo-ui-draggableGroupElement' )
+               .append( this.$status )
+               .toggleClass( 'oo-ui-draggableGroupElement-horizontal', this.orientation === 'horizontal' )
+               .prepend( this.$placeholder );
+};
+
+/* Setup */
+OO.mixinClass( OO.ui.DraggableGroupElement, OO.ui.GroupElement );
+
+/* Events */
+
+/**
+ * @event reorder
+ * @param {OO.ui.DraggableElement} item Reordered item
+ * @param {number} [newIndex] New index for the item
+ */
+
+/* Methods */
+
+/**
+ * Respond to item drag start event
+ * @param {OO.ui.DraggableElement} item Dragged item
+ */
+OO.ui.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {
+       var i, len;
+
+       // Map the index of each object
+       for ( i = 0, len = this.items.length; i < len; i++ ) {
+               this.items[i].setIndex( i );
+       }
+
+       if ( this.orientation === 'horizontal' ) {
+               // Set the height of the indicator
+               this.$placeholder.css( {
+                       height: item.$element.outerHeight(),
+                       width: 2
+               } );
+       } else {
+               // Set the width of the indicator
+               this.$placeholder.css( {
+                       height: 2,
+                       width: item.$element.outerWidth()
+               } );
+       }
+       this.setDragItem( item );
+};
+
+/**
+ * Respond to item drag end event
+ */
+OO.ui.DraggableGroupElement.prototype.onItemDragEnd = function () {
+       this.unsetDragItem();
+       return false;
+};
+
+/**
+ * Handle drop event and switch the order of the items accordingly
+ * @param {OO.ui.DraggableElement} item Dropped item
+ * @fires reorder
+ */
+OO.ui.DraggableGroupElement.prototype.onItemDrop = function ( item ) {
+       var toIndex = item.getIndex();
+       // Check if the dropped item is from the current group
+       // TODO: Figure out a way to configure a list of legally droppable
+       // elements even if they are not yet in the list
+       if ( this.getDragItem() ) {
+               // If the insertion point is 'after', the insertion index
+               // is shifted to the right (or to the left in RTL, hence 'after')
+               if ( this.sideInsertion === 'after' ) {
+                       toIndex++;
+               }
+               // Emit change event
+               this.emit( 'reorder', this.getDragItem(), toIndex );
+       }
+       // Return false to prevent propogation
+       return false;
+};
+
+/**
+ * Handle dragleave event.
+ */
+OO.ui.DraggableGroupElement.prototype.onDragLeave = function () {
+       // This means the item was dragged outside the widget
+       this.$placeholder
+               .css( 'left', 0 )
+               .hide();
+};
+
+/**
+ * Respond to dragover event
+ * @param {jQuery.Event} event Event details
+ */
+OO.ui.DraggableGroupElement.prototype.onDragOver = function ( e ) {
+       var dragOverObj, $optionWidget, itemOffset, itemMidpoint, itemBoundingRect,
+               itemSize, cssOutput, dragPosition, itemIndex, itemPosition,
+               clientX = e.originalEvent.clientX,
+               clientY = e.originalEvent.clientY;
+
+       // Get the OptionWidget item we are dragging over
+       dragOverObj = this.getElementDocument().elementFromPoint( clientX, clientY );
+       $optionWidget = $( dragOverObj ).closest( '.oo-ui-draggableElement' );
+       if ( $optionWidget[0] ) {
+               itemOffset = $optionWidget.offset();
+               itemBoundingRect = $optionWidget[0].getBoundingClientRect();
+               itemPosition = $optionWidget.position();
+               itemIndex = $optionWidget.data( 'index' );
+       }
+
+       if (
+               itemOffset &&
+               this.isDragging() &&
+               itemIndex !== this.getDragItem().getIndex()
+       ) {
+               if ( this.orientation === 'horizontal' ) {
+                       // Calculate where the mouse is relative to the item width
+                       itemSize = itemBoundingRect.width;
+                       itemMidpoint = itemBoundingRect.left + itemSize / 2;
+                       dragPosition = clientX;
+                       // Which side of the item we hover over will dictate
+                       // where the placeholder will appear, on the left or
+                       // on the right
+                       cssOutput = {
+                               left: dragPosition < itemMidpoint ? itemPosition.left : itemPosition.left + itemSize,
+                               top: itemPosition.top
+                       };
+               } else {
+                       // Calculate where the mouse is relative to the item height
+                       itemSize = itemBoundingRect.height;
+                       itemMidpoint = itemBoundingRect.top + itemSize / 2;
+                       dragPosition = clientY;
+                       // Which side of the item we hover over will dictate
+                       // where the placeholder will appear, on the top or
+                       // on the bottom
+                       cssOutput = {
+                               top: dragPosition < itemMidpoint ? itemPosition.top : itemPosition.top + itemSize,
+                               left: itemPosition.left
+                       };
+               }
+               // Store whether we are before or after an item to rearrange
+               // For horizontal layout, we need to account for RTL, as this is flipped
+               if (  this.orientation === 'horizontal' && this.$element.css( 'direction' ) === 'rtl' ) {
+                       this.sideInsertion = dragPosition < itemMidpoint ? 'after' : 'before';
+               } else {
+                       this.sideInsertion = dragPosition < itemMidpoint ? 'before' : 'after';
+               }
+               // Add drop indicator between objects
+               if ( this.sideInsertion ) {
+                       this.$placeholder
+                               .css( cssOutput )
+                               .show();
+               } else {
+                       this.$placeholder
+                               .css( {
+                                       left: 0,
+                                       top: 0
+                               } )
+                               .hide();
+               }
+       } else {
+               // This means the item was dragged outside the widget
+               this.$placeholder
+                       .css( 'left', 0 )
+                       .hide();
+       }
+       // Prevent default
+       e.preventDefault();
+};
+
+/**
+ * Set a dragged item
+ * @param {OO.ui.DraggableElement} item Dragged item
+ */
+OO.ui.DraggableGroupElement.prototype.setDragItem = function ( item ) {
+       this.dragItem = item;
+};
+
+/**
+ * Unset the current dragged item
+ */
+OO.ui.DraggableGroupElement.prototype.unsetDragItem = function () {
+       this.dragItem = null;
+       this.itemDragOver = null;
+       this.$placeholder.hide();
+       this.sideInsertion = '';
+};
+
+/**
+ * Get the current dragged item
+ * @return {OO.ui.DraggableElement|null} item Dragged item or null if no item is dragged
+ */
+OO.ui.DraggableGroupElement.prototype.getDragItem = function () {
+       return this.dragItem;
+};
+
+/**
+ * Check if there's an item being dragged.
+ * @return {Boolean} Item is being dragged
+ */
+OO.ui.DraggableGroupElement.prototype.isDragging = function () {
+       return this.getDragItem() !== null;
+};
+
 /**
  * Element containing an icon.
  *
@@ -4313,6 +4667,15 @@ OO.ui.IconElement.prototype.getIcon = function () {
        return this.icon;
 };
 
+/**
+ * Get icon title.
+ *
+ * @return {string} Icon title text
+ */
+OO.ui.IconElement.prototype.getIconTitle = function () {
+       return this.iconTitle;
+};
+
 /**
  * Element containing an indicator.
  *
@@ -4644,7 +5007,8 @@ OO.ui.PopupElement.prototype.getPopup = function () {
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @cfg {string|string[]} [flags] Styling flags, e.g. 'primary', 'destructive' or 'constructive'
+ * @cfg {string|string[]} [flags] Flags describing importance and functionality, e.g. 'primary',
+ *   'safe', 'progressive', 'destructive' or 'constructive'
  * @cfg {jQuery} [$flagged] Flagged node, assigned to #$flagged, omit to use #$element
  */
 OO.ui.FlaggedElement = function OoUiFlaggedElement( config ) {
@@ -4968,10 +5332,10 @@ OO.ui.ClippableElement.prototype.toggleClipping = function ( clipping ) {
                this.clipping = clipping;
                if ( clipping ) {
                        this.$clippableContainer = this.$( this.getClosestScrollableElementContainer() );
-                       // If the clippable container is the body, we have to listen to scroll events and check
+                       // If the clippable container is the root, we have to listen to scroll events and check
                        // jQuery.scrollTop on the window because of browser inconsistencies
-                       this.$clippableScroller = this.$clippableContainer.is( 'body' ) ?
-                               this.$( OO.ui.Element.getWindow( this.$clippableContainer ) ) :
+                       this.$clippableScroller = this.$clippableContainer.is( 'html, body' ) ?
+                               this.$( OO.ui.Element.static.getWindow( this.$clippableContainer ) ) :
                                this.$clippableContainer;
                        this.$clippableScroller.on( 'scroll', this.onClippableContainerScrollHandler );
                        this.$clippableWindow = this.$( this.getElementWindow() )
@@ -5062,9 +5426,9 @@ OO.ui.ClippableElement.prototype.clip = function () {
                return this;
        }
 
-       var buffer = 10,
+       var buffer = 7, // Chosen by fair dice roll
                cOffset = this.$clippable.offset(),
-               $container = this.$clippableContainer.is( 'body' ) ?
+               $container = this.$clippableContainer.is( 'html, body' ) ?
                        this.$clippableWindow : this.$clippableContainer,
                ccOffset = $container.offset() || { top: 0, left: 0 },
                ccHeight = $container.innerHeight() - buffer,
@@ -6460,7 +6824,7 @@ OO.ui.BookletLayout = function OoUiBookletLayout( config ) {
        }
        if ( this.autoFocus ) {
                // Event 'focus' does not bubble, but 'focusin' does
-               this.stackLayout.onDOMEvent( 'focusin', this.onStackLayoutFocus.bind( this ) );
+               this.stackLayout.$element.on( 'focusin', this.onStackLayoutFocus.bind( this ) );
        }
 
        // Initialization
@@ -6685,7 +7049,7 @@ OO.ui.BookletLayout.prototype.getPage = function ( name ) {
  *
  * @return {string|null} Current page name
  */
-OO.ui.BookletLayout.prototype.getPageName = function () {
+OO.ui.BookletLayout.prototype.getCurrentPageName = function () {
        return this.currentPageName;
 };
 
@@ -6876,6 +7240,8 @@ OO.ui.BookletLayout.prototype.selectFirstSelectablePage = function () {
  * @cfg {string} [help] Explanatory text shown as a '?' icon.
  */
 OO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {
+       var hasInputWidget = fieldWidget instanceof OO.ui.InputWidget;
+
        // Configuration initialization
        config = $.extend( { align: 'left' }, config );
 
@@ -6890,6 +7256,7 @@ OO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {
 
        // Properties
        this.$field = this.$( '<div>' );
+       this.$body = this.$( '<' + ( hasInputWidget ? 'label' : 'div' ) + '>' );
        this.align = null;
        if ( config.help ) {
                this.popupButtonWidget = new OO.ui.PopupButtonWidget( {
@@ -6910,17 +7277,21 @@ OO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {
        }
 
        // Events
-       if ( this.fieldWidget instanceof OO.ui.InputWidget ) {
+       if ( hasInputWidget ) {
                this.$label.on( 'click', this.onLabelClick.bind( this ) );
        }
        this.fieldWidget.connect( this, { disable: 'onFieldDisable' } );
 
        // Initialization
-       this.$element.addClass( 'oo-ui-fieldLayout' );
+       this.$element
+               .addClass( 'oo-ui-fieldLayout' )
+               .append( this.$help, this.$body );
+       this.$body.addClass( 'oo-ui-fieldLayout-body' );
        this.$field
                .addClass( 'oo-ui-fieldLayout-field' )
                .toggleClass( 'oo-ui-fieldLayout-disable', this.fieldWidget.isDisabled() )
                .append( this.fieldWidget.$element );
+
        this.setAlignment( config.align );
 };
 
@@ -6931,17 +7302,6 @@ OO.mixinClass( OO.ui.FieldLayout, OO.ui.LabelElement );
 
 /* Methods */
 
-/**
- * @inheritdoc
- */
-OO.ui.FieldLayout.prototype.getTagName = function () {
-       if ( this.fieldWidget instanceof OO.ui.InputWidget ) {
-               return 'label';
-       } else {
-               return 'div';
-       }
-};
-
 /**
  * Handle field disable events.
  *
@@ -6985,9 +7345,9 @@ OO.ui.FieldLayout.prototype.setAlignment = function ( value ) {
                }
                // Reorder elements
                if ( value === 'inline' ) {
-                       this.$element.append( this.$field, this.$label, this.$help );
+                       this.$body.append( this.$field, this.$label );
                } else {
-                       this.$element.append( this.$help, this.$label, this.$field );
+                       this.$body.append( this.$label, this.$field );
                }
                // Set classes. The following classes can be used here:
                // * oo-ui-fieldLayout-align-left
@@ -7223,15 +7583,15 @@ OO.ui.GridLayout.prototype.update = function () {
                        width = this.widths[x];
                        panel = this.panels[i];
                        dimensions = {
-                               width: Math.round( width * 100 ) + '%',
-                               height: Math.round( height * 100 ) + '%',
-                               top: Math.round( top * 100 ) + '%'
+                               width: ( width * 100 ) + '%',
+                               height: ( height * 100 ) + '%',
+                               top: ( top * 100 ) + '%'
                        };
                        // If RTL, reverse:
-                       if ( OO.ui.Element.getDir( this.$.context ) === 'rtl' ) {
-                               dimensions.right = Math.round( left * 100 ) + '%';
+                       if ( OO.ui.Element.static.getDir( this.$.context ) === 'rtl' ) {
+                               dimensions.right = ( left * 100 ) + '%';
                        } else {
-                               dimensions.left = Math.round( left * 100 ) + '%';
+                               dimensions.left = ( left * 100 ) + '%';
                        }
                        // HACK: Work around IE bug by setting visibility: hidden; if width or height is zero
                        if ( width === 0 || height === 0 ) {
@@ -7312,7 +7672,6 @@ OO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );
  * @constructor
  * @param {string} name Unique symbolic name of page
  * @param {Object} [config] Configuration options
- * @param {string} [outlineItem] Outline item widget
  */
 OO.ui.PageLayout = function OoUiPageLayout( name, config ) {
        // Configuration initialization
@@ -7323,7 +7682,7 @@ OO.ui.PageLayout = function OoUiPageLayout( name, config ) {
 
        // Properties
        this.name = name;
-       this.outlineItem = config.outlineItem || null;
+       this.outlineItem = null;
        this.active = false;
 
        // Initialization
@@ -7427,7 +7786,6 @@ OO.ui.PageLayout.prototype.setActive = function ( active ) {
  * @constructor
  * @param {Object} [config] Configuration options
  * @cfg {boolean} [continuous=false] Show all pages, one after another
- * @cfg {string} [icon=''] Symbolic icon name
  * @cfg {OO.ui.Layout[]} [items] Layouts to add
  */
 OO.ui.StackLayout = function OoUiStackLayout( config ) {
@@ -8154,7 +8512,7 @@ OO.ui.LookupInputWidget = function OoUiLookupInputWidget( input, config ) {
        this.lookupInput = input;
        this.$overlay = config.$overlay || this.$element;
        this.lookupMenu = new OO.ui.TextInputMenuSelectWidget( this, {
-               $: OO.ui.Element.getJQuery( this.$overlay ),
+               $: OO.ui.Element.static.getJQuery( this.$overlay ),
                input: this.lookupInput,
                $container: config.$container
        } );
@@ -8669,7 +9027,7 @@ OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
  */
 OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
        // Configuration initialization
-       config = $.extend( { target: '_blank' }, config );
+       config = config || {};
 
        // Parent constructor
        OO.ui.ButtonWidget.super.call( this, config );
@@ -9374,15 +9732,15 @@ OO.ui.InputWidget.prototype.setRTL = function ( isRTL ) {
  */
 OO.ui.InputWidget.prototype.setValue = function ( value ) {
        value = this.cleanUpValue( value );
+       // Update the DOM if it has changed. Note that with cleanUpValue, it
+       // is possible for the DOM value to change without this.value changing.
+       if ( this.$input.val() !== value ) {
+               this.$input.val( value );
+       }
        if ( this.value !== value ) {
                this.value = value;
                this.emit( 'change', this.value );
        }
-       // Update the DOM if it has changed. Note that with cleanUpValue, it
-       // is possible for the DOM value to change without this.value changing.
-       if ( this.$input.val() !== this.value ) {
-               this.$input.val( this.value );
-       }
        return this;
 };
 
@@ -9611,6 +9969,7 @@ OO.ui.ButtonInputWidget.prototype.onKeyPress = function ( e ) {
  *
  * @constructor
  * @param {Object} [config] Configuration options
+ * @cfg {boolean} [selected=false] Whether the checkbox is initially selected
  */
 OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
        // Parent constructor
@@ -9618,6 +9977,7 @@ OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
 
        // Initialization
        this.$element.addClass( 'oo-ui-checkboxInputWidget' );
+       this.setSelected( config.selected !== undefined ? config.selected : false );
 };
 
 /* Setup */
@@ -9637,39 +9997,41 @@ OO.ui.CheckboxInputWidget.prototype.getInputElement = function () {
 };
 
 /**
- * Get checked state of the checkbox
- *
- * @return {boolean} If the checkbox is checked
+ * @inheritdoc
  */
-OO.ui.CheckboxInputWidget.prototype.getValue = function () {
-       return this.value;
+OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
+       var widget = this;
+       if ( !this.isDisabled() ) {
+               // Allow the stack to clear so the value will be updated
+               setTimeout( function () {
+                       widget.setSelected( widget.$input.prop( 'checked' ) );
+               } );
+       }
 };
 
 /**
- * Set checked state of the checkbox
+ * Set selection state of this checkbox.
  *
- * @param {boolean} value New value
+ * @param {boolean} state Whether the checkbox is selected
+ * @chainable
  */
-OO.ui.CheckboxInputWidget.prototype.setValue = function ( value ) {
-       value = !!value;
-       if ( this.value !== value ) {
-               this.value = value;
-               this.$input.prop( 'checked', this.value );
-               this.emit( 'change', this.value );
+OO.ui.CheckboxInputWidget.prototype.setSelected = function ( state ) {
+       state = !!state;
+       if ( this.selected !== state ) {
+               this.selected = state;
+               this.$input.prop( 'checked', this.selected );
+               this.emit( 'change', this.selected );
        }
+       return this;
 };
 
 /**
- * @inheritdoc
+ * Check if this checkbox is selected.
+ *
+ * @return {boolean} Checkbox is selected
  */
-OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
-       var widget = this;
-       if ( !this.isDisabled() ) {
-               // Allow the stack to clear so the value will be updated
-               setTimeout( function () {
-                       widget.setValue( widget.$input.prop( 'checked' ) );
-               } );
-       }
+OO.ui.CheckboxInputWidget.prototype.isSelected = function () {
+       return this.selected;
 };
 
 /**
@@ -9678,14 +10040,12 @@ OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
  * Radio buttons only make sense as a set, and you probably want to use the OO.ui.RadioSelectWidget
  * class instead of using this class directly.
  *
- * This class doesn't make it possible to learn whether the radio button is selected ("pressed").
- *
  * @class
  * @extends OO.ui.InputWidget
  *
  * @constructor
  * @param {Object} [config] Configuration options
- * @param {boolean} [config.selected=false] Whether the radio button is initially selected
+ * @cfg {boolean} [selected=false] Whether the radio button is initially selected
  */
 OO.ui.RadioInputWidget = function OoUiRadioInputWidget( config ) {
        // Parent constructor
@@ -9779,6 +10139,14 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
        this.maxRows = config.maxRows !== undefined ? config.maxRows : 10;
        this.validate = null;
 
+       // Clone for resizing
+       if ( this.autosize ) {
+               this.$clone = this.$input
+                       .clone()
+                       .insertAfter( this.$input )
+                       .hide();
+       }
+
        this.setValidation( config.validate );
 
        // Events
@@ -9941,28 +10309,40 @@ OO.ui.TextInputWidget.prototype.setReadOnly = function ( state ) {
  * @chainable
  */
 OO.ui.TextInputWidget.prototype.adjustSize = function () {
-       var $clone, scrollHeight, innerHeight, outerHeight, maxInnerHeight, measurementError, idealHeight;
+       var scrollHeight, innerHeight, outerHeight, maxInnerHeight, measurementError, idealHeight;
 
        if ( this.multiline && this.autosize && this.$input.val() !== this.valCache ) {
-               $clone = this.$input.clone()
+               this.$clone
                        .val( this.$input.val() )
+                       .attr( 'rows', '' )
                        // Set inline height property to 0 to measure scroll height
-                       .css( 'height', 0 )
-                       .insertAfter( this.$input );
+                       .css( 'height', 0 );
+
+               this.$clone[0].style.display = 'block';
+
                this.valCache = this.$input.val();
-               scrollHeight = $clone[0].scrollHeight;
+
+               scrollHeight = this.$clone[0].scrollHeight;
+
                // Remove inline height property to measure natural heights
-               $clone.css( 'height', '' );
-               innerHeight = $clone.innerHeight();
-               outerHeight = $clone.outerHeight();
+               this.$clone.css( 'height', '' );
+               innerHeight = this.$clone.innerHeight();
+               outerHeight = this.$clone.outerHeight();
+
                // Measure max rows height
-               $clone.attr( 'rows', this.maxRows ).css( 'height', 'auto' ).val( '' );
-               maxInnerHeight = $clone.innerHeight();
+               this.$clone
+                       .attr( 'rows', this.maxRows )
+                       .css( 'height', 'auto' )
+                       .val( '' );
+               maxInnerHeight = this.$clone.innerHeight();
+
                // Difference between reported innerHeight and scrollHeight with no scrollbars present
                // Equals 1 on Blink-based browsers and 0 everywhere else
-               measurementError = maxInnerHeight - $clone[0].scrollHeight;
-               $clone.remove();
+               measurementError = maxInnerHeight - this.$clone[0].scrollHeight;
                idealHeight = Math.min( maxInnerHeight, scrollHeight + measurementError );
+
+               this.$clone[0].style.display = 'none';
+
                // Only apply inline height when expansion beyond natural height is needed
                if ( idealHeight > innerHeight ) {
                        // Use the difference between the inner and outer height as a buffer
@@ -10078,7 +10458,7 @@ OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
        ) );
        this.menu = new OO.ui.TextInputMenuSelectWidget( this.input, $.extend(
                {
-                       $: OO.ui.Element.getJQuery( this.$overlay ),
+                       $: OO.ui.Element.static.getJQuery( this.$overlay ),
                        widget: this,
                        input: this.input,
                        disabled: this.isDisabled()
@@ -11616,32 +11996,30 @@ OO.ui.SelectWidget.prototype.chooseItem = function ( item ) {
 /**
  * Get an item relative to another one.
  *
- * @param {OO.ui.OptionWidget} item Item to start at
- * @param {number} direction Direction to move in, -1 to look backward, 1 to move forward
+ * @param {OO.ui.OptionWidget|null} item Item to start at, null to get relative to list start
+ * @param {number} direction Direction to move in, -1 to move backward, 1 to move forward
  * @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the menu
  */
 OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction ) {
-       var inc = direction > 0 ? 1 : -1,
-               len = this.items.length,
-               index = item instanceof OO.ui.OptionWidget ?
-                       $.inArray( item, this.items ) : ( inc > 0 ? -1 : 0 ),
-               stopAt = Math.max( Math.min( index, len - 1 ), 0 ),
-               i = inc > 0 ?
-                       // Default to 0 instead of -1, if nothing is selected let's start at the beginning
-                       Math.max( index, -1 ) :
-                       // Default to n-1 instead of -1, if nothing is selected let's start at the end
-                       Math.min( index, len );
-
-       while ( len !== 0 ) {
-               i = ( i + inc + len ) % len;
-               item = this.items[i];
+       var currentIndex, nextIndex, i,
+               increase = direction > 0 ? 1 : -1,
+               len = this.items.length;
+
+       if ( item instanceof OO.ui.OptionWidget ) {
+               currentIndex = $.inArray( item, this.items );
+               nextIndex = ( currentIndex + increase + len ) % len;
+       } else {
+               // If no item is selected and moving forward, start at the beginning.
+               // If moving backward, start at the end.
+               nextIndex = direction > 0 ? 0 : len - 1;
+       }
+
+       for ( i = 0; i < len; i++ ) {
+               item = this.items[nextIndex];
                if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
                        return item;
                }
-               // Stop iterating when we've looped all the way around
-               if ( i === stopAt ) {
-                       break;
-               }
+               nextIndex = ( nextIndex + increase + len ) % len;
        }
        return null;
 };
@@ -12149,7 +12527,7 @@ OO.ui.TextInputMenuSelectWidget.prototype.toggle = function ( visible ) {
  */
 OO.ui.TextInputMenuSelectWidget.prototype.position = function () {
        var $container = this.$container,
-               pos = OO.ui.Element.getRelativePosition( $container, this.$element.offsetParent() );
+               pos = OO.ui.Element.static.getRelativePosition( $container, this.$element.offsetParent() );
 
        // Position under input
        pos.top += $container.height();
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.png
new file mode 100644 (file)
index 0000000..e10c539
Binary files /dev/null and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.png differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg
new file mode 100644 (file)
index 0000000..88e014b
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #00C697 }</style><circle cx="12" cy="12" r="6"></circle></svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.png
new file mode 100644 (file)
index 0000000..82c327a
Binary files /dev/null and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.png differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg
new file mode 100644 (file)
index 0000000..03c308d
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style><circle cx="12" cy="12" r="6"></circle></svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.png
new file mode 100644 (file)
index 0000000..3bdc8e2
Binary files /dev/null and b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.png differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg
new file mode 100644 (file)
index 0000000..a600581
--- /dev/null
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><circle cx="12" cy="12" r="6"></circle></svg>
index 7b49cb2..867c25e 100644 (file)
@@ -8,7 +8,7 @@
 // Cached access key prefix for used browser
 var cachedAccessKeyPrefix,
 
-       // Wether to use 'test-' instead of correct prefix (used for testing)
+       // Whether to use 'test-' instead of correct prefix (used for testing)
        useTestPrefix = false,
 
        // tag names which can have a label tag
index 662a688..3796b0b 100644 (file)
                                // Tanslations for conforming browser names
                                nameTranslations = [],
                                // Names of known layout engines
-                               layouts = ['gecko', 'konqueror', 'msie', 'trident', 'opera', 'webkit'],
+                               layouts = ['gecko', 'konqueror', 'msie', 'trident', 'edge', 'opera', 'webkit'],
                                // Translations for conforming layout names
                                layoutTranslations = [ ['konqueror', 'khtml'], ['msie', 'trident'], ['opera', 'presto'] ],
                                // Names of supported layout engines for version number
-                               layoutVersions = ['applewebkit', 'gecko', 'trident'],
+                               layoutVersions = ['applewebkit', 'gecko', 'trident', 'edge'],
                                // Names of known operating systems
                                platforms = ['win', 'wow64', 'mac', 'linux', 'sunos', 'solaris', 'iphone'],
                                // Translations for conforming operating system names
                                        version = match[1];
                                }
                        }
+                       // And IE 12's different lies about not being IE
+                       if ( name === 'chrome' && ( match = ua.match( /\bedge\/([0-9\.]*)/ ) ) ) {
+                               name = 'msie';
+                               version = match[1];
+                               layout = 'edge';
+                               layoutversion = parseInt( match[1], 10 );
+                       }
                        // And Amazon Silk's lies about being Android on mobile or Safari on desktop
                        if ( match = ua.match( /\bsilk\/([0-9.\-_]*)/ ) ) {
                                if ( match[1] ) {
index c4e2520..6c7b4d4 100644 (file)
         * Enable collapsible-functionality on all elements in the collection.
         *
         * - Will prevent binding twice to the same element.
-        * - Initial state is expanded by default, this can be overriden by adding class
+        * - Initial state is expanded by default, this can be overridden by adding class
         *   "mw-collapsed" to the "mw-collapsible" element.
         * - Elements made collapsible have jQuery data "mw-made-collapsible" set to true.
         * - The inner content is wrapped in a "div.mw-collapsible-content" (except for tables and lists).
index 632769b..bd6518d 100644 (file)
                                                                selText = selText.replace( /\r?\n/g, '\r\n' );
                                                                post = post.replace( /\r?\n/g, '\r\n' );
                                                        }
-                                                       if ( isSample && options.selectPeri && !options.splitlines ) {
+                                                       if ( isSample && options.selectPeri && ( !options.splitlines || ( options.splitlines && selText.indexOf( '\n' ) === -1 ) ) ) {
                                                                this.selectionStart = startPos + pre.length;
                                                                this.selectionEnd = startPos + pre.length + selText.length;
                                                        } else {
index 6b212c2..e4f4249 100644 (file)
@@ -8,16 +8,16 @@
         * @param {jQuery.Event} e
         */
        function doLivePreview( e ) {
-               var $wikiPreview, $editform, copySelectors, $copyElements, $spinner,
-                       targetUrl, postData, $previewDataHolder;
+               var isDiff, api, request, postData, copySelectors, section,
+                       $wikiPreview, $wikiDiff, $editform, $copyElements, $spinner;
 
                e.preventDefault();
 
-               // Deprecated: Use mw.hook instead
-               $( mw ).trigger( 'LivePreviewPrepare' );
-
+               isDiff = ( e.target.name === 'wpDiff' );
                $wikiPreview = $( '#wikiPreview' );
+               $wikiDiff = $( '#wikiDiff' );
                $editform = $( '#editform' );
+               section = $editform.find( '[name="wpSection"]' ).val();
 
                // Show #wikiPreview if it's hidden to be able to scroll to it
                // (if it is hidden, it's also empty, so nothing changes in the rendering)
                // Jump to where the preview will appear
                $wikiPreview[0].scrollIntoView();
 
-               // List of selectors matching elements that we will
-               // update from from the ajax-loaded preview page.
                copySelectors = [
                        // Main
                        '#firstHeading',
                        '#wikiPreview',
                        '#wikiDiff',
                        '#catlinks',
-                       '.hiddencats',
                        '#p-lang',
                        // Editing-related
                        '.templatesUsed',
                // (e.g. empty #catlinks)
                $copyElements.animate( { opacity: 0.4 }, 'fast' );
 
-               $previewDataHolder = $( '<div>' );
-               targetUrl = $editform.attr( 'action' );
-               targetUrl += targetUrl.indexOf( '?' ) !== -1 ? '&' : '?';
-               targetUrl += $.param( {
-                       debug: mw.config.get( 'debug' ),
+               api = new mw.Api();
+               postData = {
+                       action: 'parse',
                        uselang: mw.config.get( 'wgUserLanguage' ),
-                       useskin: mw.config.get( 'skin' )
-               } );
+                       title: mw.config.get( 'wgPageName' ),
+                       text: $editform.find( '#wpTextbox1' ).val(),
+                       summary: $editform.find( '#wpSummary' ).val()
+               };
 
-               // Gather all the data from the form
-               postData = $editform.formToArray();
-               postData.push( {
-                       name: e.target.name,
-                       value: ''
-               } );
+               if ( isDiff ) {
+                       $wikiPreview.hide();
 
-               // Load new preview data.
-               // TODO: This should use the action=parse API instead of loading the entire page,
-               // although that requires figuring out how to convert that raw data into proper HTML.
-               $previewDataHolder.load( targetUrl + ' ' + copySelectors.join( ',' ), postData, function () {
-                       var i, $from, $next, $parent;
+                       // First PST the input, then diff it
+                       postData.onlypst = '';
+                       request = api.post( postData );
+                       request.done( function ( response ) {
+                               var postData;
+                               postData = {
+                                       action: 'query',
+                                       indexpageids: '',
+                                       prop: 'revisions',
+                                       titles: mw.config.get( 'wgPageName' ),
+                                       rvdifftotext: response.parse.text['*'],
+                                       rvprop: ''
+                               };
+                               if ( section !== '' ) {
+                                       postData.rvsection = section;
+                               }
+                               return api.post( postData ).done( function ( result2 ) {
+                                       try {
+                                               var diffHtml = result2.query.pages[result2.query.pageids[0]]
+                                                       .revisions[0].diff['*'];
+                                               $wikiDiff.find( 'table.diff tbody' ).html( diffHtml );
+                                       } catch ( e ) {
+                                               // "result.blah is undefined" error, ignore
+                                               mw.log.warn( e );
+                                       }
+                                       $wikiDiff.show();
+                               } );
+                       } );
+               } else {
+                       $wikiDiff.hide();
+                       $.extend( postData, {
+                               pst: '',
+                               preview: '',
+                               prop: 'text|displaytitle|modules|categorieshtml|templates|langlinks|limitreporthtml'
+                       } );
+                       if ( section !== '' ) {
+                               postData.sectionpreview = '';
+                       }
+                       request = api.post( postData );
+                       request.done( function ( response ) {
+                               var li, newList, $next, $parent, $list;
+                               if ( response.parse.modules ) {
+                                       mw.loader.load( response.parse.modules.concat(
+                                               response.parse.modulescripts,
+                                               response.parse.modulestyles,
+                                               response.parse.modulemessages ) );
+                               }
+                               if ( response.parse.displaytitle ) {
+                                       $( '#firstHeading' ).html( '<span dir="auto">' + response.parse.displaytitle + '</span>' );
+                               }
+                               if ( response.parse.categorieshtml ) {
+                                       $( '#catlinks' ).replaceWith( response.parse.categorieshtml['*'] );
+                               }
+                               if ( response.parse.templates ) {
+                                       newList = [];
+                                       $.each( response.parse.templates, function ( i, template ) {
+                                               li = $( '<li>' )
+                                                       .append( $('<a>')
+                                                               .attr( {
+                                                                       'href': mw.util.getUrl( template['*'] ),
+                                                                       'class': ( template.exists !== undefined ? '' : 'new' )
+                                                               } )
+                                                               .text( template['*'] )
+                                                       );
+                                               newList.push( li );
+                                       } );
 
-                       // Copy the contents of the specified elements from the loaded page to the real page.
-                       // Also copy their class attributes.
-                       for ( i = 0; i < copySelectors.length; i++ ) {
-                               $from = $previewDataHolder.find( copySelectors[i] );
+                                       $editform.find( '.mw-editfooter-list' ).detach().empty().append( newList ).appendTo( '.templatesUsed' );
+                               }
+                               if ( response.parse.limitreporthtml ) {
+                                       $( '.limitreport' ).html( response.parse.limitreporthtml['*'] );
+                               }
+                               if ( response.parse.langlinks && mw.config.get( 'skin' ) === 'vector' ) {
+                                       newList = [];
+                                       $.each( response.parse.langlinks, function ( i, langlink ) {
+                                               li = $( '<li>' )
+                                                       .addClass( 'interlanguage-link interwiki-' + langlink.lang )
+                                                       .append( $( '<a>' )
+                                                               .attr( {
+                                                                       'href': langlink.url,
+                                                                       'title': langlink['*'] + ' - ' + langlink.langname,
+                                                                       'lang': langlink.lang,
+                                                                       'hreflang': langlink.lang
+                                                               } )
+                                                               .text( langlink.autonym )
+                                                       );
+                                               newList.push( li );
+                                       } );
+                                       $list = $( '#p-lang ul' );
+                                       $parent = $list.parent();
+                                       $list.detach().empty().append( newList ).prependTo( $parent );
+                               }
 
-                               if ( copySelectors[i] === '#wikiPreview' ) {
+                               if ( response.parse.text['*'] ) {
                                        $next = $wikiPreview.next();
                                        // If there is no next node, use parent instead.
                                        // Only query parent if needed, false otherwise.
 
                                        $wikiPreview
                                                .detach()
-                                               .empty()
-                                               .append( $from.contents() )
-                                               .attr( 'class', $from.attr( 'class' ) );
+                                               .html( response.parse.text['*'] );
 
                                        mw.hook( 'wikipage.content' ).fire( $wikiPreview );
 
                                        } else {
                                                $next.before( $wikiPreview );
                                        }
+                                       $wikiPreview.show();
 
-                               } else {
-                                       $( copySelectors[i] )
-                                               .empty()
-                                               .append( $from.contents() )
-                                               .attr( 'class', $from.attr( 'class' ) );
                                }
+                       } );
+               }
+               request.done( function ( response ) {
+                       if ( response.parse.parsedsummary ) {
+                               // TODO implement special behavior for section === 'new'
+                               $editform.find( '.mw-summary-preview' )
+                                       .empty()
+                                       .append(
+                                               mw.message( 'summary-preview' ).parse(),
+                                               ' ',
+                                               $( '<span>' ).addClass( 'comment' ).html(
+                                                       // There is no equivalent to rawParams
+                                                       mw.message( 'parentheses' ).escaped()
+                                                               .replace( '$1', response.parse.parsedsummary['*'] )
+                                               )
+                                       );
                        }
-
-                       // Deprecated: Use mw.hook instead
-                       $( mw ).trigger( 'LivePreviewDone', [copySelectors] );
-
+               } );
+               request.always( function () {
                        $spinner.remove();
                        $copyElements.animate( {
                                opacity: 1
                // have to fish and (hopefully) put them in the right place (since skins
                // can change where they are output).
 
-               if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) ) {
-                       $( '#p-tb' ).after(
-                               $( '<div>' ).attr( 'id', 'p-lang' )
+               if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) && mw.config.get( 'skin' ) === 'vector' ) {
+                       $( '.portal:last' ).after(
+                               $( '<div>' ).attr( {
+                                       'class': 'portal',
+                                       'id': 'p-lang',
+                                       'role': 'navigation',
+                                       'title': mw.msg( 'tooltip-p-lang' ),
+                                       'aria-labelledby': 'p-lang-label'
+                               } )
+                               .append( $( '<h3>' ).attr( 'id', 'p-lang-label' ).text( mw.msg( 'otherlanguages' ) ) )
+                               .append( $( '<div>' ).addClass( 'body' ).append( '<ul>' ) )
                        );
                }
 
 
                if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) {
                        $( '#wikiPreview' ).after(
-                               $( '<div>' ).attr( 'id', 'wikiDiff' )
+                               $( '<div>' )
+                                       .attr( 'id', 'wikiDiff' )
+                                       .html( '<table class="diff"><col class="diff-marker"/><col class="diff-content"/>' +
+                                               '<col class="diff-marker"/><col class="diff-content"/><tbody/></table>' )
                        );
                }
 
index 9972321..9b8a0ce 100644 (file)
@@ -3,10 +3,16 @@
  */
 ( function ( mw, $ ) {
        $( function () {
-               var api = new mw.Api(), pending = null, $form = $( '#editform' );
+               var idleTimeout = 5000,
+                       api = new mw.Api(),
+                       pending = null,
+                       $form = $( '#editform' ),
+                       $text = $form.find( '#wpTextbox1' ),
+                       data = {},
+                       timer = null;
 
                function stashEdit( token ) {
-                       var data = $form.serializeObject();
+                       data = $form.serializeObject();
 
                        pending = api.post( {
                                action: 'stashedit',
                        } );
                }
 
+               /* Has the edit body text changed since the last stashEdit() call? */
+               function isChanged() {
+                       // Normalize line endings to CRLF, like $.fn.serializeObject does.
+                       var newText = $text.val().replace( /\r?\n/g, '\r\n' );
+                       return newText !== data.wpTextbox1;
+               }
+
                function onEditChanged() {
-                       // If a stash request is already in flight, abort it, since its
-                       // payload has just been invalidated by this change.
+                       if ( !isChanged() ) {
+                               return;
+                       }
+
+                       // If a request is in progress, abort it; its payload is stale.
                        if ( pending ) {
                                pending.abort();
                        }
+
                        api.getToken( 'edit' ).then( stashEdit );
                }
 
+               function onKeyPress( e ) {
+                       // Ignore keystrokes that don't modify text, like cursor movements.
+                       // See <http://stackoverflow.com/q/2284844>.
+                       if ( e.which === 0 ) {
+                               return;
+                       }
+
+                       clearTimeout( timer );
+
+                       if ( pending ) {
+                               pending.abort();
+                       }
+
+                       timer = setTimeout( onEditChanged, idleTimeout );
+               }
+
                // We don't attempt to stash new section edits because in such cases
                // the parser output varies on the edit summary (since it determines
                // the new section's name).
@@ -37,6 +70,7 @@
                        return;
                }
 
-               $form.find( '#wpTextbox1' ).on( 'change', onEditChanged );
+               $text.on( { change: onEditChanged, keypress: onKeyPress } );
+
        } );
 }( mediaWiki, jQuery ) );
index dceae11..8b3a085 100644 (file)
@@ -86,7 +86,7 @@ $.extend( mw.language, {
         * Usage in message text: `{{gender:[gender|user object]|masculine|feminine|neutral}}`.
         * If second or third parameter are not specified, masculine is used.
         *
-        * These details may be overriden per language.
+        * These details may be overridden per language.
         *
         * @param {string} gender 'male', 'female', or anything else for neutral.
         * @param {Array} forms List of gender forms
diff --git a/resources/src/mediawiki.legacy/images/magnify-clip-ltr.png b/resources/src/mediawiki.legacy/images/magnify-clip-ltr.png
new file mode 100644 (file)
index 0000000..712b1b4
Binary files /dev/null and b/resources/src/mediawiki.legacy/images/magnify-clip-ltr.png differ
diff --git a/resources/src/mediawiki.legacy/images/magnify-clip-ltr.svg b/resources/src/mediawiki.legacy/images/magnify-clip-ltr.svg
new file mode 100644 (file)
index 0000000..4d3dcb6
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 15" width="15" height="11">
+    <g id="magnify-clip" fill="#fff" stroke="#000">
+        <path id="bigbox" d="M1.509 1.865h10.99v7.919h-10.99z"/>
+        <path id="smallbox" d="M-1.499 6.868h5.943v4.904h-5.943z"/>
+    </g>
+</svg>
diff --git a/resources/src/mediawiki.legacy/images/magnify-clip-rtl.png b/resources/src/mediawiki.legacy/images/magnify-clip-rtl.png
new file mode 100644 (file)
index 0000000..1d03a8c
Binary files /dev/null and b/resources/src/mediawiki.legacy/images/magnify-clip-rtl.png differ
diff --git a/resources/src/mediawiki.legacy/images/magnify-clip-rtl.svg b/resources/src/mediawiki.legacy/images/magnify-clip-rtl.svg
new file mode 100644 (file)
index 0000000..582e4ae
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 15" width="15" height="11">
+    <g id="magnify-clip" fill="#fff" stroke="#000">
+        <path id="bigbox" d="M9.491 1.865h-10.99v7.919h10.99z"/>
+        <path id="smallbox" d="M12.499 6.868h-5.943v4.904h5.943z"/>
+    </g>
+</svg>
index d92d3bb..c2bd5a7 100644 (file)
@@ -119,8 +119,12 @@ div.magnify a {
        /* …and replace it with the image */
        width: 15px;
        height: 11px;
-       /* @embed */
+       /* Use same SVG support hack as mediawiki.legacy's shared.css */
        background: url(images/magnify-clip-ltr.png) center center no-repeat;
+       /* @embed */
+       background-image: -webkit-linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
+       /* @embed */
+       background-image: linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
        /* Don't annoy people who copy-paste everything too much */
        -moz-user-select: none;
        -webkit-user-select: none;
index 7ced42f..d4e804a 100644 (file)
@@ -8,7 +8,7 @@
        /**
         * @class mw.Title
         *
-        * Parse titles into an object struture. Note that when using the constructor
+        * Parse titles into an object structure. Note that when using the constructor
         * directly, passing invalid titles will result in an exception. Use #newFromText to use the
         * logic directly and get null for invalid titles which is easier to work with.
         *
index bb5ddfc..abfb279 100644 (file)
         */
 
        /**
-        * A factory method to create a variation of mw.Uri with a different default location (for
-        * relative URLs, including protocol-relative URLs). Used so the library is still testable &
-        * purely functional.
+        * A factory method to create a Uri class with a default location to resolve relative URLs
+        * against (including protocol-relative URLs).
         *
         * @method
+        * @param {string|Function} documentLocation A full url, or function returning one.
+        *  If passed a function, the return value may change over time and this will be honoured. (T74334)
         * @member mw
         */
        mw.UriRelative = function ( documentLocation ) {
-               var defaultUri;
+               var getDefaultUri = ( function () {
+                       // Cache
+                       var href, uri;
+
+                       return function () {
+                               var hrefCur = typeof documentLocation === 'string' ? documentLocation : documentLocation();
+                               if ( href === hrefCur ) {
+                                       return uri;
+                               }
+                               href = hrefCur;
+                               uri = new Uri( href );
+                               return uri;
+                       };
+               }() );
 
                /**
                 * @class mw.Uri
                 *  override each other (`true`) or automagically convert them to an array (`false`).
                 */
                function Uri( uri, options ) {
+                       var prop,
+                               defaultUri = getDefaultUri();
+
                        options = typeof options === 'object' ? options : { strictMode: !!options };
                        options = $.extend( {
                                strictMode: false,
                                        this.parse( uri, options );
                                } else if ( typeof uri === 'object' ) {
                                        // Copy data over from existing URI object
-                                       for ( var prop in uri ) {
+                                       for ( prop in uri ) {
                                                // Only copy direct properties, not inherited ones
                                                if ( uri.hasOwnProperty( prop ) ) {
                                                        // Deep copy object properties
                        }
                };
 
-               defaultUri = new Uri( documentLocation );
-
                return Uri;
        };
 
        // Default to the current browsing location (for relative URLs).
-       mw.Uri = mw.UriRelative( location.href );
+       mw.Uri = mw.UriRelative( function () {
+               return location.href;
+       } );
 
 }( mediaWiki, jQuery ) );
index 6bcb87f..587f5b9 100644 (file)
                                { redirect: true }
                        )
                        .done( function ( result ) {
-                               if ( result.edit !== undefined ) {
-                                       if ( result.edit.result === 'Success' ) {
-                                               fb.displayThanks();
-                                       } else {
-                                               // unknown API result
-                                               fb.displayError( 'feedback-error1' );
-                                       }
+                               if ( result.edit.result === 'Success' ) {
+                                       fb.displayThanks();
                                } else {
-                                       // edit failed
-                                       fb.displayError( 'feedback-error2' );
+                                       // unknown API result
+                                       fb.displayError( 'feedback-error1' );
                                }
                        } )
-                       .fail( function () {
-                               // ajax request failed
-                               fb.displayError( 'feedback-error3' );
+                       .fail( function ( code, result ) {
+                               if ( code === 'http' ) {
+                                       // ajax request failed
+                                       fb.displayError( 'feedback-error3' );
+                                       mw.log.warn( 'Feedback report failed with HTTP error: ' +  result.textStatus );
+                               } else {
+                                       fb.displayError( 'feedback-error2' );
+                                       mw.log.warn( 'Feedback report failed with API error: ' +  code );
+                               }
                        } );
                },
 
index 9e11842..707a856 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * Base library for MediaWiki.
  *
- * Exposed as globally as `mediaWiki` with `mw` as shortcut.
+ * Exposed globally as `mediaWiki` with `mw` as shortcut.
  *
  * @class mw
  * @alternateClassName mediaWiki
@@ -89,7 +89,7 @@
 
        Map.prototype = {
                /**
-                * Get the value of one or multiple keys.
+                * Get the value of one or multiple keys.
                 *
                 * If called with no arguments, all values will be returned.
                 *
@@ -99,7 +99,7 @@
                 *  If selection was an array, returns an object of key/values (value is null if not found),
                 *  If selection was not passed or invalid, will return the 'values' object member (be careful as
                 *  objects are always passed by reference in JavaScript!).
-                * @return {string|Object|null} Values as a string or object, null if invalid/inexistant.
+                * @return {string|Object|null} Values as a string or object, null if invalid/inexistent.
                 */
                get: function ( selection, fallback ) {
                        var results, i;
                        }
 
                        /**
-                        * Generates an ISO8601 "basic" string from a UNIX timestamp
+                        * Convert UNIX timestamp to ISO8601 format
+                        * @param {number} timestamp UNIX timestamp
                         * @private
                         */
                        function formatVersionNumber( timestamp ) {
                        function sortDependencies( module, resolved, unresolved ) {
                                var n, deps, len, skip;
 
-                               if ( registry[module] === undefined ) {
+                               if ( !hasOwn.call( registry, module ) ) {
                                        throw new Error( 'Unknown dependency: ' + module );
                                }
 
                                // Build a list of modules which are in one of the specified states
                                for ( s = 0; s < states.length; s += 1 ) {
                                        for ( m = 0; m < modules.length; m += 1 ) {
-                                               if ( registry[modules[m]] === undefined ) {
+                                               if ( !hasOwn.call( registry, modules[m] ) ) {
                                                        // Module does not exist
                                                        if ( states[s] === 'unregistered' ) {
                                                                // OK, undefined
                                var key, value, media, i, urls, cssHandle, checkCssHandles,
                                        cssHandlesRegistered = false;
 
-                               if ( registry[module] === undefined ) {
+                               if ( !hasOwn.call( registry, module ) ) {
                                        throw new Error( 'Module has not been registered yet: ' + module );
                                } else if ( registry[module].state === 'registered' ) {
                                        throw new Error( 'Module has not been requested from the server yet: ' + module );
                                addScript( sourceLoadScript + '?' + $.param( request ) + '&*', null, async );
                        }
 
+                       /**
+                        * Resolve indexed dependencies.
+                        *
+                        * ResourceLoader uses an optimization to save space which replaces module names in
+                        * dependency lists with the index of that module within the array of module
+                        * registration data if it exists. The benefit is a significant reduction in the data
+                        * size of the startup module. This function changes those dependency lists back to
+                        * arrays of strings.
+                        *
+                        * @param {Array} modules Modules array
+                        */
+                       function resolveIndexedDependencies( modules ) {
+                               var i, iLen, j, jLen, module, dependency;
+
+                               // Expand indexed dependency names
+                               for ( i = 0, iLen = modules.length; i < iLen; i++ ) {
+                                       module = modules[i];
+                                       if ( module[2] ) {
+                                               for ( j = 0, jLen = module[2].length; j < jLen; j++ ) {
+                                                       dependency = module[2][j];
+                                                       if ( typeof dependency === 'number' ) {
+                                                               module[2][j] = modules[dependency][0];
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
                        /* Public Members */
                        return {
                                /**
                                        // Appends a list of modules from the queue to the batch
                                        for ( q = 0; q < queue.length; q += 1 ) {
                                                // Only request modules which are registered
-                                               if ( registry[queue[q]] !== undefined && registry[queue[q]].state === 'registered' ) {
+                                               if ( hasOwn.call( registry, queue[q] ) && registry[queue[q]].state === 'registered' ) {
                                                        // Prevent duplicate entries
                                                        if ( $.inArray( queue[q], batch ) === -1 ) {
                                                                batch[batch.length] = queue[q];
                                        for ( b = 0; b < batch.length; b += 1 ) {
                                                bSource = registry[batch[b]].source;
                                                bGroup = registry[batch[b]].group;
-                                               if ( splits[bSource] === undefined ) {
+                                               if ( !hasOwn.call( splits, bSource ) ) {
                                                        splits[bSource] = {};
                                                }
-                                               if ( splits[bSource][bGroup] === undefined ) {
+                                               if ( !hasOwn.call( splits[bSource], bGroup ) ) {
                                                        splits[bSource][bGroup] = [];
                                                }
                                                bSourceGroup = splits[bSource][bGroup];
                                                                prefix = modules[i].substr( 0, lastDotIndex );
                                                                suffix = modules[i].slice( lastDotIndex + 1 );
 
-                                                               bytesAdded = moduleMap[prefix] !== undefined
+                                                               bytesAdded = hasOwn.call( moduleMap, prefix )
                                                                        ? suffix.length + 3 // '%2C'.length == 3
                                                                        : modules[i].length + 3; // '%7C'.length == 3
 
                                                                        async = true;
                                                                        l = currReqBaseLength + 9;
                                                                }
-                                                               if ( moduleMap[prefix] === undefined ) {
+                                                               if ( !hasOwn.call( moduleMap, prefix ) ) {
                                                                        moduleMap[prefix] = [];
                                                                }
                                                                moduleMap[prefix].push( suffix );
                                                return true;
                                        }
 
-                                       if ( sources[id] !== undefined ) {
+                                       if ( hasOwn.call( sources, id ) ) {
                                                throw new Error( 'source already registered: ' + id );
                                        }
 
                                 * Register a module, letting the system know about it and its
                                 * properties. Startup modules contain calls to this function.
                                 *
-                                * @param {string} module Module name
+                                * When using multiple module registration by passing an array, dependencies that
+                                * are specified as references to modules within the array will be resolved before
+                                * the modules are registered.
+                                *
+                                * @param {string|Array} module Module name or array of arrays, each containing
+                                *   a list of arguments compatible with this method
                                 * @param {number} version Module version number as a timestamp (falls backs to 0)
                                 * @param {string|Array|Function} dependencies One string or array of strings of module
                                 *  names on which this module depends, or a function that returns that array.
                                 * @param {string} [skip=null] Script body of the skip function
                                 */
                                register: function ( module, version, dependencies, group, source, skip ) {
-                                       var m;
+                                       var i, len;
                                        // Allow multiple registration
                                        if ( typeof module === 'object' ) {
-                                               for ( m = 0; m < module.length; m += 1 ) {
+                                               resolveIndexedDependencies( module );
+                                               for ( i = 0, len = module.length; i < len; i++ ) {
                                                        // module is an array of module names
-                                                       if ( typeof module[m] === 'string' ) {
-                                                               mw.loader.register( module[m] );
+                                                       if ( typeof module[i] === 'string' ) {
+                                                               mw.loader.register( module[i] );
                                                        // module is an array of arrays
-                                                       } else if ( typeof module[m] === 'object' ) {
-                                                               mw.loader.register.apply( mw.loader, module[m] );
+                                                       } else if ( typeof module[i] === 'object' ) {
+                                                               mw.loader.register.apply( mw.loader, module[i] );
                                                        }
                                                }
                                                return;
                                        if ( typeof module !== 'string' ) {
                                                throw new Error( 'module must be a string, not a ' + typeof module );
                                        }
-                                       if ( registry[module] !== undefined ) {
+                                       if ( hasOwn.call( registry, module ) ) {
                                                throw new Error( 'module already registered: ' + module );
                                        }
                                        // List the module as registered
                                                throw new Error( 'templates must be an object, not a ' + typeof templates );
                                        }
                                        // Automatically register module
-                                       if ( registry[module] === undefined ) {
+                                       if ( !hasOwn.call( registry, module ) ) {
                                                mw.loader.register( module );
                                        }
                                        // Check for duplicate implementation
-                                       if ( registry[module] !== undefined && registry[module].script !== undefined ) {
+                                       if ( hasOwn.call( registry, module ) && registry[module].script !== undefined ) {
                                                throw new Error( 'module already implemented: ' + module );
                                        }
                                        // Attach components
                                        // an array of unrelated modules, whereas the modules passed to
                                        // using() are related and must all be loaded.
                                        for ( filtered = [], m = 0; m < modules.length; m += 1 ) {
-                                               module = registry[modules[m]];
-                                               if ( module !== undefined ) {
+                                               if ( hasOwn.call( registry, modules[m] ) ) {
+                                                       module = registry[modules[m]];
                                                        if ( $.inArray( module.state, ['error', 'missing'] ) === -1 ) {
                                                                filtered[filtered.length] = modules[m];
                                                        }
                                                }
                                                return;
                                        }
-                                       if ( registry[module] === undefined ) {
+                                       if ( !hasOwn.call( registry, module ) ) {
                                                mw.loader.register( module );
                                        }
                                        if ( $.inArray( state, ['ready', 'error', 'missing'] ) !== -1
                                /**
                                 * Get the version of a module.
                                 *
-                                * @param {string} module Name of module to get version for
+                                * @param {string} module Name of module
                                 * @return {string|null} The version, or null if the module (or its version) is not
                                 *  in the registry.
                                 */
                                getVersion: function ( module ) {
-                                       if ( registry[module] !== undefined && registry[module].version !== undefined ) {
-                                               return formatVersionNumber( registry[module].version );
+                                       if ( !hasOwn.call( registry, module ) || registry[module].version === undefined ) {
+                                               return null;
                                        }
-                                       return null;
+                                       return formatVersionNumber( registry[module].version );
                                },
 
                                /**
                                 * Get the state of a module.
                                 *
-                                * @param {string} module Name of module to get state for
+                                * @param {string} module Name of module
+                                * @return {string|null} The state, or null if the module (or its version) is not
+                                *  in the registry.
                                 */
                                getState: function ( module ) {
-                                       if ( registry[module] !== undefined && registry[module].state !== undefined ) {
-                                               return registry[module].state;
+                                       if ( !hasOwn.call( registry, module ) || registry[module].state === undefined ) {
+                                               return null;
                                        }
-                                       return null;
+                                       return registry[module].state;
                                },
 
                                /**
                                         * @return {string|null} Module key or null if module does not exist
                                         */
                                        getModuleKey: function ( module ) {
-                                               return typeof registry[module] === 'object' ?
+                                               return hasOwn.call( registry, module ) ?
                                                        ( module + '@' + registry[module].version ) : null;
                                        },
 
index cf56f29..0dde873 100644 (file)
                 * p-cactions (Content actions), p-personal (Personal tools),
                 * p-navigation (Navigation), p-tb (Toolbox)
                 *
-                * The first three paramters are required, the others are optional and
+                * The first three parameters are required, the others are optional and
                 * may be null. Though providing an id and tooltip is recommended.
                 *
                 * By default the new link will be added to the end of the list. To
index 6719bdd..cd5800c 100644 (file)
@@ -1,3 +1,3 @@
 /*
-!/common/
 !/.gitignore
+!/README
index d35ec26..4ed28a8 100644 (file)
@@ -48,11 +48,6 @@ $wgAutoloadClasses += array(
        'TestUser' => "$testDir/phpunit/includes/TestUser.php",
        'LessFileCompilationTest' => "$testDir/phpunit/LessFileCompilationTest.php",
 
-       # tests/phpunit/includes
-       'BlockTest' => "$testDir/phpunit/includes/BlockTest.php",
-       'RevisionStorageTest' => "$testDir/phpunit/includes/RevisionStorageTest.php",
-       'WikiPageTest' => "$testDir/phpunit/includes/WikiPageTest.php",
-
        # tests/phpunit/includes/api
        'ApiFormatTestBase' => "$testDir/phpunit/includes/api/format/ApiFormatTestBase.php",
        'ApiQueryTestBase' => "$testDir/phpunit/includes/api/query/ApiQueryTestBase.php",
index 529ab82..cf03ad1 100644 (file)
@@ -559,7 +559,7 @@ class ParserTest {
                        $parser->setTransparentTagHook( $tag, $callback );
                }
 
-               wfRunHooks( 'ParserTestParser', array( &$parser ) );
+               Hooks::run( 'ParserTestParser', array( &$parser ) );
 
                return $parser;
        }
@@ -901,7 +901,7 @@ class ParserTest {
                $this->savedGlobals = array();
 
                /** @since 1.20 */
-               wfRunHooks( 'ParserTestGlobals', array( &$settings ) );
+               Hooks::run( 'ParserTestGlobals', array( &$settings ) );
 
                foreach ( $settings as $var => $val ) {
                        if ( array_key_exists( $var, $GLOBALS ) ) {
@@ -954,7 +954,7 @@ class ParserTest {
                // Allow extensions to add to the list of tables to duplicate;
                // may be necessary if they hook into page save or other code
                // which will require them while running tests.
-               wfRunHooks( 'ParserTestTables', array( &$tables ) );
+               Hooks::run( 'ParserTestTables', array( &$tables ) );
 
                return $tables;
        }
index 39129cb..c7fc380 100644 (file)
@@ -16,7 +16,7 @@
 # cat           add category links
 # ill           add inter-language links
 # subpage       enable subpages (disabled by default)
-# noxml         don't check for XML well formdness
+# noxml         don't check for XML well-formedness
 # title=[[XXX]] run test using article title XXX
 # language=XXX  set content language to XXX for this test
 # variant=XXX   set the variant of language for this test (eg zh-tw)
@@ -538,7 +538,6 @@ Italics and bold: 2-quote opening sequence: (2,2)
 </p>
 !!end
 
-
 !! test
 Italics and bold: 2-quote opening sequence: (2,3)
 !! options
@@ -550,18 +549,16 @@ parsoid=wt2html
 </p>
 !!end
 
-
 # same html as previous, but wikitext adjusted to match parsoid html2wt
 !! test
 Italics and bold: 2-quote opening sequence: (2,3) w/ nowiki
 !! wikitext
-''<nowiki>foo'</nowiki>''
+''foo'<nowiki/>''
 !! html
 <p><i>foo'</i>
 </p>
 !! end
 
-
 !! test
 Italics and bold: 2-quote opening sequence: (2,4)
 !! options
@@ -573,18 +570,16 @@ parsoid=wt2html
 </p>
 !!end
 
-
 # same html as previous, but wikitext adjusted to match parsoid html2wt
 !! test
 Italics and bold: 2-quote opening sequence: (2,4) w/ nowiki
 !! wikitext
-''<nowiki>foo''</nowiki>''
+''foo<nowiki>''</nowiki>''
 !! html
 <p><i>foo''</i>
 </p>
 !! end
 
-
 # The PHP parser strips the empty tags out for giggles; parsoid doesn't.
 !! test
 Italics and bold: 2-quote opening sequence: (2,5)
@@ -620,13 +615,24 @@ Italics and bold: 2-quote opening sequence: (2,5+3) w/ nowiki
 
 !! test
 Italics and bold: 3-quote opening sequence: (3,2)
+!! options
+parsoid=wt2html
 !! wikitext
 '''foo''
-!! html
+!! html/*
 <p>'<i>foo</i>
 </p>
 !!end
 
+# same html as previous, but wikitext adjusted to match parsoid html2wt
+!! test
+Italics and bold: 3-quote opening sequence: (3,2) w/ nowiki
+!! wikitext
+'<nowiki/>''foo''
+!! html
+<p>'<i>foo</i>
+</p>
+!!end
 
 !! test
 Italics and bold: 3-quote opening sequence: (3,3)
@@ -637,7 +643,6 @@ Italics and bold: 3-quote opening sequence: (3,3)
 </p>
 !!end
 
-
 !! test
 Italics and bold: 3-quote opening sequence: (3,4)
 !! options
@@ -649,18 +654,16 @@ parsoid=wt2html
 </p>
 !!end
 
-
 # same html as previous, but wikitext adjusted to match parsoid html2wt
 !! test
 Italics and bold: 3-quote opening sequence: (3,4) w/ nowiki
 !! wikitext
-'''<nowiki>foo'</nowiki>'''
+'''foo'<nowiki/>'''
 !! html
 <p><b>foo'</b>
 </p>
 !! end
 
-
 # The PHP parser strips the empty tags out for giggles; parsoid doesn't.
 !! test
 Italics and bold: 3-quote opening sequence: (3,5)
@@ -705,7 +708,6 @@ parsoid=wt2html
 </p>
 !!end
 
-
 # same html as previous, but wikitext adjusted to match parsoid html2wt
 !! test
 Italics and bold: 4-quote opening sequence: (4,2) w/ nowiki
@@ -716,16 +718,26 @@ Italics and bold: 4-quote opening sequence: (4,2) w/ nowiki
 </p>
 !! end
 
-
 !! test
 Italics and bold: 4-quote opening sequence: (4,3)
+!! options
+parsoid=wt2html
 !! wikitext
 ''''foo'''
-!! html
+!! html/*
 <p>'<b>foo</b>
 </p>
 !!end
 
+# same html as previous, but wikitext adjusted to match parsoid html2wt
+!! test
+Italics and bold: 4-quote opening sequence: (4,3) w/ nowiki
+!! wikitext
+'<nowiki/>'''foo'''
+!! html
+<p>'<b>foo</b>
+</p>
+!!end
 
 !! test
 Italics and bold: 4-quote opening sequence: (4,4)
@@ -738,18 +750,16 @@ parsoid=wt2html
 </p>
 !!end
 
-
 # same html as previous, but wikitext adjusted to match parsoid html2wt
 !! test
 Italics and bold: 4-quote opening sequence: (4,4) w/ nowiki
 !! wikitext
-''''<nowiki>foo'</nowiki>'''
+'<nowiki/>'''foo'<nowiki/>'''
 !! html
 <p>'<b>foo'</b>
 </p>
 !! end
 
-
 # The PHP parser strips the empty tags out for giggles; parsoid doesn't.
 !! test
 Italics and bold: 4-quote opening sequence: (4,5)
@@ -769,7 +779,7 @@ parsoid=wt2html
 !! test
 Italics and bold: 4-quote opening sequence: (4,5+2) w/ nowiki
 !! wikitext
-''''foo'''''<nowiki/>''
+'<nowiki/>'''foo'''''<nowiki/>''
 !! html/php
 <p>'<b>foo</b>
 </p>
@@ -794,7 +804,6 @@ parsoid=wt2html
 </p>
 !!end
 
-
 # same html as previous, but wikitext adjusted to match parsoid html2wt
 # skipping wt2html and html2html because it wants to put <i> before <b>
 !! test
@@ -819,7 +828,6 @@ parsoid=wt2html
 </p>
 !!end
 
-
 # same html as previous, but wikitext adjusted to match parsoid html2wt
 !! test
 Italics and bold: 5-quote opening sequence: (5,3+2)
@@ -830,7 +838,6 @@ Italics and bold: 5-quote opening sequence: (5,3+2)
 </p>
 !! end
 
-
 !! test
 Italics and bold: 5-quote opening sequence: (5,4)
 !! options
@@ -842,18 +849,16 @@ parsoid=wt2html
 </p>
 !!end
 
-
 # same html as previous, but wikitext adjusted to match parsoid html2wt
 !! test
 Italics and bold: 5-quote opening sequence: (5,4+2) w/ nowiki
 !! wikitext
-'''''<nowiki>foo'</nowiki>'''''
+'''''foo'<nowiki/>'''''
 !! html
 <p><i><b>foo'</b></i>
 </p>
 !! end
 
-
 !! test
 Italics and bold: 5-quote opening sequence: (5,5)
 !! wikitext
@@ -882,7 +887,7 @@ parsoid=wt2html
 !! test
 Italics and bold: multiple quote sequences: (2,4,2+3) w/ nowiki
 !! wikitext
-''<nowiki>foo'</nowiki>'''bar'''''
+''foo'<nowiki/>'''bar'''''
 !! html
 <p><i>foo'<b>bar</b></i>
 </p>
@@ -905,7 +910,7 @@ parsoid=wt2html
 !! test
 Italics and bold: multiple quote sequences: (2,4,3+2) w/ nowiki
 !! wikitext
-''<nowiki>foo'</nowiki>'''bar'''''
+''foo'<nowiki/>'''bar'''''
 !! html
 <p><i>foo'<b>bar</b></i>
 </p>
@@ -928,7 +933,7 @@ parsoid=wt2html
 !! test
 Italics and bold: multiple quote sequences: (2,4,4+2) w/ nowiki
 !! wikitext
-''<nowiki>foo'</nowiki>'''<nowiki>bar'</nowiki>'''''
+''foo'<nowiki/>'''bar'<nowiki/>'''''
 !! html
 <p><i>foo'<b>bar'</b></i>
 </p>
@@ -1030,14 +1035,11 @@ parsoid=wt2html
 
 
 # same html as previous, but wikitext adjusted to match parsoid html2wt
-# add 'parsoid' option to use 'parsoid' normalization of the placeholder
 !! test
 Italics and bold: other quote tests: (3,2,3+2+2,2)
-!! options
-parsoid
 !! wikitext
 '''this is about ''foo'''''<nowiki/>''s family''
-!! html/*
+!! html
 <p><b>this is about <i>foo</i></b><i>s family</i>
 </p>
 !! end
@@ -1046,8 +1048,20 @@ parsoid
 !! test
 Italics and bold: other quote tests: (3,2,3,3)
 !! options
+parsoid=wt2html
 !! wikitext
 '''this is about ''foo'''s family'''
+!! html/*
+<p>'<i>this is about </i>foo<b>s family</b>
+</p>
+!!end
+
+
+# same html as previous, but wikitext adjusted to match parsoid html2wt
+!! test
+Italics and bold: other quote tests: (3,2,3,3) w/ nowiki
+!! wikitext
+'<nowiki/>''this is about ''foo'''s family'''
 !! html
 <p>'<i>this is about </i>foo<b>s family</b>
 </p>
@@ -1776,7 +1790,7 @@ b</div>
 ## of eager output of buffered tokens in the p-wrapper. But, I'm going to ignore
 ## them for now.
 !! test
-P-wrapping should leave sol-transparent tags outside p-tags where possible
+1. P-wrapping should leave sol-transparent tags outside p-tags where possible
 !! options
 parsoid=wt2html
 !! wikitext
@@ -1788,6 +1802,16 @@ a [[Category:A1]] [[Category:A2]]
 <link href="Category:A1"/> <link href="Category:A2"/> <link href="Category:A3"/> <link href="Category:A4"/>
 !! end
 
+!! test
+2. P-wrapping should leave sol-transparent tags outside p-tags where possible
+!! options
+parsoid=wt2html
+!! wikitext
+[[Category:A1]]a
+!! html/parsoid
+<link href="Category:A1"/><p>a</p>
+!! end
+
 ###
 ### Preformatted text
 ###
@@ -2244,7 +2268,8 @@ parsoid=wt2html
 <table><pre></pre></table>
 
 !! html/parsoid
-<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&lt;pre &lt;pre>x&lt;/pre>"}},"i":0}}]}'>&lt;pre </p><pre>x</pre>
+<pre about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"a":{"&lt;pre":null},"sa":{"&lt;pre":""},"stx":"html","pi":[[{"k":"1","spc":["","","",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&lt;pre &lt;pre>x&lt;/pre>"}},"i":0}}]}'>x</pre>
+
 
 <p>&lt;pre </p>
 
@@ -2423,6 +2448,41 @@ Templates: Handle comments in the target
 <p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo"}},"i":0}}]}'>foo</p>
 !!end
 
+!! test
+Templates: Handle comments in parameter names (bug 67657)
+!! wikitext
+{{echo|1
+<!-- should be ignored -->
+=foo}}
+
+{{echo|
+<!-- should be ignored -->
+1 = foo}}
+
+{{echo|1<!-- should be ignored --> = foo}}
+
+{{echo|<!-- should be ignored -->1 = foo}}
+!!html/parsoid
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"1\n&lt;!-- should be ignored -->"}}},"i":0}}]}'>foo</p>
+
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"&lt;!-- should be ignored -->\n1"}}},"i":0}}]}'>foo</p>
+
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"1&lt;!-- should be ignored -->"}}},"i":0}}]}'>foo</p>
+
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"&lt;!-- should be ignored -->1"}}},"i":0}}]}'>foo</p>
+!!end
+
+!! test
+Templates: Other wikitext in parameter names (bug 67657)
+!! wikitext
+{{echo|''1''=foo}}
+!!html/parsoid
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"&#39;&#39;1&#39;&#39;":{"wt":"foo"}},"i":0}}]}'>{{{1}}}</p>
+!!html/php
+<p>{{{1}}}
+</p>
+!!end
+
 #--------------------------------------------------------------------
 # Transclusion parameter escaping tests
 #--------------------------------------------------------------------
@@ -4099,6 +4159,46 @@ External links: with no contents
 <p><a rel="mw:ExtLink" href="http://en.wikipedia.org/wiki/Foo" title="wikipedia:Foo"><span>Bar</span></a></p>
 !! end
 
+!! test
+External links: Free with trailing punctuation
+!! wikitext
+http://example.com,
+http://example.com;
+http://example.com\
+http://example.com.
+http://example.com:
+http://example.com!
+http://example.com?
+http://example.com)
+http://example.com/url_with_(brackets)
+!! html
+<p><a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>,
+<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>;
+<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>\
+<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>.
+<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>:
+<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>!
+<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>?
+<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>)
+<a rel="nofollow" class="external free" href="http://example.com/url_with_(brackets)">http://example.com/url_with_(brackets)</a>
+</p>
+!! end
+
+!! test
+External links: No preceding word characters allowed (bug 65278)
+!! wikitext
+NOPEhttp://example.com
+N0http://example.com
+ok:http://example.com
+ok-http://example.com
+!! html
+<p>NOPEhttp://example.com
+N0http://example.com
+ok:<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>
+ok-<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>
+</p>
+!! end
+
 !! test
 External image
 !! wikitext
@@ -5440,6 +5540,9 @@ Template-generated table cell attributes and cell content
 {|
 |{{table_attribs}}
 | {{table_attribs}}
+| <!--foo--> <!--bar--> <!--baz--> {{table_attribs}}
+|align=center {{table_attribs}}
+| <!--foo--> align=center <!--bar--> {{table_attribs}}
 |}
 !! html
 <table>
@@ -5447,26 +5550,18 @@ Template-generated table cell attributes and cell content
 <td style="color: red"> Foo
 </td>
 <td style="color: red"> Foo
-</td></tr></table>
-
-!! end
-
-!! test
-Template-generated table cell attributes and cell content (2)
-!! wikitext
-{|
-|align=center {{table_attribs}}
-|}
-!! html
-<table>
-<tr>
+</td>
+<td style="color: red"> Foo
+</td>
+<td align="center" style="color: red"> Foo
+</td>
 <td align="center" style="color: red"> Foo
 </td></tr></table>
 
 !! end
 
 !! test
-Template-generated table cell attributes and cell content (3)
+Template-generated table cell attributes and cell content (2)
 !! wikitext
 {|
 |align=center {{table_cells}}
@@ -5639,6 +5734,68 @@ Build table with {{!}}
 
 !! end
 
+!! test
+Build table with pipe as data
+!! wikitext
+{| class="wikitable"
+! header
+! second header
+|- style="color:red;"
+| data || style="color:red;" | second data
+|-
+| style="color:red;" | data with | || style="color:red;" | second data with |
+|-
+|| data with | ||| second data with |
+|}
+!! html
+<table class="wikitable">
+<tr>
+<th> header
+</th>
+<th> second header
+</th></tr>
+<tr style="color:red;">
+<td> data </td>
+<td style="color:red;"> second data
+</td></tr>
+<tr>
+<td style="color:red;"> data with | </td>
+<td style="color:red;"> second data with |
+</td></tr>
+<tr>
+<td> data with | </td>
+<td> second data with |
+</td></tr></table>
+
+!! end
+
+!! test
+Build table with wikilink
+!! wikitext
+{| class="wikitable"
+! header || second header
+|- style="color:red;"
+| data [[Main Page|linktext]] || second data [[Main Page|linktext]]
+|-
+| data || second data [[Main Page|link|text with pipe]]
+|}
+!! html
+<table class="wikitable">
+<tr>
+<th> header </th>
+<th> second header
+</th></tr>
+<tr style="color:red;">
+<td> data <a href="/wiki/Main_Page" title="Main Page">linktext</a> </td>
+<td> second data <a href="/wiki/Main_Page" title="Main Page">linktext</a>
+</td></tr>
+<tr>
+<td> data </td>
+<td> second data <a href="/wiki/Main_Page" title="Main Page">link|text with pipe</a>
+</td></tr></table>
+
+!! end
+
 # The expected HTML structure in this test is debatable. The PHP parser does
 # not parse this kind of table at all. The main focus for Parsoid is on
 # round-tripping, so this output is ok for now. TODO: revisit!
@@ -6310,7 +6467,7 @@ Link containing double-single-quotes '' in text embedded in italics (bug 4598 sa
 !! test
 Link with double quotes in title part (literal) and alternate part (interpreted)
 !! wikitext
-[[File:Denys Savchenko ''Pentecoste''.jpg]]
+[[File:Denys_Savchenko_''Pentecoste''.jpg]]
 
 [[''Pentecoste'']]
 
@@ -6324,7 +6481,7 @@ Link with double quotes in title part (literal) and alternate part (interpreted)
 </p><p><a href="/index.php?title=%27%27Pentecoste%27%27&amp;action=edit&amp;redlink=1" class="new" title="''Pentecoste'' (page does not exist)"><i>Pentecoste</i></a>
 </p>
 !! html/parsoid
-<meta typeof="mw:Placeholder"/>
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="./File:Denys_Savchenko_''Pentecoste''.jpg"><img resource="./File:Denys_Savchenko_''Pentecoste''.jpg" src="./Special:FilePath/Denys_Savchenko_''Pentecoste''.jpg" height="220" width="220"/></a></span></p>
 <p><a rel="mw:WikiLink" href="''Pentecoste''" title="''Pentecoste''">''Pentecoste''</a></p>
 <p><a rel="mw:WikiLink" href="''Pentecoste''" title="''Pentecoste''">Pentecoste</a></p>
 <p><a rel="mw:WikiLink" href="''Pentecoste''" title="''Pentecoste''"><i>Pentecoste</i></a></p>
@@ -6334,15 +6491,20 @@ Link with double quotes in title part (literal) and alternate part (interpreted)
 Broken image links with HTML captions (bug 39700)
 !! wikitext
 [[File:Nonexistent|<script></script>]]
-[[File:Nonexistent|100px|<script></script>]]
+[[File:Nonexistent|100x100px|<script></script>]]
 [[File:Nonexistent|&lt;]]
 [[File:Nonexistent|a<i>b</i>c]]
-!! html
+!! html/php
 <p><a href="/index.php?title=Special:Upload&amp;wpDestFile=Nonexistent" class="new" title="File:Nonexistent">&lt;script&gt;&lt;/script&gt;</a>
 <a href="/index.php?title=Special:Upload&amp;wpDestFile=Nonexistent" class="new" title="File:Nonexistent">&lt;script&gt;&lt;/script&gt;</a>
 <a href="/index.php?title=Special:Upload&amp;wpDestFile=Nonexistent" class="new" title="File:Nonexistent">&lt;</a>
 <a href="/index.php?title=Special:Upload&amp;wpDestFile=Nonexistent" class="new" title="File:Nonexistent">abc</a>
 </p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&lt;script>&lt;/script>"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span>
+<span typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&lt;script>&lt;/script>"}'><a href="./File:Nonexistent" data-parsoid='{"a":{"href":"./File:Nonexistent"},"sa":{}}'><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="100" width="100"/></a></span>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&amp;lt;"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"a&lt;i>b&lt;/i>c"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span></p>
 !! end
 
 !! test
@@ -6916,6 +7078,8 @@ parsoid=wt2html,wt2wt,html2html
 
 !! test
 Interlanguage link
+!! options
+parsoid=wt2html,wt2wt,html2html
 !! wikitext
 Blah blah blah
 [[zh:Chinese]]
@@ -6944,6 +7108,8 @@ Blah blah blah
 
 !! test
 Double interlanguage link
+!! options
+parsoid=wt2html,wt2wt,html2html
 !! wikitext
 Blah blah blah
 [[es:Spanish]]
@@ -6959,17 +7125,23 @@ Blah blah blah
 
 !! test
 Interlanguage link variations
+!! options
+parsoid=wt2html,wt2wt,html2html
 !! wikitext
 Blah blah blah
 [[   es :Spanish]]
 [[ ZH :Chinese]]
+[[es:Foo_bar]]
+[[es:Foo bar]]
 !! html/php
 <p>Blah blah blah
 </p>
 !! html/parsoid
 <p>Blah blah blah</p>
-<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Spanish" data-parsoid='{"stx":"simple","a":{"href":"http://es.wikipedia.org/wiki/Spanish"},"sa":{"href":"   es :Spanish"}}'/>
-<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese" data-parsoid='{"stx":"simple","a":{"href":"http://zh.wikipedia.org/wiki/Chinese"},"sa":{"href":" ZH :Chinese"}}'/>
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Spanish" />
+<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese" />
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Foo_bar" />
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Foo_bar" />
 !! end
 
 !! test
@@ -7373,6 +7545,8 @@ Failing to transform badly formed HTML into correct XHTML
 </p>
 !!end
 
+## FIXME: Is Parsoid's acceptance of self-closing html-tags
+## a feature or a bug? See https://phabricator.wikimedia.org/T76962
 !! test
 Handling html with a div self-closing tag
 !! wikitext
@@ -7382,7 +7556,7 @@ Handling html with a div self-closing tag
 <div title=bar />
 <div title=bar/>
 <div title=bar/ >
-!! html
+!! html/php
 <p>&lt;div title /&gt;
 &lt;div title/&gt;
 </p>
@@ -7393,6 +7567,13 @@ Handling html with a div self-closing tag
 <div title="bar/"></div>
 </div>
 
+!! html/parsoid
+<div title="" data-parsoid='{"stx":"html","selfClose":true}'></div>
+<div title="" data-parsoid='{"stx":"html","selfClose":true}'></div>
+<div title="" data-parsoid='{"stx":"html","selfClose":true,"brokenHTMLTag":true}'></div>
+<div title="bar" data-parsoid='{"stx":"html","selfClose":true}'></div>
+<div title="bar" data-parsoid='{"stx":"html","selfClose":true}'></div>
+<div title="bar/" data-parsoid='{"stx":"html","autoInsertedEnd":true}'></div>
 !! end
 
 !! test
@@ -7415,7 +7596,7 @@ Handling html with a br self-closing tag
 !! html/parsoid
 <p><br title="" />
 <br title="" />
-<br />
+<br title="" />
 <br title="bar" />
 <br title="bar" />
 <br title="bar/" />
@@ -8720,6 +8901,15 @@ RFC 822
 </p>
 !! end
 
+!! test
+Magic links: RFC (bug 65278)
+!! wikitext
+This is RFC 822 but thisRFC 822 is not RFC 822linked.
+!! html
+<p>This is <a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc822">RFC 822</a> but thisRFC 822 is not RFC 822linked.
+</p>
+!! end
+
 !! test
 Magic links: ISBN (bug 1937)
 !! wikitext
@@ -8729,6 +8919,15 @@ ISBN 0-306-40615-2
 </p>
 !! end
 
+!! test
+Magic links: ISBN (bug 65278)
+!! wikitext
+This is ISBN 978-0-316-09811-3 but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked.
+!! html
+<p>This is <a href="/wiki/Special:BookSources/9780316098113" class="internal mw-magiclink-isbn">ISBN 978-0-316-09811-3</a> but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked.
+</p>
+!! end
+
 !! test
 Magic links: PMID incorrectly converts space to underscore
 !! wikitext
@@ -8738,6 +8937,15 @@ PMID 1234
 </p>
 !! end
 
+!! test
+Magic links: PMID (bug 65278)
+!! wikitext
+This is PMID 1234 but thisPMID 1234 is not PMID 1234linked.
+!! html
+<p>This is <a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a> but thisPMID 1234 is not PMID 1234linked.
+</p>
+!! end
+
 ###
 ### Templates
 ####
@@ -8963,8 +9171,7 @@ Template with complex template as argument
 !! test
 Template with thumb image (with link in description)
 !! wikitext
-{{paramtest|
-  param =[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]}}
+{{paramtest|param =[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]}}
 !! html/php
 This is a test template with parameter <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&amp;wpDestFile=Noimage.png" class="new" title="File:Noimage.png">File:Noimage.png</a>  <div class="thumbcaption"><a href="/index.php?title=No_link&amp;action=edit&amp;redlink=1" class="new" title="No link (page does not exist)">link</a> <a href="/index.php?title=No_link&amp;action=edit&amp;redlink=1" class="new" title="No link (page does not exist)">caption</a></div></div></div>
 
@@ -8975,6 +9182,8 @@ This is a test template with parameter <div class="thumb tright"><div class="thu
 <div class="thumbcaption"><a href="/index.php?title=No_link&amp;action=edit&amp;redlink=1" class="new" title="No link (page does not exist)">link</a> <a href="/index.php?title=No_link&amp;action=edit&amp;redlink=1" class="new" title="No link (page does not exist)">caption</a></div>
 </div>
 </div>
+!! html/parsoid
+<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"paramtest","href":"./Template:Paramtest"},"params":{"param":{"wt":"[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]"}},"i":0}}]}'>This is a test template with parameter </p><figure class="mw-default-size" typeof="mw:Error mw:Image/Thumb" about="#mwt1" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="./File:Noimage.png" ><img resource="./File:Noimage.png" src="./Special:FilePath/Noimage.png" height="220" width="220"/></a><figcaption><a rel="mw:WikiLink" href="./No_link" title="No link">link</a> <a rel="mw:WikiLink" href="./No_link" title="No link">caption</a></figcaption></figure>
 !! end
 
 !! article
@@ -11095,6 +11304,15 @@ thumbsize=220
 </figcaption></figure>
 !! end
 
+!! test
+Titles in unlinked images (T23454)
+!! wikitext
+[[File:Foobar.jpg|link=|stuff]]
+!! html/php
+<p><img alt="stuff" src="http://example.com/images/3/3a/Foobar.jpg" title="stuff" width="1941" height="220" />
+</p>
+!! end
+
 !! test
 Link with empty target
 !! wikitext
@@ -12067,11 +12285,13 @@ File:Barfoo.jpg
 #REDIRECT [[File:Barfoo.jpg]]
 !! endarticle
 
+# FIXME: Parsoid should run this test -- but we'd need to teach the
+# mockAPI about the redirected Barfoo.jpg image.
 !! test
 Redirected image
 !! wikitext
 [[Image:Barfoo.jpg]]
-!! html
+!! html/php
 <p><a href="/wiki/File:Barfoo.jpg" title="File:Barfoo.jpg">File:Barfoo.jpg</a>
 </p>
 !! end
@@ -12081,10 +12301,12 @@ Missing image with uploads disabled
 !! options
 wgEnableUploads=0
 !! wikitext
-[[Image:Foobaz.jpg]]
-!! html
+[[File:Foobaz.jpg]]
+!! html/php
 <p><a href="/wiki/File:Foobaz.jpg" title="File:Foobaz.jpg">File:Foobaz.jpg</a>
 </p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="File:Foobaz.jpg"><img resource="./File:Foobaz.jpg" src="./Special:FilePath/Foobaz.jpg" height="220" width="220"/></a></span></p>
 !! end
 
 # Parsoid-specific testing for images
@@ -12323,7 +12545,12 @@ subpage title=[[Subpage test]]
 </p>
 !! end
 
-# TODO: make this PHP-parser compatible!
+!! article
+Subpage test/1/2/subpage
+!! text
+blah
+!! endarticle
+
 !! test
 Relative subpage noslash link
 !! options
@@ -12333,8 +12560,12 @@ subpage title=[[Subpage test/1/2/3/4]]
 [[../../subpage/]]
 
 [[../../subpage]]
-!! html
-<p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage/" title="Subpage test/1/2/subpage/">subpage</a></p>
+!! html/php
+<p><a href="/wiki/Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">subpage</a>
+</p><p><a href="/wiki/Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">Subpage test/1/2/subpage</a>
+</p>
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">subpage</a></p>
 <p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">Subpage_test/1/2/subpage</a></p>
 !! end
 
@@ -13671,19 +13902,23 @@ Media link to nonexistent file (bug 1702)
 !! test
 Image link to nonexistent file (bug 1850 - good)
 !! wikitext
-[[Image:No such.jpg]]
-!! html
+[[File:No_such.jpg]]
+!! html/php
 <p><a href="/index.php?title=Special:Upload&amp;wpDestFile=No_such.jpg" class="new" title="File:No such.jpg">File:No such.jpg</a>
 </p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="File:No_such.jpg"><img resource="./File:No_such.jpg" src="./Special:FilePath/No_such.jpg" height="220" width="220"/></a></span></p>
 !! end
 
 !! test
 :Image link to nonexistent file (bug 1850 - bad)
 !! wikitext
 [[:Image:No such.jpg]]
-!! html
+!! html/php
 <p><a href="/index.php?title=File:No_such.jpg&amp;action=edit&amp;redlink=1" class="new" title="File:No such.jpg (page does not exist)">Image:No such.jpg</a>
 </p>
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="./File:No_such.jpg" title="File:No such.jpg">Image:No such.jpg</a></p>
 !! end
 
 
@@ -15042,7 +15277,7 @@ Fuzz testing: image with bogus manual thumbnail
 <div class="thumb tright"><div class="thumbinner" style="width:182px;">Error creating thumbnail:   <div class="thumbcaption"></div></div></div>
 
 !! html/parsoid
-<meta typeof="mw:Placeholder" data-parsoid='{"src":"[[Image:foobar.jpg|thumbnail= ]]","optList":[{"ck":"manualthumb","ak":"thumbnail= "}]}'/>
+<figure class="mw-default-size" typeof="mw:Error mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"manualthumb","ak":"thumbnail= "}],"dsr":[0,32,2,2]}' data-mw='{"errors":[{"key":"missing-thumbnail","message":"This thumbnail does not exist.","params":{"name":""}}],"thumb":""}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{},"dsr":[2,30,null,null]}'><img resource="./File:Foobar.jpg" src="./Special:FilePath/" height="220" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"220"},"sa":{"resource":"Image:foobar.jpg"}}'/></a></figure>
 !!end
 
 !! test
@@ -16248,8 +16483,8 @@ image4    |300px| centre
 Gallery (with options)
 !! wikitext
 <gallery widths='70px' heights='40px' perrow='2' caption='Foo [[Main Page]]' >
-File:Nonexistant.jpg|caption
-File:Nonexistant.jpg
+File:Nonexistent.jpg|caption
+File:Nonexistent.jpg
 image:foobar.jpg|some '''caption''' [[Main Page]]
 image:foobar.jpg
 image:foobar.jpg|Blabla|alt=This is a foo-bar.|blabla.
@@ -16258,14 +16493,14 @@ image:foobar.jpg|Blabla|alt=This is a foo-bar.|blabla.
 <ul class="gallery mw-gallery-traditional" style="max-width: 226px;_width: 226px;">
        <li class='gallerycaption'>Foo <a href="/wiki/Main_Page" title="Main Page">Main Page</a></li>
                <li class="gallerybox" style="width: 105px"><div style="width: 105px">
-                       <div class="thumb" style="height: 70px;">Nonexistant.jpg</div>
+                       <div class="thumb" style="height: 70px;">Nonexistent.jpg</div>
                        <div class="gallerytext">
 <p>caption
 </p>
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 105px"><div style="width: 105px">
-                       <div class="thumb" style="height: 70px;">Nonexistant.jpg</div>
+                       <div class="thumb" style="height: 70px;">Nonexistent.jpg</div>
                        <div class="gallerytext">
                        </div>
                </div></li>
@@ -16354,25 +16589,25 @@ File:foobar.jpg|{{Test|unamedParam|alt=param}}|alt=galleryalt
 gallery (with showfilename option)
 !! wikitext
 <gallery showfilename>
-File:Nonexistant.jpg|caption
-File:Nonexistant.jpg
+File:Nonexistent.jpg|caption
+File:Nonexistent.jpg
 image:foobar.jpg|some '''caption''' [[Main Page]]
 File:Foobar.jpg
 </gallery>
 !! html
 <ul class="gallery mw-gallery-traditional">
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="height: 150px;">Nonexistant.jpg</div>
+                       <div class="thumb" style="height: 150px;">Nonexistent.jpg</div>
                        <div class="gallerytext">
-<p><a href="/wiki/File:Nonexistant.jpg" title="File:Nonexistant.jpg">Nonexistant.jpg</a><br />
+<p><a href="/wiki/File:Nonexistent.jpg" title="File:Nonexistent.jpg">Nonexistent.jpg</a><br />
 caption
 </p>
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="height: 150px;">Nonexistant.jpg</div>
+                       <div class="thumb" style="height: 150px;">Nonexistent.jpg</div>
                        <div class="gallerytext">
-<p><a href="/wiki/File:Nonexistant.jpg" title="File:Nonexistant.jpg">Nonexistant.jpg</a><br />
+<p><a href="/wiki/File:Nonexistent.jpg" title="File:Nonexistent.jpg">Nonexistent.jpg</a><br />
 </p>
                        </div>
                </div></li>
@@ -16399,20 +16634,20 @@ some <b>caption</b> <a href="/wiki/Main_Page" title="Main Page">Main Page</a>
 Gallery (with namespace-less filenames)
 !! wikitext
 <gallery>
-File:Nonexistant.jpg
-Nonexistant.jpg
+File:Nonexistent.jpg
+Nonexistent.jpg
 image:foobar.jpg
 foobar.jpg
 </gallery>
 !! html
 <ul class="gallery mw-gallery-traditional">
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="height: 150px;">Nonexistant.jpg</div>
+                       <div class="thumb" style="height: 150px;">Nonexistent.jpg</div>
                        <div class="gallerytext">
                        </div>
                </div></li>
                <li class="gallerybox" style="width: 155px"><div style="width: 155px">
-                       <div class="thumb" style="height: 150px;">Nonexistant.jpg</div>
+                       <div class="thumb" style="height: 150px;">Nonexistent.jpg</div>
                        <div class="gallerytext">
                        </div>
                </div></li>
@@ -16625,9 +16860,11 @@ Image with page parameter
 djvu
 !! wikitext
 [[File:LoremIpsum.djvu|page=2]]
-!! html
+!! html/php
 <p><a href="/index.php?title=File:LoremIpsum.djvu&amp;page=2" class="image"><img alt="LoremIpsum.djvu" src="http://example.com/images/thumb/5/5f/LoremIpsum.djvu/page2-2480px-LoremIpsum.djvu.jpg" width="2480" height="3508" srcset="http://example.com/images/thumb/5/5f/LoremIpsum.djvu/page2-3720px-LoremIpsum.djvu.jpg 1.5x, http://example.com/images/thumb/5/5f/LoremIpsum.djvu/page2-4960px-LoremIpsum.djvu.jpg 2x" /></a>
 </p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"page","ak":"page=2"}]}'><a href="./File:LoremIpsum.djvu" data-parsoid='{"a":{"href":"./File:LoremIpsum.djvu"},"sa":{}}'><img resource="./File:LoremIpsum.djvu" src="//example.com/images/5/5f/LoremIpsum.djvu" height="3508" width="2480" data-parsoid='{"a":{"resource":"./File:LoremIpsum.djvu","height":"3508","width":"2480"},"sa":{"resource":"File:LoremIpsum.djvu"}}'/></a></span></p>
 !! end
 
 !! test
@@ -18156,30 +18393,34 @@ comment
 <a href="/index.php?title=ABC3D%25_%2B%2B&amp;action=edit&amp;redlink=1" class="new" title="ABC3D% ++ (page does not exist)">ABC3D% ++</a> <a href="/index.php?title=ABC3D%25_%2B%2B&amp;action=edit&amp;redlink=1" class="new" title="ABC3D% ++ (page does not exist)">+%20</a>
 !! end
 
-# FIXME: Omitting the php sections here because of differences in the local and
-# jenkins output. But, more importantly, the Bad.jpg isn't being stripped,
-# which seems to be a problem with the testing infrastructure.
+# Parsoid doesn't support this yet: see bug 73581
+# but it *should* omit the 'src' attribute if the image is bad.
+# PHP side of tests was disabled in
+# mediawiki/core:6bd31e7d95161a6e88fa86df60871051da997c3c
+# because of issues in the PHP parserTests infrastructure
+# (but the output below is indeed what the PHP side emits)
 !! test
 Bad images - basic functionality
 !! wikitext
 [[File:Bad.jpg]]
+!! DISABLED/html/php
 !! html/parsoid
-<meta typeof="mw:Placeholder" data-parsoid='{"src":"[[File:Bad.jpg]]","optList":[]}'/>
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"bad-image","message":"This image is blacklisted in this context."}]}'><a href="File:Bad.jpg"><img resource="./File:Bad.jpg" height="220" width="220"/></a></span></p>
 !! end
 
-# FIXME: Same reasoning as above. The expected php is:
-#  <p>Foo bar
-#  </p><p>Bar foo
-#  </p>
 !! test
 Bad images - bug 16039: text after bad image disappears
 !! wikitext
 Foo bar
 [[File:Bad.jpg]]
 Bar foo
+!! DISABLED/html/php
+<p>Foo bar
+</p><p>Bar foo
+</p>
 !! html/parsoid
 <p>Foo bar
-<meta typeof="mw:Placeholder" data-parsoid='{"src":"[[File:Bad.jpg]]","optList":[]}'/>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"bad-image","message":"This image is blacklisted in this context."}]}'><a href="File:Bad.jpg"><img resource="./File:Bad.jpg" height="220" width="220"/></a></span>
 Bar foo</p>
 !! end
 
@@ -18393,14 +18634,16 @@ percent-encoding and + signs in internal links (Bug 26410)
 !! wikitext
 [[User:+%]] [[Page+title%]]
 [[%+]] [[%+|%20]] [[%+ ]] [[%+r]]
-[[%]] [[+]] [[image:%+abc%39|foo|[[bar]]]]
+[[%]] [[+]] [[File:%+abc%39|foo|[[bar]]]]
 [[%33%45]] [[%33%45+]]
-!! html
+!! html/php
 <p><a href="/index.php?title=User:%2B%25&amp;action=edit&amp;redlink=1" class="new" title="User:+% (page does not exist)">User:+%</a> <a href="/index.php?title=Page%2Btitle%25&amp;action=edit&amp;redlink=1" class="new" title="Page+title% (page does not exist)">Page+title%</a>
 <a href="/index.php?title=%25%2B&amp;action=edit&amp;redlink=1" class="new" title="%+ (page does not exist)">%+</a> <a href="/index.php?title=%25%2B&amp;action=edit&amp;redlink=1" class="new" title="%+ (page does not exist)">%20</a> <a href="/index.php?title=%25%2B&amp;action=edit&amp;redlink=1" class="new" title="%+ (page does not exist)">%+ </a> <a href="/index.php?title=%25%2Br&amp;action=edit&amp;redlink=1" class="new" title="%+r (page does not exist)">%+r</a>
 <a href="/index.php?title=%25&amp;action=edit&amp;redlink=1" class="new" title="% (page does not exist)">%</a> <a href="/index.php?title=%2B&amp;action=edit&amp;redlink=1" class="new" title="+ (page does not exist)">+</a> <a href="/index.php?title=Special:Upload&amp;wpDestFile=%25%2Babc9" class="new" title="File:%+abc9">bar</a>
 <a href="/index.php?title=3E&amp;action=edit&amp;redlink=1" class="new" title="3E (page does not exist)">3E</a> <a href="/index.php?title=3E%2B&amp;action=edit&amp;redlink=1" class="new" title="3E+ (page does not exist)">3E+</a>
 </p>
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="User:+%" title="User:+%">User:+%</a> <a rel="mw:WikiLink" href="Page+title%" title="Page+title%">Page+title%</a> <a rel="mw:WikiLink" href="%+" title="%+">%+</a> <a rel="mw:WikiLink" href="%+" title="%+">%20</a> <a rel="mw:WikiLink" href="%+" title="%+">%+ </a> <a rel="mw:WikiLink" href="%+r" title="%+r">%+r</a> <a rel="mw:WikiLink" href="%" title="%">%</a> <a rel="mw:WikiLink" href="+" title="+">+</a> <span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"[[bar]]"}'><a href="File:%+abc9"><img resource="./File:%25+abc9" src="./Special:FilePath/%+abc9" height="220" width="220"/></a></span> <a rel="mw:WikiLink" href="3E" title="3E">3E</a> <a rel="mw:WikiLink" href="3E+" title="3E+">3E+</a></p>
 !! end
 
 !! test
@@ -18408,13 +18651,15 @@ Special characters in embedded file links (bug 27679)
 !! wikitext
 [[File:Contains & ampersand.jpg]]
 [[File:Does not exist.jpg|Title with & ampersand]]
-!! html
+!! html/php
 <p><a href="/index.php?title=Special:Upload&amp;wpDestFile=Contains_%26_ampersand.jpg" class="new" title="File:Contains &amp; ampersand.jpg">File:Contains &amp; ampersand.jpg</a>
 <a href="/index.php?title=Special:Upload&amp;wpDestFile=Does_not_exist.jpg" class="new" title="File:Does not exist.jpg">Title with &amp; ampersand</a>
 </p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="File:Contains_&amp;_ampersand.jpg"><img resource="./File:Contains_&amp;_ampersand.jpg" src="./Special:FilePath/Contains_&amp;_ampersand.jpg" height="220" width="220"/></a></span>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"Title with &amp; ampersand"}'><a href="File:Does_not_exist.jpg"><img resource="./File:Does_not_exist.jpg" src="./Special:FilePath/Does_not_exist.jpg" height="220" width="220"/></a></span></p>
 !! end
 
-
 !! test
 Confirm that 'apos' named character reference doesn't make it to output (not legal in HTML 4)
 !! wikitext
@@ -19399,6 +19644,22 @@ A <ref >foo</ref >
 <li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo</li></ol>
 !!end
 
+!!test
+Ref: 17. Generate valid HTML5 id/about attributes
+!!options
+parsoid
+!!wikitext
+<ref name="a b">foo</ref>
+
+<references />
+!!html
+<p><span class="reference" id="cite_ref-a_b-1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{"name":"a b"}}'><a href="#cite_note-a_b-1">[1]</a></span>
+</p>
+
+<ol class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'>
+<li id="cite_note-a_b-1"><span rel="mw:referencedBy"><a href="#cite_ref-a_b-1-0">↑</a></span> foo</li>
+!!end
+
 !!test
 References: 1. references tag without any refs should be handled properly
 !!options
@@ -19536,7 +19797,7 @@ parsoid
 !! wikitext
 <ref name="test &amp; me">hi</ref>
 !! html
-<p><span about="#mwt2" class="reference" id="cite_ref-test &amp; me-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"&lt;ref name=\"test &amp;amp; me\">hi&lt;/ref>"}' data-mw='{"name":"ref","body":{"html":"hi"},"attrs":{"name":"test &amp; me"}}'><a href="#cite_note-test &amp; me-1">[1]</a></span></p>
+<p><span about="#mwt2" class="reference" id="cite_ref-test_&amp;_me-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"&lt;ref name=\"test &amp;amp; me\">hi&lt;/ref>"}' data-mw='{"name":"ref","body":{"html":"hi"},"attrs":{"name":"test &amp; me"}}'><a href="#cite_note-test_&amp;_me-1">[1]</a></span></p>
 !! end
 
 # This test is wt2html only because we're permitting the serializer to produce
@@ -20550,24 +20811,24 @@ ISBN 1234567890's
 !! options
 parsoid=html2wt,wt2wt
 !! wikitext
-''<nowiki>'foo'</nowiki>''
+''<nowiki/>'foo'<nowiki/>''
 ''<nowiki>''foo''</nowiki>''
 ''<nowiki>'''foo'''</nowiki>''
 ''foo''<nowiki/>'s
-'''<nowiki>'foo'</nowiki>'''
+'''<nowiki/>'foo'<nowiki/>'''
 '''<nowiki>''foo''</nowiki>'''
 '''<nowiki>'''foo'''</nowiki>'''
-'''<nowiki>foo'</nowiki>''<nowiki>bar'</nowiki>''baz'''
+'''foo'<nowiki/>''bar'<nowiki/>''baz'''
 '''foo'''<nowiki/>'s
-'''foo''
+'<nowiki/>''foo''
 ''foo''<nowiki/>'
 '<nowiki/>''foo''<nowiki/>'
-''''foo'''
+'<nowiki/>'''foo'''
 '''foo'''<nowiki/>'
 '<nowiki/>'''foo'''<nowiki/>'
 ''fools'<span> errand</span>''
 ''<span>fool</span>'s errand''
-!! html
+!! html/*
 <p><i>'foo'</i>
 <i>''foo''</i>
 <i>'''foo'''</i>
@@ -20582,9 +20843,10 @@ parsoid=html2wt,wt2wt
 '<i>foo</i>'
 '<b>foo</b>
 <b>foo</b>'
-'<b>foo</b>'</p>
+'<b>foo</b>'
 <i>fools'<span> errand</span></i>
 <i><span>fool</span>'s errand</i>
+</p>
 !! end
 
 !! test
@@ -21221,15 +21483,12 @@ parsoid
 
 !!test
 Multi-line image caption generated by templates with/without trailing newlines
-!!options
-parsoid
 !! wikitext
-[[File:foo.jpg|thumb|300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}]]
-[[File:foo.jpg|thumb|300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}\n\n]]
-!! html
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&amp;wpDestFile=Foo.jpg" class="new" title="File:Foo.jpg">File:Foo.jpg</a>  <div class="thumbcaption">foo\nA\nB\nC</div></div></div>
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&amp;wpDestFile=Foo.jpg" class="new" title="File:Foo.jpg">File:Foo.jpg</a>  <div class="thumbcaption">foo\nA\nB\nC\n\n</div></div></div>
-
+[[File:Foobar.jpg|thumb|300x300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}]]
+[[File:Foobar.jpg|thumb|300x300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}\n\n]]
+!! html/parsoid
+<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" height="34" width="300"/></a><figcaption>foo\n<span about="#mwt9" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"A"}},"i":0}}]}'>A</span>\n<span about="#mwt10" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"B"}},"i":0}}]}'>B</span>\n<span about="#mwt11" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"C"}},"i":0}}]}'>C</span></figcaption></figure>
+<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" height="34" width="300"/></a><figcaption>foo\n<span about="#mwt12" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"A"}},"i":0}}]}'>A</span>\n<span about="#mwt13" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"B"}},"i":0}}]}'>B</span>\n<span about="#mwt14" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"C"}},"i":0}}]}'>C</span>\n\n</figcaption></figure>
 !!end
 
 !! test
@@ -21533,6 +21792,17 @@ parsoid=html2wt
 <object data="test.swf"></object>
 !!end
 
+!! test
+Don't block XML namespace declaration
+!! wikitext
+<span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">MediaWiki</span>
+!! html/php
+<p><span>MediaWiki</span>
+</p>
+!! html/parsoid
+<p><span xmlns:dct="http://purl.org/dc/terms/" data-x-property="dct:title" data-parsoid='{"stx":"html"}'>MediaWiki</span></p>
+!! end
+
 # -----------------------------------------------------------------
 # The following section of tests are primarily to spec requirements
 # around serialization of new/edited content.
@@ -21551,6 +21821,64 @@ parsoid=html2wt
 <p><a rel="mw:ExtLink" href="http://mi.wikipedia.org/wiki/Foo">Foo</a></p>
 !! end
 
+!! test
+New wiki links (href variations)
+!! options
+parsoid=html2wt
+!! html
+<a rel="mw:WikiLink" href="./Foo_bar">Foo_bar</a>
+<a rel="mw:WikiLink" href="Foo_bar">Foo_bar</a>
+<a rel="mw:WikiLink" href="Foo bar">Foo_bar</a>
+<a rel="mw:WikiLink" href="./Toxine_bact%C3%A9rienne">Toxine bactérienne</a>
+!! wikitext
+[[Foo_bar]]
+[[Foo_bar]]
+[[Foo_bar]]
+[[Toxine bactérienne]]
+!! end
+
+!! test
+New wiki links (content string variations)
+!! options
+parsoid=html2wt
+!! html
+<a rel="mw:WikiLink" href="./Foo_bar">Foo_bar</a>
+<a rel="mw:WikiLink" href="./Foo_bar">Foo bar</a>
+<a rel="mw:WikiLink" href="./Foo_bar">./Foo_bar</a>
+!! wikitext
+[[Foo_bar]]
+[[Foo bar]]
+[[Foo_bar|./Foo_bar]]
+!! end
+
+!! test
+New category links (href variations)
+!! options
+parsoid=html2wt
+!! html
+<link rel="mw:PageProp/Category" href="./Category:Toxine_bactérienne" />
+<link rel="mw:PageProp/Category" href="./Category:Toxine_bact%C3%A9rienne" />
+<link rel="mw:PageProp/Category" href="Category:Toxine_bact%C3%A9rienne" />
+!! wikitext
+[[Category:Toxine bactérienne]]
+[[Category:Toxine bactérienne]]
+[[Category:Toxine bactérienne]]
+!! end
+
+!! test
+New interlanguage links (href variations)
+!! options
+parsoid=html2wt
+!! html
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Toxine bactérienne" />
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Toxine_bactérienne" />
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Toxine_bact%C3%A9rienne" />
+!! wikitext
+[[es:Toxine bactérienne]]
+[[es:Toxine_bactérienne]]
+[[es:Toxine_bactérienne]]
+!! end
+
 !! test
 Image: Modifying size of an image (1)
 !! options
@@ -21693,33 +22021,31 @@ parsoid
 #!! options
 #parsoid=html2wt
 #language=ar
-#!! input
+#!! wikitext
 #[[Imagen:Foobar.jpg|derecha|miniaturadeimagen]]
-#!! result
+#!! html
 #<figure class="mw-default-size mw-halign-right" typeof="mw:Image/Thumb"><a href="Imagen:Foobar.jpg"><img resource="./Imagen:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="20" width="180"/></a></figure>
 #!! end
 
 !! test
 Image: Block level image should have \n before and after
-!! options
-parsoid
 !! wikitext
 123
 [[File:Foobar.jpg|right|thumb|150x150px]]
 456
-!! html
-<p>123</p><figure typeof="mw:Image/Thumb" class="mw-halign-right"><a href="./File:Foobar.png"><img src="http://192.168.142.128/mw/images/thumb/b/bc/Foobar.png/131px-Foobar.png" width="131" height="150" resource="./File:Foobar.png" data-parsoid='{"a":{"resource":"./File:Foobar.png","width":"131"},"sa":{"resource":"File:Foobar.png","width":"150"}}'></a></figure><p>456</p>
+!! html/parsoid
+<p>123</p>
+<figure class="mw-halign-right" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="17" width="150"/></a></figure>
+<p>456</p>
 !!end
 
 !! test
 Image: New block level image should have \n before and after (existing content)
-!! options
-parsoid
 !! wikitext
 123
 [[File:Foobar.jpg|right|thumb|150x150px]]
 456
-!! html
+!! html/parsoid
 <p>123</p>
 <figure class="mw-halign-right" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"right","ak":"right"},{"ck":"thumbnail","ak":"thumb"},{"ck":"width","ak":"150x150px"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/150px-Foobar.jpg" height="17" width="150" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"17","width":"150"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></figure>
 <p>456</p>
@@ -22025,7 +22351,7 @@ parsoid=html2wt
 !! wikitext
 ''A''<i>B</i>
 
-''A'''''<i>B</i>'''
+''A''<nowiki/>'''<i>B</i>'''
 !! html
 <p><i>A</i><i data-parsoid='{"stx":"html"}'>B</i></p>
 <p><i>A</i><b><i data-parsoid='{"stx":"html"}'>B</i></b></p>
@@ -22176,6 +22502,16 @@ parsoid=html2wt
 <link rel="mw:PageProp/redirect" href="Bar" data-parsoid='{"src":"#REDIRECT ","a":{"href":"./Foo"},"sa":{"href":"Foo"}}'>
 !! end
 
+!! test
+T75121: Infer extension name from typeOf if data-mw is not present
+!! options
+parsoid=html2wt
+!! wikitext
+<foo />
+!! html
+<div typeOf="mw:Extension/foo"></div>
+!! end
+
 # -----------------------------------------------------------------
 # End of section for Parsoid-only html2wt tests for serialization
 # of new content
index c3e2a30..3f4c6f9 100644 (file)
@@ -83,7 +83,7 @@ help:
        #                       You will need the Xdebug PHP extension for the later.
        #   [no]parser          Skip or only run Parser tests
        #
-       #   list-groups         List availabe Tests groups.
+       #   list-groups         List available Tests groups.
        #
        #  Options:
        #   CONFIG_FILE         Path to a PHPUnit configuration file (default: suite.xml)
index 2cd549e..327c1da 100644 (file)
@@ -634,7 +634,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                if ( isset( $compatibility[$func] ) ) {
                        return call_user_func_array( array( $this, $compatibility[$func] ), $args );
                } else {
-                       throw new MWException( "Called non-existant $func method on "
+                       throw new MWException( "Called non-existent $func method on "
                                . get_class( $this ) );
                }
        }
index a8829cd..992581b 100644 (file)
@@ -637,7 +637,7 @@ class HtmlTest extends MediaWikiTestCase {
                                . 'Depending on compatibility mode IE might use "button", instead.',
                );
 
-               # <select> specifc handling
+               # <select> specific handling
                $cases[] = array( '<select multiple></select>',
                        'select', array( 'size' => '4', 'multiple' => true ),
                );
index d0f6208..e737056 100644 (file)
@@ -42,12 +42,12 @@ class PrefixSearchTest extends MediaWikiLangTestCase {
                $this->insertPage( 'Example Foo/Bar' );
                $this->insertPage( 'Example/Baz' );
                $this->insertPage( 'Redirect test', '#REDIRECT [[Redirect Test]]' );
-               $this->insertPage( 'Redirect Test');
-               $this->insertPage( 'Redirect Test Worse Result');
+               $this->insertPage( 'Redirect Test' );
+               $this->insertPage( 'Redirect Test Worse Result' );
                $this->insertPage( 'Redirect test2', '#REDIRECT [[Redirect Test2]]' );
                $this->insertPage( 'Redirect TEST2', '#REDIRECT [[Redirect Test2]]' );
-               $this->insertPage( 'Redirect Test2');
-               $this->insertPage( 'Redirect Test2 Worse Result');
+               $this->insertPage( 'Redirect Test2' );
+               $this->insertPage( 'Redirect Test2 Worse Result' );
 
                $this->insertPage( 'Talk:Sandbox' );
                $this->insertPage( 'Talk:Example' );
@@ -171,7 +171,7 @@ class PrefixSearchTest extends MediaWikiLangTestCase {
                array_shift( $case['results'] );
                // And sometimes we expect a different last result
                $expected = isset( $case['offsetresult'] ) ?
-                       array_merge( $case['results'], $case['offsetresult'] ):
+                       array_merge( $case['results'], $case['offsetresult'] ) :
                        $case['results'];
 
                $this->assertEquals(
index f9ef317..8cc2a8e 100644 (file)
@@ -342,7 +342,7 @@ class UserTest extends MediaWikiTestCase {
        public static function provideGetCanonicalName() {
                return array(
                        array( ' trailing space ', array( 'creatable' => 'Trailing space' ), 'Trailing spaces' ),
-                       // @todo FIXME: Maybe the createable name should be 'Talk:Username' or false to reject?
+                       // @todo FIXME: Maybe the creatable name should be 'Talk:Username' or false to reject?
                        array( 'Talk:Username', array( 'creatable' => 'Username', 'usable' => 'Username',
                                'valid' => 'Username', 'false' => 'Talk:Username' ), 'Namespace prefix' ),
                        array( ' name with # hash', array( 'creatable' => false, 'usable' => false ), 'With hash' ),
index 9f154bb..0e03add 100644 (file)
@@ -166,7 +166,7 @@ class XmlSelectTest extends MediaWikiTestCase {
                        'razor'
                );
 
-               # inexistant keys should give us 'null'
+               # inexistent keys should give us 'null'
                $this->assertEquals(
                        $this->select->getAttribute( 'I DO NOT EXIT' ),
                        null
index 4bf6deb..51d03ed 100644 (file)
@@ -61,4 +61,22 @@ class ApiMainTest extends ApiTestCase {
                }
        }
 
+       /**
+        * Test if all classes in the main module manager exists
+        */
+       public function testClassNamesInModuleManager() {
+               global $wgAutoloadLocalClasses;
+
+               $api = new ApiMain(
+                       new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
+               );
+               $modules = $api->getModuleManager()->getNamesWithClasses();
+               foreach( $modules as $name => $class ) {
+                       $this->assertArrayHasKey(
+                               $class,
+                               $wgAutoloadLocalClasses,
+                               'Class ' . $class . ' for api module ' . $name . ' not in autoloader (with exact case)'
+                       );
+               }
+       }
 }
index d075f54..5170856 100644 (file)
@@ -8,10 +8,11 @@
  */
 class ApiFormatWddxTest extends ApiFormatTestBase {
 
-       /**
-        * @requires function wddx_deserialize
-        */
        public function testValidSyntax( ) {
+               if ( !function_exists( 'wddx_deserialize' ) ) {
+                       $this->markTestSkipped( "Function 'wddx_deserialize' not exist, skipping." );
+               }
+
                $data = $this->apiRequest( 'wddx', array( 'action' => 'query', 'meta' => 'siteinfo' ) );
 
                $this->assertInternalType( 'array', wddx_deserialize( $data ) );
index 200027d..3ab1334 100644 (file)
@@ -116,4 +116,24 @@ class ApiQueryTest extends ApiTestCase {
                        array( 'apiquerytestiw:foo', NS_MAIN, null, true ),
                );
        }
+
+       /**
+        * Test if all classes in the query module manager exists
+        */
+       public function testClassNamesInModuleManager() {
+               global $wgAutoloadLocalClasses;
+
+               $api = new ApiMain(
+                       new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
+               );
+               $queryApi = new ApiQuery( $api, 'query' );
+               $modules = $queryApi->getModuleManager()->getNamesWithClasses();
+               foreach( $modules as $name => $class ) {
+                       $this->assertArrayHasKey(
+                               $class,
+                               $wgAutoloadLocalClasses,
+                               'Class ' . $class . ' for api module ' . $name . ' not in autoloader (with exact case)'
+                       );
+               }
+       }
 }
index 24b5186..a0d308a 100644 (file)
@@ -7,8 +7,6 @@
  */
 class LocalisationCacheTest extends MediaWikiTestCase {
        protected function setUp() {
-               global $IP;
-
                parent::setUp();
                $this->setMwGlobals( array(
                        'wgExtensionMessagesFiles' => array(),
index 588e544..d32c1a6 100644 (file)
@@ -297,7 +297,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
                        $out = $wgProfiler['output'];
                        if ( $out === 'db' ) {
                                $profileToDb = true;
-                       } elseif( is_array( $out ) && in_array( 'db', $out ) ) {
+                       } elseif ( is_array( $out ) && in_array( 'db', $out ) ) {
                                $profileToDb = true;
                        }
                }
index 97aa0a3..54758f9 100644 (file)
@@ -90,14 +90,14 @@ class FormatMetadataTest extends MediaWikiMediaTestCase {
                        'multiValue' => array( array( 'first', 'second', 'third', '_type' => 'ol' ), 'first' ),
                        'noType' => array( array( 'first', 'second', 'third' ), 'first' ),
                        'typeFirst' => array( array( '_type' => 'ol', 'first', 'second', 'third' ), 'first' ),
-                   'multilang' => array(
-                           array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ),
-                           array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ),
-                   ),
-                   'multilang-multivalue' => array(
-                           array( 'en' => array( 'first', 'second' ), 'de' => array( 'Erste', 'Zweite' ), '_type' => 'lang' ),
-                           array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ),
-                   ),
+                       'multilang' => array(
+                               array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ),
+                               array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ),
+                       ),
+                       'multilang-multivalue' => array(
+                               array( 'en' => array( 'first', 'second' ), 'de' => array( 'Erste', 'Zweite' ), '_type' => 'lang' ),
+                               array( 'en' => 'first', 'de' => 'Erste', '_type' => 'lang' ),
+                       ),
                );
        }
 }
index 0df52f5..010ae66 100644 (file)
@@ -434,7 +434,7 @@ class NewParserTest extends MediaWikiTestCase {
                $this->savedGlobals = array();
 
                /** @since 1.20 */
-               wfRunHooks( 'ParserTestGlobals', array( &$settings ) );
+               Hooks::run( 'ParserTestGlobals', array( &$settings ) );
 
                $langObj = Language::factory( $lang );
                $settings['wgContLang'] = $langObj;
@@ -939,7 +939,7 @@ class NewParserTest extends MediaWikiTestCase {
                $class = $wgParserConf['class'];
                $parser = new $class( array( 'preprocessorClass' => $preprocessor ) + $wgParserConf );
 
-               wfRunHooks( 'ParserTestParser', array( &$parser ) );
+               Hooks::run( 'ParserTestParser', array( &$parser ) );
 
                return $parser;
        }
index 1c25211..3fddc1e 100644 (file)
@@ -23,7 +23,7 @@ mw.loader.addSource( {
 } );mw.loader.register( [
     [
         "test.blank",
-        "1388534400"
+        1388534400
     ]
 ] );',
                        ) ),
@@ -40,17 +40,17 @@ mw.loader.addSource( {
 } );mw.loader.register( [
     [
         "test.blank",
-        "1388534400"
+        1388534400
     ],
     [
         "test.group.foo",
-        "1388534400",
+        1388534400,
         [],
         "x-foo"
     ],
     [
         "test.group.bar",
-        "1388534400",
+        1388534400,
         [],
         "x-bar"
     ]
@@ -68,7 +68,7 @@ mw.loader.addSource( {
 } );mw.loader.register( [
     [
         "test.blank",
-        "1388534400"
+        1388534400
     ]
 ] );'
                        ) ),
@@ -90,7 +90,7 @@ mw.loader.addSource( {
 } );mw.loader.register( [
     [
         "test.blank",
-        "1388534400",
+        1388534400,
         [],
         null,
         "example"
@@ -115,8 +115,8 @@ mw.loader.addSource( {
                                        'test.z.foo' => new ResourceLoaderTestModule( array(
                                                'dependencies' => array(
                                                        'test.x.core',
-                                                       'test.x.polyfil',
-                                                       'test.y.polyfil',
+                                                       'test.x.polyfill',
+                                                       'test.y.polyfill',
                                                ),
                                        ) ),
                                ),
@@ -126,31 +126,31 @@ mw.loader.addSource( {
 } );mw.loader.register( [
     [
         "test.x.core",
-        "1388534400"
+        1388534400
     ],
     [
         "test.x.polyfill",
-        "1388534400",
+        1388534400,
         [],
         null,
-        "local",
+        null,
         "return true;"
     ],
     [
         "test.y.polyfill",
-        "1388534400",
+        1388534400,
         [],
         null,
-        "local",
+        null,
         "return !!(    window.JSON \u0026\u0026    JSON.parse \u0026\u0026    JSON.stringify);"
     ],
     [
         "test.z.foo",
-        "1388534400",
+        1388534400,
         [
-            "test.x.core",
-            "test.x.polyfil",
-            "test.y.polyfil"
+            0,
+            1,
+            2
         ]
     ]
 ] );',
@@ -222,63 +222,63 @@ mw.loader.addSource( {
 } );mw.loader.register( [
     [
         "test.blank",
-        "1388534400"
+        1388534400
     ],
     [
         "test.x.core",
-        "1388534400"
+        1388534400
     ],
     [
         "test.x.util",
-        "1388534400",
+        1388534400,
         [
-            "test.x.core"
+            1
         ]
     ],
     [
         "test.x.foo",
-        "1388534400",
+        1388534400,
         [
-            "test.x.core"
+            1
         ]
     ],
     [
         "test.x.bar",
-        "1388534400",
+        1388534400,
         [
-            "test.x.util"
+            2
         ]
     ],
     [
         "test.x.quux",
-        "1388534400",
+        1388534400,
         [
-            "test.x.foo",
-            "test.x.bar",
+            3,
+            4,
             "test.x.unknown"
         ]
     ],
     [
         "test.group.foo.1",
-        "1388534400",
+        1388534400,
         [],
         "x-foo"
     ],
     [
         "test.group.foo.2",
-        "1388534400",
+        1388534400,
         [],
         "x-foo"
     ],
     [
         "test.group.bar.1",
-        "1388534400",
+        1388534400,
         [],
         "x-bar"
     ],
     [
         "test.group.bar.2",
-        "1388534400",
+        1388534400,
         [],
         "x-bar",
         "example"
@@ -344,8 +344,8 @@ mw.loader.addSource( {
                $this->assertEquals(
 'mw.loader.addSource({"local":"/w/load.php"});'
 . 'mw.loader.register(['
-. '["test.blank","1388534400"],'
-. '["test.min","1388534400",["test.blank"],null,"local",'
+. '["test.blank",1388534400],'
+. '["test.min",1388534400,[0],null,null,'
 . '"return!!(window.JSON\u0026\u0026JSON.parse\u0026\u0026JSON.stringify);"'
 . ']]);',
                        $module->getModuleRegistrations( $context ),
@@ -367,16 +367,16 @@ mw.loader.addSource( {
 } );mw.loader.register( [
     [
         "test.blank",
-        "1388534400"
+        1388534400
     ],
     [
         "test.min",
-        "1388534400",
+        1388534400,
         [
-            "test.blank"
+            0
         ],
         null,
-        "local",
+        null,
         "return !!(    window.JSON \u0026\u0026    JSON.parse \u0026\u0026    JSON.stringify);"
     ]
 ] );',
index 26662d5..6ef2e23 100644 (file)
@@ -608,4 +608,4 @@ class BackupTextPassTestModelHandler extends TextContentHandler {
                return strtoupper( $text );
        }
 
-}
\ No newline at end of file
+}
index 116065f..723328e 100644 (file)
@@ -10,7 +10,7 @@ class ExtensionsTestSuite extends PHPUnit_Framework_TestSuite {
                parent::__construct();
                $paths = array();
                // Extensions can return a list of files or directories
-               wfRunHooks( 'UnitTestsList', array( &$paths ) );
+               Hooks::run( 'UnitTestsList', array( &$paths ) );
                foreach ( $paths as $path ) {
                        if ( is_dir( $path ) ) {
                                // If the path is a directory, search for test cases.
index c6dd91c..ee0f060 100644 (file)
                                        rtl: true
                                }
                        },
+                       // Internet Explorer 12
+                       'Mozilla/5.0 (Windows NT 6.4; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36 Edge/12.0': {
+                               title: 'Internet Explorer 12',
+                               platform: 'WOW64',
+                               profile: {
+                                       name: 'msie',
+                                       layout: 'edge',
+                                       layoutVersion: 12,
+                                       platform: 'win',
+                                       version: '12.0',
+                                       versionBase: '12',
+                                       versionNumber: 12
+                               },
+                               wikiEditor: {
+                                       ltr: true,
+                                       rtl: true
+                               }
+                       },
                        // Firefox 2
                        // Firefox 3.5
                        'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.19) Gecko/20110420 Firefox/3.5.19': {
index 7571b92..795c2bb 100644 (file)
                assert.equal( $.escapeRE( '0123456789' ), '0123456789', 'escapeRE - Leave numbers alone' );
        } );
 
-       QUnit.test( 'Is functions', 15, function ( assert ) {
-               assert.strictEqual( $.isDomElement( document.getElementById( 'qunit-header' ) ), true,
-                       'isDomElement: #qunit-header Node' );
-               assert.strictEqual( $.isDomElement( document.getElementById( 'random-name' ) ), false,
-                       'isDomElement: #random-name (null)' );
+       QUnit.test( 'isDomElement', 6, function ( assert ) {
+               assert.strictEqual( $.isDomElement( document.createElement( 'div' ) ), true,
+                       'isDomElement: HTMLElement' );
+               assert.strictEqual( $.isDomElement( document.createTextNode( '' ) ), true,
+                       'isDomElement: TextNode' );
+               assert.strictEqual( $.isDomElement( null ), false,
+                       'isDomElement: null' );
                assert.strictEqual( $.isDomElement( document.getElementsByTagName( 'div' ) ), false,
-                       'isDomElement: getElementsByTagName Array' );
-               assert.strictEqual( $.isDomElement( document.getElementsByTagName( 'div' )[0] ), true,
-                       'isDomElement: getElementsByTagName(..)[0] Node' );
+                       'isDomElement: NodeList' );
                assert.strictEqual( $.isDomElement( $( 'div' ) ), false,
-                       'isDomElement: jQuery object' );
-               assert.strictEqual( $.isDomElement( $( 'div' ).get( 0 ) ), true,
-                       'isDomElement: jQuery object > Get node' );
-               assert.strictEqual( $.isDomElement( document.createElement( 'div' ) ), true,
-                       'isDomElement: createElement' );
+                       'isDomElement: jQuery' );
                assert.strictEqual( $.isDomElement( { foo: 1 } ), false,
-                       'isDomElement: Object' );
+                       'isDomElement: Plain Object' );
+       } );
 
+       QUnit.test( 'isEmpty', 7, function ( assert ) {
                assert.strictEqual( $.isEmpty( 'string' ), false, 'isEmpty: "string"' );
                assert.strictEqual( $.isEmpty( '0' ), true, 'isEmpty: "0"' );
                assert.strictEqual( $.isEmpty( '' ), true, 'isEmpty: ""' );
index 7a58d38..ba36655 100644 (file)
                assert.equal( uri.toString(), 'http://www.example.com/dir/', 'empty array value is ommitted' );
        } );
 
+       QUnit.test( 'Variable defaultUri', 2, function ( assert ) {
+               var uri,
+                       href = 'http://example.org/w/index.php#here',
+                       UriClass = mw.UriRelative( function () {
+                               return href;
+                       } );
+
+               uri = new UriClass();
+               assert.deepEqual(
+                       {
+                               protocol: uri.protocol,
+                               user: uri.user,
+                               password: uri.password,
+                               host: uri.host,
+                               port: uri.port,
+                               path: uri.path,
+                               query: uri.query,
+                               fragment: uri.fragment
+                       },
+                       {
+                               protocol: 'http',
+                               user: undefined,
+                               password: undefined,
+                               host: 'example.org',
+                               port: undefined,
+                               path: '/w/index.php',
+                               query: {},
+                               fragment: 'here'
+                       },
+                       'basic object properties'
+               );
+
+               // Default URI may change, e.g. via history.replaceState, pushState or location.hash (T74334)
+               href = 'https://example.com/wiki/Foo?v=2';
+               uri = new UriClass();
+               assert.deepEqual(
+                       {
+                               protocol: uri.protocol,
+                               user: uri.user,
+                               password: uri.password,
+                               host: uri.host,
+                               port: uri.port,
+                               path: uri.path,
+                               query: uri.query,
+                               fragment: uri.fragment
+                       },
+                       {
+                               protocol: 'https',
+                               user: undefined,
+                               password: undefined,
+                               host: 'example.com',
+                               port: undefined,
+                               path: '/wiki/Foo',
+                               query: { 'v': '2' },
+                               fragment: undefined
+                       },
+                       'basic object properties'
+               );
+       } );
+
        QUnit.test( 'Advanced URL', 11, function ( assert ) {
                var uri, queryString, relativePath;
 
                uri = new UriClass( testPath );
                href = uri.toString();
                assert.equal( href, testProtocol + testServer + ':' + testPort + testPath, 'Root-relative URL gets host, protocol, and port supplied' );
-
        } );
 }( mediaWiki, jQuery ) );
index 7e0ee91..409f3e6 100644 (file)
                } );
        } );
 
+       QUnit.asyncTest( 'mw.loader with Object method as module name', 2, function ( assert ) {
+               var isAwesomeDone;
+
+               mw.loader.testCallback = function () {
+                       QUnit.start();
+                       assert.strictEqual( isAwesomeDone, undefined, 'Implementing module hasOwnProperty: isAwesomeDone should still be undefined' );
+                       isAwesomeDone = true;
+               };
+
+               mw.loader.implement( 'hasOwnProperty', [QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' )], {}, {} );
+
+               mw.loader.using( 'hasOwnProperty', function () {
+
+                       // /sample/awesome.js declares the "mw.loader.testCallback" function
+                       // which contains a call to start() and ok()
+                       assert.strictEqual( isAwesomeDone, true, 'hasOwnProperty module should\'ve caused isAwesomeDone to be true' );
+                       delete mw.loader.testCallback;
+
+               }, function () {
+                       QUnit.start();
+                       assert.ok( false, 'Error callback fired while loader.using "hasOwnProperty" module' );
+               } );
+       } );
+
        QUnit.asyncTest( 'mw.loader.using( .. ).promise', 2, function ( assert ) {
                var isAwesomeDone;