Merge "Make getCacheSetOptions() and WAN cache handle broken replication"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 3 Dec 2015 12:24:37 +0000 (12:24 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 3 Dec 2015 12:24:37 +0000 (12:24 +0000)
150 files changed:
HISTORY
RELEASE-NOTES-1.26 [deleted file]
RELEASE-NOTES-1.27
autoload.php
includes/DefaultSettings.php
includes/EditPage.php
includes/HttpFunctions.php
includes/Setup.php
includes/User.php [deleted file]
includes/UserArray.php [deleted file]
includes/UserArrayFromResult.php [deleted file]
includes/UserRightsProxy.php [deleted file]
includes/api/ApiBase.php
includes/api/ApiFeedWatchlist.php
includes/api/ApiQueryAllUsers.php
includes/api/ApiQuerySiteinfo.php
includes/api/ApiQueryUserInfo.php
includes/api/ApiQueryUsers.php
includes/api/i18n/en.json
includes/api/i18n/eu.json
includes/api/i18n/it.json
includes/api/i18n/ja.json
includes/api/i18n/pl.json
includes/api/i18n/ps.json
includes/api/i18n/qqq.json
includes/api/i18n/sd.json
includes/api/i18n/zh-hans.json
includes/cache/HTMLFileCache.php
includes/debug/logger/LoggerFactory.php
includes/deferred/LinksUpdate.php
includes/diff/DairikiDiff.php
includes/installer/i18n/el.json
includes/installer/i18n/eu.json
includes/installer/i18n/is.json
includes/installer/i18n/mk.json
includes/installer/i18n/sd.json
includes/installer/i18n/tt-cyrl.json
includes/libs/SamplingStatsdClient.php
includes/libs/objectcache/WANObjectCache.php
includes/skins/Skin.php
includes/skins/SkinTemplate.php
includes/specials/SpecialContributions.php
includes/specials/SpecialMovepage.php
includes/specials/SpecialUndelete.php
includes/specials/SpecialUserrights.php
includes/user/CentralIdLookup.php [new file with mode: 0644]
includes/user/LocalIdLookup.php [new file with mode: 0644]
includes/user/User.php [new file with mode: 0644]
includes/user/UserArray.php [new file with mode: 0644]
includes/user/UserArrayFromResult.php [new file with mode: 0644]
includes/user/UserRightsProxy.php [new file with mode: 0644]
languages/i18n/ady-cyrl.json
languages/i18n/af.json
languages/i18n/ar.json
languages/i18n/as.json
languages/i18n/ast.json
languages/i18n/az.json
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/bg.json
languages/i18n/bgn.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/ca.json
languages/i18n/ce.json
languages/i18n/ckb.json
languages/i18n/cs.json
languages/i18n/de.json
languages/i18n/diq.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/es.json
languages/i18n/et.json
languages/i18n/eu.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/fy.json
languages/i18n/gd.json
languages/i18n/gl.json
languages/i18n/gsw.json
languages/i18n/he.json
languages/i18n/hif-latn.json
languages/i18n/hr.json
languages/i18n/hy.json
languages/i18n/ia.json
languages/i18n/ilo.json
languages/i18n/is.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/kk-cyrl.json
languages/i18n/ko.json
languages/i18n/la.json
languages/i18n/lb.json
languages/i18n/lij.json
languages/i18n/lmo.json
languages/i18n/lrc.json
languages/i18n/lt.json
languages/i18n/mk.json
languages/i18n/mr.json
languages/i18n/ms.json
languages/i18n/nap.json
languages/i18n/nb.json
languages/i18n/nl.json
languages/i18n/nn.json
languages/i18n/oc.json
languages/i18n/or.json
languages/i18n/pl.json
languages/i18n/ps.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ro.json
languages/i18n/ru.json
languages/i18n/sa.json
languages/i18n/sco.json
languages/i18n/sd.json
languages/i18n/sgs.json
languages/i18n/sh.json
languages/i18n/sl.json
languages/i18n/sq.json
languages/i18n/sr-ec.json
languages/i18n/sr-el.json
languages/i18n/sv.json
languages/i18n/th.json
languages/i18n/tr.json
languages/i18n/tt-cyrl.json
languages/i18n/tt-latn.json
languages/i18n/uk.json
languages/i18n/ur.json
languages/i18n/uz.json
languages/i18n/vec.json
languages/i18n/vi.json
languages/i18n/yue.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
resources/ResourcesOOUI.php
resources/src/mediawiki.action/mediawiki.action.edit.preview.js
resources/src/mediawiki/mediawiki.ForeignStructuredUpload.js
resources/src/mediawiki/page/startup.js
resources/src/oojs-ui-local.js [new file with mode: 0644]
tests/phpunit/includes/UserArrayFromResultTest.php [deleted file]
tests/phpunit/includes/UserTest.php [deleted file]
tests/phpunit/includes/parser/MediaWikiParserTest.php
tests/phpunit/includes/parser/NewParserTest.php
tests/phpunit/includes/user/CentralIdLookupTest.php [new file with mode: 0644]
tests/phpunit/includes/user/LocalIdLookupTest.php [new file with mode: 0644]
tests/phpunit/includes/user/UserArrayFromResultTest.php [new file with mode: 0644]
tests/phpunit/includes/user/UserTest.php [new file with mode: 0644]
tests/phpunit/suite.xml

diff --git a/HISTORY b/HISTORY
index 0c2b8ac..e9de01a 100644 (file)
--- a/HISTORY
+++ b/HISTORY
@@ -1,5 +1,249 @@
 Change notes from older releases. For current info see RELEASE-NOTES-1.27.
 
+== MediaWiki 1.26 ==
+
+=== Configuration changes in 1.26 ===
+* $wgPasswordResetRoutes['email'] = true by default.
+* $wgEnableParserCache was deprecated, set $wgParserCacheType to CACHE_NONE
+  instead if you want to disable the parser cache.
+* New-style continuation is now the default for API action=continue. Clients may
+  use the 'rawcontinue' parameter to receive raw query-continue data, but the
+  new style is encouraged as it's harder to implement incorrectly.
+* Deprecated API formats dump and wddx have been completely removed.
+* (T7645) The "Signature" button on the edit toolbar is now hidden by default
+  in non-talk namespaces. A new configuration variable,
+  $wgExtraSignatureNamespaces, controls in which subject (non-talk) namespaces
+  the "Signature" button on the edit toolbar will be displayed.
+* $wgResourceLoaderUseESI was deprecated and removed. This was an experimental
+  feature that was never enabled by default.
+* $wgResourceLoaderExperimentalAsyncLoading was deprecated and removed.
+  This experimental feature was never enabled by default and is obsolete as of
+  MediaWiki 1.26, in where ResourceLoader became fully asynchronous.
+* $wgMasterWaitTimeout was removed (deprecated in 1.24).
+* Fields in ParserOptions are now private. Use the accessors instead.
+* Custom LESS functions (defined via $wgResourceLoaderLESSFunctions or
+  in extension.json) have been removed, after being deprecated in 1.24.
+* $wgAlwaysUseTidy has been removed.
+* ResetSessionID hook has been removed. Nothing seems to use it.
+* Certain AuthPlugin methods are deprecated in favor of new hooks:
+** AuthPlugin::initUser() is replaced by LocalUserCreated.
+** AuthPlugin::updateUser() is replaced by UserLoggedIn.
+** AuthPlugin::updateExternalDB() is replaced by the existing UserSaveSettings.
+** AuthPlugin::updateExternalDBGroups() is replaced by UserGroupsChanged.
+** AuthPluginUser::isHidden() is replaced by UserIsHidden.
+** AuthPluginUser::isLocked() is replaced by UserIsLocked.
+* The UserRights hook is deprecated in favor of the new UserGroupsChanged hook.
+* AuthPlugin::initUser() and AuthPlugin::updateUser() should no longer replace
+  the passed User object.
+* $wgBlockAllowsUTEdit is now set to true by default. This allows
+  blocked users to edit their talk pages unless explicitly disabled
+  when they are being blocked.
+
+=== New features in 1.26 ===
+* (T51506) Now action=info gives estimates of actual watchers for a page.
+  See $wgRCMaxAge, $wgWatchersMaxAge and $wgUnwatchedPageSecret
+  to learn how to configure if needed.
+* Change tags can now be hidden in the interface by disabling the associated
+  "tag-<id>" interface message.
+* ':' (colon) is now invalid in usernames for new accounts. Existing accounts
+  are not affected.
+* Added a new hook, 'LogException', to log exceptions in nonstandard ways.
+* Revive the 'SpecialSearchResultsAppend' hook which occurs after the list of
+  search results are rendered. The initial use case is to append a "give us
+  feedback" link beneath the search results.
+* Added a new hook, 'RejectParserCacheValue', which allows extensions to
+  reject an otherwise-successful parser cache lookup. The intent is to allow
+  extensions to manage the eviction of archaic HTML output from the cache.
+* (T68699) The expiration of the UserID and Token login cookies
+  ($wgExtendedLoginCookieExpiration) can be configured independently of the
+  expiration of all other cookies ($wgCookieExpiration).
+* (T50519) Support for generating JPEG/PNG thumbnails from WebP images added
+  if ImageMagick is used as image scaler ($wgUseImageMagick = true). Uploading
+  of WebP images still disabled by default. Add $wgFileExtensions[] =
+  'webp'; to LocalSettings.php to enable uploading of WebP images.
+* Added new hooks 'EnhancedChangesListModifyLineData' &
+  'EnhancedChangesListModifyBlockLineData', to modify the data used to build
+  lines in enhanced recentchanges and watchlist.
+* Caches that need purging ability now use the WANObjectCache interface.
+  This corresponds to a new $wgMainWANCache setting, which defaults to using
+  the $wgMainCacheType settings.
+* Callers needing fast light-weight data stores use $wgMainStash to select
+  the store type from $wgObjectCaches. The default is the local database.
+* Interface message overrides in the MediaWiki namespace will now be cached in
+  memcached and APC (if available), rather than memcached and local files.
+* Added a new hook, 'RandomPageQuery', to allow modification of the query used
+  by Special:Random to select random pages.
+* $wgTransactionalTimeLimit was added, which controls the request time limit
+  for potentially slow POST requests that need to be as atomic as possible.
+* ResourceLoader now loads all scripts asynchronously. The top-queue and
+  startup modules are no longer synchronously loaded.
+* 'mediawiki.ui.button' styles are no longer unconditionally loaded on every
+  page. During the deprecation period, the styles will only be loaded on pages
+  which contain 'mw-ui-button' in their HTML. Starting in 1.28, the styles will
+  only be loaded if explicitly required.
+* If search returns zero results and current search engine has a "did you mean"
+  suggestion, results for suggestion will be shown. Can be disabled by setting
+  $wgSearchRunSuggestedQuery to false.
+* Added several JavaScript libraries for uploading files to MediaWiki
+  from the client-side. See documentation for mw.Upload and its
+  subclasses for more information.
+* Added OOUI dialogs and layout for file upload interfaces. See
+  documentation for mw.Upload.Dialog, mw.Upload.BookletLayout and its
+  subclasses for more information.
+
+== extension.json changes in 1.26 ==
+* (T99344) The extension.json schema is now versioned. All extensions
+  and skins should set a "manifest_version" property corresponding to
+  the schema version they were written for. The only supported version
+  currently is "1".
+* (T102523) The error message if a non-array attribute is set was improved.
+* (T107646) Configuration settings can now specify how they should be merged,
+  which is necessary for arrays using integer keys.
+* (T110389) Adding namespaces through extension.json now actually works
+* $wgNamespaceProtection can now be set in extension.json.
+* $wgCapitalLinkOverrides can now be set in extension.json.
+* (T97186) Extensions using a custom prefix for their configuration settings
+  can now set a "_prefix" key to override the default of "wg".
+* (T99084) Extensions can now specify what MediaWiki core versions they
+  depend upon.
+* (T105236) The extension.json schema now validates custom classes in
+  the "ResourceModules" property properly.
+
+=== External library changes in 1.26 ===
+==== Upgraded external libraries ====
+* Updated es5-shim from v4.0.0 to v4.1.5.
+* Updated json2 from revision 2014-02-04 to 2015-05-03.
+* Updated Sinon.JS from 1.10.3 to 1.15.4.
+* Updated jQuery Client from v1.0.0 to v2.0.0.
+* Updated QUnit from v1.17.1 to v1.18.0.
+* Updated liuggio/statsd-php-client from v1.0.12 to v1.0.16.
+* Updated oojs/oojs-ui from v0.11.3 to v0.12.12.
+* Updated wikimedia/cdb from v1.0.1 to v1.3.0.
+* Updated wikimedia/utfnormal from v1.0.2 to v1.0.3.
+* Updated wikimedia/composer-merge-plugin from v1.0.0 to v1.3.0.
+* Updated zordius/lightncandy from v0.18 to v0.21.
+
+==== New external libraries ====
+* Added composer/semver v1.0.0.
+* Added mediawiki/at-ease v1.1.0.
+* Added wikimedia/assert v0.2.2.
+* Added wikimedia/ip-set v1.0.1.
+* Added wikimedia/wrappedstring v2.0.0.
+
+==== Removed and replaced external libraries ====
+* Replaced leafo/lessphp v0.5.0 with oyejorge/less.php v1.7.0.9.
+
+=== Bug fixes in 1.26 ===
+* (T53283) load.php sometimes sends 304 response without full headers
+* (T65198) Talk page tabs now have a "rel=discussion" attribute
+* (T98841) {{msgnw:}} now preserves comments even when subst: is not used.
+* (T104142) $wgEmergencyContact and $wgPasswordSender now use their default
+  value if set to an empty string.
+
+=== Action API changes in 1.26 ===
+* New-style continuation is now the default for action=continue. Clients may
+  use the 'rawcontinue' parameter to receive raw query-continue data, but the
+  new style is encouraged as it's harder to implement incorrectly.
+* Deprecated API formats dump and wddx have been completely removed.
+* API action=query&list=tags: The displayname can now be boolean false if the
+  tag is meant to be hidden from user interfaces.
+* action=import no longer allows both the namespace= and rootpage= parameters
+  to be set. If they are both set, the value of rootpage= will be ignored.
+* prop=revision output in enum mode is now sorted by timestamp rather than
+  revision ID. This usually won't make any difference.
+* (T102645) Namespace list from meta=siteinfo&siprop=namespaces is now an array
+  with formatversion=2.
+* Various other output from meta=siteinfo will now always be arrays instead of
+  sometimes being numerically-indexed objects with formatversion=2.
+* When errors about users being blocked are returned, they now include
+  information about the relevant block.
+* (T99926) list=random has higher limits, in line with other API modules.
+* list=random's rnredirect parameter is deprecated in favor of a new
+  rnfilterredir parameter that also allows for listing both redirects and
+  non-redirects.
+* list=random now supports continuation.
+* API responses to GET requests may now include ETag and Last-Modified headers,
+  and will honor corresponding If-None-Match and If-Modified-Since on such
+  requests.
+
+=== Action API internal changes in 1.26 ===
+* New metadata item ApiResult::META_KVP_MERGE to allow for merging the KVP key
+  into the value when the value is an assoc.
+* API action modules may now provide values for the RFC 7232 ETag and
+  Last-Modified headers. The API will check these against If-None-Match and
+  If-Modified-Since request headers on GET requests and avoid executing the
+  module when appropriate.
+
+=== Languages updated in 1.26 ===
+
+MediaWiki supports over 350 languages. Many localisations are updated
+regularly. Below only new and removed languages are listed, as well as
+changes to languages because of Phabricator reports.
+
+* Languages added:
+** ase (American sign language), thanks to translator Icemandeaf
+** dty (डोटेली/Doteli), thanks to translators जनक राज भट्ट, बिप्लब आनन्द,
+   मेश सिंह बोहरा, and राम प्रसाद जोशी
+** luz (لئری دوٙمینی / Southern Luri)
+** olo (Livvinкarjala / Livvi-Karelian), thanks to translators Denö, Hiloin Natoi,
+   Ilja.mos, and Mashoi7
+
+=== Other changes in 1.26 ===
+* ChangeTags::tagDescription() will return false if the interface message
+  for the tag is disabled.
+* Added PageHistoryPager::doBatchLookups hook.
+* Added $wikiId parameter to FormatAutocomments hook.
+* Added ParserCacheSaveComplete to ParserCache
+* supportsDirectEditing and supportsDirectApiEditing methods added to
+  ContentHandler, to provide a way for ApiEditPage and EditPage to check
+  if direct editing of content is allowed. These methods return false,
+  by default for the ContentHandler base class and true for TextContentHandler
+  and it's derivative classes (everything in core). For Content types that
+  do not support direct editing, an alternative mechanism should be provided
+  for editing, such as action overrides or specific api modules.
+* mediaWiki.confirmCloseWindow now returns an object of functions, instead of
+  one function. The callback can't be called directly any more. The callback
+  function is replaced with confirmCloseWindow.release().
+* BREAKING CHANGE: Added an optional ResouceLoaderContext parameter to
+  ResourceLoaderModule::getDependencies(). Extension classes that override that
+  method should be updated. If they aren't updated, PHP Strict standards
+  warnings will appear when E_STRICT error reporting is enabled. Note: in the
+  near future, this parameter will probably become non-optional.
+* Removed maintenance script deleteImageMemcached.php.
+* MWFunction::newObj() was removed (deprecated in 1.25).
+  ObjectFactory::getObjectFromSpec() should be used instead.
+* The parser will no longer randomize the string it uses to mark the place of
+  items that were stripped during parsing. It will use a fixed string instead.
+  This causes the parser to re-use the regular expressions it uses to search
+  and replace markers rather than generate novel expressions on each parse.
+  Re-using regular expressions will improve performance on HHVM and the
+  forthcoming PHP 7. The interfaces changes accompanying this change are:
+  - Parser::getRandomString() and Parser::uniqPrefix() have been deprecated.
+  - The $uniq_prefix argument for Parser::extractTagsAndParams() and the
+    $prefix argument for StripState::_construct() are deprecated and their
+    value is ignored.
+* wfSuppressWarnings() and wfRestoreWarnings() were split into a separate library,
+  mediawiki/at-ease, and are now deprecated. Callers should use
+  MediaWiki\suppressWarnings() and MediaWiki\restoreWarnings() directly.
+* The Block class constructor now takes an associative array of parameters
+  instead of many optional positional arguments. Calling the constructor the old
+  way will issue a deprecation warning.
+* The jquery.mwExtension module was deprecated.
+* $wgSpecialPageGroups was removed (deprecated in 1.21).
+* SpecialPageFactory::setGroup was removed (deprecated in 1.21).
+* SpecialPageFactory::getGroup was removed (deprecated in 1.21).
+* DatabaseBase::ignoreErrors() is now protected.
+* BREAKING CHANGE: mediawiki.legacy.ajax has been removed, following
+  a lengthy deprecation period.
+* The ScopedPHPTimeout class was removed.
+* Removed maintenance script fixSlaveDesync.php.
+* Watchlist tokens, SpecialResetTokens, and User::getTokenFromOption()
+  are deprecated. Applications using those can work via the OAuth
+  extension instead. New tokens types should not be added.
+* DatabaseBase::errorCount() was removed (unused).
+* $wgDeferredUpdateList was removed.
+* DeferredUpdates::addHTMLCacheUpdate() was removed.
+
 == MediaWiki 1.25 ==
 
 === Configuration changes in 1.25 ===
diff --git a/RELEASE-NOTES-1.26 b/RELEASE-NOTES-1.26
deleted file mode 100644 (file)
index ac2f947..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-Security reminder: If you have PHP's register_globals option set, you must
-turn it off. MediaWiki will not work with it enabled.
-
-== MediaWiki 1.26 ==
-
-THIS IS NOT A RELEASE YET
-
-MediaWiki 1.26 is an alpha-quality branch and is not recommended for use in
-production.
-
-=== Configuration changes in 1.26 ===
-* $wgPasswordResetRoutes['email'] = true by default.
-* $wgEnableParserCache was deprecated, set $wgParserCacheType to CACHE_NONE
-  instead if you want to disable the parser cache.
-* New-style continuation is now the default for API action=continue. Clients may
-  use the 'rawcontinue' parameter to receive raw query-continue data, but the
-  new style is encouraged as it's harder to implement incorrectly.
-* Deprecated API formats dump and wddx have been completely removed.
-* (T7645) The "Signature" button on the edit toolbar is now hidden by default
-  in non-talk namespaces. A new configuration variable,
-  $wgExtraSignatureNamespaces, controls in which subject (non-talk) namespaces
-  the "Signature" button on the edit toolbar will be displayed.
-* $wgResourceLoaderUseESI was deprecated and removed. This was an experimental
-  feature that was never enabled by default.
-* $wgResourceLoaderExperimentalAsyncLoading was deprecated and removed.
-  This experimental feature was never enabled by default and is obsolete as of
-  MediaWiki 1.26, in where ResourceLoader became fully asynchronous.
-* $wgMasterWaitTimeout was removed (deprecated in 1.24).
-* Fields in ParserOptions are now private. Use the accessors instead.
-* Custom LESS functions (defined via $wgResourceLoaderLESSFunctions or
-  in extension.json) have been removed, after being deprecated in 1.24.
-* $wgAlwaysUseTidy has been removed.
-* ResetSessionID hook has been removed. Nothing seems to use it.
-* Certain AuthPlugin methods are deprecated in favor of new hooks:
-** AuthPlugin::initUser() is replaced by LocalUserCreated.
-** AuthPlugin::updateUser() is replaced by UserLoggedIn.
-** AuthPlugin::updateExternalDB() is replaced by the existing UserSaveSettings.
-** AuthPlugin::updateExternalDBGroups() is replaced by UserGroupsChanged.
-** AuthPluginUser::isHidden() is replaced by UserIsHidden.
-** AuthPluginUser::isLocked() is replaced by UserIsLocked.
-* The UserRights hook is deprecated in favor of the new UserGroupsChanged hook.
-* AuthPlugin::initUser() and AuthPlugin::updateUser() should no longer replace
-  the passed User object.
-* $wgBlockAllowsUTEdit is now set to true by default. This allows
-  blocked users to edit their talk pages unless explicitly disabled
-  when they are being blocked.
-
-=== New features in 1.26 ===
-* (T51506) Now action=info gives estimates of actual watchers for a page.
-  See $wgRCMaxAge, $wgWatchersMaxAge and $wgUnwatchedPageSecret
-  to learn how to configure if needed.
-* Change tags can now be hidden in the interface by disabling the associated
-  "tag-<id>" interface message.
-* ':' (colon) is now invalid in usernames for new accounts. Existing accounts
-  are not affected.
-* Added a new hook, 'LogException', to log exceptions in nonstandard ways.
-* Revive the 'SpecialSearchResultsAppend' hook which occurs after the list of
-  search results are rendered. The initial use case is to append a "give us
-  feedback" link beneath the search results.
-* Added a new hook, 'RejectParserCacheValue', which allows extensions to
-  reject an otherwise-successful parser cache lookup. The intent is to allow
-  extensions to manage the eviction of archaic HTML output from the cache.
-* (T68699) The expiration of the UserID and Token login cookies
-  ($wgExtendedLoginCookieExpiration) can be configured independently of the
-  expiration of all other cookies ($wgCookieExpiration).
-* (T50519) Support for generating JPEG/PNG thumbnails from WebP images added
-  if ImageMagick is used as image scaler ($wgUseImageMagick = true). Uploading
-  of WebP images still disabled by default. Add $wgFileExtensions[] =
-  'webp'; to LocalSettings.php to enable uploading of WebP images.
-* Added new hooks 'EnhancedChangesListModifyLineData' &
-  'EnhancedChangesListModifyBlockLineData', to modify the data used to build
-  lines in enhanced recentchanges and watchlist.
-* Caches that need purging ability now use the WANObjectCache interface.
-  This corresponds to a new $wgMainWANCache setting, which defaults to using
-  the $wgMainCacheType settings.
-* Callers needing fast light-weight data stores use $wgMainStash to select
-  the store type from $wgObjectCaches. The default is the local database.
-* Interface message overrides in the MediaWiki namespace will now be cached in
-  memcached and APC (if available), rather than memcached and local files.
-* Added a new hook, 'RandomPageQuery', to allow modification of the query used
-  by Special:Random to select random pages.
-* $wgTransactionalTimeLimit was added, which controls the request time limit
-  for potentially slow POST requests that need to be as atomic as possible.
-* ResourceLoader now loads all scripts asynchronously. The top-queue and
-  startup modules are no longer synchronously loaded.
-* 'mediawiki.ui.button' styles are no longer unconditionally loaded on every
-  page. During the deprecation period, the styles will only be loaded on pages
-  which contain 'mw-ui-button' in their HTML. Starting in 1.28, the styles will
-  only be loaded if explicitly required.
-* If search returns zero results and current search engine has a "did you mean"
-  suggestion, results for suggestion will be shown. Can be disabled by setting
-  $wgSearchRunSuggestedQuery to false.
-* Added several JavaScript libraries for uploading files to MediaWiki
-  from the client-side. See documentation for mw.Upload and its
-  subclasses for more information.
-* Added OOUI dialogs and layout for file upload interfaces. See
-  documentation for mw.Upload.Dialog, mw.Upload.BookletLayout and its
-  subclasses for more information.
-
-== extension.json changes in 1.26 ==
-* (T99344) The extension.json schema is now versioned. All extensions
-  and skins should set a "manifest_version" property corresponding to
-  the schema version they were written for. The only supported version
-  currently is "1".
-* (T102523) The error message if a non-array attribute is set was improved.
-* (T107646) Configuration settings can now specify how they should be merged,
-  which is necessary for arrays using integer keys.
-* (T110389) Adding namespaces through extension.json now actually works
-* $wgNamespaceProtection can now be set in extension.json.
-* $wgCapitalLinkOverrides can now be set in extension.json.
-* (T97186) Extensions using a custom prefix for their configuration settings
-  can now set a "_prefix" key to override the default of "wg".
-* (T99084) Extensions can now specify what MediaWiki core versions they
-  depend upon.
-* (T105236) The extension.json schema now validates custom classes in
-  the "ResourceModules" property properly.
-
-=== External library changes in 1.26 ===
-==== Upgraded external libraries ====
-* Updated es5-shim from v4.0.0 to v4.1.5.
-* Updated json2 from revision 2014-02-04 to 2015-05-03.
-* Updated Sinon.JS from 1.10.3 to 1.15.4.
-* Updated jQuery Client from v1.0.0 to v2.0.0.
-* Updated QUnit from v1.17.1 to v1.18.0.
-* Updated liuggio/statsd-php-client from v1.0.12 to v1.0.16.
-* Updated oojs/oojs-ui from v0.11.3 to v0.12.12.
-* Updated wikimedia/cdb from v1.0.1 to v1.3.0.
-* Updated wikimedia/utfnormal from v1.0.2 to v1.0.3.
-* Updated wikimedia/composer-merge-plugin from v1.0.0 to v1.3.0.
-* Updated zordius/lightncandy from v0.18 to v0.21.
-
-==== New external libraries ====
-* Added composer/semver v1.0.0.
-* Added mediawiki/at-ease v1.1.0.
-* Added wikimedia/assert v0.2.2.
-* Added wikimedia/ip-set v1.0.1.
-* Added wikimedia/wrappedstring v2.0.0.
-
-==== Removed and replaced external libraries ====
-* Replaced leafo/lessphp v0.5.0 with oyejorge/less.php v1.7.0.9.
-
-=== Bug fixes in 1.26 ===
-* (T53283) load.php sometimes sends 304 response without full headers
-* (T65198) Talk page tabs now have a "rel=discussion" attribute
-* (T98841) {{msgnw:}} now preserves comments even when subst: is not used.
-* (T104142) $wgEmergencyContact and $wgPasswordSender now use their default
-  value if set to an empty string.
-
-=== Action API changes in 1.26 ===
-* New-style continuation is now the default for action=continue. Clients may
-  use the 'rawcontinue' parameter to receive raw query-continue data, but the
-  new style is encouraged as it's harder to implement incorrectly.
-* Deprecated API formats dump and wddx have been completely removed.
-* API action=query&list=tags: The displayname can now be boolean false if the
-  tag is meant to be hidden from user interfaces.
-* action=import no longer allows both the namespace= and rootpage= parameters
-  to be set. If they are both set, the value of rootpage= will be ignored.
-* prop=revision output in enum mode is now sorted by timestamp rather than
-  revision ID. This usually won't make any difference.
-* (T102645) Namespace list from meta=siteinfo&siprop=namespaces is now an array
-  with formatversion=2.
-* Various other output from meta=siteinfo will now always be arrays instead of
-  sometimes being numerically-indexed objects with formatversion=2.
-* When errors about users being blocked are returned, they now include
-  information about the relevant block.
-* (T99926) list=random has higher limits, in line with other API modules.
-* list=random's rnredirect parameter is deprecated in favor of a new
-  rnfilterredir parameter that also allows for listing both redirects and
-  non-redirects.
-* list=random now supports continuation.
-* API responses to GET requests may now include ETag and Last-Modified headers,
-  and will honor corresponding If-None-Match and If-Modified-Since on such
-  requests.
-
-=== Action API internal changes in 1.26 ===
-* New metadata item ApiResult::META_KVP_MERGE to allow for merging the KVP key
-  into the value when the value is an assoc.
-* API action modules may now provide values for the RFC 7232 ETag and
-  Last-Modified headers. The API will check these against If-None-Match and
-  If-Modified-Since request headers on GET requests and avoid executing the
-  module when appropriate.
-
-=== Languages updated in 1.26 ===
-
-MediaWiki supports over 350 languages. Many localisations are updated
-regularly. Below only new and removed languages are listed, as well as
-changes to languages because of Phabricator reports.
-
-* Languages added:
-** ase (American sign language), thanks to translator Icemandeaf
-** dty (डोटेली/Doteli), thanks to translators जनक राज भट्ट, बिप्लब आनन्द,
-   मेश सिंह बोहरा, and राम प्रसाद जोशी
-** luz (لئری دوٙمینی / Southern Luri)
-** olo (Livvinкarjala / Livvi-Karelian), thanks to translators Denö, Hiloin Natoi,
-   Ilja.mos, and Mashoi7
-
-=== Other changes in 1.26 ===
-* ChangeTags::tagDescription() will return false if the interface message
-  for the tag is disabled.
-* Added PageHistoryPager::doBatchLookups hook.
-* Added $wikiId parameter to FormatAutocomments hook.
-* Added ParserCacheSaveComplete to ParserCache
-* supportsDirectEditing and supportsDirectApiEditing methods added to
-  ContentHandler, to provide a way for ApiEditPage and EditPage to check
-  if direct editing of content is allowed. These methods return false,
-  by default for the ContentHandler base class and true for TextContentHandler
-  and it's derivative classes (everything in core). For Content types that
-  do not support direct editing, an alternative mechanism should be provided
-  for editing, such as action overrides or specific api modules.
-* mediaWiki.confirmCloseWindow now returns an object of functions, instead of
-  one function. The callback can't be called directly any more. The callback
-  function is replaced with confirmCloseWindow.release().
-* BREAKING CHANGE: Added an optional ResouceLoaderContext parameter to
-  ResourceLoaderModule::getDependencies(). Extension classes that override that
-  method should be updated. If they aren't updated, PHP Strict standards
-  warnings will appear when E_STRICT error reporting is enabled. Note: in the
-  near future, this parameter will probably become non-optional.
-* Removed maintenance script deleteImageMemcached.php.
-* MWFunction::newObj() was removed (deprecated in 1.25).
-  ObjectFactory::getObjectFromSpec() should be used instead.
-* The parser will no longer randomize the string it uses to mark the place of
-  items that were stripped during parsing. It will use a fixed string instead.
-  This causes the parser to re-use the regular expressions it uses to search
-  and replace markers rather than generate novel expressions on each parse.
-  Re-using regular expressions will improve performance on HHVM and the
-  forthcoming PHP 7. The interfaces changes accompanying this change are:
-  - Parser::getRandomString() and Parser::uniqPrefix() have been deprecated.
-  - The $uniq_prefix argument for Parser::extractTagsAndParams() and the
-    $prefix argument for StripState::_construct() are deprecated and their
-    value is ignored.
-* wfSuppressWarnings() and wfRestoreWarnings() were split into a separate library,
-  mediawiki/at-ease, and are now deprecated. Callers should use
-  MediaWiki\suppressWarnings() and MediaWiki\restoreWarnings() directly.
-* The Block class constructor now takes an associative array of parameters
-  instead of many optional positional arguments. Calling the constructor the old
-  way will issue a deprecation warning.
-* The jquery.mwExtension module was deprecated.
-* $wgSpecialPageGroups was removed (deprecated in 1.21).
-* SpecialPageFactory::setGroup was removed (deprecated in 1.21).
-* SpecialPageFactory::getGroup was removed (deprecated in 1.21).
-* DatabaseBase::ignoreErrors() is now protected.
-* BREAKING CHANGE: mediawiki.legacy.ajax has been removed, following
-  a lengthy deprecation period.
-* The ScopedPHPTimeout class was removed.
-* Removed maintenance script fixSlaveDesync.php.
-* Watchlist tokens, SpecialResetTokens, and User::getTokenFromOption()
-  are deprecated. Applications using those can work via the OAuth
-  extension instead. New tokens types should not be added.
-* DatabaseBase::errorCount() was removed (unused).
-* $wgDeferredUpdateList was removed.
-* DeferredUpdates::addHTMLCacheUpdate() was removed.
-
-== Compatibility ==
-
-MediaWiki 1.26 requires PHP 5.3.3 or later. There is experimental support for
-HHVM 3.3.0.
-
-MySQL is the recommended DBMS. PostgreSQL or SQLite can also be used, but
-support for them is somewhat less mature. There is experimental support for
-Oracle and Microsoft SQL Server.
-
-The supported versions are:
-
-* MySQL 5.0.3 or later
-* PostgreSQL 8.3 or later
-* SQLite 3.3.7 or later
-* Oracle 9.0.1 or later
-* Microsoft SQL Server 2005 (9.00.1399)
-
-== Upgrading ==
-
-1.26 has several database changes since 1.25, and will not work without schema
-updates. Note that due to changes to some very large tables like the revision
-table, the schema update may take quite long (minutes on a medium sized site,
-many hours on a large site).
-
-If upgrading from before 1.11, and you are using a wiki as a commons
-repository, make sure that it is updated as well. Otherwise, errors may arise
-due to database schema changes.
-
-If upgrading from before 1.7, you may want to run refreshLinks.php to ensure
-new database fields are filled with data.
-
-If you are upgrading from MediaWiki 1.4.x or earlier, you should upgrade to
-1.5 first. The upgrade script maintenance/upgrade1_5.php has been removed
-with MediaWiki 1.21.
-
-Don't forget to always back up your database before upgrading!
-
-See the file UPGRADE for more detailed upgrade instructions.
-
-For notes on 1.25.x and older releases, see HISTORY.
-
-== Online documentation ==
-
-Documentation for both end-users and site administrators is available on
-MediaWiki.org, and is covered under the GNU Free Documentation License (except
-for pages that explicitly state that their contents are in the public domain):
-
-       https://www.mediawiki.org/wiki/Documentation
-
-== Mailing list ==
-
-A mailing list is available for MediaWiki user support and discussion:
-
-       https://lists.wikimedia.org/mailman/listinfo/mediawiki-l
-
-A low-traffic announcements-only list is also available:
-
-       https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce
-
-It's highly recommended that you sign up for one of these lists if you're
-going to run a public MediaWiki, so you can be notified of security fixes.
-
-== IRC help ==
-
-There's usually someone online in #mediawiki on irc.freenode.net.
index 262bbbc..8d0853e 100644 (file)
@@ -84,6 +84,9 @@ production.
 * Added MWTimestamp::getTimezoneString() which returns the localized timezone
   string, if available. To localize this string, see the comments of
   $wgLocaltimezone in includes/DefaultSettings.php.
+* Added CentralIdLookup, a service that allows extensions needing a concept of
+  "central" users to get that without having to know about specific central
+  authentication extensions.
 
 === External library changes in 1.27 ===
 ==== Upgraded external libraries ====
index 2844dc7..c37cbaa 100644 (file)
@@ -198,6 +198,7 @@ $wgAutoloadLocalClasses = array(
        'CdbException' => __DIR__ . '/includes/compat/CdbCompat.php',
        'CdbReader' => __DIR__ . '/includes/compat/CdbCompat.php',
        'CdbWriter' => __DIR__ . '/includes/compat/CdbCompat.php',
+       'CentralIdLookup' => __DIR__ . '/includes/user/CentralIdLookup.php',
        'CgzCopyTransaction' => __DIR__ . '/maintenance/storage/recompressTracked.php',
        'ChangePassword' => __DIR__ . '/maintenance/changePassword.php',
        'ChangeTags' => __DIR__ . '/includes/changetags/ChangeTags.php',
@@ -693,6 +694,7 @@ $wgAutoloadLocalClasses = array(
        'LocalFileDeleteBatch' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
        'LocalFileMoveBatch' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
        'LocalFileRestoreBatch' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
+       'LocalIdLookup' => __DIR__ . '/includes/user/LocalIdLookup.php',
        'LocalRepo' => __DIR__ . '/includes/filerepo/LocalRepo.php',
        'LocalSettingsGenerator' => __DIR__ . '/includes/installer/LocalSettingsGenerator.php',
        'LocalisationCache' => __DIR__ . '/includes/cache/LocalisationCache.php',
@@ -1320,9 +1322,9 @@ $wgAutoloadLocalClasses = array(
        'UploadStashZeroLengthFileException' => __DIR__ . '/includes/upload/UploadStash.php',
        'UppercaseCollation' => __DIR__ . '/includes/Collation.php',
        'UsageException' => __DIR__ . '/includes/api/ApiMain.php',
-       'User' => __DIR__ . '/includes/User.php',
-       'UserArray' => __DIR__ . '/includes/UserArray.php',
-       'UserArrayFromResult' => __DIR__ . '/includes/UserArrayFromResult.php',
+       'User' => __DIR__ . '/includes/user/User.php',
+       'UserArray' => __DIR__ . '/includes/user/UserArray.php',
+       'UserArrayFromResult' => __DIR__ . '/includes/user/UserArrayFromResult.php',
        'UserBlockedError' => __DIR__ . '/includes/exception/UserBlockedError.php',
        'UserCache' => __DIR__ . '/includes/cache/UserCache.php',
        'UserDupes' => __DIR__ . '/maintenance/userDupes.inc',
@@ -1330,7 +1332,7 @@ $wgAutoloadLocalClasses = array(
        'UserNotLoggedIn' => __DIR__ . '/includes/exception/UserNotLoggedIn.php',
        'UserOptions' => __DIR__ . '/maintenance/userOptions.inc',
        'UserPasswordPolicy' => __DIR__ . '/includes/password/UserPasswordPolicy.php',
-       'UserRightsProxy' => __DIR__ . '/includes/UserRightsProxy.php',
+       'UserRightsProxy' => __DIR__ . '/includes/user/UserRightsProxy.php',
        'UsercreateTemplate' => __DIR__ . '/includes/templates/Usercreate.php',
        'UserloginTemplate' => __DIR__ . '/includes/templates/Userlogin.php',
        'UserrightsPage' => __DIR__ . '/includes/specials/SpecialUserrights.php',
index fa6f13a..3d859a9 100644 (file)
@@ -2440,10 +2440,8 @@ $wgStyleVersion = '303';
 
 /**
  * This will cache static pages for non-logged-in users to reduce
- * database traffic on public sites.
- * Automatically sets $wgShowIPinHeader = false
- * ResourceLoader requests to default language and skins are cached
- * as well as single module requests.
+ * database traffic on public sites. ResourceLoader requests to default
+ * language and skins are cached as well as single module requests.
  */
 $wgUseFileCache = false;
 
@@ -3162,13 +3160,6 @@ $wgWellFormedXml = true;
  */
 $wgXhtmlNamespaces = array();
 
-/**
- * Show IP address, for non-logged in users. It's necessary to switch this off
- * for some forms of caching.
- * @warning Will disable file cache.
- */
-$wgShowIPinHeader = true;
-
 /**
  * Site notice shown at the top of each page
  *
@@ -4342,6 +4333,21 @@ $wgActiveUserDays = 30;
  * @{
  */
 
+/**
+ * Central ID lookup providers
+ * Key is the provider ID, value is a specification for ObjectFactory
+ * @since 1.27
+ */
+$wgCentralIdLookupProviders = array(
+       'local' => array( 'class' => 'LocalIdLookup' ),
+);
+
+/**
+ * Central ID lookup provider to use by default
+ * @var string
+ */
+$wgCentralIdLookupProvider = 'local';
+
 /**
  * Password policy for local wiki users. A user's effective policy
  * is the superset of all policy statements from the policies for the
index 58936e0..c709d00 100644 (file)
@@ -1211,7 +1211,7 @@ class EditPage {
         * across a recoverable edit conflict, the ID of the newer revision to
         * which we have rebased this page.
         *
-        * @since 1.25
+        * @since 1.27
         * @return int Revision ID
         */
        public function getParentRevId() {
index 60196ab..e6801e3 100644 (file)
@@ -80,7 +80,8 @@ class Http {
                } else {
                        $errors = $status->getErrorsByType( 'error' );
                        $logger = LoggerFactory::getInstance( 'http' );
-                       $logger->warning( $status->getWikiText(), array( 'caller' => $caller ) );
+                       $logger->warning( $status->getWikiText(),
+                               array( 'error' => $errors, 'caller' => $caller, 'content' => $req->getContent() ) );
                        return false;
                }
        }
index 44c1f71..a94bd12 100644 (file)
@@ -421,11 +421,9 @@ if ( is_array( $wgExtraNamespaces ) ) {
 // To determine the user language, use $wgLang->getCode()
 $wgContLanguageCode = $wgLanguageCode;
 
-// Easy to forget to falsify $wgShowIPinHeader for static caches.
+// Easy to forget to falsify $wgDebugToolbar for static caches.
 // If file cache or squid cache is on, just disable this (DWIMD).
-// Do the same for $wgDebugToolbar.
 if ( $wgUseFileCache || $wgUseSquid ) {
-       $wgShowIPinHeader = false;
        $wgDebugToolbar = false;
 }
 
diff --git a/includes/User.php b/includes/User.php
deleted file mode 100644 (file)
index 3d1aa7e..0000000
+++ /dev/null
@@ -1,5334 +0,0 @@
-<?php
-/**
- * Implements the User class for the %MediaWiki software.
- *
- * 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
- */
-
-/**
- * String Some punctuation to prevent editing from broken text-mangling proxies.
- * @ingroup Constants
- */
-define( 'EDIT_TOKEN_SUFFIX', '+\\' );
-
-/**
- * The User object encapsulates all of the user-specific settings (user_id,
- * name, rights, email address, options, last login time). Client
- * classes use the getXXX() functions to access these fields. These functions
- * do all the work of determining whether the user is logged in,
- * whether the requested option can be satisfied from cookies or
- * whether a database query is needed. Most of the settings needed
- * for rendering normal pages are set in the cookie to minimize use
- * of the database.
- */
-class User implements IDBAccessObject {
-       /**
-        * @const int Number of characters in user_token field.
-        */
-       const TOKEN_LENGTH = 32;
-
-       /**
-        * Global constant made accessible as class constants so that autoloader
-        * magic can be used.
-        */
-       const EDIT_TOKEN_SUFFIX = EDIT_TOKEN_SUFFIX;
-
-       /**
-        * @const int Serialized record version.
-        */
-       const VERSION = 10;
-
-       /**
-        * Maximum items in $mWatchedItems
-        */
-       const MAX_WATCHED_ITEMS_CACHE = 100;
-
-       /**
-        * Exclude user options that are set to their default value.
-        * @since 1.25
-        */
-       const GETOPTIONS_EXCLUDE_DEFAULTS = 1;
-
-       /**
-        * Array of Strings List of member variables which are saved to the
-        * shared cache (memcached). Any operation which changes the
-        * corresponding database fields must call a cache-clearing function.
-        * @showinitializer
-        */
-       protected static $mCacheVars = array(
-               // user table
-               'mId',
-               'mName',
-               'mRealName',
-               'mEmail',
-               'mTouched',
-               'mToken',
-               'mEmailAuthenticated',
-               'mEmailToken',
-               'mEmailTokenExpires',
-               'mRegistration',
-               'mEditCount',
-               // user_groups table
-               'mGroups',
-               // user_properties table
-               'mOptionOverrides',
-       );
-
-       /**
-        * Array of Strings Core rights.
-        * Each of these should have a corresponding message of the form
-        * "right-$right".
-        * @showinitializer
-        */
-       protected static $mCoreRights = array(
-               'apihighlimits',
-               'applychangetags',
-               'autoconfirmed',
-               'autopatrol',
-               'bigdelete',
-               'block',
-               'blockemail',
-               'bot',
-               'browsearchive',
-               'changetags',
-               'createaccount',
-               'createpage',
-               'createtalk',
-               'delete',
-               'deletedhistory',
-               'deletedtext',
-               'deletelogentry',
-               'deleterevision',
-               'edit',
-               'editcontentmodel',
-               'editinterface',
-               'editprotected',
-               'editmyoptions',
-               'editmyprivateinfo',
-               'editmyusercss',
-               'editmyuserjs',
-               'editmywatchlist',
-               'editsemiprotected',
-               'editusercssjs', # deprecated
-               'editusercss',
-               'edituserjs',
-               'hideuser',
-               'import',
-               'importupload',
-               'ipblock-exempt',
-               'managechangetags',
-               'markbotedits',
-               'mergehistory',
-               'minoredit',
-               'move',
-               'movefile',
-               'move-categorypages',
-               'move-rootuserpages',
-               'move-subpages',
-               'nominornewtalk',
-               'noratelimit',
-               'override-export-depth',
-               'pagelang',
-               'passwordreset',
-               'patrol',
-               'patrolmarks',
-               'protect',
-               'proxyunbannable',
-               'purge',
-               'read',
-               'reupload',
-               'reupload-own',
-               'reupload-shared',
-               'rollback',
-               'sendemail',
-               'siteadmin',
-               'suppressionlog',
-               'suppressredirect',
-               'suppressrevision',
-               'unblockself',
-               'undelete',
-               'unwatchedpages',
-               'upload',
-               'upload_by_url',
-               'userrights',
-               'userrights-interwiki',
-               'viewmyprivateinfo',
-               'viewmywatchlist',
-               'viewsuppressed',
-               'writeapi',
-       );
-
-       /**
-        * String Cached results of getAllRights()
-        */
-       protected static $mAllRights = false;
-
-       /** Cache variables */
-       // @{
-       public $mId;
-       /** @var string */
-       public $mName;
-       /** @var string */
-       public $mRealName;
-
-       /** @var string */
-       public $mEmail;
-       /** @var string TS_MW timestamp from the DB */
-       public $mTouched;
-       /** @var string TS_MW timestamp from cache */
-       protected $mQuickTouched;
-       /** @var string */
-       protected $mToken;
-       /** @var string */
-       public $mEmailAuthenticated;
-       /** @var string */
-       protected $mEmailToken;
-       /** @var string */
-       protected $mEmailTokenExpires;
-       /** @var string */
-       protected $mRegistration;
-       /** @var int */
-       protected $mEditCount;
-       /** @var array */
-       public $mGroups;
-       /** @var array */
-       protected $mOptionOverrides;
-       // @}
-
-       /**
-        * Bool Whether the cache variables have been loaded.
-        */
-       // @{
-       public $mOptionsLoaded;
-
-       /**
-        * Array with already loaded items or true if all items have been loaded.
-        */
-       protected $mLoadedItems = array();
-       // @}
-
-       /**
-        * String Initialization data source if mLoadedItems!==true. May be one of:
-        *  - 'defaults'   anonymous user initialised from class defaults
-        *  - 'name'       initialise from mName
-        *  - 'id'         initialise from mId
-        *  - 'session'    log in from cookies or session if possible
-        *
-        * Use the User::newFrom*() family of functions to set this.
-        */
-       public $mFrom;
-
-       /**
-        * Lazy-initialized variables, invalidated with clearInstanceCache
-        */
-       protected $mNewtalk;
-       /** @var string */
-       protected $mDatePreference;
-       /** @var string */
-       public $mBlockedby;
-       /** @var string */
-       protected $mHash;
-       /** @var array */
-       public $mRights;
-       /** @var string */
-       protected $mBlockreason;
-       /** @var array */
-       protected $mEffectiveGroups;
-       /** @var array */
-       protected $mImplicitGroups;
-       /** @var array */
-       protected $mFormerGroups;
-       /** @var bool */
-       protected $mBlockedGlobally;
-       /** @var bool */
-       protected $mLocked;
-       /** @var bool */
-       public $mHideName;
-       /** @var array */
-       public $mOptions;
-
-       /**
-        * @var WebRequest
-        */
-       private $mRequest;
-
-       /** @var Block */
-       public $mBlock;
-
-       /** @var bool */
-       protected $mAllowUsertalk;
-
-       /** @var Block */
-       private $mBlockedFromCreateAccount = false;
-
-       /** @var array */
-       private $mWatchedItems = array();
-
-       /** @var integer User::READ_* constant bitfield used to load data */
-       protected $queryFlagsUsed = self::READ_NORMAL;
-
-       public static $idCacheByName = array();
-
-       /**
-        * Lightweight constructor for an anonymous user.
-        * Use the User::newFrom* factory functions for other kinds of users.
-        *
-        * @see newFromName()
-        * @see newFromId()
-        * @see newFromConfirmationCode()
-        * @see newFromSession()
-        * @see newFromRow()
-        */
-       public function __construct() {
-               $this->clearInstanceCache( 'defaults' );
-       }
-
-       /**
-        * @return string
-        */
-       public function __toString() {
-               return $this->getName();
-       }
-
-       /**
-        * Load the user table data for this object from the source given by mFrom.
-        *
-        * @param integer $flags User::READ_* constant bitfield
-        */
-       public function load( $flags = self::READ_NORMAL ) {
-               if ( $this->mLoadedItems === true ) {
-                       return;
-               }
-
-               // Set it now to avoid infinite recursion in accessors
-               $this->mLoadedItems = true;
-               $this->queryFlagsUsed = $flags;
-
-               switch ( $this->mFrom ) {
-                       case 'defaults':
-                               $this->loadDefaults();
-                               break;
-                       case 'name':
-                               // Make sure this thread sees its own changes
-                               if ( wfGetLB()->hasOrMadeRecentMasterChanges() ) {
-                                       $flags |= self::READ_LATEST;
-                                       $this->queryFlagsUsed = $flags;
-                               }
-
-                               $this->mId = self::idFromName( $this->mName, $flags );
-                               if ( !$this->mId ) {
-                                       // Nonexistent user placeholder object
-                                       $this->loadDefaults( $this->mName );
-                               } else {
-                                       $this->loadFromId( $flags );
-                               }
-                               break;
-                       case 'id':
-                               $this->loadFromId( $flags );
-                               break;
-                       case 'session':
-                               if ( !$this->loadFromSession() ) {
-                                       // Loading from session failed. Load defaults.
-                                       $this->loadDefaults();
-                               }
-                               Hooks::run( 'UserLoadAfterLoadFromSession', array( $this ) );
-                               break;
-                       default:
-                               throw new UnexpectedValueException(
-                                       "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
-               }
-       }
-
-       /**
-        * Load user table data, given mId has already been set.
-        * @param integer $flags User::READ_* constant bitfield
-        * @return bool False if the ID does not exist, true otherwise
-        */
-       public function loadFromId( $flags = self::READ_NORMAL ) {
-               if ( $this->mId == 0 ) {
-                       $this->loadDefaults();
-                       return false;
-               }
-
-               // Try cache (unless this needs data from the master DB).
-               // NOTE: if this thread called saveSettings(), the cache was cleared.
-               $latest = DBAccessObjectUtils::hasFlags( $flags, self::READ_LATEST );
-               if ( $latest || !$this->loadFromCache() ) {
-                       wfDebug( "User: cache miss for user {$this->mId}\n" );
-                       // Load from DB (make sure this thread sees its own changes)
-                       if ( wfGetLB()->hasOrMadeRecentMasterChanges() ) {
-                               $flags |= self::READ_LATEST;
-                       }
-                       if ( !$this->loadFromDatabase( $flags ) ) {
-                               // Can't load from ID, user is anonymous
-                               return false;
-                       }
-                       $this->saveToCache();
-               }
-
-               $this->mLoadedItems = true;
-               $this->queryFlagsUsed = $flags;
-
-               return true;
-       }
-
-       /**
-        * @since 1.27
-        * @param string $wikiId
-        * @param integer $userId
-        */
-       public static function purge( $wikiId, $userId ) {
-               $cache = ObjectCache::getMainWANInstance();
-               $cache->delete( $cache->makeGlobalKey( 'user', 'id', $wikiId, $userId ) );
-       }
-
-       /**
-        * @since 1.27
-        * @param WANObjectCache $cache
-        * @return string
-        */
-       protected function getCacheKey( WANObjectCache $cache ) {
-               return $cache->makeGlobalKey( 'user', 'id', wfWikiID(), $this->mId );
-       }
-
-       /**
-        * Load user data from shared cache, given mId has already been set.
-        *
-        * @return bool false if the ID does not exist or data is invalid, true otherwise
-        * @since 1.25
-        */
-       protected function loadFromCache() {
-               if ( $this->mId == 0 ) {
-                       $this->loadDefaults();
-                       return false;
-               }
-
-               $cache = ObjectCache::getMainWANInstance();
-               $data = $cache->get( $this->getCacheKey( $cache ) );
-               if ( !is_array( $data ) || $data['mVersion'] < self::VERSION ) {
-                       // Object is expired
-                       return false;
-               }
-
-               wfDebug( "User: got user {$this->mId} from cache\n" );
-
-               // Restore from cache
-               foreach ( self::$mCacheVars as $name ) {
-                       $this->$name = $data[$name];
-               }
-
-               return true;
-       }
-
-       /**
-        * Save user data to the shared cache
-        *
-        * This method should not be called outside the User class
-        */
-       public function saveToCache() {
-               $this->load();
-               $this->loadGroups();
-               $this->loadOptions();
-
-               if ( $this->isAnon() ) {
-                       // Anonymous users are uncached
-                       return;
-               }
-
-               $data = array();
-               foreach ( self::$mCacheVars as $name ) {
-                       $data[$name] = $this->$name;
-               }
-               $data['mVersion'] = self::VERSION;
-               $opts = Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) );
-
-               $cache = ObjectCache::getMainWANInstance();
-               $key = $this->getCacheKey( $cache );
-               $cache->set( $key, $data, $cache::TTL_HOUR, $opts );
-       }
-
-       /** @name newFrom*() static factory methods */
-       // @{
-
-       /**
-        * Static factory method for creation from username.
-        *
-        * This is slightly less efficient than newFromId(), so use newFromId() if
-        * you have both an ID and a name handy.
-        *
-        * @param string $name Username, validated by Title::newFromText()
-        * @param string|bool $validate Validate username. Takes the same parameters as
-        *  User::getCanonicalName(), except that true is accepted as an alias
-        *  for 'valid', for BC.
-        *
-        * @return User|bool User object, or false if the username is invalid
-        *  (e.g. if it contains illegal characters or is an IP address). If the
-        *  username is not present in the database, the result will be a user object
-        *  with a name, zero user ID and default settings.
-        */
-       public static function newFromName( $name, $validate = 'valid' ) {
-               if ( $validate === true ) {
-                       $validate = 'valid';
-               }
-               $name = self::getCanonicalName( $name, $validate );
-               if ( $name === false ) {
-                       return false;
-               } else {
-                       // Create unloaded user object
-                       $u = new User;
-                       $u->mName = $name;
-                       $u->mFrom = 'name';
-                       $u->setItemLoaded( 'name' );
-                       return $u;
-               }
-       }
-
-       /**
-        * Static factory method for creation from a given user ID.
-        *
-        * @param int $id Valid user ID
-        * @return User The corresponding User object
-        */
-       public static function newFromId( $id ) {
-               $u = new User;
-               $u->mId = $id;
-               $u->mFrom = 'id';
-               $u->setItemLoaded( 'id' );
-               return $u;
-       }
-
-       /**
-        * Factory method to fetch whichever user has a given email confirmation code.
-        * This code is generated when an account is created or its e-mail address
-        * has changed.
-        *
-        * If the code is invalid or has expired, returns NULL.
-        *
-        * @param string $code Confirmation code
-        * @param int $flags User::READ_* bitfield
-        * @return User|null
-        */
-       public static function newFromConfirmationCode( $code, $flags = 0 ) {
-               $db = ( $flags & self::READ_LATEST ) == self::READ_LATEST
-                       ? wfGetDB( DB_MASTER )
-                       : wfGetDB( DB_SLAVE );
-
-               $id = $db->selectField(
-                       'user',
-                       'user_id',
-                       array(
-                               'user_email_token' => md5( $code ),
-                               'user_email_token_expires > ' . $db->addQuotes( $db->timestamp() ),
-                       )
-               );
-
-               return $id ? User::newFromId( $id ) : null;
-       }
-
-       /**
-        * Create a new user object using data from session or cookies. If the
-        * login credentials are invalid, the result is an anonymous user.
-        *
-        * @param WebRequest|null $request Object to use; $wgRequest will be used if omitted.
-        * @return User
-        */
-       public static function newFromSession( WebRequest $request = null ) {
-               $user = new User;
-               $user->mFrom = 'session';
-               $user->mRequest = $request;
-               return $user;
-       }
-
-       /**
-        * Create a new user object from a user row.
-        * The row should have the following fields from the user table in it:
-        * - either user_name or user_id to load further data if needed (or both)
-        * - user_real_name
-        * - all other fields (email, etc.)
-        * It is useless to provide the remaining fields if either user_id,
-        * user_name and user_real_name are not provided because the whole row
-        * will be loaded once more from the database when accessing them.
-        *
-        * @param stdClass $row A row from the user table
-        * @param array $data Further data to load into the object (see User::loadFromRow for valid keys)
-        * @return User
-        */
-       public static function newFromRow( $row, $data = null ) {
-               $user = new User;
-               $user->loadFromRow( $row, $data );
-               return $user;
-       }
-
-       /**
-        * Static factory method for creation of a "system" user from username.
-        *
-        * A "system" user is an account that's used to attribute logged actions
-        * taken by MediaWiki itself, as opposed to a bot or human user. Examples
-        * might include the 'Maintenance script' or 'Conversion script' accounts
-        * used by various scripts in the maintenance/ directory or accounts such
-        * as 'MediaWiki message delivery' used by the MassMessage extension.
-        *
-        * This can optionally create the user if it doesn't exist, and "steal" the
-        * account if it does exist.
-        *
-        * @param string $name Username
-        * @param array $options Options are:
-        *  - validate: As for User::getCanonicalName(), default 'valid'
-        *  - create: Whether to create the user if it doesn't already exist, default true
-        *  - steal: Whether to reset the account's password and email if it
-        *    already exists, default false
-        * @return User|null
-        */
-       public static function newSystemUser( $name, $options = array() ) {
-               $options += array(
-                       'validate' => 'valid',
-                       'create' => true,
-                       'steal' => false,
-               );
-
-               $name = self::getCanonicalName( $name, $options['validate'] );
-               if ( $name === false ) {
-                       return null;
-               }
-
-               $dbw = wfGetDB( DB_MASTER );
-               $row = $dbw->selectRow(
-                       'user',
-                       array_merge(
-                               self::selectFields(),
-                               array( 'user_password', 'user_newpassword' )
-                       ),
-                       array( 'user_name' => $name ),
-                       __METHOD__
-               );
-               if ( !$row ) {
-                       // No user. Create it?
-                       return $options['create'] ? self::createNew( $name ) : null;
-               }
-               $user = self::newFromRow( $row );
-
-               // A user is considered to exist as a non-system user if it has a
-               // password set, or a temporary password set, or an email set.
-               $passwordFactory = new PasswordFactory();
-               $passwordFactory->init( RequestContext::getMain()->getConfig() );
-               try {
-                       $password = $passwordFactory->newFromCiphertext( $row->user_password );
-               } catch ( PasswordError $e ) {
-                       wfDebug( 'Invalid password hash found in database.' );
-                       $password = PasswordFactory::newInvalidPassword();
-               }
-               try {
-                       $newpassword = $passwordFactory->newFromCiphertext( $row->user_newpassword );
-               } catch ( PasswordError $e ) {
-                       wfDebug( 'Invalid password hash found in database.' );
-                       $newpassword = PasswordFactory::newInvalidPassword();
-               }
-               if ( !$password instanceof InvalidPassword || !$newpassword instanceof InvalidPassword
-                       || $user->mEmail
-               ) {
-                       // User exists. Steal it?
-                       if ( !$options['steal'] ) {
-                               return null;
-                       }
-
-                       $nopass = PasswordFactory::newInvalidPassword()->toString();
-
-                       $dbw->update(
-                               'user',
-                               array(
-                                       'user_password' => $nopass,
-                                       'user_newpassword' => $nopass,
-                                       'user_newpass_time' => null,
-                               ),
-                               array( 'user_id' => $user->getId() ),
-                               __METHOD__
-                       );
-                       $user->invalidateEmail();
-                       $user->saveSettings();
-               }
-
-               return $user;
-       }
-
-       // @}
-
-       /**
-        * Get the username corresponding to a given user ID
-        * @param int $id User ID
-        * @return string|bool The corresponding username
-        */
-       public static function whoIs( $id ) {
-               return UserCache::singleton()->getProp( $id, 'name' );
-       }
-
-       /**
-        * Get the real name of a user given their user ID
-        *
-        * @param int $id User ID
-        * @return string|bool The corresponding user's real name
-        */
-       public static function whoIsReal( $id ) {
-               return UserCache::singleton()->getProp( $id, 'real_name' );
-       }
-
-       /**
-        * Get database id given a user name
-        * @param string $name Username
-        * @param integer $flags User::READ_* constant bitfield
-        * @return int|null The corresponding user's ID, or null if user is nonexistent
-        */
-       public static function idFromName( $name, $flags = self::READ_NORMAL ) {
-               $nt = Title::makeTitleSafe( NS_USER, $name );
-               if ( is_null( $nt ) ) {
-                       // Illegal name
-                       return null;
-               }
-
-               if ( !( $flags & self::READ_LATEST ) && isset( self::$idCacheByName[$name] ) ) {
-                       return self::$idCacheByName[$name];
-               }
-
-               $db = ( $flags & self::READ_LATEST )
-                       ? wfGetDB( DB_MASTER )
-                       : wfGetDB( DB_SLAVE );
-
-               $s = $db->selectRow(
-                       'user',
-                       array( 'user_id' ),
-                       array( 'user_name' => $nt->getText() ),
-                       __METHOD__
-               );
-
-               if ( $s === false ) {
-                       $result = null;
-               } else {
-                       $result = $s->user_id;
-               }
-
-               self::$idCacheByName[$name] = $result;
-
-               if ( count( self::$idCacheByName ) > 1000 ) {
-                       self::$idCacheByName = array();
-               }
-
-               return $result;
-       }
-
-       /**
-        * Reset the cache used in idFromName(). For use in tests.
-        */
-       public static function resetIdByNameCache() {
-               self::$idCacheByName = array();
-       }
-
-       /**
-        * Does the string match an anonymous IPv4 address?
-        *
-        * This function exists for username validation, in order to reject
-        * usernames which are similar in form to IP addresses. Strings such
-        * as 300.300.300.300 will return true because it looks like an IP
-        * address, despite not being strictly valid.
-        *
-        * We match "\d{1,3}\.\d{1,3}\.\d{1,3}\.xxx" as an anonymous IP
-        * address because the usemod software would "cloak" anonymous IP
-        * addresses like this, if we allowed accounts like this to be created
-        * new users could get the old edits of these anonymous users.
-        *
-        * @param string $name Name to match
-        * @return bool
-        */
-       public static function isIP( $name ) {
-               return preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/', $name )
-                       || IP::isIPv6( $name );
-       }
-
-       /**
-        * Is the input a valid username?
-        *
-        * Checks if the input is a valid username, we don't want an empty string,
-        * an IP address, anything that contains slashes (would mess up subpages),
-        * is longer than the maximum allowed username size or doesn't begin with
-        * a capital letter.
-        *
-        * @param string $name Name to match
-        * @return bool
-        */
-       public static function isValidUserName( $name ) {
-               global $wgContLang, $wgMaxNameChars;
-
-               if ( $name == ''
-                       || User::isIP( $name )
-                       || strpos( $name, '/' ) !== false
-                       || strlen( $name ) > $wgMaxNameChars
-                       || $name != $wgContLang->ucfirst( $name )
-               ) {
-                       wfDebugLog( 'username', __METHOD__ .
-                               ": '$name' invalid due to empty, IP, slash, length, or lowercase" );
-                       return false;
-               }
-
-               // Ensure that the name can't be misresolved as a different title,
-               // such as with extra namespace keys at the start.
-               $parsed = Title::newFromText( $name );
-               if ( is_null( $parsed )
-                       || $parsed->getNamespace()
-                       || strcmp( $name, $parsed->getPrefixedText() ) ) {
-                       wfDebugLog( 'username', __METHOD__ .
-                               ": '$name' invalid due to ambiguous prefixes" );
-                       return false;
-               }
-
-               // Check an additional blacklist of troublemaker characters.
-               // Should these be merged into the title char list?
-               $unicodeBlacklist = '/[' .
-                       '\x{0080}-\x{009f}' . # iso-8859-1 control chars
-                       '\x{00a0}' .          # non-breaking space
-                       '\x{2000}-\x{200f}' . # various whitespace
-                       '\x{2028}-\x{202f}' . # breaks and control chars
-                       '\x{3000}' .          # ideographic space
-                       '\x{e000}-\x{f8ff}' . # private use
-                       ']/u';
-               if ( preg_match( $unicodeBlacklist, $name ) ) {
-                       wfDebugLog( 'username', __METHOD__ .
-                               ": '$name' invalid due to blacklisted characters" );
-                       return false;
-               }
-
-               return true;
-       }
-
-       /**
-        * Usernames which fail to pass this function will be blocked
-        * from user login and new account registrations, but may be used
-        * internally by batch processes.
-        *
-        * If an account already exists in this form, login will be blocked
-        * by a failure to pass this function.
-        *
-        * @param string $name Name to match
-        * @return bool
-        */
-       public static function isUsableName( $name ) {
-               global $wgReservedUsernames;
-               // Must be a valid username, obviously ;)
-               if ( !self::isValidUserName( $name ) ) {
-                       return false;
-               }
-
-               static $reservedUsernames = false;
-               if ( !$reservedUsernames ) {
-                       $reservedUsernames = $wgReservedUsernames;
-                       Hooks::run( 'UserGetReservedNames', array( &$reservedUsernames ) );
-               }
-
-               // Certain names may be reserved for batch processes.
-               foreach ( $reservedUsernames as $reserved ) {
-                       if ( substr( $reserved, 0, 4 ) == 'msg:' ) {
-                               $reserved = wfMessage( substr( $reserved, 4 ) )->inContentLanguage()->text();
-                       }
-                       if ( $reserved == $name ) {
-                               return false;
-                       }
-               }
-               return true;
-       }
-
-       /**
-        * Usernames which fail to pass this function will be blocked
-        * from new account registrations, but may be used internally
-        * either by batch processes or by user accounts which have
-        * already been created.
-        *
-        * Additional blacklisting may be added here rather than in
-        * isValidUserName() to avoid disrupting existing accounts.
-        *
-        * @param string $name String to match
-        * @return bool
-        */
-       public static function isCreatableName( $name ) {
-               global $wgInvalidUsernameCharacters;
-
-               // Ensure that the username isn't longer than 235 bytes, so that
-               // (at least for the builtin skins) user javascript and css files
-               // will work. (bug 23080)
-               if ( strlen( $name ) > 235 ) {
-                       wfDebugLog( 'username', __METHOD__ .
-                               ": '$name' invalid due to length" );
-                       return false;
-               }
-
-               // Preg yells if you try to give it an empty string
-               if ( $wgInvalidUsernameCharacters !== '' ) {
-                       if ( preg_match( '/[' . preg_quote( $wgInvalidUsernameCharacters, '/' ) . ']/', $name ) ) {
-                               wfDebugLog( 'username', __METHOD__ .
-                                       ": '$name' invalid due to wgInvalidUsernameCharacters" );
-                               return false;
-                       }
-               }
-
-               return self::isUsableName( $name );
-       }
-
-       /**
-        * Is the input a valid password for this user?
-        *
-        * @param string $password Desired password
-        * @return bool
-        */
-       public function isValidPassword( $password ) {
-               // simple boolean wrapper for getPasswordValidity
-               return $this->getPasswordValidity( $password ) === true;
-       }
-
-
-       /**
-        * Given unvalidated password input, return error message on failure.
-        *
-        * @param string $password Desired password
-        * @return bool|string|array True on success, string or array of error message on failure
-        */
-       public function getPasswordValidity( $password ) {
-               $result = $this->checkPasswordValidity( $password );
-               if ( $result->isGood() ) {
-                       return true;
-               } else {
-                       $messages = array();
-                       foreach ( $result->getErrorsByType( 'error' ) as $error ) {
-                               $messages[] = $error['message'];
-                       }
-                       foreach ( $result->getErrorsByType( 'warning' ) as $warning ) {
-                               $messages[] = $warning['message'];
-                       }
-                       if ( count( $messages ) === 1 ) {
-                               return $messages[0];
-                       }
-                       return $messages;
-               }
-       }
-
-       /**
-        * Check if this is a valid password for this user
-        *
-        * Create a Status object based on the password's validity.
-        * The Status should be set to fatal if the user should not
-        * be allowed to log in, and should have any errors that
-        * would block changing the password.
-        *
-        * If the return value of this is not OK, the password
-        * should not be checked. If the return value is not Good,
-        * the password can be checked, but the user should not be
-        * able to set their password to this.
-        *
-        * @param string $password Desired password
-        * @param string $purpose one of 'login', 'create', 'reset'
-        * @return Status
-        * @since 1.23
-        */
-       public function checkPasswordValidity( $password, $purpose = 'login' ) {
-               global $wgPasswordPolicy;
-
-               $upp = new UserPasswordPolicy(
-                       $wgPasswordPolicy['policies'],
-                       $wgPasswordPolicy['checks']
-               );
-
-               $status = Status::newGood();
-               $result = false; // init $result to false for the internal checks
-
-               if ( !Hooks::run( 'isValidPassword', array( $password, &$result, $this ) ) ) {
-                       $status->error( $result );
-                       return $status;
-               }
-
-               if ( $result === false ) {
-                       $status->merge( $upp->checkUserPassword( $this, $password, $purpose ) );
-                       return $status;
-               } elseif ( $result === true ) {
-                       return $status;
-               } else {
-                       $status->error( $result );
-                       return $status; // the isValidPassword hook set a string $result and returned true
-               }
-       }
-
-       /**
-        * Given unvalidated user input, return a canonical username, or false if
-        * the username is invalid.
-        * @param string $name User input
-        * @param string|bool $validate Type of validation to use:
-        *   - false        No validation
-        *   - 'valid'      Valid for batch processes
-        *   - 'usable'     Valid for batch processes and login
-        *   - 'creatable'  Valid for batch processes, login and account creation
-        *
-        * @throws InvalidArgumentException
-        * @return bool|string
-        */
-       public static function getCanonicalName( $name, $validate = 'valid' ) {
-               // Force usernames to capital
-               global $wgContLang;
-               $name = $wgContLang->ucfirst( $name );
-
-               # Reject names containing '#'; these will be cleaned up
-               # with title normalisation, but then it's too late to
-               # check elsewhere
-               if ( strpos( $name, '#' ) !== false ) {
-                       return false;
-               }
-
-               // Clean up name according to title rules,
-               // but only when validation is requested (bug 12654)
-               $t = ( $validate !== false ) ?
-                       Title::newFromText( $name ) : Title::makeTitle( NS_USER, $name );
-               // Check for invalid titles
-               if ( is_null( $t ) ) {
-                       return false;
-               }
-
-               // Reject various classes of invalid names
-               global $wgAuth;
-               $name = $wgAuth->getCanonicalName( $t->getText() );
-
-               switch ( $validate ) {
-                       case false:
-                               break;
-                       case 'valid':
-                               if ( !User::isValidUserName( $name ) ) {
-                                       $name = false;
-                               }
-                               break;
-                       case 'usable':
-                               if ( !User::isUsableName( $name ) ) {
-                                       $name = false;
-                               }
-                               break;
-                       case 'creatable':
-                               if ( !User::isCreatableName( $name ) ) {
-                                       $name = false;
-                               }
-                               break;
-                       default:
-                               throw new InvalidArgumentException(
-                                       'Invalid parameter value for $validate in ' . __METHOD__ );
-               }
-               return $name;
-       }
-
-       /**
-        * Count the number of edits of a user
-        *
-        * @param int $uid User ID to check
-        * @return int The user's edit count
-        *
-        * @deprecated since 1.21 in favour of User::getEditCount
-        */
-       public static function edits( $uid ) {
-               wfDeprecated( __METHOD__, '1.21' );
-               $user = self::newFromId( $uid );
-               return $user->getEditCount();
-       }
-
-       /**
-        * Return a random password.
-        *
-        * @deprecated since 1.27, use PasswordFactory::generateRandomPasswordString()
-        * @return string New random password
-        */
-       public static function randomPassword() {
-               global $wgMinimalPasswordLength;
-               return PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
-       }
-
-       /**
-        * Set cached properties to default.
-        *
-        * @note This no longer clears uncached lazy-initialised properties;
-        *       the constructor does that instead.
-        *
-        * @param string|bool $name
-        */
-       public function loadDefaults( $name = false ) {
-               $this->mId = 0;
-               $this->mName = $name;
-               $this->mRealName = '';
-               $this->mEmail = '';
-               $this->mOptionOverrides = null;
-               $this->mOptionsLoaded = false;
-
-               $loggedOut = $this->getRequest()->getCookie( 'LoggedOut' );
-               if ( $loggedOut !== null ) {
-                       $this->mTouched = wfTimestamp( TS_MW, $loggedOut );
-               } else {
-                       $this->mTouched = '1'; # Allow any pages to be cached
-               }
-
-               $this->mToken = null; // Don't run cryptographic functions till we need a token
-               $this->mEmailAuthenticated = null;
-               $this->mEmailToken = '';
-               $this->mEmailTokenExpires = null;
-               $this->mRegistration = wfTimestamp( TS_MW );
-               $this->mGroups = array();
-
-               Hooks::run( 'UserLoadDefaults', array( $this, $name ) );
-       }
-
-       /**
-        * Return whether an item has been loaded.
-        *
-        * @param string $item Item to check. Current possibilities:
-        *   - id
-        *   - name
-        *   - realname
-        * @param string $all 'all' to check if the whole object has been loaded
-        *   or any other string to check if only the item is available (e.g.
-        *   for optimisation)
-        * @return bool
-        */
-       public function isItemLoaded( $item, $all = 'all' ) {
-               return ( $this->mLoadedItems === true && $all === 'all' ) ||
-                       ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] === true );
-       }
-
-       /**
-        * Set that an item has been loaded
-        *
-        * @param string $item
-        */
-       protected function setItemLoaded( $item ) {
-               if ( is_array( $this->mLoadedItems ) ) {
-                       $this->mLoadedItems[$item] = true;
-               }
-       }
-
-       /**
-        * Load user data from the session or login cookie.
-        *
-        * @return bool True if the user is logged in, false otherwise.
-        */
-       private function loadFromSession() {
-               $result = null;
-               Hooks::run( 'UserLoadFromSession', array( $this, &$result ) );
-               if ( $result !== null ) {
-                       return $result;
-               }
-
-               $request = $this->getRequest();
-
-               $cookieId = $request->getCookie( 'UserID' );
-               $sessId = $request->getSessionData( 'wsUserID' );
-
-               if ( $cookieId !== null ) {
-                       $sId = intval( $cookieId );
-                       if ( $sessId !== null && $cookieId != $sessId ) {
-                               wfDebugLog( 'loginSessions', "Session user ID ($sessId) and
-                                       cookie user ID ($sId) don't match!" );
-                               return false;
-                       }
-                       $request->setSessionData( 'wsUserID', $sId );
-               } elseif ( $sessId !== null && $sessId != 0 ) {
-                       $sId = $sessId;
-               } else {
-                       return false;
-               }
-
-               if ( $request->getSessionData( 'wsUserName' ) !== null ) {
-                       $sName = $request->getSessionData( 'wsUserName' );
-               } elseif ( $request->getCookie( 'UserName' ) !== null ) {
-                       $sName = $request->getCookie( 'UserName' );
-                       $request->setSessionData( 'wsUserName', $sName );
-               } else {
-                       return false;
-               }
-
-               $proposedUser = User::newFromId( $sId );
-               if ( !$proposedUser->isLoggedIn() ) {
-                       // Not a valid ID
-                       return false;
-               }
-
-               global $wgBlockDisablesLogin;
-               if ( $wgBlockDisablesLogin && $proposedUser->isBlocked() ) {
-                       // User blocked and we've disabled blocked user logins
-                       return false;
-               }
-
-               if ( $request->getSessionData( 'wsToken' ) ) {
-                       $passwordCorrect =
-                               ( $proposedUser->getToken( false ) === $request->getSessionData( 'wsToken' ) );
-                       $from = 'session';
-               } elseif ( $request->getCookie( 'Token' ) ) {
-                       # Get the token from DB/cache and clean it up to remove garbage padding.
-                       # This deals with historical problems with bugs and the default column value.
-                       $token = rtrim( $proposedUser->getToken( false ) ); // correct token
-                       // Make comparison in constant time (bug 61346)
-                       $passwordCorrect = strlen( $token )
-                               && hash_equals( $token, $request->getCookie( 'Token' ) );
-                       $from = 'cookie';
-               } else {
-                       // No session or persistent login cookie
-                       return false;
-               }
-
-               if ( ( $sName === $proposedUser->getName() ) && $passwordCorrect ) {
-                       $this->loadFromUserObject( $proposedUser );
-                       $request->setSessionData( 'wsToken', $this->mToken );
-                       wfDebug( "User: logged in from $from\n" );
-                       return true;
-               } else {
-                       // Invalid credentials
-                       wfDebug( "User: can't log in from $from, invalid credentials\n" );
-                       return false;
-               }
-       }
-
-       /**
-        * Load user and user_group data from the database.
-        * $this->mId must be set, this is how the user is identified.
-        *
-        * @param integer $flags User::READ_* constant bitfield
-        * @return bool True if the user exists, false if the user is anonymous
-        */
-       public function loadFromDatabase( $flags = self::READ_LATEST ) {
-               // Paranoia
-               $this->mId = intval( $this->mId );
-
-               // Anonymous user
-               if ( !$this->mId ) {
-                       $this->loadDefaults();
-                       return false;
-               }
-
-               list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
-               $db = wfGetDB( $index );
-
-               $s = $db->selectRow(
-                       'user',
-                       self::selectFields(),
-                       array( 'user_id' => $this->mId ),
-                       __METHOD__,
-                       $options
-               );
-
-               $this->queryFlagsUsed = $flags;
-               Hooks::run( 'UserLoadFromDatabase', array( $this, &$s ) );
-
-               if ( $s !== false ) {
-                       // Initialise user table data
-                       $this->loadFromRow( $s );
-                       $this->mGroups = null; // deferred
-                       $this->getEditCount(); // revalidation for nulls
-                       return true;
-               } else {
-                       // Invalid user_id
-                       $this->mId = 0;
-                       $this->loadDefaults();
-                       return false;
-               }
-       }
-
-       /**
-        * Initialize this object from a row from the user table.
-        *
-        * @param stdClass $row Row from the user table to load.
-        * @param array $data Further user data to load into the object
-        *
-        *      user_groups             Array with groups out of the user_groups table
-        *      user_properties         Array with properties out of the user_properties table
-        */
-       protected function loadFromRow( $row, $data = null ) {
-               $all = true;
-
-               $this->mGroups = null; // deferred
-
-               if ( isset( $row->user_name ) ) {
-                       $this->mName = $row->user_name;
-                       $this->mFrom = 'name';
-                       $this->setItemLoaded( 'name' );
-               } else {
-                       $all = false;
-               }
-
-               if ( isset( $row->user_real_name ) ) {
-                       $this->mRealName = $row->user_real_name;
-                       $this->setItemLoaded( 'realname' );
-               } else {
-                       $all = false;
-               }
-
-               if ( isset( $row->user_id ) ) {
-                       $this->mId = intval( $row->user_id );
-                       $this->mFrom = 'id';
-                       $this->setItemLoaded( 'id' );
-               } else {
-                       $all = false;
-               }
-
-               if ( isset( $row->user_id ) && isset( $row->user_name ) ) {
-                       self::$idCacheByName[$row->user_name] = $row->user_id;
-               }
-
-               if ( isset( $row->user_editcount ) ) {
-                       $this->mEditCount = $row->user_editcount;
-               } else {
-                       $all = false;
-               }
-
-               if ( isset( $row->user_email ) ) {
-                       $this->mEmail = $row->user_email;
-                       $this->mTouched = wfTimestamp( TS_MW, $row->user_touched );
-                       $this->mToken = $row->user_token;
-                       if ( $this->mToken == '' ) {
-                               $this->mToken = null;
-                       }
-                       $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
-                       $this->mEmailToken = $row->user_email_token;
-                       $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
-                       $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
-               } else {
-                       $all = false;
-               }
-
-               if ( $all ) {
-                       $this->mLoadedItems = true;
-               }
-
-               if ( is_array( $data ) ) {
-                       if ( isset( $data['user_groups'] ) && is_array( $data['user_groups'] ) ) {
-                               $this->mGroups = $data['user_groups'];
-                       }
-                       if ( isset( $data['user_properties'] ) && is_array( $data['user_properties'] ) ) {
-                               $this->loadOptions( $data['user_properties'] );
-                       }
-               }
-       }
-
-       /**
-        * Load the data for this user object from another user object.
-        *
-        * @param User $user
-        */
-       protected function loadFromUserObject( $user ) {
-               $user->load();
-               $user->loadGroups();
-               $user->loadOptions();
-               foreach ( self::$mCacheVars as $var ) {
-                       $this->$var = $user->$var;
-               }
-       }
-
-       /**
-        * Load the groups from the database if they aren't already loaded.
-        */
-       private function loadGroups() {
-               if ( is_null( $this->mGroups ) ) {
-                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                               ? wfGetDB( DB_MASTER )
-                               : wfGetDB( DB_SLAVE );
-                       $res = $db->select( 'user_groups',
-                               array( 'ug_group' ),
-                               array( 'ug_user' => $this->mId ),
-                               __METHOD__ );
-                       $this->mGroups = array();
-                       foreach ( $res as $row ) {
-                               $this->mGroups[] = $row->ug_group;
-                       }
-               }
-       }
-
-       /**
-        * Add the user to the group if he/she meets given criteria.
-        *
-        * Contrary to autopromotion by \ref $wgAutopromote, the group will be
-        *   possible to remove manually via Special:UserRights. In such case it
-        *   will not be re-added automatically. The user will also not lose the
-        *   group if they no longer meet the criteria.
-        *
-        * @param string $event Key in $wgAutopromoteOnce (each one has groups/criteria)
-        *
-        * @return array Array of groups the user has been promoted to.
-        *
-        * @see $wgAutopromoteOnce
-        */
-       public function addAutopromoteOnceGroups( $event ) {
-               global $wgAutopromoteOnceLogInRC, $wgAuth;
-
-               if ( wfReadOnly() || !$this->getId() ) {
-                       return array();
-               }
-
-               $toPromote = Autopromote::getAutopromoteOnceGroups( $this, $event );
-               if ( !count( $toPromote ) ) {
-                       return array();
-               }
-
-               if ( !$this->checkAndSetTouched() ) {
-                       return array(); // raced out (bug T48834)
-               }
-
-               $oldGroups = $this->getGroups(); // previous groups
-               foreach ( $toPromote as $group ) {
-                       $this->addGroup( $group );
-               }
-               // update groups in external authentication database
-               Hooks::run( 'UserGroupsChanged', array( $this, $toPromote, array(), false ) );
-               $wgAuth->updateExternalDBGroups( $this, $toPromote );
-
-               $newGroups = array_merge( $oldGroups, $toPromote ); // all groups
-
-               $logEntry = new ManualLogEntry( 'rights', 'autopromote' );
-               $logEntry->setPerformer( $this );
-               $logEntry->setTarget( $this->getUserPage() );
-               $logEntry->setParameters( array(
-                       '4::oldgroups' => $oldGroups,
-                       '5::newgroups' => $newGroups,
-               ) );
-               $logid = $logEntry->insert();
-               if ( $wgAutopromoteOnceLogInRC ) {
-                       $logEntry->publish( $logid );
-               }
-
-               return $toPromote;
-       }
-
-       /**
-        * Bump user_touched if it didn't change since this object was loaded
-        *
-        * On success, the mTouched field is updated.
-        * The user serialization cache is always cleared.
-        *
-        * @return bool Whether user_touched was actually updated
-        * @since 1.26
-        */
-       protected function checkAndSetTouched() {
-               $this->load();
-
-               if ( !$this->mId ) {
-                       return false; // anon
-               }
-
-               // Get a new user_touched that is higher than the old one
-               $oldTouched = $this->mTouched;
-               $newTouched = $this->newTouchedTimestamp();
-
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->update( 'user',
-                       array( 'user_touched' => $dbw->timestamp( $newTouched ) ),
-                       array(
-                               'user_id' => $this->mId,
-                               'user_touched' => $dbw->timestamp( $oldTouched ) // CAS check
-                       ),
-                       __METHOD__
-               );
-               $success = ( $dbw->affectedRows() > 0 );
-
-               if ( $success ) {
-                       $this->mTouched = $newTouched;
-                       $this->clearSharedCache();
-               } else {
-                       // Clears on failure too since that is desired if the cache is stale
-                       $this->clearSharedCache( 'refresh' );
-               }
-
-               return $success;
-       }
-
-       /**
-        * Clear various cached data stored in this object. The cache of the user table
-        * data (i.e. self::$mCacheVars) is not cleared unless $reloadFrom is given.
-        *
-        * @param bool|string $reloadFrom Reload user and user_groups table data from a
-        *   given source. May be "name", "id", "defaults", "session", or false for no reload.
-        */
-       public function clearInstanceCache( $reloadFrom = false ) {
-               $this->mNewtalk = -1;
-               $this->mDatePreference = null;
-               $this->mBlockedby = -1; # Unset
-               $this->mHash = false;
-               $this->mRights = null;
-               $this->mEffectiveGroups = null;
-               $this->mImplicitGroups = null;
-               $this->mGroups = null;
-               $this->mOptions = null;
-               $this->mOptionsLoaded = false;
-               $this->mEditCount = null;
-
-               if ( $reloadFrom ) {
-                       $this->mLoadedItems = array();
-                       $this->mFrom = $reloadFrom;
-               }
-       }
-
-       /**
-        * Combine the language default options with any site-specific options
-        * and add the default language variants.
-        *
-        * @return array Array of String options
-        */
-       public static function getDefaultOptions() {
-               global $wgNamespacesToBeSearchedDefault, $wgDefaultUserOptions, $wgContLang, $wgDefaultSkin;
-
-               static $defOpt = null;
-               if ( !defined( 'MW_PHPUNIT_TEST' ) && $defOpt !== null ) {
-                       // Disabling this for the unit tests, as they rely on being able to change $wgContLang
-                       // mid-request and see that change reflected in the return value of this function.
-                       // Which is insane and would never happen during normal MW operation
-                       return $defOpt;
-               }
-
-               $defOpt = $wgDefaultUserOptions;
-               // Default language setting
-               $defOpt['language'] = $wgContLang->getCode();
-               foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
-                       $defOpt[$langCode == $wgContLang->getCode() ? 'variant' : "variant-$langCode"] = $langCode;
-               }
-               foreach ( SearchEngine::searchableNamespaces() as $nsnum => $nsname ) {
-                       $defOpt['searchNs' . $nsnum] = !empty( $wgNamespacesToBeSearchedDefault[$nsnum] );
-               }
-               $defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin );
-
-               Hooks::run( 'UserGetDefaultOptions', array( &$defOpt ) );
-
-               return $defOpt;
-       }
-
-       /**
-        * Get a given default option value.
-        *
-        * @param string $opt Name of option to retrieve
-        * @return string Default option value
-        */
-       public static function getDefaultOption( $opt ) {
-               $defOpts = self::getDefaultOptions();
-               if ( isset( $defOpts[$opt] ) ) {
-                       return $defOpts[$opt];
-               } else {
-                       return null;
-               }
-       }
-
-       /**
-        * Get blocking information
-        * @param bool $bFromSlave Whether to check the slave database first.
-        *   To improve performance, non-critical checks are done against slaves.
-        *   Check when actually saving should be done against master.
-        */
-       private function getBlockedStatus( $bFromSlave = true ) {
-               global $wgProxyWhitelist, $wgUser, $wgApplyIpBlocksToXff;
-
-               if ( -1 != $this->mBlockedby ) {
-                       return;
-               }
-
-               wfDebug( __METHOD__ . ": checking...\n" );
-
-               // Initialize data...
-               // Otherwise something ends up stomping on $this->mBlockedby when
-               // things get lazy-loaded later, causing false positive block hits
-               // due to -1 !== 0. Probably session-related... Nothing should be
-               // overwriting mBlockedby, surely?
-               $this->load();
-
-               # We only need to worry about passing the IP address to the Block generator if the
-               # user is not immune to autoblocks/hardblocks, and they are the current user so we
-               # know which IP address they're actually coming from
-               if ( !$this->isAllowed( 'ipblock-exempt' ) && $this->equals( $wgUser ) ) {
-                       $ip = $this->getRequest()->getIP();
-               } else {
-                       $ip = null;
-               }
-
-               // User/IP blocking
-               $block = Block::newFromTarget( $this, $ip, !$bFromSlave );
-
-               // Proxy blocking
-               if ( !$block instanceof Block && $ip !== null && !$this->isAllowed( 'proxyunbannable' )
-                       && !in_array( $ip, $wgProxyWhitelist )
-               ) {
-                       // Local list
-                       if ( self::isLocallyBlockedProxy( $ip ) ) {
-                               $block = new Block;
-                               $block->setBlocker( wfMessage( 'proxyblocker' )->text() );
-                               $block->mReason = wfMessage( 'proxyblockreason' )->text();
-                               $block->setTarget( $ip );
-                       } elseif ( $this->isAnon() && $this->isDnsBlacklisted( $ip ) ) {
-                               $block = new Block;
-                               $block->setBlocker( wfMessage( 'sorbs' )->text() );
-                               $block->mReason = wfMessage( 'sorbsreason' )->text();
-                               $block->setTarget( $ip );
-                       }
-               }
-
-               // (bug 23343) Apply IP blocks to the contents of XFF headers, if enabled
-               if ( !$block instanceof Block
-                       && $wgApplyIpBlocksToXff
-                       && $ip !== null
-                       && !$this->isAllowed( 'proxyunbannable' )
-                       && !in_array( $ip, $wgProxyWhitelist )
-               ) {
-                       $xff = $this->getRequest()->getHeader( 'X-Forwarded-For' );
-                       $xff = array_map( 'trim', explode( ',', $xff ) );
-                       $xff = array_diff( $xff, array( $ip ) );
-                       $xffblocks = Block::getBlocksForIPList( $xff, $this->isAnon(), !$bFromSlave );
-                       $block = Block::chooseBlock( $xffblocks, $xff );
-                       if ( $block instanceof Block ) {
-                               # Mangle the reason to alert the user that the block
-                               # originated from matching the X-Forwarded-For header.
-                               $block->mReason = wfMessage( 'xffblockreason', $block->mReason )->text();
-                       }
-               }
-
-               if ( $block instanceof Block ) {
-                       wfDebug( __METHOD__ . ": Found block.\n" );
-                       $this->mBlock = $block;
-                       $this->mBlockedby = $block->getByName();
-                       $this->mBlockreason = $block->mReason;
-                       $this->mHideName = $block->mHideName;
-                       $this->mAllowUsertalk = !$block->prevents( 'editownusertalk' );
-               } else {
-                       $this->mBlockedby = '';
-                       $this->mHideName = 0;
-                       $this->mAllowUsertalk = false;
-               }
-
-               // Extensions
-               Hooks::run( 'GetBlockedStatus', array( &$this ) );
-
-       }
-
-       /**
-        * Whether the given IP is in a DNS blacklist.
-        *
-        * @param string $ip IP to check
-        * @param bool $checkWhitelist Whether to check the whitelist first
-        * @return bool True if blacklisted.
-        */
-       public function isDnsBlacklisted( $ip, $checkWhitelist = false ) {
-               global $wgEnableDnsBlacklist, $wgDnsBlacklistUrls, $wgProxyWhitelist;
-
-               if ( !$wgEnableDnsBlacklist ) {
-                       return false;
-               }
-
-               if ( $checkWhitelist && in_array( $ip, $wgProxyWhitelist ) ) {
-                       return false;
-               }
-
-               return $this->inDnsBlacklist( $ip, $wgDnsBlacklistUrls );
-       }
-
-       /**
-        * Whether the given IP is in a given DNS blacklist.
-        *
-        * @param string $ip IP to check
-        * @param string|array $bases Array of Strings: URL of the DNS blacklist
-        * @return bool True if blacklisted.
-        */
-       public function inDnsBlacklist( $ip, $bases ) {
-
-               $found = false;
-               // @todo FIXME: IPv6 ???  (http://bugs.php.net/bug.php?id=33170)
-               if ( IP::isIPv4( $ip ) ) {
-                       // Reverse IP, bug 21255
-                       $ipReversed = implode( '.', array_reverse( explode( '.', $ip ) ) );
-
-                       foreach ( (array)$bases as $base ) {
-                               // Make hostname
-                               // If we have an access key, use that too (ProjectHoneypot, etc.)
-                               $basename = $base;
-                               if ( is_array( $base ) ) {
-                                       if ( count( $base ) >= 2 ) {
-                                               // Access key is 1, base URL is 0
-                                               $host = "{$base[1]}.$ipReversed.{$base[0]}";
-                                       } else {
-                                               $host = "$ipReversed.{$base[0]}";
-                                       }
-                                       $basename = $base[0];
-                               } else {
-                                       $host = "$ipReversed.$base";
-                               }
-
-                               // Send query
-                               $ipList = gethostbynamel( $host );
-
-                               if ( $ipList ) {
-                                       wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $basename!" );
-                                       $found = true;
-                                       break;
-                               } else {
-                                       wfDebugLog( 'dnsblacklist', "Requested $host, not found in $basename." );
-                               }
-                       }
-               }
-
-               return $found;
-       }
-
-       /**
-        * Check if an IP address is in the local proxy list
-        *
-        * @param string $ip
-        *
-        * @return bool
-        */
-       public static function isLocallyBlockedProxy( $ip ) {
-               global $wgProxyList;
-
-               if ( !$wgProxyList ) {
-                       return false;
-               }
-
-               if ( !is_array( $wgProxyList ) ) {
-                       // Load from the specified file
-                       $wgProxyList = array_map( 'trim', file( $wgProxyList ) );
-               }
-
-               if ( !is_array( $wgProxyList ) ) {
-                       $ret = false;
-               } elseif ( array_search( $ip, $wgProxyList ) !== false ) {
-                       $ret = true;
-               } elseif ( array_key_exists( $ip, $wgProxyList ) ) {
-                       // Old-style flipped proxy list
-                       $ret = true;
-               } else {
-                       $ret = false;
-               }
-               return $ret;
-       }
-
-       /**
-        * Is this user subject to rate limiting?
-        *
-        * @return bool True if rate limited
-        */
-       public function isPingLimitable() {
-               global $wgRateLimitsExcludedIPs;
-               if ( in_array( $this->getRequest()->getIP(), $wgRateLimitsExcludedIPs ) ) {
-                       // No other good way currently to disable rate limits
-                       // for specific IPs. :P
-                       // But this is a crappy hack and should die.
-                       return false;
-               }
-               return !$this->isAllowed( 'noratelimit' );
-       }
-
-       /**
-        * Primitive rate limits: enforce maximum actions per time period
-        * to put a brake on flooding.
-        *
-        * The method generates both a generic profiling point and a per action one
-        * (suffix being "-$action".
-        *
-        * @note When using a shared cache like memcached, IP-address
-        * last-hit counters will be shared across wikis.
-        *
-        * @param string $action Action to enforce; 'edit' if unspecified
-        * @param int $incrBy Positive amount to increment counter by [defaults to 1]
-        * @return bool True if a rate limiter was tripped
-        */
-       public function pingLimiter( $action = 'edit', $incrBy = 1 ) {
-               // Call the 'PingLimiter' hook
-               $result = false;
-               if ( !Hooks::run( 'PingLimiter', array( &$this, $action, &$result, $incrBy ) ) ) {
-                       return $result;
-               }
-
-               global $wgRateLimits;
-               if ( !isset( $wgRateLimits[$action] ) ) {
-                       return false;
-               }
-
-               // Some groups shouldn't trigger the ping limiter, ever
-               if ( !$this->isPingLimitable() ) {
-                       return false;
-               }
-
-               $limits = $wgRateLimits[$action];
-               $keys = array();
-               $id = $this->getId();
-               $userLimit = false;
-
-               if ( isset( $limits['anon'] ) && $id == 0 ) {
-                       $keys[wfMemcKey( 'limiter', $action, 'anon' )] = $limits['anon'];
-               }
-
-               if ( isset( $limits['user'] ) && $id != 0 ) {
-                       $userLimit = $limits['user'];
-               }
-               if ( $this->isNewbie() ) {
-                       if ( isset( $limits['newbie'] ) && $id != 0 ) {
-                               $keys[wfMemcKey( 'limiter', $action, 'user', $id )] = $limits['newbie'];
-                       }
-                       if ( isset( $limits['ip'] ) ) {
-                               $ip = $this->getRequest()->getIP();
-                               $keys["mediawiki:limiter:$action:ip:$ip"] = $limits['ip'];
-                       }
-                       if ( isset( $limits['subnet'] ) ) {
-                               $ip = $this->getRequest()->getIP();
-                               $matches = array();
-                               $subnet = false;
-                               if ( IP::isIPv6( $ip ) ) {
-                                       $parts = IP::parseRange( "$ip/64" );
-                                       $subnet = $parts[0];
-                               } elseif ( preg_match( '/^(\d+\.\d+\.\d+)\.\d+$/', $ip, $matches ) ) {
-                                       // IPv4
-                                       $subnet = $matches[1];
-                               }
-                               if ( $subnet !== false ) {
-                                       $keys["mediawiki:limiter:$action:subnet:$subnet"] = $limits['subnet'];
-                               }
-                       }
-               }
-               // Check for group-specific permissions
-               // If more than one group applies, use the group with the highest limit
-               foreach ( $this->getGroups() as $group ) {
-                       if ( isset( $limits[$group] ) ) {
-                               if ( $userLimit === false
-                                       || $limits[$group][0] / $limits[$group][1] > $userLimit[0] / $userLimit[1]
-                               ) {
-                                       $userLimit = $limits[$group];
-                               }
-                       }
-               }
-               // Set the user limit key
-               if ( $userLimit !== false ) {
-                       list( $max, $period ) = $userLimit;
-                       wfDebug( __METHOD__ . ": effective user limit: $max in {$period}s\n" );
-                       $keys[wfMemcKey( 'limiter', $action, 'user', $id )] = $userLimit;
-               }
-
-               $cache = ObjectCache::getLocalClusterInstance();
-
-               $triggered = false;
-               foreach ( $keys as $key => $limit ) {
-                       list( $max, $period ) = $limit;
-                       $summary = "(limit $max in {$period}s)";
-                       $count = $cache->get( $key );
-                       // Already pinged?
-                       if ( $count ) {
-                               if ( $count >= $max ) {
-                                       wfDebugLog( 'ratelimit', "User '{$this->getName()}' " .
-                                               "(IP {$this->getRequest()->getIP()}) tripped $key at $count $summary" );
-                                       $triggered = true;
-                               } else {
-                                       wfDebug( __METHOD__ . ": ok. $key at $count $summary\n" );
-                               }
-                       } else {
-                               wfDebug( __METHOD__ . ": adding record for $key $summary\n" );
-                               if ( $incrBy > 0 ) {
-                                       $cache->add( $key, 0, intval( $period ) ); // first ping
-                               }
-                       }
-                       if ( $incrBy > 0 ) {
-                               $cache->incr( $key, $incrBy );
-                       }
-               }
-
-               return $triggered;
-       }
-
-       /**
-        * Check if user is blocked
-        *
-        * @param bool $bFromSlave Whether to check the slave database instead of
-        *   the master. Hacked from false due to horrible probs on site.
-        * @return bool True if blocked, false otherwise
-        */
-       public function isBlocked( $bFromSlave = true ) {
-               return $this->getBlock( $bFromSlave ) instanceof Block && $this->getBlock()->prevents( 'edit' );
-       }
-
-       /**
-        * Get the block affecting the user, or null if the user is not blocked
-        *
-        * @param bool $bFromSlave Whether to check the slave database instead of the master
-        * @return Block|null
-        */
-       public function getBlock( $bFromSlave = true ) {
-               $this->getBlockedStatus( $bFromSlave );
-               return $this->mBlock instanceof Block ? $this->mBlock : null;
-       }
-
-       /**
-        * Check if user is blocked from editing a particular article
-        *
-        * @param Title $title Title to check
-        * @param bool $bFromSlave Whether to check the slave database instead of the master
-        * @return bool
-        */
-       public function isBlockedFrom( $title, $bFromSlave = false ) {
-               global $wgBlockAllowsUTEdit;
-
-               $blocked = $this->isBlocked( $bFromSlave );
-               $allowUsertalk = ( $wgBlockAllowsUTEdit ? $this->mAllowUsertalk : false );
-               // If a user's name is suppressed, they cannot make edits anywhere
-               if ( !$this->mHideName && $allowUsertalk && $title->getText() === $this->getName()
-                       && $title->getNamespace() == NS_USER_TALK ) {
-                       $blocked = false;
-                       wfDebug( __METHOD__ . ": self-talk page, ignoring any blocks\n" );
-               }
-
-               Hooks::run( 'UserIsBlockedFrom', array( $this, $title, &$blocked, &$allowUsertalk ) );
-
-               return $blocked;
-       }
-
-       /**
-        * If user is blocked, return the name of the user who placed the block
-        * @return string Name of blocker
-        */
-       public function blockedBy() {
-               $this->getBlockedStatus();
-               return $this->mBlockedby;
-       }
-
-       /**
-        * If user is blocked, return the specified reason for the block
-        * @return string Blocking reason
-        */
-       public function blockedFor() {
-               $this->getBlockedStatus();
-               return $this->mBlockreason;
-       }
-
-       /**
-        * If user is blocked, return the ID for the block
-        * @return int Block ID
-        */
-       public function getBlockId() {
-               $this->getBlockedStatus();
-               return ( $this->mBlock ? $this->mBlock->getId() : false );
-       }
-
-       /**
-        * Check if user is blocked on all wikis.
-        * Do not use for actual edit permission checks!
-        * This is intended for quick UI checks.
-        *
-        * @param string $ip IP address, uses current client if none given
-        * @return bool True if blocked, false otherwise
-        */
-       public function isBlockedGlobally( $ip = '' ) {
-               if ( $this->mBlockedGlobally !== null ) {
-                       return $this->mBlockedGlobally;
-               }
-               // User is already an IP?
-               if ( IP::isIPAddress( $this->getName() ) ) {
-                       $ip = $this->getName();
-               } elseif ( !$ip ) {
-                       $ip = $this->getRequest()->getIP();
-               }
-               $blocked = false;
-               Hooks::run( 'UserIsBlockedGlobally', array( &$this, $ip, &$blocked ) );
-               $this->mBlockedGlobally = (bool)$blocked;
-               return $this->mBlockedGlobally;
-       }
-
-       /**
-        * Check if user account is locked
-        *
-        * @return bool True if locked, false otherwise
-        */
-       public function isLocked() {
-               if ( $this->mLocked !== null ) {
-                       return $this->mLocked;
-               }
-               global $wgAuth;
-               $authUser = $wgAuth->getUserInstance( $this );
-               $this->mLocked = (bool)$authUser->isLocked();
-               Hooks::run( 'UserIsLocked', array( $this, &$this->mLocked ) );
-               return $this->mLocked;
-       }
-
-       /**
-        * Check if user account is hidden
-        *
-        * @return bool True if hidden, false otherwise
-        */
-       public function isHidden() {
-               if ( $this->mHideName !== null ) {
-                       return $this->mHideName;
-               }
-               $this->getBlockedStatus();
-               if ( !$this->mHideName ) {
-                       global $wgAuth;
-                       $authUser = $wgAuth->getUserInstance( $this );
-                       $this->mHideName = (bool)$authUser->isHidden();
-                       Hooks::run( 'UserIsHidden', array( $this, &$this->mHideName ) );
-               }
-               return $this->mHideName;
-       }
-
-       /**
-        * Get the user's ID.
-        * @return int The user's ID; 0 if the user is anonymous or nonexistent
-        */
-       public function getId() {
-               if ( $this->mId === null && $this->mName !== null && User::isIP( $this->mName ) ) {
-                       // Special case, we know the user is anonymous
-                       return 0;
-               } elseif ( !$this->isItemLoaded( 'id' ) ) {
-                       // Don't load if this was initialized from an ID
-                       $this->load();
-               }
-               return $this->mId;
-       }
-
-       /**
-        * Set the user and reload all fields according to a given ID
-        * @param int $v User ID to reload
-        */
-       public function setId( $v ) {
-               $this->mId = $v;
-               $this->clearInstanceCache( 'id' );
-       }
-
-       /**
-        * Get the user name, or the IP of an anonymous user
-        * @return string User's name or IP address
-        */
-       public function getName() {
-               if ( $this->isItemLoaded( 'name', 'only' ) ) {
-                       // Special case optimisation
-                       return $this->mName;
-               } else {
-                       $this->load();
-                       if ( $this->mName === false ) {
-                               // Clean up IPs
-                               $this->mName = IP::sanitizeIP( $this->getRequest()->getIP() );
-                       }
-                       return $this->mName;
-               }
-       }
-
-       /**
-        * Set the user name.
-        *
-        * This does not reload fields from the database according to the given
-        * name. Rather, it is used to create a temporary "nonexistent user" for
-        * later addition to the database. It can also be used to set the IP
-        * address for an anonymous user to something other than the current
-        * remote IP.
-        *
-        * @note User::newFromName() has roughly the same function, when the named user
-        * does not exist.
-        * @param string $str New user name to set
-        */
-       public function setName( $str ) {
-               $this->load();
-               $this->mName = $str;
-       }
-
-       /**
-        * Get the user's name escaped by underscores.
-        * @return string Username escaped by underscores.
-        */
-       public function getTitleKey() {
-               return str_replace( ' ', '_', $this->getName() );
-       }
-
-       /**
-        * Check if the user has new messages.
-        * @return bool True if the user has new messages
-        */
-       public function getNewtalk() {
-               $this->load();
-
-               // Load the newtalk status if it is unloaded (mNewtalk=-1)
-               if ( $this->mNewtalk === -1 ) {
-                       $this->mNewtalk = false; # reset talk page status
-
-                       // Check memcached separately for anons, who have no
-                       // entire User object stored in there.
-                       if ( !$this->mId ) {
-                               global $wgDisableAnonTalk;
-                               if ( $wgDisableAnonTalk ) {
-                                       // Anon newtalk disabled by configuration.
-                                       $this->mNewtalk = false;
-                               } else {
-                                       $this->mNewtalk = $this->checkNewtalk( 'user_ip', $this->getName() );
-                               }
-                       } else {
-                               $this->mNewtalk = $this->checkNewtalk( 'user_id', $this->mId );
-                       }
-               }
-
-               return (bool)$this->mNewtalk;
-       }
-
-       /**
-        * Return the data needed to construct links for new talk page message
-        * alerts. If there are new messages, this will return an associative array
-        * with the following data:
-        *     wiki: The database name of the wiki
-        *     link: Root-relative link to the user's talk page
-        *     rev: The last talk page revision that the user has seen or null. This
-        *         is useful for building diff links.
-        * If there are no new messages, it returns an empty array.
-        * @note This function was designed to accomodate multiple talk pages, but
-        * currently only returns a single link and revision.
-        * @return array
-        */
-       public function getNewMessageLinks() {
-               $talks = array();
-               if ( !Hooks::run( 'UserRetrieveNewTalks', array( &$this, &$talks ) ) ) {
-                       return $talks;
-               } elseif ( !$this->getNewtalk() ) {
-                       return array();
-               }
-               $utp = $this->getTalkPage();
-               $dbr = wfGetDB( DB_SLAVE );
-               // Get the "last viewed rev" timestamp from the oldest message notification
-               $timestamp = $dbr->selectField( 'user_newtalk',
-                       'MIN(user_last_timestamp)',
-                       $this->isAnon() ? array( 'user_ip' => $this->getName() ) : array( 'user_id' => $this->getID() ),
-                       __METHOD__ );
-               $rev = $timestamp ? Revision::loadFromTimestamp( $dbr, $utp, $timestamp ) : null;
-               return array( array( 'wiki' => wfWikiID(), 'link' => $utp->getLocalURL(), 'rev' => $rev ) );
-       }
-
-       /**
-        * Get the revision ID for the last talk page revision viewed by the talk
-        * page owner.
-        * @return int|null Revision ID or null
-        */
-       public function getNewMessageRevisionId() {
-               $newMessageRevisionId = null;
-               $newMessageLinks = $this->getNewMessageLinks();
-               if ( $newMessageLinks ) {
-                       // Note: getNewMessageLinks() never returns more than a single link
-                       // and it is always for the same wiki, but we double-check here in
-                       // case that changes some time in the future.
-                       if ( count( $newMessageLinks ) === 1
-                               && $newMessageLinks[0]['wiki'] === wfWikiID()
-                               && $newMessageLinks[0]['rev']
-                       ) {
-                               /** @var Revision $newMessageRevision */
-                               $newMessageRevision = $newMessageLinks[0]['rev'];
-                               $newMessageRevisionId = $newMessageRevision->getId();
-                       }
-               }
-               return $newMessageRevisionId;
-       }
-
-       /**
-        * Internal uncached check for new messages
-        *
-        * @see getNewtalk()
-        * @param string $field 'user_ip' for anonymous users, 'user_id' otherwise
-        * @param string|int $id User's IP address for anonymous users, User ID otherwise
-        * @return bool True if the user has new messages
-        */
-       protected function checkNewtalk( $field, $id ) {
-               $dbr = wfGetDB( DB_SLAVE );
-
-               $ok = $dbr->selectField( 'user_newtalk', $field, array( $field => $id ), __METHOD__ );
-
-               return $ok !== false;
-       }
-
-       /**
-        * Add or update the new messages flag
-        * @param string $field 'user_ip' for anonymous users, 'user_id' otherwise
-        * @param string|int $id User's IP address for anonymous users, User ID otherwise
-        * @param Revision|null $curRev New, as yet unseen revision of the user talk page. Ignored if null.
-        * @return bool True if successful, false otherwise
-        */
-       protected function updateNewtalk( $field, $id, $curRev = null ) {
-               // Get timestamp of the talk page revision prior to the current one
-               $prevRev = $curRev ? $curRev->getPrevious() : false;
-               $ts = $prevRev ? $prevRev->getTimestamp() : null;
-               // Mark the user as having new messages since this revision
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->insert( 'user_newtalk',
-                       array( $field => $id, 'user_last_timestamp' => $dbw->timestampOrNull( $ts ) ),
-                       __METHOD__,
-                       'IGNORE' );
-               if ( $dbw->affectedRows() ) {
-                       wfDebug( __METHOD__ . ": set on ($field, $id)\n" );
-                       return true;
-               } else {
-                       wfDebug( __METHOD__ . " already set ($field, $id)\n" );
-                       return false;
-               }
-       }
-
-       /**
-        * Clear the new messages flag for the given user
-        * @param string $field 'user_ip' for anonymous users, 'user_id' otherwise
-        * @param string|int $id User's IP address for anonymous users, User ID otherwise
-        * @return bool True if successful, false otherwise
-        */
-       protected function deleteNewtalk( $field, $id ) {
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->delete( 'user_newtalk',
-                       array( $field => $id ),
-                       __METHOD__ );
-               if ( $dbw->affectedRows() ) {
-                       wfDebug( __METHOD__ . ": killed on ($field, $id)\n" );
-                       return true;
-               } else {
-                       wfDebug( __METHOD__ . ": already gone ($field, $id)\n" );
-                       return false;
-               }
-       }
-
-       /**
-        * Update the 'You have new messages!' status.
-        * @param bool $val Whether the user has new messages
-        * @param Revision $curRev New, as yet unseen revision of the user talk
-        *   page. Ignored if null or !$val.
-        */
-       public function setNewtalk( $val, $curRev = null ) {
-               if ( wfReadOnly() ) {
-                       return;
-               }
-
-               $this->load();
-               $this->mNewtalk = $val;
-
-               if ( $this->isAnon() ) {
-                       $field = 'user_ip';
-                       $id = $this->getName();
-               } else {
-                       $field = 'user_id';
-                       $id = $this->getId();
-               }
-
-               if ( $val ) {
-                       $changed = $this->updateNewtalk( $field, $id, $curRev );
-               } else {
-                       $changed = $this->deleteNewtalk( $field, $id );
-               }
-
-               if ( $changed ) {
-                       $this->invalidateCache();
-               }
-       }
-
-       /**
-        * Generate a current or new-future timestamp to be stored in the
-        * user_touched field when we update things.
-        * @return string Timestamp in TS_MW format
-        */
-       private function newTouchedTimestamp() {
-               global $wgClockSkewFudge;
-
-               $time = wfTimestamp( TS_MW, time() + $wgClockSkewFudge );
-               if ( $this->mTouched && $time <= $this->mTouched ) {
-                       $time = wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $this->mTouched ) + 1 );
-               }
-
-               return $time;
-       }
-
-       /**
-        * Clear user data from memcached
-        *
-        * Use after applying updates to the database; caller's
-        * responsibility to update user_touched if appropriate.
-        *
-        * Called implicitly from invalidateCache() and saveSettings().
-        *
-        * @param string $mode Use 'refresh' to clear now; otherwise before DB commit
-        */
-       public function clearSharedCache( $mode = 'changed' ) {
-               if ( !$this->getId() ) {
-                       return;
-               }
-
-               $cache = ObjectCache::getMainWANInstance();
-               $key = $this->getCacheKey( $cache );
-               if ( $mode === 'refresh' ) {
-                       $cache->delete( $key, 1 );
-               } else {
-                       wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $cache, $key ) {
-                               $cache->delete( $key );
-                       } );
-               }
-       }
-
-       /**
-        * Immediately touch the user data cache for this account
-        *
-        * Calls touch() and removes account data from memcached
-        */
-       public function invalidateCache() {
-               $this->touch();
-               $this->clearSharedCache();
-       }
-
-       /**
-        * Update the "touched" timestamp for the user
-        *
-        * This is useful on various login/logout events when making sure that
-        * a browser or proxy that has multiple tenants does not suffer cache
-        * pollution where the new user sees the old users content. The value
-        * of getTouched() is checked when determining 304 vs 200 responses.
-        * Unlike invalidateCache(), this preserves the User object cache and
-        * avoids database writes.
-        *
-        * @since 1.25
-        */
-       public function touch() {
-               $id = $this->getId();
-               if ( $id ) {
-                       $key = wfMemcKey( 'user-quicktouched', 'id', $id );
-                       ObjectCache::getMainWANInstance()->touchCheckKey( $key );
-                       $this->mQuickTouched = null;
-               }
-       }
-
-       /**
-        * Validate the cache for this account.
-        * @param string $timestamp A timestamp in TS_MW format
-        * @return bool
-        */
-       public function validateCache( $timestamp ) {
-               return ( $timestamp >= $this->getTouched() );
-       }
-
-       /**
-        * Get the user touched timestamp
-        *
-        * Use this value only to validate caches via inequalities
-        * such as in the case of HTTP If-Modified-Since response logic
-        *
-        * @return string TS_MW Timestamp
-        */
-       public function getTouched() {
-               $this->load();
-
-               if ( $this->mId ) {
-                       if ( $this->mQuickTouched === null ) {
-                               $key = wfMemcKey( 'user-quicktouched', 'id', $this->mId );
-                               $cache = ObjectCache::getMainWANInstance();
-
-                               $this->mQuickTouched = wfTimestamp( TS_MW, $cache->getCheckKeyTime( $key ) );
-                       }
-
-                       return max( $this->mTouched, $this->mQuickTouched );
-               }
-
-               return $this->mTouched;
-       }
-
-       /**
-        * Get the user_touched timestamp field (time of last DB updates)
-        * @return string TS_MW Timestamp
-        * @since 1.26
-        */
-       public function getDBTouched() {
-               $this->load();
-
-               return $this->mTouched;
-       }
-
-       /**
-        * @deprecated Removed in 1.27.
-        * @return Password
-        * @since 1.24
-        */
-       public function getPassword() {
-               throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
-       }
-
-       /**
-        * @deprecated Removed in 1.27.
-        * @return Password
-        * @since 1.24
-        */
-       public function getTemporaryPassword() {
-               throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
-       }
-
-       /**
-        * Set the password and reset the random token.
-        * Calls through to authentication plugin if necessary;
-        * will have no effect if the auth plugin refuses to
-        * pass the change through or if the legal password
-        * checks fail.
-        *
-        * As a special case, setting the password to null
-        * wipes it, so the account cannot be logged in until
-        * a new password is set, for instance via e-mail.
-        *
-        * @deprecated since 1.27. AuthManager is coming.
-        * @param string $str New password to set
-        * @throws PasswordError On failure
-        * @return bool
-        */
-       public function setPassword( $str ) {
-               global $wgAuth;
-
-               if ( $str !== null ) {
-                       if ( !$wgAuth->allowPasswordChange() ) {
-                               throw new PasswordError( wfMessage( 'password-change-forbidden' )->text() );
-                       }
-
-                       $status = $this->checkPasswordValidity( $str );
-                       if ( !$status->isGood() ) {
-                               throw new PasswordError( $status->getMessage()->text() );
-                       }
-               }
-
-               if ( !$wgAuth->setPassword( $this, $str ) ) {
-                       throw new PasswordError( wfMessage( 'externaldberror' )->text() );
-               }
-
-               $this->setToken();
-               $this->setOption( 'watchlisttoken', false );
-               $this->setPasswordInternal( $str );
-
-               return true;
-       }
-
-       /**
-        * Set the password and reset the random token unconditionally.
-        *
-        * @deprecated since 1.27. AuthManager is coming.
-        * @param string|null $str New password to set or null to set an invalid
-        *  password hash meaning that the user will not be able to log in
-        *  through the web interface.
-        */
-       public function setInternalPassword( $str ) {
-               global $wgAuth;
-
-               if ( $wgAuth->allowSetLocalPassword() ) {
-                       $this->setToken();
-                       $this->setOption( 'watchlisttoken', false );
-                       $this->setPasswordInternal( $str );
-               }
-       }
-
-       /**
-        * Actually set the password and such
-        * @since 1.27 cannot set a password for a user not in the database
-        * @param string|null $str New password to set or null to set an invalid
-        *  password hash meaning that the user will not be able to log in
-        *  through the web interface.
-        */
-       private function setPasswordInternal( $str ) {
-               $id = self::idFromName( $this->getName(), self::READ_LATEST );
-               if ( $id == 0 ) {
-                       throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
-               }
-
-               $passwordFactory = new PasswordFactory();
-               $passwordFactory->init( RequestContext::getMain()->getConfig() );
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->update(
-                       'user',
-                       array(
-                               'user_password' => $passwordFactory->newFromPlaintext( $str )->toString(),
-                               'user_newpassword' => PasswordFactory::newInvalidPassword()->toString(),
-                               'user_newpass_time' => $dbw->timestampOrNull( null ),
-                       ),
-                       array(
-                               'user_id' => $id,
-                       ),
-                       __METHOD__
-               );
-       }
-
-       /**
-        * Get the user's current token.
-        * @param bool $forceCreation Force the generation of a new token if the
-        *   user doesn't have one (default=true for backwards compatibility).
-        * @return string Token
-        */
-       public function getToken( $forceCreation = true ) {
-               $this->load();
-               if ( !$this->mToken && $forceCreation ) {
-                       $this->setToken();
-               }
-               return $this->mToken;
-       }
-
-       /**
-        * Set the random token (used for persistent authentication)
-        * Called from loadDefaults() among other places.
-        *
-        * @param string|bool $token If specified, set the token to this value
-        */
-       public function setToken( $token = false ) {
-               $this->load();
-               if ( !$token ) {
-                       $this->mToken = MWCryptRand::generateHex( self::TOKEN_LENGTH );
-               } else {
-                       $this->mToken = $token;
-               }
-       }
-
-       /**
-        * Set the password for a password reminder or new account email
-        *
-        * @deprecated since 1.27, AuthManager is coming
-        * @param string $str New password to set or null to set an invalid
-        *  password hash meaning that the user will not be able to use it
-        * @param bool $throttle If true, reset the throttle timestamp to the present
-        */
-       public function setNewpassword( $str, $throttle = true ) {
-               $id = $this->getId();
-               if ( $id == 0 ) {
-                       throw new LogicException( 'Cannot set new password for a user that is not in the database.' );
-               }
-
-               $dbw = wfGetDB( DB_MASTER );
-
-               $passwordFactory = new PasswordFactory();
-               $passwordFactory->init( RequestContext::getMain()->getConfig() );
-               $update = array(
-                       'user_newpassword' => $passwordFactory->newFromPlaintext( $str )->toString(),
-               );
-
-               if ( $str === null ) {
-                       $update['user_newpass_time'] = null;
-               } elseif ( $throttle ) {
-                       $update['user_newpass_time'] = $dbw->timestamp();
-               }
-
-               $dbw->update( 'user', $update, array( 'user_id' => $id ), __METHOD__ );
-       }
-
-       /**
-        * Has password reminder email been sent within the last
-        * $wgPasswordReminderResendTime hours?
-        * @return bool
-        */
-       public function isPasswordReminderThrottled() {
-               global $wgPasswordReminderResendTime;
-
-               if ( !$wgPasswordReminderResendTime ) {
-                       return false;
-               }
-
-               $this->load();
-
-               $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                       ? wfGetDB( DB_MASTER )
-                       : wfGetDB( DB_SLAVE );
-               $newpassTime = $db->selectField(
-                       'user',
-                       'user_newpass_time',
-                       array( 'user_id' => $this->getId() ),
-                       __METHOD__
-               );
-
-               if ( $newpassTime === null ) {
-                       return false;
-               }
-               $expiry = wfTimestamp( TS_UNIX, $newpassTime ) + $wgPasswordReminderResendTime * 3600;
-               return time() < $expiry;
-       }
-
-       /**
-        * Get the user's e-mail address
-        * @return string User's email address
-        */
-       public function getEmail() {
-               $this->load();
-               Hooks::run( 'UserGetEmail', array( $this, &$this->mEmail ) );
-               return $this->mEmail;
-       }
-
-       /**
-        * Get the timestamp of the user's e-mail authentication
-        * @return string TS_MW timestamp
-        */
-       public function getEmailAuthenticationTimestamp() {
-               $this->load();
-               Hooks::run( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
-               return $this->mEmailAuthenticated;
-       }
-
-       /**
-        * Set the user's e-mail address
-        * @param string $str New e-mail address
-        */
-       public function setEmail( $str ) {
-               $this->load();
-               if ( $str == $this->mEmail ) {
-                       return;
-               }
-               $this->invalidateEmail();
-               $this->mEmail = $str;
-               Hooks::run( 'UserSetEmail', array( $this, &$this->mEmail ) );
-       }
-
-       /**
-        * Set the user's e-mail address and a confirmation mail if needed.
-        *
-        * @since 1.20
-        * @param string $str New e-mail address
-        * @return Status
-        */
-       public function setEmailWithConfirmation( $str ) {
-               global $wgEnableEmail, $wgEmailAuthentication;
-
-               if ( !$wgEnableEmail ) {
-                       return Status::newFatal( 'emaildisabled' );
-               }
-
-               $oldaddr = $this->getEmail();
-               if ( $str === $oldaddr ) {
-                       return Status::newGood( true );
-               }
-
-               $this->setEmail( $str );
-
-               if ( $str !== '' && $wgEmailAuthentication ) {
-                       // Send a confirmation request to the new address if needed
-                       $type = $oldaddr != '' ? 'changed' : 'set';
-                       $result = $this->sendConfirmationMail( $type );
-                       if ( $result->isGood() ) {
-                               // Say to the caller that a confirmation mail has been sent
-                               $result->value = 'eauth';
-                       }
-               } else {
-                       $result = Status::newGood( true );
-               }
-
-               return $result;
-       }
-
-       /**
-        * Get the user's real name
-        * @return string User's real name
-        */
-       public function getRealName() {
-               if ( !$this->isItemLoaded( 'realname' ) ) {
-                       $this->load();
-               }
-
-               return $this->mRealName;
-       }
-
-       /**
-        * Set the user's real name
-        * @param string $str New real name
-        */
-       public function setRealName( $str ) {
-               $this->load();
-               $this->mRealName = $str;
-       }
-
-       /**
-        * Get the user's current setting for a given option.
-        *
-        * @param string $oname The option to check
-        * @param string $defaultOverride A default value returned if the option does not exist
-        * @param bool $ignoreHidden Whether to ignore the effects of $wgHiddenPrefs
-        * @return string User's current value for the option
-        * @see getBoolOption()
-        * @see getIntOption()
-        */
-       public function getOption( $oname, $defaultOverride = null, $ignoreHidden = false ) {
-               global $wgHiddenPrefs;
-               $this->loadOptions();
-
-               # We want 'disabled' preferences to always behave as the default value for
-               # users, even if they have set the option explicitly in their settings (ie they
-               # set it, and then it was disabled removing their ability to change it).  But
-               # we don't want to erase the preferences in the database in case the preference
-               # is re-enabled again.  So don't touch $mOptions, just override the returned value
-               if ( !$ignoreHidden && in_array( $oname, $wgHiddenPrefs ) ) {
-                       return self::getDefaultOption( $oname );
-               }
-
-               if ( array_key_exists( $oname, $this->mOptions ) ) {
-                       return $this->mOptions[$oname];
-               } else {
-                       return $defaultOverride;
-               }
-       }
-
-       /**
-        * 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( $flags = 0 ) {
-               global $wgHiddenPrefs;
-               $this->loadOptions();
-               $options = $this->mOptions;
-
-               # We want 'disabled' preferences to always behave as the default value for
-               # users, even if they have set the option explicitly in their settings (ie they
-               # set it, and then it was disabled removing their ability to change it).  But
-               # we don't want to erase the preferences in the database in case the preference
-               # is re-enabled again.  So don't touch $mOptions, just override the returned value
-               foreach ( $wgHiddenPrefs as $pref ) {
-                       $default = self::getDefaultOption( $pref );
-                       if ( $default !== null ) {
-                               $options[$pref] = $default;
-                       }
-               }
-
-               if ( $flags & self::GETOPTIONS_EXCLUDE_DEFAULTS ) {
-                       $options = array_diff_assoc( $options, self::getDefaultOptions() );
-               }
-
-               return $options;
-       }
-
-       /**
-        * Get the user's current setting for a given option, as a boolean value.
-        *
-        * @param string $oname The option to check
-        * @return bool User's current value for the option
-        * @see getOption()
-        */
-       public function getBoolOption( $oname ) {
-               return (bool)$this->getOption( $oname );
-       }
-
-       /**
-        * Get the user's current setting for a given option, as an integer value.
-        *
-        * @param string $oname The option to check
-        * @param int $defaultOverride A default value returned if the option does not exist
-        * @return int User's current value for the option
-        * @see getOption()
-        */
-       public function getIntOption( $oname, $defaultOverride = 0 ) {
-               $val = $this->getOption( $oname );
-               if ( $val == '' ) {
-                       $val = $defaultOverride;
-               }
-               return intval( $val );
-       }
-
-       /**
-        * Set the given option for a user.
-        *
-        * You need to call saveSettings() to actually write to the database.
-        *
-        * @param string $oname The option to set
-        * @param mixed $val New value to set
-        */
-       public function setOption( $oname, $val ) {
-               $this->loadOptions();
-
-               // Explicitly NULL values should refer to defaults
-               if ( is_null( $val ) ) {
-                       $val = self::getDefaultOption( $oname );
-               }
-
-               $this->mOptions[$oname] = $val;
-       }
-
-       /**
-        * Get a token stored in the preferences (like the watchlist one),
-        * resetting it if it's empty (and saving changes).
-        *
-        * @param string $oname The option name to retrieve the token from
-        * @return string|bool User's current value for the option, or false if this option is disabled.
-        * @see resetTokenFromOption()
-        * @see getOption()
-        * @deprecated 1.26 Applications should use the OAuth extension
-        */
-       public function getTokenFromOption( $oname ) {
-               global $wgHiddenPrefs;
-
-               $id = $this->getId();
-               if ( !$id || in_array( $oname, $wgHiddenPrefs ) ) {
-                       return false;
-               }
-
-               $token = $this->getOption( $oname );
-               if ( !$token ) {
-                       // Default to a value based on the user token to avoid space
-                       // wasted on storing tokens for all users. When this option
-                       // is set manually by the user, only then is it stored.
-                       $token = hash_hmac( 'sha1', "$oname:$id", $this->getToken() );
-               }
-
-               return $token;
-       }
-
-       /**
-        * Reset a token stored in the preferences (like the watchlist one).
-        * *Does not* save user's preferences (similarly to setOption()).
-        *
-        * @param string $oname The option name to reset the token in
-        * @return string|bool New token value, or false if this option is disabled.
-        * @see getTokenFromOption()
-        * @see setOption()
-        */
-       public function resetTokenFromOption( $oname ) {
-               global $wgHiddenPrefs;
-               if ( in_array( $oname, $wgHiddenPrefs ) ) {
-                       return false;
-               }
-
-               $token = MWCryptRand::generateHex( 40 );
-               $this->setOption( $oname, $token );
-               return $token;
-       }
-
-       /**
-        * Return a list of the types of user options currently returned by
-        * User::getOptionKinds().
-        *
-        * Currently, the option kinds are:
-        * - 'registered' - preferences which are registered in core MediaWiki or
-        *                  by extensions using the UserGetDefaultOptions hook.
-        * - 'registered-multiselect' - as above, using the 'multiselect' type.
-        * - 'registered-checkmatrix' - as above, using the 'checkmatrix' type.
-        * - 'userjs' - preferences with names starting with 'userjs-', intended to
-        *              be used by user scripts.
-        * - 'special' - "preferences" that are not accessible via User::getOptions
-        *               or User::setOptions.
-        * - 'unused' - preferences about which MediaWiki doesn't know anything.
-        *              These are usually legacy options, removed in newer versions.
-        *
-        * The API (and possibly others) use this function to determine the possible
-        * option types for validation purposes, so make sure to update this when a
-        * new option kind is added.
-        *
-        * @see User::getOptionKinds
-        * @return array Option kinds
-        */
-       public static function listOptionKinds() {
-               return array(
-                       'registered',
-                       'registered-multiselect',
-                       'registered-checkmatrix',
-                       'userjs',
-                       'special',
-                       'unused'
-               );
-       }
-
-       /**
-        * Return an associative array mapping preferences keys to the kind of a preference they're
-        * used for. Different kinds are handled differently when setting or reading preferences.
-        *
-        * See User::listOptionKinds for the list of valid option types that can be provided.
-        *
-        * @see User::listOptionKinds
-        * @param IContextSource $context
-        * @param array $options Assoc. array with options keys to check as keys.
-        *   Defaults to $this->mOptions.
-        * @return array The key => kind mapping data
-        */
-       public function getOptionKinds( IContextSource $context, $options = null ) {
-               $this->loadOptions();
-               if ( $options === null ) {
-                       $options = $this->mOptions;
-               }
-
-               $prefs = Preferences::getPreferences( $this, $context );
-               $mapping = array();
-
-               // Pull out the "special" options, so they don't get converted as
-               // multiselect or checkmatrix.
-               $specialOptions = array_fill_keys( Preferences::getSaveBlacklist(), true );
-               foreach ( $specialOptions as $name => $value ) {
-                       unset( $prefs[$name] );
-               }
-
-               // Multiselect and checkmatrix options are stored in the database with
-               // one key per option, each having a boolean value. Extract those keys.
-               $multiselectOptions = array();
-               foreach ( $prefs as $name => $info ) {
-                       if ( ( isset( $info['type'] ) && $info['type'] == 'multiselect' ) ||
-                                       ( isset( $info['class'] ) && $info['class'] == 'HTMLMultiSelectField' ) ) {
-                               $opts = HTMLFormField::flattenOptions( $info['options'] );
-                               $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
-
-                               foreach ( $opts as $value ) {
-                                       $multiselectOptions["$prefix$value"] = true;
-                               }
-
-                               unset( $prefs[$name] );
-                       }
-               }
-               $checkmatrixOptions = array();
-               foreach ( $prefs as $name => $info ) {
-                       if ( ( isset( $info['type'] ) && $info['type'] == 'checkmatrix' ) ||
-                                       ( isset( $info['class'] ) && $info['class'] == 'HTMLCheckMatrix' ) ) {
-                               $columns = HTMLFormField::flattenOptions( $info['columns'] );
-                               $rows = HTMLFormField::flattenOptions( $info['rows'] );
-                               $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
-
-                               foreach ( $columns as $column ) {
-                                       foreach ( $rows as $row ) {
-                                               $checkmatrixOptions["$prefix$column-$row"] = true;
-                                       }
-                               }
-
-                               unset( $prefs[$name] );
-                       }
-               }
-
-               // $value is ignored
-               foreach ( $options as $key => $value ) {
-                       if ( isset( $prefs[$key] ) ) {
-                               $mapping[$key] = 'registered';
-                       } elseif ( isset( $multiselectOptions[$key] ) ) {
-                               $mapping[$key] = 'registered-multiselect';
-                       } elseif ( isset( $checkmatrixOptions[$key] ) ) {
-                               $mapping[$key] = 'registered-checkmatrix';
-                       } elseif ( isset( $specialOptions[$key] ) ) {
-                               $mapping[$key] = 'special';
-                       } elseif ( substr( $key, 0, 7 ) === 'userjs-' ) {
-                               $mapping[$key] = 'userjs';
-                       } else {
-                               $mapping[$key] = 'unused';
-                       }
-               }
-
-               return $mapping;
-       }
-
-       /**
-        * Reset certain (or all) options to the site defaults
-        *
-        * The optional parameter determines which kinds of preferences will be reset.
-        * Supported values are everything that can be reported by getOptionKinds()
-        * and 'all', which forces a reset of *all* preferences and overrides everything else.
-        *
-        * @param array|string $resetKinds Which kinds of preferences to reset. Defaults to
-        *  array( 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused' )
-        *  for backwards-compatibility.
-        * @param IContextSource|null $context Context source used when $resetKinds
-        *  does not contain 'all', passed to getOptionKinds().
-        *  Defaults to RequestContext::getMain() when null.
-        */
-       public function resetOptions(
-               $resetKinds = array( 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused' ),
-               IContextSource $context = null
-       ) {
-               $this->load();
-               $defaultOptions = self::getDefaultOptions();
-
-               if ( !is_array( $resetKinds ) ) {
-                       $resetKinds = array( $resetKinds );
-               }
-
-               if ( in_array( 'all', $resetKinds ) ) {
-                       $newOptions = $defaultOptions;
-               } else {
-                       if ( $context === null ) {
-                               $context = RequestContext::getMain();
-                       }
-
-                       $optionKinds = $this->getOptionKinds( $context );
-                       $resetKinds = array_intersect( $resetKinds, self::listOptionKinds() );
-                       $newOptions = array();
-
-                       // Use default values for the options that should be deleted, and
-                       // copy old values for the ones that shouldn't.
-                       foreach ( $this->mOptions as $key => $value ) {
-                               if ( in_array( $optionKinds[$key], $resetKinds ) ) {
-                                       if ( array_key_exists( $key, $defaultOptions ) ) {
-                                               $newOptions[$key] = $defaultOptions[$key];
-                                       }
-                               } else {
-                                       $newOptions[$key] = $value;
-                               }
-                       }
-               }
-
-               Hooks::run( 'UserResetAllOptions', array( $this, &$newOptions, $this->mOptions, $resetKinds ) );
-
-               $this->mOptions = $newOptions;
-               $this->mOptionsLoaded = true;
-       }
-
-       /**
-        * Get the user's preferred date format.
-        * @return string User's preferred date format
-        */
-       public function getDatePreference() {
-               // Important migration for old data rows
-               if ( is_null( $this->mDatePreference ) ) {
-                       global $wgLang;
-                       $value = $this->getOption( 'date' );
-                       $map = $wgLang->getDatePreferenceMigrationMap();
-                       if ( isset( $map[$value] ) ) {
-                               $value = $map[$value];
-                       }
-                       $this->mDatePreference = $value;
-               }
-               return $this->mDatePreference;
-       }
-
-       /**
-        * Determine based on the wiki configuration and the user's options,
-        * whether this user must be over HTTPS no matter what.
-        *
-        * @return bool
-        */
-       public function requiresHTTPS() {
-               global $wgSecureLogin;
-               if ( !$wgSecureLogin ) {
-                       return false;
-               } else {
-                       $https = $this->getBoolOption( 'prefershttps' );
-                       Hooks::run( 'UserRequiresHTTPS', array( $this, &$https ) );
-                       if ( $https ) {
-                               $https = wfCanIPUseHTTPS( $this->getRequest()->getIP() );
-                       }
-                       return $https;
-               }
-       }
-
-       /**
-        * Get the user preferred stub threshold
-        *
-        * @return int
-        */
-       public function getStubThreshold() {
-               global $wgMaxArticleSize; # Maximum article size, in Kb
-               $threshold = $this->getIntOption( 'stubthreshold' );
-               if ( $threshold > $wgMaxArticleSize * 1024 ) {
-                       // If they have set an impossible value, disable the preference
-                       // so we can use the parser cache again.
-                       $threshold = 0;
-               }
-               return $threshold;
-       }
-
-       /**
-        * Get the permissions this user has.
-        * @return array Array of String permission names
-        */
-       public function getRights() {
-               if ( is_null( $this->mRights ) ) {
-                       $this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() );
-                       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 ) );
-               }
-               return $this->mRights;
-       }
-
-       /**
-        * Get the list of explicit group memberships this user has.
-        * The implicit * and user groups are not included.
-        * @return array Array of String internal group names
-        */
-       public function getGroups() {
-               $this->load();
-               $this->loadGroups();
-               return $this->mGroups;
-       }
-
-       /**
-        * Get the list of implicit group memberships this user has.
-        * This includes all explicit groups, plus 'user' if logged in,
-        * '*' for all accounts, and autopromoted groups
-        * @param bool $recache Whether to avoid the cache
-        * @return array Array of String internal group names
-        */
-       public function getEffectiveGroups( $recache = false ) {
-               if ( $recache || is_null( $this->mEffectiveGroups ) ) {
-                       $this->mEffectiveGroups = array_unique( array_merge(
-                               $this->getGroups(), // explicit groups
-                               $this->getAutomaticGroups( $recache ) // implicit groups
-                       ) );
-                       // Hook for additional groups
-                       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 ) );
-               }
-               return $this->mEffectiveGroups;
-       }
-
-       /**
-        * Get the list of implicit group memberships this user has.
-        * This includes 'user' if logged in, '*' for all accounts,
-        * and autopromoted groups
-        * @param bool $recache Whether to avoid the cache
-        * @return array Array of String internal group names
-        */
-       public function getAutomaticGroups( $recache = false ) {
-               if ( $recache || is_null( $this->mImplicitGroups ) ) {
-                       $this->mImplicitGroups = array( '*' );
-                       if ( $this->getId() ) {
-                               $this->mImplicitGroups[] = 'user';
-
-                               $this->mImplicitGroups = array_unique( array_merge(
-                                       $this->mImplicitGroups,
-                                       Autopromote::getAutopromoteGroups( $this )
-                               ) );
-                       }
-                       if ( $recache ) {
-                               // Assure data consistency with rights/groups,
-                               // as getEffectiveGroups() depends on this function
-                               $this->mEffectiveGroups = null;
-                       }
-               }
-               return $this->mImplicitGroups;
-       }
-
-       /**
-        * Returns the groups the user has belonged to.
-        *
-        * The user may still belong to the returned groups. Compare with getGroups().
-        *
-        * The function will not return groups the user had belonged to before MW 1.17
-        *
-        * @return array Names of the groups the user has belonged to.
-        */
-       public function getFormerGroups() {
-               $this->load();
-
-               if ( is_null( $this->mFormerGroups ) ) {
-                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                               ? wfGetDB( DB_MASTER )
-                               : wfGetDB( DB_SLAVE );
-                       $res = $db->select( 'user_former_groups',
-                               array( 'ufg_group' ),
-                               array( 'ufg_user' => $this->mId ),
-                               __METHOD__ );
-                       $this->mFormerGroups = array();
-                       foreach ( $res as $row ) {
-                               $this->mFormerGroups[] = $row->ufg_group;
-                       }
-               }
-
-               return $this->mFormerGroups;
-       }
-
-       /**
-        * Get the user's edit count.
-        * @return int|null Null for anonymous users
-        */
-       public function getEditCount() {
-               if ( !$this->getId() ) {
-                       return null;
-               }
-
-               if ( $this->mEditCount === null ) {
-                       /* Populate the count, if it has not been populated yet */
-                       $dbr = wfGetDB( DB_SLAVE );
-                       // check if the user_editcount field has been initialized
-                       $count = $dbr->selectField(
-                               'user', 'user_editcount',
-                               array( 'user_id' => $this->mId ),
-                               __METHOD__
-                       );
-
-                       if ( $count === null ) {
-                               // it has not been initialized. do so.
-                               $count = $this->initEditCount();
-                       }
-                       $this->mEditCount = $count;
-               }
-               return (int)$this->mEditCount;
-       }
-
-       /**
-        * Add the user to the given group.
-        * This takes immediate effect.
-        * @param string $group Name of the group to add
-        * @return bool
-        */
-       public function addGroup( $group ) {
-               $this->load();
-
-               if ( !Hooks::run( 'UserAddGroup', array( $this, &$group ) ) ) {
-                       return false;
-               }
-
-               $dbw = wfGetDB( DB_MASTER );
-               if ( $this->getId() ) {
-                       $dbw->insert( 'user_groups',
-                               array(
-                                       'ug_user' => $this->getID(),
-                                       'ug_group' => $group,
-                               ),
-                               __METHOD__,
-                               array( 'IGNORE' ) );
-               }
-
-               $this->loadGroups();
-               $this->mGroups[] = $group;
-               // In case loadGroups was not called before, we now have the right twice.
-               // Get rid of the duplicate.
-               $this->mGroups = array_unique( $this->mGroups );
-
-               // Refresh the groups caches, and clear the rights cache so it will be
-               // refreshed on the next call to $this->getRights().
-               $this->getEffectiveGroups( true );
-               $this->mRights = null;
-
-               $this->invalidateCache();
-
-               return true;
-       }
-
-       /**
-        * Remove the user from the given group.
-        * This takes immediate effect.
-        * @param string $group Name of the group to remove
-        * @return bool
-        */
-       public function removeGroup( $group ) {
-               $this->load();
-               if ( !Hooks::run( 'UserRemoveGroup', array( $this, &$group ) ) ) {
-                       return false;
-               }
-
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->delete( 'user_groups',
-                       array(
-                               'ug_user' => $this->getID(),
-                               'ug_group' => $group,
-                       ), __METHOD__
-               );
-               // Remember that the user was in this group
-               $dbw->insert( 'user_former_groups',
-                       array(
-                               'ufg_user' => $this->getID(),
-                               'ufg_group' => $group,
-                       ),
-                       __METHOD__,
-                       array( 'IGNORE' )
-               );
-
-               $this->loadGroups();
-               $this->mGroups = array_diff( $this->mGroups, array( $group ) );
-
-               // Refresh the groups caches, and clear the rights cache so it will be
-               // refreshed on the next call to $this->getRights().
-               $this->getEffectiveGroups( true );
-               $this->mRights = null;
-
-               $this->invalidateCache();
-
-               return true;
-       }
-
-       /**
-        * Get whether the user is logged in
-        * @return bool
-        */
-       public function isLoggedIn() {
-               return $this->getID() != 0;
-       }
-
-       /**
-        * Get whether the user is anonymous
-        * @return bool
-        */
-       public function isAnon() {
-               return !$this->isLoggedIn();
-       }
-
-       /**
-        * Check if user is allowed to access a feature / make an action
-        *
-        * @param string ... Permissions to test
-        * @return bool True if user is allowed to perform *any* of the given actions
-        */
-       public function isAllowedAny() {
-               $permissions = func_get_args();
-               foreach ( $permissions as $permission ) {
-                       if ( $this->isAllowed( $permission ) ) {
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       /**
-        *
-        * @param string ... Permissions to test
-        * @return bool True if the user is allowed to perform *all* of the given actions
-        */
-       public function isAllowedAll() {
-               $permissions = func_get_args();
-               foreach ( $permissions as $permission ) {
-                       if ( !$this->isAllowed( $permission ) ) {
-                               return false;
-                       }
-               }
-               return true;
-       }
-
-       /**
-        * Internal mechanics of testing a permission
-        * @param string $action
-        * @return bool
-        */
-       public function isAllowed( $action = '' ) {
-               if ( $action === '' ) {
-                       return true; // In the spirit of DWIM
-               }
-               // Patrolling may not be enabled
-               if ( $action === 'patrol' || $action === 'autopatrol' ) {
-                       global $wgUseRCPatrol, $wgUseNPPatrol;
-                       if ( !$wgUseRCPatrol && !$wgUseNPPatrol ) {
-                               return false;
-                       }
-               }
-               // Use strict parameter to avoid matching numeric 0 accidentally inserted
-               // by misconfiguration: 0 == 'foo'
-               return in_array( $action, $this->getRights(), true );
-       }
-
-       /**
-        * Check whether to enable recent changes patrol features for this user
-        * @return bool True or false
-        */
-       public function useRCPatrol() {
-               global $wgUseRCPatrol;
-               return $wgUseRCPatrol && $this->isAllowedAny( 'patrol', 'patrolmarks' );
-       }
-
-       /**
-        * Check whether to enable new pages patrol features for this user
-        * @return bool True or false
-        */
-       public function useNPPatrol() {
-               global $wgUseRCPatrol, $wgUseNPPatrol;
-               return (
-                       ( $wgUseRCPatrol || $wgUseNPPatrol )
-                               && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
-               );
-       }
-
-       /**
-        * Get the WebRequest object to use with this object
-        *
-        * @return WebRequest
-        */
-       public function getRequest() {
-               if ( $this->mRequest ) {
-                       return $this->mRequest;
-               } else {
-                       global $wgRequest;
-                       return $wgRequest;
-               }
-       }
-
-       /**
-        * Get the current skin, loading it if required
-        * @return Skin The current skin
-        * @todo FIXME: Need to check the old failback system [AV]
-        * @deprecated since 1.18 Use ->getSkin() in the most relevant outputting context you have
-        */
-       public function getSkin() {
-               wfDeprecated( __METHOD__, '1.18' );
-               return RequestContext::getMain()->getSkin();
-       }
-
-       /**
-        * Get a WatchedItem for this user and $title.
-        *
-        * @since 1.22 $checkRights parameter added
-        * @param Title $title
-        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
-        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
-        * @return WatchedItem
-        */
-       public function getWatchedItem( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
-               $key = $checkRights . ':' . $title->getNamespace() . ':' . $title->getDBkey();
-
-               if ( isset( $this->mWatchedItems[$key] ) ) {
-                       return $this->mWatchedItems[$key];
-               }
-
-               if ( count( $this->mWatchedItems ) >= self::MAX_WATCHED_ITEMS_CACHE ) {
-                       $this->mWatchedItems = array();
-               }
-
-               $this->mWatchedItems[$key] = WatchedItem::fromUserTitle( $this, $title, $checkRights );
-               return $this->mWatchedItems[$key];
-       }
-
-       /**
-        * Check the watched status of an article.
-        * @since 1.22 $checkRights parameter added
-        * @param Title $title Title of the article to look at
-        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
-        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
-        * @return bool
-        */
-       public function isWatched( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
-               return $this->getWatchedItem( $title, $checkRights )->isWatched();
-       }
-
-       /**
-        * Watch an article.
-        * @since 1.22 $checkRights parameter added
-        * @param Title $title Title of the article to look at
-        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
-        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
-        */
-       public function addWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
-               $this->getWatchedItem( $title, $checkRights )->addWatch();
-               $this->invalidateCache();
-       }
-
-       /**
-        * Stop watching an article.
-        * @since 1.22 $checkRights parameter added
-        * @param Title $title Title of the article to look at
-        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
-        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
-        */
-       public function removeWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
-               $this->getWatchedItem( $title, $checkRights )->removeWatch();
-               $this->invalidateCache();
-       }
-
-       /**
-        * Clear the user's notification timestamp for the given title.
-        * If e-notif e-mails are on, they will receive notification mails on
-        * the next change of the page if it's watched etc.
-        * @note If the user doesn't have 'editmywatchlist', this will do nothing.
-        * @param Title $title Title of the article to look at
-        * @param int $oldid The revision id being viewed. If not given or 0, latest revision is assumed.
-        */
-       public function clearNotification( &$title, $oldid = 0 ) {
-               global $wgUseEnotif, $wgShowUpdatedMarker;
-
-               // Do nothing if the database is locked to writes
-               if ( wfReadOnly() ) {
-                       return;
-               }
-
-               // Do nothing if not allowed to edit the watchlist
-               if ( !$this->isAllowed( 'editmywatchlist' ) ) {
-                       return;
-               }
-
-               // 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 ( !Hooks::run( 'UserClearNewTalkNotification', array( &$this, $oldid ) ) ) {
-                               return;
-                       }
-
-                       $that = $this;
-                       // Try to update the DB post-send and only if needed...
-                       DeferredUpdates::addCallableUpdate( function() use ( $that, $title, $oldid ) {
-                               if ( !$that->getNewtalk() ) {
-                                       return; // no notifications to clear
-                               }
-
-                               // Delete the last notifications (they stack up)
-                               $that->setNewtalk( false );
-
-                               // If there is a new, unseen, revision, use its timestamp
-                               $nextid = $oldid
-                                       ? $title->getNextRevisionID( $oldid, Title::GAID_FOR_UPDATE )
-                                       : null;
-                               if ( $nextid ) {
-                                       $that->setNewtalk( true, Revision::newFromId( $nextid ) );
-                               }
-                       } );
-               }
-
-               if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
-                       return;
-               }
-
-               if ( $this->isAnon() ) {
-                       // Nothing else to do...
-                       return;
-               }
-
-               // Only update the timestamp if the page is being watched.
-               // The query to find out if it is watched is cached both in memcached and per-invocation,
-               // and when it does have to be executed, it can be on a slave
-               // If this is the user's newtalk page, we always update the timestamp
-               $force = '';
-               if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
-                       $force = 'force';
-               }
-
-               $this->getWatchedItem( $title )->resetNotificationTimestamp(
-                       $force, $oldid, WatchedItem::DEFERRED
-               );
-       }
-
-       /**
-        * Resets all of the given user's page-change notification timestamps.
-        * If e-notif e-mails are on, they will receive notification mails on
-        * the next change of any watched page.
-        * @note If the user doesn't have 'editmywatchlist', this will do nothing.
-        */
-       public function clearAllNotifications() {
-               if ( wfReadOnly() ) {
-                       return;
-               }
-
-               // Do nothing if not allowed to edit the watchlist
-               if ( !$this->isAllowed( 'editmywatchlist' ) ) {
-                       return;
-               }
-
-               global $wgUseEnotif, $wgShowUpdatedMarker;
-               if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
-                       $this->setNewtalk( false );
-                       return;
-               }
-               $id = $this->getId();
-               if ( $id != 0 ) {
-                       $dbw = wfGetDB( DB_MASTER );
-                       $dbw->update( 'watchlist',
-                               array( /* SET */ 'wl_notificationtimestamp' => null ),
-                               array( /* WHERE */ 'wl_user' => $id, 'wl_notificationtimestamp IS NOT NULL' ),
-                               __METHOD__
-                       );
-                       // We also need to clear here the "you have new message" notification for the own user_talk page;
-                       // it's cleared one page view later in WikiPage::doViewUpdates().
-               }
-       }
-
-       /**
-        * Set a cookie on the user's client. Wrapper for
-        * WebResponse::setCookie
-        * @param string $name Name of the cookie to set
-        * @param string $value Value to set
-        * @param int $exp Expiration time, as a UNIX time value;
-        *                   if 0 or not specified, use the default $wgCookieExpiration
-        * @param bool $secure
-        *  true: Force setting the secure attribute when setting the cookie
-        *  false: Force NOT setting the secure attribute when setting the cookie
-        *  null (default): Use the default ($wgCookieSecure) to set the secure attribute
-        * @param array $params Array of options sent passed to WebResponse::setcookie()
-        * @param WebRequest|null $request WebRequest object to use; $wgRequest will be used if null
-        *        is passed.
-        */
-       protected function setCookie(
-               $name, $value, $exp = 0, $secure = null, $params = array(), $request = null
-       ) {
-               if ( $request === null ) {
-                       $request = $this->getRequest();
-               }
-               $params['secure'] = $secure;
-               $request->response()->setCookie( $name, $value, $exp, $params );
-       }
-
-       /**
-        * Clear a cookie on the user's client
-        * @param string $name Name of the cookie to clear
-        * @param bool $secure
-        *  true: Force setting the secure attribute when setting the cookie
-        *  false: Force NOT setting the secure attribute when setting the cookie
-        *  null (default): Use the default ($wgCookieSecure) to set the secure attribute
-        * @param array $params Array of options sent passed to WebResponse::setcookie()
-        */
-       protected function clearCookie( $name, $secure = null, $params = array() ) {
-               $this->setCookie( $name, '', time() - 86400, $secure, $params );
-       }
-
-       /**
-        * Set an extended login cookie on the user's client. The expiry of the cookie
-        * is controlled by the $wgExtendedLoginCookieExpiration configuration
-        * variable.
-        *
-        * @see User::setCookie
-        *
-        * @param string $name Name of the cookie to set
-        * @param string $value Value to set
-        * @param bool $secure
-        *  true: Force setting the secure attribute when setting the cookie
-        *  false: Force NOT setting the secure attribute when setting the cookie
-        *  null (default): Use the default ($wgCookieSecure) to set the secure attribute
-        */
-       protected function setExtendedLoginCookie( $name, $value, $secure ) {
-               global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
-
-               $exp = time();
-               $exp += $wgExtendedLoginCookieExpiration !== null
-                       ? $wgExtendedLoginCookieExpiration
-                       : $wgCookieExpiration;
-
-               $this->setCookie( $name, $value, $exp, $secure );
-       }
-
-       /**
-        * Set the default cookies for this session on the user's client.
-        *
-        * @param WebRequest|null $request WebRequest object to use; $wgRequest will be used if null
-        *        is passed.
-        * @param bool $secure Whether to force secure/insecure cookies or use default
-        * @param bool $rememberMe Whether to add a Token cookie for elongated sessions
-        */
-       public function setCookies( $request = null, $secure = null, $rememberMe = false ) {
-               global $wgExtendedLoginCookies;
-
-               if ( $request === null ) {
-                       $request = $this->getRequest();
-               }
-
-               $this->load();
-               if ( 0 == $this->mId ) {
-                       return;
-               }
-               if ( !$this->mToken ) {
-                       // When token is empty or NULL generate a new one and then save it to the database
-                       // This allows a wiki to re-secure itself after a leak of it's user table or $wgSecretKey
-                       // Simply by setting every cell in the user_token column to NULL and letting them be
-                       // regenerated as users log back into the wiki.
-                       $this->setToken();
-                       if ( !wfReadOnly() ) {
-                               $this->saveSettings();
-                       }
-               }
-               $session = array(
-                       'wsUserID' => $this->mId,
-                       'wsToken' => $this->mToken,
-                       'wsUserName' => $this->getName()
-               );
-               $cookies = array(
-                       'UserID' => $this->mId,
-                       'UserName' => $this->getName(),
-               );
-               if ( $rememberMe ) {
-                       $cookies['Token'] = $this->mToken;
-               } else {
-                       $cookies['Token'] = false;
-               }
-
-               Hooks::run( 'UserSetCookies', array( $this, &$session, &$cookies ) );
-
-               foreach ( $session as $name => $value ) {
-                       $request->setSessionData( $name, $value );
-               }
-               foreach ( $cookies as $name => $value ) {
-                       if ( $value === false ) {
-                               $this->clearCookie( $name );
-                       } elseif ( $rememberMe && in_array( $name, $wgExtendedLoginCookies ) ) {
-                               $this->setExtendedLoginCookie( $name, $value, $secure );
-                       } else {
-                               $this->setCookie( $name, $value, 0, $secure, array(), $request );
-                       }
-               }
-
-               /**
-                * If wpStickHTTPS was selected, also set an insecure cookie that
-                * will cause the site to redirect the user to HTTPS, if they access
-                * it over HTTP. Bug 29898. Use an un-prefixed cookie, so it's the same
-                * as the one set by centralauth (bug 53538). Also set it to session, or
-                * standard time setting, based on if rememberme was set.
-                */
-               if ( $request->getCheck( 'wpStickHTTPS' ) || $this->requiresHTTPS() ) {
-                       $this->setCookie(
-                               'forceHTTPS',
-                               'true',
-                               $rememberMe ? 0 : null,
-                               false,
-                               array( 'prefix' => '' ) // no prefix
-                       );
-               }
-       }
-
-       /**
-        * Log this user out.
-        */
-       public function logout() {
-               if ( Hooks::run( 'UserLogout', array( &$this ) ) ) {
-                       $this->doLogout();
-               }
-       }
-
-       /**
-        * Clear the user's cookies and session, and reset the instance cache.
-        * @see logout()
-        */
-       public function doLogout() {
-               $this->clearInstanceCache( 'defaults' );
-
-               $this->getRequest()->setSessionData( 'wsUserID', 0 );
-
-               $this->clearCookie( 'UserID' );
-               $this->clearCookie( 'Token' );
-               $this->clearCookie( 'forceHTTPS', false, array( 'prefix' => '' ) );
-
-               // Remember when user logged out, to prevent seeing cached pages
-               $this->setCookie( 'LoggedOut', time(), time() + 86400 );
-       }
-
-       /**
-        * Save this user's settings into the database.
-        * @todo Only rarely do all these fields need to be set!
-        */
-       public function saveSettings() {
-               if ( wfReadOnly() ) {
-                       // @TODO: caller should deal with this instead!
-                       // This should really just be an exception.
-                       MWExceptionHandler::logException( new DBExpectedError(
-                               null,
-                               "Could not update user with ID '{$this->mId}'; DB is read-only."
-                       ) );
-                       return;
-               }
-
-               $this->load();
-               if ( 0 == $this->mId ) {
-                       return; // anon
-               }
-
-               // Get a new user_touched that is higher than the old one.
-               // This will be used for a CAS check as a last-resort safety
-               // check against race conditions and slave lag.
-               $oldTouched = $this->mTouched;
-               $newTouched = $this->newTouchedTimestamp();
-
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->update( 'user',
-                       array( /* SET */
-                               'user_name' => $this->mName,
-                               'user_real_name' => $this->mRealName,
-                               'user_email' => $this->mEmail,
-                               'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
-                               'user_touched' => $dbw->timestamp( $newTouched ),
-                               'user_token' => strval( $this->mToken ),
-                               'user_email_token' => $this->mEmailToken,
-                               'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
-                       ), array( /* WHERE */
-                               'user_id' => $this->mId,
-                               'user_touched' => $dbw->timestamp( $oldTouched ) // CAS check
-                       ), __METHOD__
-               );
-
-               if ( !$dbw->affectedRows() ) {
-                       // Maybe the problem was a missed cache update; clear it to be safe
-                       $this->clearSharedCache( 'refresh' );
-                       // User was changed in the meantime or loaded with stale data
-                       $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'master' : 'slave';
-                       throw new MWException(
-                               "CAS update failed on user_touched for user ID '{$this->mId}' (read from $from);" .
-                               " the version of the user to be saved is older than the current version."
-                       );
-               }
-
-               $this->mTouched = $newTouched;
-               $this->saveOptions();
-
-               Hooks::run( 'UserSaveSettings', array( $this ) );
-               $this->clearSharedCache();
-               $this->getUserPage()->invalidateCache();
-       }
-
-       /**
-        * If only this user's username is known, and it exists, return the user ID.
-        *
-        * @param int $flags Bitfield of User:READ_* constants; useful for existence checks
-        * @return int
-        */
-       public function idForName( $flags = 0 ) {
-               $s = trim( $this->getName() );
-               if ( $s === '' ) {
-                       return 0;
-               }
-
-               $db = ( ( $flags & self::READ_LATEST ) == self::READ_LATEST )
-                       ? wfGetDB( DB_MASTER )
-                       : wfGetDB( DB_SLAVE );
-
-               $options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
-                       ? array( 'LOCK IN SHARE MODE' )
-                       : array();
-
-               $id = $db->selectField( 'user',
-                       'user_id', array( 'user_name' => $s ), __METHOD__, $options );
-
-               return (int)$id;
-       }
-
-       /**
-        * Add a user to the database, return the user object
-        *
-        * @param string $name Username to add
-        * @param array $params Array of Strings Non-default parameters to save to
-        *   the database as user_* fields:
-        *   - email: The user's email address.
-        *   - email_authenticated: The email authentication timestamp.
-        *   - real_name: The user's real name.
-        *   - options: An associative array of non-default options.
-        *   - token: Random authentication token. Do not set.
-        *   - registration: Registration timestamp. Do not set.
-        *
-        * @return User|null User object, or null if the username already exists.
-        */
-       public static function createNew( $name, $params = array() ) {
-               foreach ( array( 'password', 'newpassword', 'newpass_time', 'password_expires' ) as $field ) {
-                       if ( isset( $params[$field] ) ) {
-                               wfDeprecated( __METHOD__ . " with param '$field'", '1.27' );
-                               unset( $params[$field] );
-                       }
-               }
-
-               $user = new User;
-               $user->load();
-               $user->setToken(); // init token
-               if ( isset( $params['options'] ) ) {
-                       $user->mOptions = $params['options'] + (array)$user->mOptions;
-                       unset( $params['options'] );
-               }
-               $dbw = wfGetDB( DB_MASTER );
-               $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
-
-               $noPass = PasswordFactory::newInvalidPassword()->toString();
-
-               $fields = array(
-                       'user_id' => $seqVal,
-                       'user_name' => $name,
-                       'user_password' => $noPass,
-                       'user_newpassword' => $noPass,
-                       'user_email' => $user->mEmail,
-                       'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
-                       'user_real_name' => $user->mRealName,
-                       'user_token' => strval( $user->mToken ),
-                       'user_registration' => $dbw->timestamp( $user->mRegistration ),
-                       'user_editcount' => 0,
-                       'user_touched' => $dbw->timestamp( $user->newTouchedTimestamp() ),
-               );
-               foreach ( $params as $name => $value ) {
-                       $fields["user_$name"] = $value;
-               }
-               $dbw->insert( 'user', $fields, __METHOD__, array( 'IGNORE' ) );
-               if ( $dbw->affectedRows() ) {
-                       $newUser = User::newFromId( $dbw->insertId() );
-               } else {
-                       $newUser = null;
-               }
-               return $newUser;
-       }
-
-       /**
-        * Add this existing user object to the database. If the user already
-        * exists, a fatal status object is returned, and the user object is
-        * initialised with the data from the database.
-        *
-        * Previously, this function generated a DB error due to a key conflict
-        * if the user already existed. Many extension callers use this function
-        * in code along the lines of:
-        *
-        *   $user = User::newFromName( $name );
-        *   if ( !$user->isLoggedIn() ) {
-        *       $user->addToDatabase();
-        *   }
-        *   // do something with $user...
-        *
-        * However, this was vulnerable to a race condition (bug 16020). By
-        * initialising the user object if the user exists, we aim to support this
-        * calling sequence as far as possible.
-        *
-        * Note that if the user exists, this function will acquire a write lock,
-        * so it is still advisable to make the call conditional on isLoggedIn(),
-        * and to commit the transaction after calling.
-        *
-        * @throws MWException
-        * @return Status
-        */
-       public function addToDatabase() {
-               $this->load();
-               if ( !$this->mToken ) {
-                       $this->setToken(); // init token
-               }
-
-               $this->mTouched = $this->newTouchedTimestamp();
-
-               $noPass = PasswordFactory::newInvalidPassword()->toString();
-
-               $dbw = wfGetDB( DB_MASTER );
-               $inWrite = $dbw->writesOrCallbacksPending();
-               $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
-               $dbw->insert( 'user',
-                       array(
-                               'user_id' => $seqVal,
-                               'user_name' => $this->mName,
-                               'user_password' => $noPass,
-                               'user_newpassword' => $noPass,
-                               'user_email' => $this->mEmail,
-                               'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
-                               'user_real_name' => $this->mRealName,
-                               'user_token' => strval( $this->mToken ),
-                               'user_registration' => $dbw->timestamp( $this->mRegistration ),
-                               'user_editcount' => 0,
-                               'user_touched' => $dbw->timestamp( $this->mTouched ),
-                       ), __METHOD__,
-                       array( 'IGNORE' )
-               );
-               if ( !$dbw->affectedRows() ) {
-                       // The queries below cannot happen in the same REPEATABLE-READ snapshot.
-                       // Handle this by COMMIT, if possible, or by LOCK IN SHARE MODE otherwise.
-                       if ( $inWrite ) {
-                               // Can't commit due to pending writes that may need atomicity.
-                               // This may cause some lock contention unlike the case below.
-                               $options = array( 'LOCK IN SHARE MODE' );
-                               $flags = self::READ_LOCKING;
-                       } else {
-                               // Often, this case happens early in views before any writes when
-                               // using CentralAuth. It's should be OK to commit and break the snapshot.
-                               $dbw->commit( __METHOD__, 'flush' );
-                               $options = array();
-                               $flags = self::READ_LATEST;
-                       }
-                       $this->mId = $dbw->selectField( 'user', 'user_id',
-                               array( 'user_name' => $this->mName ), __METHOD__, $options );
-                       $loaded = false;
-                       if ( $this->mId ) {
-                               if ( $this->loadFromDatabase( $flags ) ) {
-                                       $loaded = true;
-                               }
-                       }
-                       if ( !$loaded ) {
-                               throw new MWException( __METHOD__ . ": hit a key conflict attempting " .
-                                       "to insert user '{$this->mName}' row, but it was not present in select!" );
-                       }
-                       return Status::newFatal( 'userexists' );
-               }
-               $this->mId = $dbw->insertId();
-               self::$idCacheByName[$this->mName] = $this->mId;
-
-               // Clear instance cache other than user table data, which is already accurate
-               $this->clearInstanceCache();
-
-               $this->saveOptions();
-               return Status::newGood();
-       }
-
-       /**
-        * If this user is logged-in and blocked,
-        * block any IP address they've successfully logged in from.
-        * @return bool A block was spread
-        */
-       public function spreadAnyEditBlock() {
-               if ( $this->isLoggedIn() && $this->isBlocked() ) {
-                       return $this->spreadBlock();
-               }
-               return false;
-       }
-
-       /**
-        * If this (non-anonymous) user is blocked,
-        * block the IP address they've successfully logged in from.
-        * @return bool A block was spread
-        */
-       protected function spreadBlock() {
-               wfDebug( __METHOD__ . "()\n" );
-               $this->load();
-               if ( $this->mId == 0 ) {
-                       return false;
-               }
-
-               $userblock = Block::newFromTarget( $this->getName() );
-               if ( !$userblock ) {
-                       return false;
-               }
-
-               return (bool)$userblock->doAutoblock( $this->getRequest()->getIP() );
-       }
-
-       /**
-        * Get whether the user is explicitly blocked from account creation.
-        * @return bool|Block
-        */
-       public function isBlockedFromCreateAccount() {
-               $this->getBlockedStatus();
-               if ( $this->mBlock && $this->mBlock->prevents( 'createaccount' ) ) {
-                       return $this->mBlock;
-               }
-
-               # bug 13611: if the IP address the user is trying to create an account from is
-               # blocked with createaccount disabled, prevent new account creation there even
-               # when the user is logged in
-               if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
-                       $this->mBlockedFromCreateAccount = Block::newFromTarget( null, $this->getRequest()->getIP() );
-               }
-               return $this->mBlockedFromCreateAccount instanceof Block
-                       && $this->mBlockedFromCreateAccount->prevents( 'createaccount' )
-                       ? $this->mBlockedFromCreateAccount
-                       : false;
-       }
-
-       /**
-        * Get whether the user is blocked from using Special:Emailuser.
-        * @return bool
-        */
-       public function isBlockedFromEmailuser() {
-               $this->getBlockedStatus();
-               return $this->mBlock && $this->mBlock->prevents( 'sendemail' );
-       }
-
-       /**
-        * Get whether the user is allowed to create an account.
-        * @return bool
-        */
-       public function isAllowedToCreateAccount() {
-               return $this->isAllowed( 'createaccount' ) && !$this->isBlockedFromCreateAccount();
-       }
-
-       /**
-        * Get this user's personal page title.
-        *
-        * @return Title User's personal page title
-        */
-       public function getUserPage() {
-               return Title::makeTitle( NS_USER, $this->getName() );
-       }
-
-       /**
-        * Get this user's talk page title.
-        *
-        * @return Title User's talk page title
-        */
-       public function getTalkPage() {
-               $title = $this->getUserPage();
-               return $title->getTalkPage();
-       }
-
-       /**
-        * Determine whether the user is a newbie. Newbies are either
-        * anonymous IPs, or the most recently created accounts.
-        * @return bool
-        */
-       public function isNewbie() {
-               return !$this->isAllowed( 'autoconfirmed' );
-       }
-
-       /**
-        * Check to see if the given clear-text password is one of the accepted passwords
-        * @deprecated since 1.27. AuthManager is coming.
-        * @param string $password User password
-        * @return bool True if the given password is correct, otherwise False
-        */
-       public function checkPassword( $password ) {
-               global $wgAuth, $wgLegacyEncoding;
-
-               $this->load();
-
-               // Some passwords will give a fatal Status, which means there is
-               // some sort of technical or security reason for this password to
-               // be completely invalid and should never be checked (e.g., T64685)
-               if ( !$this->checkPasswordValidity( $password )->isOK() ) {
-                       return false;
-               }
-
-               // Certain authentication plugins do NOT want to save
-               // domain passwords in a mysql database, so we should
-               // check this (in case $wgAuth->strict() is false).
-               if ( $wgAuth->authenticate( $this->getName(), $password ) ) {
-                       return true;
-               } elseif ( $wgAuth->strict() ) {
-                       // Auth plugin doesn't allow local authentication
-                       return false;
-               } elseif ( $wgAuth->strictUserAuth( $this->getName() ) ) {
-                       // Auth plugin doesn't allow local authentication for this user name
-                       return false;
-               }
-
-               $passwordFactory = new PasswordFactory();
-               $passwordFactory->init( RequestContext::getMain()->getConfig() );
-               $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                       ? wfGetDB( DB_MASTER )
-                       : wfGetDB( DB_SLAVE );
-
-               try {
-                       $mPassword = $passwordFactory->newFromCiphertext( $db->selectField(
-                               'user', 'user_password', array( 'user_id' => $this->getId() ), __METHOD__
-                       ) );
-               } catch ( PasswordError $e ) {
-                       wfDebug( 'Invalid password hash found in database.' );
-                       $mPassword = PasswordFactory::newInvalidPassword();
-               }
-
-               if ( !$mPassword->equals( $password ) ) {
-                       if ( $wgLegacyEncoding ) {
-                               // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
-                               // Check for this with iconv
-                               $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
-                               if ( $cp1252Password === $password || !$mPassword->equals( $cp1252Password ) ) {
-                                       return false;
-                               }
-                       } else {
-                               return false;
-                       }
-               }
-
-               if ( $passwordFactory->needsUpdate( $mPassword ) && !wfReadOnly() ) {
-                       $this->setPasswordInternal( $password );
-               }
-
-               return true;
-       }
-
-       /**
-        * Check if the given clear-text password matches the temporary password
-        * sent by e-mail for password reset operations.
-        *
-        * @deprecated since 1.27. AuthManager is coming.
-        * @param string $plaintext
-        * @return bool True if matches, false otherwise
-        */
-       public function checkTemporaryPassword( $plaintext ) {
-               global $wgNewPasswordExpiry;
-
-               $this->load();
-
-               $passwordFactory = new PasswordFactory();
-               $passwordFactory->init( RequestContext::getMain()->getConfig() );
-               $db = ( $this->queryFlagsUsed & self::READ_LATEST )
-                       ? wfGetDB( DB_MASTER )
-                       : wfGetDB( DB_SLAVE );
-
-               $row = $db->selectRow(
-                       'user',
-                       array( 'user_newpassword', 'user_newpass_time' ),
-                       array( 'user_id' => $this->getId() ),
-                       __METHOD__
-               );
-               try {
-                       $newPassword = $passwordFactory->newFromCiphertext( $row->user_newpassword );
-               } catch ( PasswordError $e ) {
-                       wfDebug( 'Invalid password hash found in database.' );
-                       $newPassword = PasswordFactory::newInvalidPassword();
-               }
-
-               if ( $newPassword->equals( $plaintext ) ) {
-                       if ( is_null( $row->user_newpass_time ) ) {
-                               return true;
-                       }
-                       $expiry = wfTimestamp( TS_UNIX, $row->user_newpass_time ) + $wgNewPasswordExpiry;
-                       return ( time() < $expiry );
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * Alias for getEditToken.
-        * @deprecated since 1.19, use getEditToken instead.
-        *
-        * @param string|array $salt Array of Strings Optional function-specific data for hashing
-        * @param WebRequest|null $request WebRequest object to use or null to use $wgRequest
-        * @return string The new edit token
-        */
-       public function editToken( $salt = '', $request = null ) {
-               wfDeprecated( __METHOD__, '1.19' );
-               return $this->getEditToken( $salt, $request );
-       }
-
-       /**
-        * Internal implementation for self::getEditToken() and
-        * self::matchEditToken().
-        *
-        * @param string|array $salt
-        * @param WebRequest $request
-        * @param string|int $timestamp
-        * @return string
-        */
-       private function getEditTokenAtTimestamp( $salt, $request, $timestamp ) {
-               if ( $this->isAnon() ) {
-                       return self::EDIT_TOKEN_SUFFIX;
-               } else {
-                       $token = $request->getSessionData( 'wsEditToken' );
-                       if ( $token === null ) {
-                               $token = MWCryptRand::generateHex( 32 );
-                               $request->setSessionData( 'wsEditToken', $token );
-                       }
-                       if ( is_array( $salt ) ) {
-                               $salt = implode( '|', $salt );
-                       }
-                       return hash_hmac( 'md5', $timestamp . $salt, $token, false ) .
-                               dechex( $timestamp ) .
-                               self::EDIT_TOKEN_SUFFIX;
-               }
-       }
-
-       /**
-        * Initialize (if necessary) and return a session token value
-        * which can be used in edit forms to show that the user's
-        * login credentials aren't being hijacked with a foreign form
-        * submission.
-        *
-        * @since 1.19
-        *
-        * @param string|array $salt Array of Strings Optional function-specific data for hashing
-        * @param WebRequest|null $request WebRequest object to use or null to use $wgRequest
-        * @return string The new edit token
-        */
-       public function getEditToken( $salt = '', $request = null ) {
-               return $this->getEditTokenAtTimestamp(
-                       $salt, $request ?: $this->getRequest(), wfTimestamp()
-               );
-       }
-
-       /**
-        * Generate a looking random token for various uses.
-        *
-        * @return string The new random token
-        * @deprecated since 1.20: Use MWCryptRand for secure purposes or
-        *   wfRandomString for pseudo-randomness.
-        */
-       public static function generateToken() {
-               return MWCryptRand::generateHex( 32 );
-       }
-
-       /**
-        * Get the embedded timestamp from a token.
-        * @param string $val Input token
-        * @return int|null
-        */
-       public static function getEditTokenTimestamp( $val ) {
-               $suffixLen = strlen( self::EDIT_TOKEN_SUFFIX );
-               if ( strlen( $val ) <= 32 + $suffixLen ) {
-                       return null;
-               }
-
-               return hexdec( substr( $val, 32, -$suffixLen ) );
-       }
-
-       /**
-        * Check given value against the token value stored in the session.
-        * A match should confirm that the form was submitted from the
-        * user's own login session, not a form submission from a third-party
-        * site.
-        *
-        * @param string $val Input value to compare
-        * @param string $salt Optional function-specific data for hashing
-        * @param WebRequest|null $request Object to use or null to use $wgRequest
-        * @param int $maxage Fail tokens older than this, in seconds
-        * @return bool Whether the token matches
-        */
-       public function matchEditToken( $val, $salt = '', $request = null, $maxage = null ) {
-               if ( $this->isAnon() ) {
-                       return $val === self::EDIT_TOKEN_SUFFIX;
-               }
-
-               $timestamp = self::getEditTokenTimestamp( $val );
-               if ( $timestamp === null ) {
-                       return false;
-               }
-               if ( $maxage !== null && $timestamp < wfTimestamp() - $maxage ) {
-                       // Expired token
-                       return false;
-               }
-
-               $sessionToken = $this->getEditTokenAtTimestamp(
-                       $salt, $request ?: $this->getRequest(), $timestamp
-               );
-
-               if ( $val != $sessionToken ) {
-                       wfDebug( "User::matchEditToken: broken session data\n" );
-               }
-
-               return hash_equals( $sessionToken, $val );
-       }
-
-       /**
-        * Check given value against the token value stored in the session,
-        * ignoring the suffix.
-        *
-        * @param string $val Input value to compare
-        * @param string $salt Optional function-specific data for hashing
-        * @param WebRequest|null $request Object to use or null to use $wgRequest
-        * @param int $maxage Fail tokens older than this, in seconds
-        * @return bool Whether the token matches
-        */
-       public function matchEditTokenNoSuffix( $val, $salt = '', $request = null, $maxage = null ) {
-               $val = substr( $val, 0, strspn( $val, '0123456789abcdef' ) ) . self::EDIT_TOKEN_SUFFIX;
-               return $this->matchEditToken( $val, $salt, $request, $maxage );
-       }
-
-       /**
-        * Generate a new e-mail confirmation token and send a confirmation/invalidation
-        * mail to the user's given address.
-        *
-        * @param string $type Message to send, either "created", "changed" or "set"
-        * @return Status
-        */
-       public function sendConfirmationMail( $type = 'created' ) {
-               global $wgLang;
-               $expiration = null; // gets passed-by-ref and defined in next line.
-               $token = $this->confirmationToken( $expiration );
-               $url = $this->confirmationTokenUrl( $token );
-               $invalidateURL = $this->invalidationTokenUrl( $token );
-               $this->saveSettings();
-
-               if ( $type == 'created' || $type === false ) {
-                       $message = 'confirmemail_body';
-               } elseif ( $type === true ) {
-                       $message = 'confirmemail_body_changed';
-               } else {
-                       // Messages: confirmemail_body_changed, confirmemail_body_set
-                       $message = 'confirmemail_body_' . $type;
-               }
-
-               return $this->sendMail( wfMessage( 'confirmemail_subject' )->text(),
-                       wfMessage( $message,
-                               $this->getRequest()->getIP(),
-                               $this->getName(),
-                               $url,
-                               $wgLang->timeanddate( $expiration, false ),
-                               $invalidateURL,
-                               $wgLang->date( $expiration, false ),
-                               $wgLang->time( $expiration, false ) )->text() );
-       }
-
-       /**
-        * Send an e-mail to this user's account. Does not check for
-        * confirmed status or validity.
-        *
-        * @param string $subject Message subject
-        * @param string $body Message body
-        * @param User|null $from Optional sending user; if unspecified, default
-        *   $wgPasswordSender will be used.
-        * @param string $replyto Reply-To address
-        * @return Status
-        */
-       public function sendMail( $subject, $body, $from = null, $replyto = null ) {
-               global $wgPasswordSender;
-
-               if ( $from instanceof User ) {
-                       $sender = MailAddress::newFromUser( $from );
-               } else {
-                       $sender = new MailAddress( $wgPasswordSender,
-                               wfMessage( 'emailsender' )->inContentLanguage()->text() );
-               }
-               $to = MailAddress::newFromUser( $this );
-
-               return UserMailer::send( $to, $sender, $subject, $body, array(
-                       'replyTo' => $replyto,
-               ) );
-       }
-
-       /**
-        * Generate, store, and return a new e-mail confirmation code.
-        * A hash (unsalted, since it's used as a key) is stored.
-        *
-        * @note Call saveSettings() after calling this function to commit
-        * this change to the database.
-        *
-        * @param string &$expiration Accepts the expiration time
-        * @return string New token
-        */
-       protected function confirmationToken( &$expiration ) {
-               global $wgUserEmailConfirmationTokenExpiry;
-               $now = time();
-               $expires = $now + $wgUserEmailConfirmationTokenExpiry;
-               $expiration = wfTimestamp( TS_MW, $expires );
-               $this->load();
-               $token = MWCryptRand::generateHex( 32 );
-               $hash = md5( $token );
-               $this->mEmailToken = $hash;
-               $this->mEmailTokenExpires = $expiration;
-               return $token;
-       }
-
-       /**
-        * Return a URL the user can use to confirm their email address.
-        * @param string $token Accepts the email confirmation token
-        * @return string New token URL
-        */
-       protected function confirmationTokenUrl( $token ) {
-               return $this->getTokenUrl( 'ConfirmEmail', $token );
-       }
-
-       /**
-        * Return a URL the user can use to invalidate their email address.
-        * @param string $token Accepts the email confirmation token
-        * @return string New token URL
-        */
-       protected function invalidationTokenUrl( $token ) {
-               return $this->getTokenUrl( 'InvalidateEmail', $token );
-       }
-
-       /**
-        * Internal function to format the e-mail validation/invalidation URLs.
-        * This uses a quickie hack to use the
-        * hardcoded English names of the Special: pages, for ASCII safety.
-        *
-        * @note Since these URLs get dropped directly into emails, using the
-        * short English names avoids insanely long URL-encoded links, which
-        * also sometimes can get corrupted in some browsers/mailers
-        * (bug 6957 with Gmail and Internet Explorer).
-        *
-        * @param string $page Special page
-        * @param string $token Token
-        * @return string Formatted URL
-        */
-       protected function getTokenUrl( $page, $token ) {
-               // Hack to bypass localization of 'Special:'
-               $title = Title::makeTitle( NS_MAIN, "Special:$page/$token" );
-               return $title->getCanonicalURL();
-       }
-
-       /**
-        * Mark the e-mail address confirmed.
-        *
-        * @note Call saveSettings() after calling this function to commit the change.
-        *
-        * @return bool
-        */
-       public function confirmEmail() {
-               // Check if it's already confirmed, so we don't touch the database
-               // and fire the ConfirmEmailComplete hook on redundant confirmations.
-               if ( !$this->isEmailConfirmed() ) {
-                       $this->setEmailAuthenticationTimestamp( wfTimestampNow() );
-                       Hooks::run( 'ConfirmEmailComplete', array( $this ) );
-               }
-               return true;
-       }
-
-       /**
-        * Invalidate the user's e-mail confirmation, and unauthenticate the e-mail
-        * address if it was already confirmed.
-        *
-        * @note Call saveSettings() after calling this function to commit the change.
-        * @return bool Returns true
-        */
-       public function invalidateEmail() {
-               $this->load();
-               $this->mEmailToken = null;
-               $this->mEmailTokenExpires = null;
-               $this->setEmailAuthenticationTimestamp( null );
-               $this->mEmail = '';
-               Hooks::run( 'InvalidateEmailComplete', array( $this ) );
-               return true;
-       }
-
-       /**
-        * Set the e-mail authentication timestamp.
-        * @param string $timestamp TS_MW timestamp
-        */
-       public function setEmailAuthenticationTimestamp( $timestamp ) {
-               $this->load();
-               $this->mEmailAuthenticated = $timestamp;
-               Hooks::run( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
-       }
-
-       /**
-        * Is this user allowed to send e-mails within limits of current
-        * site configuration?
-        * @return bool
-        */
-       public function canSendEmail() {
-               global $wgEnableEmail, $wgEnableUserEmail;
-               if ( !$wgEnableEmail || !$wgEnableUserEmail || !$this->isAllowed( 'sendemail' ) ) {
-                       return false;
-               }
-               $canSend = $this->isEmailConfirmed();
-               Hooks::run( 'UserCanSendEmail', array( &$this, &$canSend ) );
-               return $canSend;
-       }
-
-       /**
-        * Is this user allowed to receive e-mails within limits of current
-        * site configuration?
-        * @return bool
-        */
-       public function canReceiveEmail() {
-               return $this->isEmailConfirmed() && !$this->getOption( 'disablemail' );
-       }
-
-       /**
-        * Is this user's e-mail address valid-looking and confirmed within
-        * limits of the current site configuration?
-        *
-        * @note If $wgEmailAuthentication is on, this may require the user to have
-        * confirmed their address by returning a code or using a password
-        * sent to the address from the wiki.
-        *
-        * @return bool
-        */
-       public function isEmailConfirmed() {
-               global $wgEmailAuthentication;
-               $this->load();
-               $confirmed = true;
-               if ( Hooks::run( 'EmailConfirmed', array( &$this, &$confirmed ) ) ) {
-                       if ( $this->isAnon() ) {
-                               return false;
-                       }
-                       if ( !Sanitizer::validateEmail( $this->mEmail ) ) {
-                               return false;
-                       }
-                       if ( $wgEmailAuthentication && !$this->getEmailAuthenticationTimestamp() ) {
-                               return false;
-                       }
-                       return true;
-               } else {
-                       return $confirmed;
-               }
-       }
-
-       /**
-        * Check whether there is an outstanding request for e-mail confirmation.
-        * @return bool
-        */
-       public function isEmailConfirmationPending() {
-               global $wgEmailAuthentication;
-               return $wgEmailAuthentication &&
-                       !$this->isEmailConfirmed() &&
-                       $this->mEmailToken &&
-                       $this->mEmailTokenExpires > wfTimestamp();
-       }
-
-       /**
-        * Get the timestamp of account creation.
-        *
-        * @return string|bool|null Timestamp of account creation, false for
-        *  non-existent/anonymous user accounts, or null if existing account
-        *  but information is not in database.
-        */
-       public function getRegistration() {
-               if ( $this->isAnon() ) {
-                       return false;
-               }
-               $this->load();
-               return $this->mRegistration;
-       }
-
-       /**
-        * Get the timestamp of the first edit
-        *
-        * @return string|bool Timestamp of first edit, or false for
-        *  non-existent/anonymous user accounts.
-        */
-       public function getFirstEditTimestamp() {
-               if ( $this->getId() == 0 ) {
-                       return false; // anons
-               }
-               $dbr = wfGetDB( DB_SLAVE );
-               $time = $dbr->selectField( 'revision', 'rev_timestamp',
-                       array( 'rev_user' => $this->getId() ),
-                       __METHOD__,
-                       array( 'ORDER BY' => 'rev_timestamp ASC' )
-               );
-               if ( !$time ) {
-                       return false; // no edits
-               }
-               return wfTimestamp( TS_MW, $time );
-       }
-
-       /**
-        * Get the permissions associated with a given list of groups
-        *
-        * @param array $groups Array of Strings List of internal group names
-        * @return array Array of Strings List of permission key names for given groups combined
-        */
-       public static function getGroupPermissions( $groups ) {
-               global $wgGroupPermissions, $wgRevokePermissions;
-               $rights = array();
-               // grant every granted permission first
-               foreach ( $groups as $group ) {
-                       if ( isset( $wgGroupPermissions[$group] ) ) {
-                               $rights = array_merge( $rights,
-                                       // array_filter removes empty items
-                                       array_keys( array_filter( $wgGroupPermissions[$group] ) ) );
-                       }
-               }
-               // now revoke the revoked permissions
-               foreach ( $groups as $group ) {
-                       if ( isset( $wgRevokePermissions[$group] ) ) {
-                               $rights = array_diff( $rights,
-                                       array_keys( array_filter( $wgRevokePermissions[$group] ) ) );
-                       }
-               }
-               return array_unique( $rights );
-       }
-
-       /**
-        * Get all the groups who have a given permission
-        *
-        * @param string $role Role to check
-        * @return array Array of Strings List of internal group names with the given permission
-        */
-       public static function getGroupsWithPermission( $role ) {
-               global $wgGroupPermissions;
-               $allowedGroups = array();
-               foreach ( array_keys( $wgGroupPermissions ) as $group ) {
-                       if ( self::groupHasPermission( $group, $role ) ) {
-                               $allowedGroups[] = $group;
-                       }
-               }
-               return $allowedGroups;
-       }
-
-       /**
-        * Check, if the given group has the given permission
-        *
-        * If you're wanting to check whether all users have a permission, use
-        * User::isEveryoneAllowed() instead. That properly checks if it's revoked
-        * from anyone.
-        *
-        * @since 1.21
-        * @param string $group Group to check
-        * @param string $role Role to check
-        * @return bool
-        */
-       public static function groupHasPermission( $group, $role ) {
-               global $wgGroupPermissions, $wgRevokePermissions;
-               return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
-                       && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
-       }
-
-       /**
-        * Check if all users have the given permission
-        *
-        * @since 1.22
-        * @param string $right Right to check
-        * @return bool
-        */
-       public static function isEveryoneAllowed( $right ) {
-               global $wgGroupPermissions, $wgRevokePermissions;
-               static $cache = array();
-
-               // Use the cached results, except in unit tests which rely on
-               // being able change the permission mid-request
-               if ( isset( $cache[$right] ) && !defined( 'MW_PHPUNIT_TEST' ) ) {
-                       return $cache[$right];
-               }
-
-               if ( !isset( $wgGroupPermissions['*'][$right] ) || !$wgGroupPermissions['*'][$right] ) {
-                       $cache[$right] = false;
-                       return false;
-               }
-
-               // If it's revoked anywhere, then everyone doesn't have it
-               foreach ( $wgRevokePermissions as $rights ) {
-                       if ( isset( $rights[$right] ) && $rights[$right] ) {
-                               $cache[$right] = false;
-                               return false;
-                       }
-               }
-
-               // Allow extensions (e.g. OAuth) to say false
-               if ( !Hooks::run( 'UserIsEveryoneAllowed', array( $right ) ) ) {
-                       $cache[$right] = false;
-                       return false;
-               }
-
-               $cache[$right] = true;
-               return true;
-       }
-
-       /**
-        * Get the localized descriptive name for a group, if it exists
-        *
-        * @param string $group Internal group name
-        * @return string Localized descriptive group name
-        */
-       public static function getGroupName( $group ) {
-               $msg = wfMessage( "group-$group" );
-               return $msg->isBlank() ? $group : $msg->text();
-       }
-
-       /**
-        * Get the localized descriptive name for a member of a group, if it exists
-        *
-        * @param string $group Internal group name
-        * @param string $username Username for gender (since 1.19)
-        * @return string Localized name for group member
-        */
-       public static function getGroupMember( $group, $username = '#' ) {
-               $msg = wfMessage( "group-$group-member", $username );
-               return $msg->isBlank() ? $group : $msg->text();
-       }
-
-       /**
-        * Return the set of defined explicit groups.
-        * The implicit groups (by default *, 'user' and 'autoconfirmed')
-        * are not included, as they are defined automatically, not in the database.
-        * @return array Array of internal group names
-        */
-       public static function getAllGroups() {
-               global $wgGroupPermissions, $wgRevokePermissions;
-               return array_diff(
-                       array_merge( array_keys( $wgGroupPermissions ), array_keys( $wgRevokePermissions ) ),
-                       self::getImplicitGroups()
-               );
-       }
-
-       /**
-        * Get a list of all available permissions.
-        * @return string[] Array of permission names
-        */
-       public static function getAllRights() {
-               if ( self::$mAllRights === false ) {
-                       global $wgAvailableRights;
-                       if ( count( $wgAvailableRights ) ) {
-                               self::$mAllRights = array_unique( array_merge( self::$mCoreRights, $wgAvailableRights ) );
-                       } else {
-                               self::$mAllRights = self::$mCoreRights;
-                       }
-                       Hooks::run( 'UserGetAllRights', array( &self::$mAllRights ) );
-               }
-               return self::$mAllRights;
-       }
-
-       /**
-        * Get a list of implicit groups
-        * @return array Array of Strings Array of internal group names
-        */
-       public static function getImplicitGroups() {
-               global $wgImplicitGroups;
-
-               $groups = $wgImplicitGroups;
-               # Deprecated, use $wgImplicitGroups instead
-               Hooks::run( 'UserGetImplicitGroups', array( &$groups ), '1.25' );
-
-               return $groups;
-       }
-
-       /**
-        * Get the title of a page describing a particular group
-        *
-        * @param string $group Internal group name
-        * @return Title|bool Title of the page if it exists, false otherwise
-        */
-       public static function getGroupPage( $group ) {
-               $msg = wfMessage( 'grouppage-' . $group )->inContentLanguage();
-               if ( $msg->exists() ) {
-                       $title = Title::newFromText( $msg->text() );
-                       if ( is_object( $title ) ) {
-                               return $title;
-                       }
-               }
-               return false;
-       }
-
-       /**
-        * Create a link to the group in HTML, if available;
-        * else return the group name.
-        *
-        * @param string $group Internal name of the group
-        * @param string $text The text of the link
-        * @return string HTML link to the group
-        */
-       public static function makeGroupLinkHTML( $group, $text = '' ) {
-               if ( $text == '' ) {
-                       $text = self::getGroupName( $group );
-               }
-               $title = self::getGroupPage( $group );
-               if ( $title ) {
-                       return Linker::link( $title, htmlspecialchars( $text ) );
-               } else {
-                       return htmlspecialchars( $text );
-               }
-       }
-
-       /**
-        * Create a link to the group in Wikitext, if available;
-        * else return the group name.
-        *
-        * @param string $group Internal name of the group
-        * @param string $text The text of the link
-        * @return string Wikilink to the group
-        */
-       public static function makeGroupLinkWiki( $group, $text = '' ) {
-               if ( $text == '' ) {
-                       $text = self::getGroupName( $group );
-               }
-               $title = self::getGroupPage( $group );
-               if ( $title ) {
-                       $page = $title->getFullText();
-                       return "[[$page|$text]]";
-               } else {
-                       return $text;
-               }
-       }
-
-       /**
-        * Returns an array of the groups that a particular group can add/remove.
-        *
-        * @param string $group The group to check for whether it can add/remove
-        * @return array Array( 'add' => array( addablegroups ),
-        *     'remove' => array( removablegroups ),
-        *     'add-self' => array( addablegroups to self),
-        *     'remove-self' => array( removable groups from self) )
-        */
-       public static function changeableByGroup( $group ) {
-               global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
-
-               $groups = array(
-                       'add' => array(),
-                       'remove' => array(),
-                       'add-self' => array(),
-                       'remove-self' => array()
-               );
-
-               if ( empty( $wgAddGroups[$group] ) ) {
-                       // Don't add anything to $groups
-               } elseif ( $wgAddGroups[$group] === true ) {
-                       // You get everything
-                       $groups['add'] = self::getAllGroups();
-               } elseif ( is_array( $wgAddGroups[$group] ) ) {
-                       $groups['add'] = $wgAddGroups[$group];
-               }
-
-               // Same thing for remove
-               if ( empty( $wgRemoveGroups[$group] ) ) {
-                       // Do nothing
-               } elseif ( $wgRemoveGroups[$group] === true ) {
-                       $groups['remove'] = self::getAllGroups();
-               } elseif ( is_array( $wgRemoveGroups[$group] ) ) {
-                       $groups['remove'] = $wgRemoveGroups[$group];
-               }
-
-               // Re-map numeric keys of AddToSelf/RemoveFromSelf to the 'user' key for backwards compatibility
-               if ( empty( $wgGroupsAddToSelf['user'] ) || $wgGroupsAddToSelf['user'] !== true ) {
-                       foreach ( $wgGroupsAddToSelf as $key => $value ) {
-                               if ( is_int( $key ) ) {
-                                       $wgGroupsAddToSelf['user'][] = $value;
-                               }
-                       }
-               }
-
-               if ( empty( $wgGroupsRemoveFromSelf['user'] ) || $wgGroupsRemoveFromSelf['user'] !== true ) {
-                       foreach ( $wgGroupsRemoveFromSelf as $key => $value ) {
-                               if ( is_int( $key ) ) {
-                                       $wgGroupsRemoveFromSelf['user'][] = $value;
-                               }
-                       }
-               }
-
-               // Now figure out what groups the user can add to him/herself
-               if ( empty( $wgGroupsAddToSelf[$group] ) ) {
-                       // Do nothing
-               } elseif ( $wgGroupsAddToSelf[$group] === true ) {
-                       // No idea WHY this would be used, but it's there
-                       $groups['add-self'] = User::getAllGroups();
-               } elseif ( is_array( $wgGroupsAddToSelf[$group] ) ) {
-                       $groups['add-self'] = $wgGroupsAddToSelf[$group];
-               }
-
-               if ( empty( $wgGroupsRemoveFromSelf[$group] ) ) {
-                       // Do nothing
-               } elseif ( $wgGroupsRemoveFromSelf[$group] === true ) {
-                       $groups['remove-self'] = User::getAllGroups();
-               } elseif ( is_array( $wgGroupsRemoveFromSelf[$group] ) ) {
-                       $groups['remove-self'] = $wgGroupsRemoveFromSelf[$group];
-               }
-
-               return $groups;
-       }
-
-       /**
-        * Returns an array of groups that this user can add and remove
-        * @return array Array( 'add' => array( addablegroups ),
-        *  'remove' => array( removablegroups ),
-        *  'add-self' => array( addablegroups to self),
-        *  'remove-self' => array( removable groups from self) )
-        */
-       public function changeableGroups() {
-               if ( $this->isAllowed( 'userrights' ) ) {
-                       // This group gives the right to modify everything (reverse-
-                       // compatibility with old "userrights lets you change
-                       // everything")
-                       // Using array_merge to make the groups reindexed
-                       $all = array_merge( User::getAllGroups() );
-                       return array(
-                               'add' => $all,
-                               'remove' => $all,
-                               'add-self' => array(),
-                               'remove-self' => array()
-                       );
-               }
-
-               // Okay, it's not so simple, we will have to go through the arrays
-               $groups = array(
-                       'add' => array(),
-                       'remove' => array(),
-                       'add-self' => array(),
-                       'remove-self' => array()
-               );
-               $addergroups = $this->getEffectiveGroups();
-
-               foreach ( $addergroups as $addergroup ) {
-                       $groups = array_merge_recursive(
-                               $groups, $this->changeableByGroup( $addergroup )
-                       );
-                       $groups['add'] = array_unique( $groups['add'] );
-                       $groups['remove'] = array_unique( $groups['remove'] );
-                       $groups['add-self'] = array_unique( $groups['add-self'] );
-                       $groups['remove-self'] = array_unique( $groups['remove-self'] );
-               }
-               return $groups;
-       }
-
-       /**
-        * Deferred version of incEditCountImmediate()
-        */
-       public function incEditCount() {
-               $that = $this;
-               wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $that ) {
-                       $that->incEditCountImmediate();
-               } );
-       }
-
-       /**
-        * Increment the user's edit-count field.
-        * Will have no effect for anonymous users.
-        * @since 1.26
-        */
-       public function incEditCountImmediate() {
-               if ( $this->isAnon() ) {
-                       return;
-               }
-
-               $dbw = wfGetDB( DB_MASTER );
-               // No rows will be "affected" if user_editcount is NULL
-               $dbw->update(
-                       'user',
-                       array( 'user_editcount=user_editcount+1' ),
-                       array( 'user_id' => $this->getId(), 'user_editcount IS NOT NULL' ),
-                       __METHOD__
-               );
-               // Lazy initialization check...
-               if ( $dbw->affectedRows() == 0 ) {
-                       // Now here's a goddamn hack...
-                       $dbr = wfGetDB( DB_SLAVE );
-                       if ( $dbr !== $dbw ) {
-                               // If we actually have a slave server, the count is
-                               // at least one behind because the current transaction
-                               // has not been committed and replicated.
-                               $this->initEditCount( 1 );
-                       } else {
-                               // But if DB_SLAVE is selecting the master, then the
-                               // count we just read includes the revision that was
-                               // just added in the working transaction.
-                               $this->initEditCount();
-                       }
-               }
-               // Edit count in user cache too
-               $this->invalidateCache();
-       }
-
-       /**
-        * Initialize user_editcount from data out of the revision table
-        *
-        * @param int $add Edits to add to the count from the revision table
-        * @return int Number of edits
-        */
-       protected function initEditCount( $add = 0 ) {
-               // Pull from a slave to be less cruel to servers
-               // Accuracy isn't the point anyway here
-               $dbr = wfGetDB( DB_SLAVE );
-               $count = (int)$dbr->selectField(
-                       'revision',
-                       'COUNT(rev_user)',
-                       array( 'rev_user' => $this->getId() ),
-                       __METHOD__
-               );
-               $count = $count + $add;
-
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->update(
-                       'user',
-                       array( 'user_editcount' => $count ),
-                       array( 'user_id' => $this->getId() ),
-                       __METHOD__
-               );
-
-               return $count;
-       }
-
-       /**
-        * Get the description of a given right
-        *
-        * @param string $right Right to query
-        * @return string Localized description of the right
-        */
-       public static function getRightDescription( $right ) {
-               $key = "right-$right";
-               $msg = wfMessage( $key );
-               return $msg->isBlank() ? $right : $msg->text();
-       }
-
-       /**
-        * Make a new-style password hash
-        *
-        * @param string $password Plain-text password
-        * @param bool|string $salt Optional salt, may be random or the user ID.
-        *  If unspecified or false, will generate one automatically
-        * @return string Password hash
-        * @deprecated since 1.24, use Password class
-        */
-       public static function crypt( $password, $salt = false ) {
-               wfDeprecated( __METHOD__, '1.24' );
-               $passwordFactory = new PasswordFactory();
-               $passwordFactory->init( RequestContext::getMain()->getConfig() );
-               $hash = $passwordFactory->newFromPlaintext( $password );
-               return $hash->toString();
-       }
-
-       /**
-        * Compare a password hash with a plain-text password. Requires the user
-        * ID if there's a chance that the hash is an old-style hash.
-        *
-        * @param string $hash Password hash
-        * @param string $password Plain-text password to compare
-        * @param string|bool $userId User ID for old-style password salt
-        *
-        * @return bool
-        * @deprecated since 1.24, use Password class
-        */
-       public static function comparePasswords( $hash, $password, $userId = false ) {
-               wfDeprecated( __METHOD__, '1.24' );
-
-               // Check for *really* old password hashes that don't even have a type
-               // The old hash format was just an md5 hex hash, with no type information
-               if ( preg_match( '/^[0-9a-f]{32}$/', $hash ) ) {
-                       global $wgPasswordSalt;
-                       if ( $wgPasswordSalt ) {
-                               $password = ":B:{$userId}:{$hash}";
-                       } else {
-                               $password = ":A:{$hash}";
-                       }
-               }
-
-               $passwordFactory = new PasswordFactory();
-               $passwordFactory->init( RequestContext::getMain()->getConfig() );
-               $hash = $passwordFactory->newFromCiphertext( $hash );
-               return $hash->equals( $password );
-       }
-
-       /**
-        * Add a newuser log entry for this user.
-        * Before 1.19 the return value was always true.
-        *
-        * @param string|bool $action Account creation type.
-        *   - String, one of the following values:
-        *     - 'create' for an anonymous user creating an account for himself.
-        *       This will force the action's performer to be the created user itself,
-        *       no matter the value of $wgUser
-        *     - 'create2' for a logged in user creating an account for someone else
-        *     - 'byemail' when the created user will receive its password by e-mail
-        *     - 'autocreate' when the user is automatically created (such as by CentralAuth).
-        *   - Boolean means whether the account was created by e-mail (deprecated):
-        *     - true will be converted to 'byemail'
-        *     - false will be converted to 'create' if this object is the same as
-        *       $wgUser and to 'create2' otherwise
-        *
-        * @param string $reason User supplied reason
-        *
-        * @return int|bool True if not $wgNewUserLog; otherwise ID of log item or 0 on failure
-        */
-       public function addNewUserLogEntry( $action = false, $reason = '' ) {
-               global $wgUser, $wgNewUserLog;
-               if ( empty( $wgNewUserLog ) ) {
-                       return true; // disabled
-               }
-
-               if ( $action === true ) {
-                       $action = 'byemail';
-               } elseif ( $action === false ) {
-                       if ( $this->equals( $wgUser ) ) {
-                               $action = 'create';
-                       } else {
-                               $action = 'create2';
-                       }
-               }
-
-               if ( $action === 'create' || $action === 'autocreate' ) {
-                       $performer = $this;
-               } else {
-                       $performer = $wgUser;
-               }
-
-               $logEntry = new ManualLogEntry( 'newusers', $action );
-               $logEntry->setPerformer( $performer );
-               $logEntry->setTarget( $this->getUserPage() );
-               $logEntry->setComment( $reason );
-               $logEntry->setParameters( array(
-                       '4::userid' => $this->getId(),
-               ) );
-               $logid = $logEntry->insert();
-
-               if ( $action !== 'autocreate' ) {
-                       $logEntry->publish( $logid );
-               }
-
-               return (int)$logid;
-       }
-
-       /**
-        * Add an autocreate newuser log entry for this user
-        * Used by things like CentralAuth and perhaps other authplugins.
-        * Consider calling addNewUserLogEntry() directly instead.
-        *
-        * @return bool
-        */
-       public function addNewUserLogEntryAutoCreate() {
-               $this->addNewUserLogEntry( 'autocreate' );
-
-               return true;
-       }
-
-       /**
-        * Load the user options either from cache, the database or an array
-        *
-        * @param array $data Rows for the current user out of the user_properties table
-        */
-       protected function loadOptions( $data = null ) {
-               global $wgContLang;
-
-               $this->load();
-
-               if ( $this->mOptionsLoaded ) {
-                       return;
-               }
-
-               $this->mOptions = self::getDefaultOptions();
-
-               if ( !$this->getId() ) {
-                       // For unlogged-in users, load language/variant options from request.
-                       // There's no need to do it for logged-in users: they can set preferences,
-                       // and handling of page content is done by $pageLang->getPreferredVariant() and such,
-                       // so don't override user's choice (especially when the user chooses site default).
-                       $variant = $wgContLang->getDefaultVariant();
-                       $this->mOptions['variant'] = $variant;
-                       $this->mOptions['language'] = $variant;
-                       $this->mOptionsLoaded = true;
-                       return;
-               }
-
-               // Maybe load from the object
-               if ( !is_null( $this->mOptionOverrides ) ) {
-                       wfDebug( "User: loading options for user " . $this->getId() . " from override cache.\n" );
-                       foreach ( $this->mOptionOverrides as $key => $value ) {
-                               $this->mOptions[$key] = $value;
-                       }
-               } else {
-                       if ( !is_array( $data ) ) {
-                               wfDebug( "User: loading options for user " . $this->getId() . " from database.\n" );
-                               // Load from database
-                               $dbr = ( $this->queryFlagsUsed & self::READ_LATEST )
-                                       ? wfGetDB( DB_MASTER )
-                                       : wfGetDB( DB_SLAVE );
-
-                               $res = $dbr->select(
-                                       'user_properties',
-                                       array( 'up_property', 'up_value' ),
-                                       array( 'up_user' => $this->getId() ),
-                                       __METHOD__
-                               );
-
-                               $this->mOptionOverrides = array();
-                               $data = array();
-                               foreach ( $res as $row ) {
-                                       $data[$row->up_property] = $row->up_value;
-                               }
-                       }
-                       foreach ( $data as $property => $value ) {
-                               $this->mOptionOverrides[$property] = $value;
-                               $this->mOptions[$property] = $value;
-                       }
-               }
-
-               $this->mOptionsLoaded = true;
-
-               Hooks::run( 'UserLoadOptions', array( $this, &$this->mOptions ) );
-       }
-
-       /**
-        * Saves the non-default options for this user, as previously set e.g. via
-        * setOption(), in the database's "user_properties" (preferences) table.
-        * Usually used via saveSettings().
-        */
-       protected function saveOptions() {
-               $this->loadOptions();
-
-               // Not using getOptions(), to keep hidden preferences in database
-               $saveOptions = $this->mOptions;
-
-               // Allow hooks to abort, for instance to save to a global profile.
-               // Reset options to default state before saving.
-               if ( !Hooks::run( 'UserSaveOptions', array( $this, &$saveOptions ) ) ) {
-                       return;
-               }
-
-               $userId = $this->getId();
-
-               $insert_rows = array(); // all the new preference rows
-               foreach ( $saveOptions as $key => $value ) {
-                       // Don't bother storing default values
-                       $defaultOption = self::getDefaultOption( $key );
-                       if ( ( $defaultOption === null && $value !== false && $value !== null )
-                               || $value != $defaultOption
-                       ) {
-                               $insert_rows[] = array(
-                                       'up_user' => $userId,
-                                       'up_property' => $key,
-                                       'up_value' => $value,
-                               );
-                       }
-               }
-
-               $dbw = wfGetDB( DB_MASTER );
-
-               $res = $dbw->select( 'user_properties',
-                       array( 'up_property', 'up_value' ), array( 'up_user' => $userId ), __METHOD__ );
-
-               // Find prior rows that need to be removed or updated. These rows will
-               // all be deleted (the later so that INSERT IGNORE applies the new values).
-               $keysDelete = array();
-               foreach ( $res as $row ) {
-                       if ( !isset( $saveOptions[$row->up_property] )
-                               || strcmp( $saveOptions[$row->up_property], $row->up_value ) != 0
-                       ) {
-                               $keysDelete[] = $row->up_property;
-                       }
-               }
-
-               if ( count( $keysDelete ) ) {
-                       // Do the DELETE by PRIMARY KEY for prior rows.
-                       // In the past a very large portion of calls to this function are for setting
-                       // 'rememberpassword' for new accounts (a preference that has since been removed).
-                       // Doing a blanket per-user DELETE for new accounts with no rows in the table
-                       // caused gap locks on [max user ID,+infinity) which caused high contention since
-                       // updates would pile up on each other as they are for higher (newer) user IDs.
-                       // It might not be necessary these days, but it shouldn't hurt either.
-                       $dbw->delete( 'user_properties',
-                               array( 'up_user' => $userId, 'up_property' => $keysDelete ), __METHOD__ );
-               }
-               // Insert the new preference rows
-               $dbw->insert( 'user_properties', $insert_rows, __METHOD__, array( 'IGNORE' ) );
-       }
-
-       /**
-        * Lazily instantiate and return a factory object for making passwords
-        *
-        * @deprecated since 1.27, create a PasswordFactory directly instead
-        * @return PasswordFactory
-        */
-       public static function getPasswordFactory() {
-               wfDeprecated( __METHOD__, '1.27' );
-               $ret = new PasswordFactory();
-               $ret->init( RequestContext::getMain()->getConfig() );
-               return $ret;
-       }
-
-       /**
-        * Provide an array of HTML5 attributes to put on an input element
-        * intended for the user to enter a new password.  This may include
-        * required, title, and/or pattern, depending on $wgMinimalPasswordLength.
-        *
-        * Do *not* use this when asking the user to enter his current password!
-        * Regardless of configuration, users may have invalid passwords for whatever
-        * reason (e.g., they were set before requirements were tightened up).
-        * Only use it when asking for a new password, like on account creation or
-        * ResetPass.
-        *
-        * Obviously, you still need to do server-side checking.
-        *
-        * NOTE: A combination of bugs in various browsers means that this function
-        * actually just returns array() unconditionally at the moment.  May as
-        * well keep it around for when the browser bugs get fixed, though.
-        *
-        * @todo FIXME: This does not belong here; put it in Html or Linker or somewhere
-        *
-        * @deprecated since 1.27
-        * @return array Array of HTML attributes suitable for feeding to
-        *   Html::element(), directly or indirectly.  (Don't feed to Xml::*()!
-        *   That will get confused by the boolean attribute syntax used.)
-        */
-       public static function passwordChangeInputAttribs() {
-               global $wgMinimalPasswordLength;
-
-               if ( $wgMinimalPasswordLength == 0 ) {
-                       return array();
-               }
-
-               # Note that the pattern requirement will always be satisfied if the
-               # input is empty, so we need required in all cases.
-
-               # @todo FIXME: Bug 23769: This needs to not claim the password is required
-               # if e-mail confirmation is being used.  Since HTML5 input validation
-               # is b0rked anyway in some browsers, just return nothing.  When it's
-               # re-enabled, fix this code to not output required for e-mail
-               # registration.
-               # $ret = array( 'required' );
-               $ret = array();
-
-               # We can't actually do this right now, because Opera 9.6 will print out
-               # the entered password visibly in its error message!  When other
-               # browsers add support for this attribute, or Opera fixes its support,
-               # we can add support with a version check to avoid doing this on Opera
-               # versions where it will be a problem.  Reported to Opera as
-               # DSK-262266, but they don't have a public bug tracker for us to follow.
-               /*
-               if ( $wgMinimalPasswordLength > 1 ) {
-                       $ret['pattern'] = '.{' . intval( $wgMinimalPasswordLength ) . ',}';
-                       $ret['title'] = wfMessage( 'passwordtooshort' )
-                               ->numParams( $wgMinimalPasswordLength )->text();
-               }
-               */
-
-               return $ret;
-       }
-
-       /**
-        * Return the list of user fields that should be selected to create
-        * a new user object.
-        * @return array
-        */
-       public static function selectFields() {
-               return array(
-                       'user_id',
-                       'user_name',
-                       'user_real_name',
-                       'user_email',
-                       'user_touched',
-                       'user_token',
-                       'user_email_authenticated',
-                       'user_email_token',
-                       'user_email_token_expires',
-                       'user_registration',
-                       'user_editcount',
-               );
-       }
-
-       /**
-        * Factory function for fatal permission-denied errors
-        *
-        * @since 1.22
-        * @param string $permission User right required
-        * @return Status
-        */
-       static function newFatalPermissionDeniedStatus( $permission ) {
-               global $wgLang;
-
-               $groups = array_map(
-                       array( 'User', 'makeGroupLinkWiki' ),
-                       User::getGroupsWithPermission( $permission )
-               );
-
-               if ( $groups ) {
-                       return Status::newFatal( 'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );
-               } else {
-                       return Status::newFatal( 'badaccess-group0' );
-               }
-       }
-
-       /**
-        * Checks if two user objects point to the same user.
-        *
-        * @since 1.25
-        * @param User $user
-        * @return bool
-        */
-       public function equals( User $user ) {
-               return $this->getName() === $user->getName();
-       }
-}
diff --git a/includes/UserArray.php b/includes/UserArray.php
deleted file mode 100644 (file)
index 31bd601..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-/**
- * Class to walk into a list of User objects.
- *
- * 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
- */
-
-abstract class UserArray implements Iterator {
-       /**
-        * @param ResultWrapper $res
-        * @return UserArrayFromResult
-        */
-       static function newFromResult( $res ) {
-               $userArray = null;
-               if ( !Hooks::run( 'UserArrayFromResult', array( &$userArray, $res ) ) ) {
-                       return null;
-               }
-               if ( $userArray === null ) {
-                       $userArray = self::newFromResult_internal( $res );
-               }
-               return $userArray;
-       }
-
-       /**
-        * @param array $ids
-        * @return UserArrayFromResult
-        */
-       static function newFromIDs( $ids ) {
-               $ids = array_map( 'intval', (array)$ids ); // paranoia
-               if ( !$ids ) {
-                       // Database::select() doesn't like empty arrays
-                       return new ArrayIterator( array() );
-               }
-               $dbr = wfGetDB( DB_SLAVE );
-               $res = $dbr->select(
-                       'user',
-                       User::selectFields(),
-                       array( 'user_id' => array_unique( $ids ) ),
-                       __METHOD__
-               );
-               return self::newFromResult( $res );
-       }
-
-       /**
-        * @since 1.25
-        * @param array $names
-        * @return UserArrayFromResult
-        */
-       static function newFromNames( $names ) {
-               $names = array_map( 'strval', (array)$names ); // paranoia
-               if ( !$names ) {
-                       // Database::select() doesn't like empty arrays
-                       return new ArrayIterator( array() );
-               }
-               $dbr = wfGetDB( DB_SLAVE );
-               $res = $dbr->select(
-                       'user',
-                       User::selectFields(),
-                       array( 'user_name' => array_unique( $names ) ),
-                       __METHOD__
-               );
-               return self::newFromResult( $res );
-       }
-
-       /**
-        * @param ResultWrapper $res
-        * @return UserArrayFromResult
-        */
-       protected static function newFromResult_internal( $res ) {
-               return new UserArrayFromResult( $res );
-       }
-}
diff --git a/includes/UserArrayFromResult.php b/includes/UserArrayFromResult.php
deleted file mode 100644 (file)
index fb533d0..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<?php
-/**
- * Class to walk into a list of User objects.
- *
- * 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 UserArrayFromResult extends UserArray implements Countable {
-       /** @var ResultWrapper */
-       public $res;
-
-       /** @var int */
-       public $key;
-
-       /** @var bool|stdClass */
-       public $current;
-
-       /**
-        * @param ResultWrapper $res
-        */
-       function __construct( $res ) {
-               $this->res = $res;
-               $this->key = 0;
-               $this->setCurrent( $this->res->current() );
-       }
-
-       /**
-        * @param bool|stdClass $row
-        * @return void
-        */
-       protected function setCurrent( $row ) {
-               if ( $row === false ) {
-                       $this->current = false;
-               } else {
-                       $this->current = User::newFromRow( $row );
-               }
-       }
-
-       /**
-        * @return int
-        */
-       public function count() {
-               return $this->res->numRows();
-       }
-
-       /**
-        * @return User
-        */
-       function current() {
-               return $this->current;
-       }
-
-       function key() {
-               return $this->key;
-       }
-
-       function next() {
-               $row = $this->res->next();
-               $this->setCurrent( $row );
-               $this->key++;
-       }
-
-       function rewind() {
-               $this->res->rewind();
-               $this->key = 0;
-               $this->setCurrent( $this->res->current() );
-       }
-
-       /**
-        * @return bool
-        */
-       function valid() {
-               return $this->current !== false;
-       }
-}
diff --git a/includes/UserRightsProxy.php b/includes/UserRightsProxy.php
deleted file mode 100644 (file)
index e686ae3..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-<?php
-/**
- * Representation of an user on a other locally-hosted wiki.
- *
- * 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
- */
-
-/**
- * Cut-down copy of User interface for local-interwiki-database
- * user rights manipulation.
- */
-class UserRightsProxy {
-
-       /**
-        * Constructor.
-        *
-        * @see newFromId()
-        * @see newFromName()
-        * @param IDatabase $db Db connection
-        * @param string $database Database name
-        * @param string $name User name
-        * @param int $id User ID
-        */
-       private function __construct( $db, $database, $name, $id ) {
-               $this->db = $db;
-               $this->database = $database;
-               $this->name = $name;
-               $this->id = intval( $id );
-               $this->newOptions = array();
-       }
-
-       /**
-        * Accessor for $this->database
-        *
-        * @return string Database name
-        */
-       public function getDBName() {
-               return $this->database;
-       }
-
-       /**
-        * Confirm the selected database name is a valid local interwiki database name.
-        *
-        * @param string $database Database name
-        * @return bool
-        */
-       public static function validDatabase( $database ) {
-               global $wgLocalDatabases;
-               return in_array( $database, $wgLocalDatabases );
-       }
-
-       /**
-        * Same as User::whoIs()
-        *
-        * @param string $database Database name
-        * @param int $id User ID
-        * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
-        * @return string User name or false if the user doesn't exist
-        */
-       public static function whoIs( $database, $id, $ignoreInvalidDB = false ) {
-               $user = self::newFromId( $database, $id, $ignoreInvalidDB );
-               if ( $user ) {
-                       return $user->name;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * Factory function; get a remote user entry by ID number.
-        *
-        * @param string $database Database name
-        * @param int $id User ID
-        * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
-        * @return UserRightsProxy|null If doesn't exist
-        */
-       public static function newFromId( $database, $id, $ignoreInvalidDB = false ) {
-               return self::newFromLookup( $database, 'user_id', intval( $id ), $ignoreInvalidDB );
-       }
-
-       /**
-        * Factory function; get a remote user entry by name.
-        *
-        * @param string $database Database name
-        * @param string $name User name
-        * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
-        * @return UserRightsProxy|null If doesn't exist
-        */
-       public static function newFromName( $database, $name, $ignoreInvalidDB = false ) {
-               return self::newFromLookup( $database, 'user_name', $name, $ignoreInvalidDB );
-       }
-
-       /**
-        * @param string $database
-        * @param string $field
-        * @param string $value
-        * @param bool $ignoreInvalidDB
-        * @return null|UserRightsProxy
-        */
-       private static function newFromLookup( $database, $field, $value, $ignoreInvalidDB = false ) {
-               global $wgSharedDB, $wgSharedTables;
-               // If the user table is shared, perform the user query on it,
-               // but don't pass it to the UserRightsProxy,
-               // as user rights are normally not shared.
-               if ( $wgSharedDB && in_array( 'user', $wgSharedTables ) ) {
-                       $userdb = self::getDB( $wgSharedDB, $ignoreInvalidDB );
-               } else {
-                       $userdb = self::getDB( $database, $ignoreInvalidDB );
-               }
-
-               $db = self::getDB( $database, $ignoreInvalidDB );
-
-               if ( $db && $userdb ) {
-                       $row = $userdb->selectRow( 'user',
-                               array( 'user_id', 'user_name' ),
-                               array( $field => $value ),
-                               __METHOD__ );
-
-                       if ( $row !== false ) {
-                               return new UserRightsProxy( $db, $database,
-                                       $row->user_name,
-                                       intval( $row->user_id ) );
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * Open a database connection to work on for the requested user.
-        * This may be a new connection to another database for remote users.
-        *
-        * @param string $database
-        * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
-        * @return IDatabase|null If invalid selection
-        */
-       public static function getDB( $database, $ignoreInvalidDB = false ) {
-               global $wgDBname;
-               if ( $ignoreInvalidDB || self::validDatabase( $database ) ) {
-                       if ( $database == $wgDBname ) {
-                               // Hmm... this shouldn't happen though. :)
-                               return wfGetDB( DB_MASTER );
-                       } else {
-                               return wfGetDB( DB_MASTER, array(), $database );
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * @return int
-        */
-       public function getId() {
-               return $this->id;
-       }
-
-       /**
-        * @return bool
-        */
-       public function isAnon() {
-               return $this->getId() == 0;
-       }
-
-       /**
-        * Same as User::getName()
-        *
-        * @return string
-        */
-       public function getName() {
-               return $this->name . '@' . $this->database;
-       }
-
-       /**
-        * Same as User::getUserPage()
-        *
-        * @return Title
-        */
-       public function getUserPage() {
-               return Title::makeTitle( NS_USER, $this->getName() );
-       }
-
-       /**
-        * Replaces User::getUserGroups()
-        * @return array
-        */
-       function getGroups() {
-               $res = $this->db->select( 'user_groups',
-                       array( 'ug_group' ),
-                       array( 'ug_user' => $this->id ),
-                       __METHOD__ );
-               $groups = array();
-               foreach ( $res as $row ) {
-                       $groups[] = $row->ug_group;
-               }
-               return $groups;
-       }
-
-       /**
-        * Replaces User::addUserGroup()
-        * @param string $group
-        *
-        * @return bool
-        */
-       function addGroup( $group ) {
-               $this->db->insert( 'user_groups',
-                       array(
-                               'ug_user' => $this->id,
-                               'ug_group' => $group,
-                       ),
-                       __METHOD__,
-                       array( 'IGNORE' ) );
-
-               return true;
-       }
-
-       /**
-        * Replaces User::removeUserGroup()
-        * @param string $group
-        *
-        * @return bool
-        */
-       function removeGroup( $group ) {
-               $this->db->delete( 'user_groups',
-                       array(
-                               'ug_user' => $this->id,
-                               'ug_group' => $group,
-                       ),
-                       __METHOD__ );
-
-               return true;
-       }
-
-       /**
-        * Replaces User::setOption()
-        * @param string $option
-        * @param mixed $value
-        */
-       public function setOption( $option, $value ) {
-               $this->newOptions[$option] = $value;
-       }
-
-       public function saveSettings() {
-               $rows = array();
-               foreach ( $this->newOptions as $option => $value ) {
-                       $rows[] = array(
-                               'up_user' => $this->id,
-                               'up_property' => $option,
-                               'up_value' => $value,
-                       );
-               }
-               $this->db->replace( 'user_properties',
-                       array( array( 'up_user', 'up_property' ) ),
-                       $rows, __METHOD__
-               );
-               $this->invalidateCache();
-       }
-
-       /**
-        * Replaces User::touchUser()
-        */
-       function invalidateCache() {
-               $this->db->update( 'user',
-                       array( 'user_touched' => $this->db->timestamp() ),
-                       array( 'user_id' => $this->id ),
-                       __METHOD__ );
-
-               $wikiId = $this->db->getWikiID();
-               $userId = $this->id;
-               $this->db->onTransactionPreCommitOrIdle( function() use ( $wikiId, $userId ) {
-                       User::purge( $wikiId, $userId );
-               } );
-       }
-}
index 8e5cdcc..8a98197 100644 (file)
@@ -97,7 +97,7 @@ abstract class ApiBase extends ContextSource {
        /** (integer) Lowest value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'. */
        const PARAM_MIN = 5;
 
-       /** (boolean) Allow the same value to be set more than once when PARAM_MULTI is true? */
+       /** (boolean) Allow the same value to be set more than once when PARAM_ISMULTI is true? */
        const PARAM_ALLOW_DUPLICATES = 6;
 
        /** (boolean) Is the parameter deprecated (will show a warning)? */
index 77a3a21..c841d83 100644 (file)
@@ -265,7 +265,9 @@ class ApiFeedWatchlist extends ApiBase {
                                if ( !isset( $p[ApiBase::PARAM_HELP_MSG] ) ) {
                                        $p[ApiBase::PARAM_HELP_MSG] = "apihelp-query+watchlist-param-$from";
                                }
-                               if ( is_array( $p[ApiBase::PARAM_TYPE] ) && isset( $p[ApiBase::PARAM_HELP_MSG_PER_VALUE] ) ) {
+                               if ( isset( $p[ApiBase::PARAM_TYPE] ) && is_array( $p[ApiBase::PARAM_TYPE] ) &&
+                                       isset( $p[ApiBase::PARAM_HELP_MSG_PER_VALUE] )
+                               ) {
                                        foreach ( $p[ApiBase::PARAM_TYPE] as $v ) {
                                                if ( !isset( $p[ApiBase::PARAM_HELP_MSG_PER_VALUE][$v] ) ) {
                                                        $p[ApiBase::PARAM_HELP_MSG_PER_VALUE][$v] = "apihelp-query+watchlist-paramvalue-$from-$v";
index ffcb2f5..9ea1b1e 100644 (file)
@@ -59,9 +59,10 @@ class ApiQueryAllUsers extends ApiQueryBase {
                        $fld_rights = isset( $prop['rights'] );
                        $fld_registration = isset( $prop['registration'] );
                        $fld_implicitgroups = isset( $prop['implicitgroups'] );
+                       $fld_centralids = isset( $prop['centralids'] );
                } else {
                        $fld_blockinfo = $fld_editcount = $fld_groups = $fld_registration =
-                               $fld_rights = $fld_implicitgroups = false;
+                               $fld_rights = $fld_implicitgroups = $fld_centralids = false;
                }
 
                $limit = $params['limit'];
@@ -239,6 +240,12 @@ class ApiQueryAllUsers extends ApiQueryBase {
                                'name' => $row->user_name,
                        );
 
+                       if ( $fld_centralids ) {
+                               $data += ApiQueryUserInfo::getCentralUserInfo(
+                                       $this->getConfig(), User::newFromId( $row->user_id ), $params['attachedwiki']
+                               );
+                       }
+
                        if ( $fld_blockinfo && !is_null( $row->ipb_by_text ) ) {
                                $data['blockid'] = (int)$row->ipb_id;
                                $data['blockedby'] = $row->ipb_by_text;
@@ -338,7 +345,8 @@ class ApiQueryAllUsers extends ApiQueryBase {
                                        'implicitgroups',
                                        'rights',
                                        'editcount',
-                                       'registration'
+                                       'registration',
+                                       'centralids',
                                ),
                                ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
                        ),
@@ -357,6 +365,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
                                        $this->getConfig()->get( 'ActiveUserDays' )
                                ),
                        ),
+                       'attachedwiki' => null,
                );
        }
 
index 7047339..1c031ff 100644 (file)
@@ -265,6 +265,10 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                        $data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
                }
 
+               $data['centralidlookupprovider'] = $this->getConfig()->get( 'CentralIdLookupProvider' );
+               $providerIds = array_keys( $this->getConfig()->get( 'CentralIdLookupProviders' ) );
+               $data['allcentralidlookupproviders'] = $providerIds;
+
                Hooks::run( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
 
                return $this->getResult()->addValue( 'query', $property, $data );
index 93c0dd0..27663a1 100644 (file)
@@ -33,6 +33,7 @@ class ApiQueryUserInfo extends ApiQueryBase {
 
        const WL_UNREAD_LIMIT = 1000;
 
+       private $params = array();
        private $prop = array();
 
        public function __construct( ApiQuery $query, $moduleName ) {
@@ -40,11 +41,11 @@ class ApiQueryUserInfo extends ApiQueryBase {
        }
 
        public function execute() {
-               $params = $this->extractRequestParams();
+               $this->params = $this->extractRequestParams();
                $result = $this->getResult();
 
-               if ( !is_null( $params['prop'] ) ) {
-                       $this->prop = array_flip( $params['prop'] );
+               if ( !is_null( $this->params['prop'] ) ) {
+                       $this->prop = array_flip( $this->params['prop'] );
                }
 
                $r = $this->getCurrentUserInfo();
@@ -76,6 +77,45 @@ class ApiQueryUserInfo extends ApiQueryBase {
                return $vals;
        }
 
+       /**
+        * Get central user info
+        * @param Config $config
+        * @param User $user
+        * @param string|null $attachedWiki
+        * @return array Central user info
+        *  - centralids: Array mapping non-local Central ID provider names to IDs
+        *  - attachedlocal: Array mapping Central ID provider names to booleans
+        *    indicating whether the local user is attached.
+        *  - attachedwiki: Array mapping Central ID provider names to booleans
+        *    indicating whether the user is attached to $attachedWiki.
+        */
+       public static function getCentralUserInfo( Config $config, User $user, $attachedWiki = null ) {
+               $providerIds = array_keys( $config->get( 'CentralIdLookupProviders' ) );
+
+               $ret = array(
+                       'centralids' => array(),
+                       'attachedlocal' => array(),
+               );
+               ApiResult::setArrayType( $ret['centralids'], 'assoc' );
+               ApiResult::setArrayType( $ret['attachedlocal'], 'assoc' );
+               if ( $attachedWiki ) {
+                       $ret['attachedwiki'] = array();
+                       ApiResult::setArrayType( $ret['attachedwiki'], 'assoc' );
+               }
+
+               $name = $user->getName();
+               foreach ( $providerIds as $providerId ) {
+                       $provider = CentralIdLookup::factory( $providerId );
+                       $ret['centralids'][$providerId] = $provider->centralIdFromName( $name );
+                       $ret['attachedlocal'][$providerId] = $provider->isAttached( $user );
+                       if ( $attachedWiki ) {
+                               $ret['attachedwiki'][$providerId] = $provider->isAttached( $user, $attachedWiki );
+                       }
+               }
+
+               return $ret;
+       }
+
        protected function getCurrentUserInfo() {
                $user = $this->getUser();
                $vals = array();
@@ -205,6 +245,12 @@ class ApiQueryUserInfo extends ApiQueryBase {
                        }
                }
 
+               if ( isset( $this->prop['centralids'] ) ) {
+                       $vals += self::getCentralUserInfo(
+                               $this->getConfig(), $this->getUser(), $this->params['attachedwiki']
+                       );
+               }
+
                return $vals;
        }
 
@@ -267,6 +313,7 @@ class ApiQueryUserInfo extends ApiQueryBase {
                                        'acceptlang',
                                        'registrationdate',
                                        'unreadcount',
+                                       'centralids',
                                ),
                                ApiBase::PARAM_HELP_MSG_PER_VALUE => array(
                                        'unreadcount' => array(
@@ -275,7 +322,8 @@ class ApiQueryUserInfo extends ApiQueryBase {
                                                self::WL_UNREAD_LIMIT . '+',
                                        ),
                                ),
-                       )
+                       ),
+                       'attachedwiki' => null,
                );
        }
 
index a826c1b..db5fb65 100644 (file)
@@ -48,6 +48,7 @@ class ApiQueryUsers extends ApiQueryBase {
                'registration',
                'emailable',
                'gender',
+               'centralids',
        );
 
        public function __construct( ApiQuery $query, $moduleName ) {
@@ -213,6 +214,12 @@ class ApiQueryUsers extends ApiQueryBase {
                                        $data[$name]['gender'] = $gender;
                                }
 
+                               if ( isset( $this->prop['centralids'] ) ) {
+                                       $data[$name] += ApiQueryUserInfo::getCentralUserInfo(
+                                               $this->getConfig(), $user, $params['attachedwiki']
+                                       );
+                               }
+
                                if ( !is_null( $params['token'] ) ) {
                                        $tokenFunctions = $this->getTokenFunctions();
                                        foreach ( $params['token'] as $t ) {
@@ -304,9 +311,11 @@ class ApiQueryUsers extends ApiQueryBase {
                                        'registration',
                                        'emailable',
                                        'gender',
+                                       'centralids',
                                ),
                                ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
                        ),
+                       'attachedwiki' => null,
                        'users' => array(
                                ApiBase::PARAM_ISMULTI => true
                        ),
index 4c2d0be..897c05e 100644 (file)
        "apihelp-query+allusers-paramvalue-prop-rights": "Lists rights that the user has.",
        "apihelp-query+allusers-paramvalue-prop-editcount": "Adds the edit count of the user.",
        "apihelp-query+allusers-paramvalue-prop-registration": "Adds the timestamp of when the user registered if available (may be blank).",
+       "apihelp-query+allusers-paramvalue-prop-centralids": "Adds the central IDs and attachment status for the user.",
        "apihelp-query+allusers-param-limit": "How many total user names to return.",
        "apihelp-query+allusers-param-witheditsonly": "Only list users who have made edits.",
        "apihelp-query+allusers-param-activeusers": "Only list users active in the last $1 {{PLURAL:$1|day|days}}.",
+       "apihelp-query+allusers-param-attachedwiki": "With <kbd>$1prop=centralids</kbd>, also indicate whether the user is attached with the wiki identified by this ID.",
        "apihelp-query+allusers-example-Y": "List users starting at <kbd>Y</kbd>.",
 
        "apihelp-query+backlinks-description": "Find all pages that link to the given page.",
        "apihelp-query+userinfo-paramvalue-prop-acceptlang": "Echoes the <code>Accept-Language</code> header sent by the client in a structured format.",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Adds the user's registration date.",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "Adds the count of unread pages on the user's watchlist (maximum $1; returns <samp>$2</samp> if more).",
+       "apihelp-query+userinfo-paramvalue-prop-centralids": "Adds the central IDs and attachment status for the user.",
+       "apihelp-query+userinfo-param-attachedwiki": "With <kbd>$1prop=centralids</kbd>, indicate whether the user is attached with the wiki identified by this ID.",
        "apihelp-query+userinfo-example-simple": "Get information about the current user.",
        "apihelp-query+userinfo-example-data": "Get additional information about the current user.",
 
        "apihelp-query+users-paramvalue-prop-registration": "Adds the user's registration timestamp.",
        "apihelp-query+users-paramvalue-prop-emailable": "Tags if the user can and wants to receive email through [[Special:Emailuser]].",
        "apihelp-query+users-paramvalue-prop-gender": "Tags the gender of the user. Returns \"male\", \"female\", or \"unknown\".",
+       "apihelp-query+users-paramvalue-prop-centralids": "Adds the central IDs and attachment status for the user.",
+       "apihelp-query+users-param-attachedwiki": "With <kbd>$1prop=centralids</kbd>, indicate whether the user is attached with the wiki identified by this ID.",
        "apihelp-query+users-param-users": "A list of users to obtain information for.",
        "apihelp-query+users-param-token": "Use <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd> instead.",
        "apihelp-query+users-example-simple": "Return information for user <kbd>Example</kbd>.",
index 370ee0d..079eeb2 100644 (file)
@@ -2,9 +2,11 @@
        "@metadata": {
                "authors": [
                        "Subi",
-                       "Sator"
+                       "Sator",
+                       "An13sa"
                ]
        },
+       "apihelp-main-param-action": "Zein ekintza burutuko da.",
        "apihelp-main-param-format": "Irteerako formatua.",
        "apihelp-block-description": "Blokeatu erabiltzaile bat.",
        "apihelp-block-param-reason": "Blokeatzeko arrazoia.",
@@ -14,7 +16,9 @@
        "apihelp-createaccount-param-realname": "Erabiltzailearen benetako izena (aukerakoa).",
        "apihelp-delete-description": "Orrialde bat ezabatu.",
        "apihelp-delete-example-simple": "Ezabatu <kbd>Main Page</kbd>.",
+       "apihelp-disabled-description": "Modulu hau ezgaitu da.",
        "apihelp-edit-description": "Orrialdeak sortu eta aldatu.",
+       "apihelp-edit-param-sectiontitle": "Atal berri baten titulua.",
        "apihelp-edit-param-text": "Orrialdearen edukia.",
        "apihelp-edit-param-minor": "Aldaketa txikia.",
        "apihelp-edit-example-edit": "Orrialde bat aldatu",
@@ -22,6 +26,7 @@
        "apihelp-emailuser-param-subject": "Gaiaren goiburua.",
        "apihelp-emailuser-param-text": "Mezuaren gorputza.",
        "apihelp-expandtemplates-param-title": "Orrialdearen izenburua.",
+       "apihelp-expandtemplates-paramvalue-prop-wikitext": "Wikitestu zabaldua.",
        "apihelp-feedcontributions-param-year": "Urtetik aurrera (eta lehenagotik)",
        "apihelp-feedcontributions-param-month": "Hilabetetik aurrera (eta lehenagotik)",
        "apihelp-feedrecentchanges-param-hideminor": "Ezkutatu aldaketa txikiak.",
        "apihelp-feedrecentchanges-example-simple": "Erakutsi aldaketa berriak",
        "apihelp-feedrecentchanges-example-30days": "Erakutsi aldaketa berriak 30 egunez",
        "apihelp-filerevert-param-comment": "Iruzkina igo.",
+       "apihelp-help-example-recursive": "Laguntza guztia orrialde batean.",
        "apihelp-imagerotate-description": "Irudi bat edo gehiago biratu.",
+       "apihelp-import-param-summary": "Inportazioaren laburpena.",
+       "apihelp-import-param-xml": "XML fitxategia igo da.",
        "apihelp-login-param-name": "Erabiltzaile izena.",
        "apihelp-login-param-password": "Pasahitza.",
        "apihelp-login-param-domain": "Domeinua (hautazkoa).",
        "apihelp-login-example-login": "Saioa hasi",
        "apihelp-move-description": "Orrialde bat mugitu",
        "apihelp-move-param-reason": "Berrizenpenaren arrazoia.",
+       "apihelp-move-param-noredirect": "Birzuzenketarik ez sortu.",
+       "apihelp-move-param-ignorewarnings": "Edozein ohar ezikusi.",
+       "apihelp-opensearch-param-namespace": "Bilatzeko izen-tarteak.",
+       "apihelp-opensearch-param-format": "Irteerako formatua.",
        "apihelp-options-example-reset": "Berrezarri hobespen guztiak.",
+       "apihelp-paraminfo-description": "API moduluei buruzko informazioa eskuratu.",
+       "apihelp-parse-param-summary": "Analizatzeko laburpena.",
        "apihelp-protect-param-reason": "Babesteko edo babesa kentzeko zergatia.",
        "apihelp-protect-example-protect": "Orrialde bat babestu",
+       "apihelp-query+allcategories-description": "Kategoria guztiak zenbakitu.",
        "apihelp-query+allusers-param-witheditsonly": "Bakarrik zerrendatu aldaketak egin dituzten erabiltzaileak.",
        "apihelp-query+allusers-param-activeusers": "Bakarrik zerrendatu azken {{PLURAL:$1|eguneko|$1 egunetako}} erabiltzaile aktiboak.",
        "apihelp-query+blocks-description": "Zerrendatu blokeatutako erabiltzaile eta IP helbide guztiak.",
@@ -53,6 +68,8 @@
        "apihelp-query+prefixsearch-param-search": "Bilatu katea.",
        "apihelp-query+protectedtitles-example-simple": "Zerrendatu babestutako izenburuak",
        "apihelp-query+recentchanges-example-simple": "Zerrendatu aldaketa berriak.",
+       "apihelp-query+revisions-example-last5": "<kbd>Orrialde Nagusiaren</kbd> azken 5 berrikuspenak eskuratu.",
+       "apihelp-query+revisions-example-first5": "<kbd>Orrialde Nagusiaren</kbd> lehen 5 berrikuspenak eskuratu.",
        "apihelp-upload-param-file": "Fitxategiaren edukia.",
        "apihelp-upload-example-url": "Igo URL batetik.",
        "apihelp-userrights-param-reason": "Aldaketarako arrazoia.",
index 2734a8e..c4f7a3f 100644 (file)
@@ -9,7 +9,8 @@
                        "Ricordisamoa",
                        "Valepert",
                        "Sannita",
-                       "Macofe"
+                       "Macofe",
+                       "Nemo bis"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentazione (in inglese)]]\n* [[mw:API:FAQ|FAQ (in inglese)]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailing list]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annunci sull'API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bug & richieste]\n</div>\n<strong>Stato:</strong> Tutte le funzioni e caratteristiche mostrate su questa pagina dovrebbero funzionare, ma l'API è ancora in fase d'attivo sviluppo, e potrebbe cambiare in qualsiasi momenento. Iscriviti alla [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce mailing list] per essere informato sugli aggiornamenti.\n\n<strong>Istruzioni sbagliate:</strong> quando vengono impartite all'API delle istruzioni sbagliate, un'intestazione HTTP verrà inviata col messaggio \"MediaWiki-API-Error\" e sia al valore dell'intestazione sia al codice d'errore verrà impostato lo stesso valore. Per maggiori informazioni leggi [[mw:API:Errors_and_warnings|API:Errori ed avvertimenti (in inglese)]].",
@@ -22,6 +23,7 @@
        "apihelp-block-description": "Blocca  un utente.",
        "apihelp-block-param-user": "Nome utente, indirizzo IP o range di IP da bloccare.",
        "apihelp-block-param-reason": "Motivo del blocco.",
+       "apihelp-block-param-anononly": "Blocca solo gli utenti non registrati (cioè disattiva i contributi anonimi da questo indirizzo IP).",
        "apihelp-block-param-nocreate": "Impedisci creazione di utenze.",
        "apihelp-block-param-hidename": "Nascondi il nome utente dal registro dei blocchi (Richiede i permessi di <code>hideuser</code>).",
        "apihelp-block-param-reblock": "Se l'utente è già bloccato, sovrascrivere il blocco esistente.",
index 1a5fcea..287e147 100644 (file)
        "apihelp-query+alllinks-param-from": "列挙を開始するリンクのページ名。",
        "apihelp-query+alllinks-param-to": "列挙を終了するリンクのページ名。",
        "apihelp-query+alllinks-param-prefix": "この値で始まるすべてのリンクされたページを検索する。",
+       "apihelp-query+alllinks-param-unique": "リンクされたページ名を一度だけ表示します。<kbd>$1prop=ids</kbd> とは同時に使用できません。ジェネレーターとして使用される場合、リンク元ではなくリンク先のページを生成します。",
        "apihelp-query+alllinks-param-prop": "どの情報を結果に含めるか:",
        "apihelp-query+alllinks-paramvalue-prop-title": "リンクのページ名を追加します。",
        "apihelp-query+alllinks-param-namespace": "列挙する名前空間。",
        "apihelp-query+allredirects-param-from": "列挙を開始するリダイレクトのページ名。",
        "apihelp-query+allredirects-param-to": "列挙を終了するリダイレクトのページ名。",
        "apihelp-query+allredirects-param-prefix": "この値で始まるすべてのページを検索する。",
+       "apihelp-query+allredirects-param-unique": "転送先ページ名を一度だけ表示します。<kbd>$1prop=ids|fragment|interwiki</kbd> とは同時に使用できません。ジェネレーターとして使用される場合、転送元ではなく転送先のページを生成します。",
        "apihelp-query+allredirects-param-prop": "どの情報を結果に含めるか:",
        "apihelp-query+allredirects-paramvalue-prop-title": "転送ページのページ名を追加します。",
        "apihelp-query+allredirects-param-namespace": "列挙する名前空間。",
        "apihelp-query+info-param-prop": "追加で取得するプロパティ:",
        "apihelp-query+info-paramvalue-prop-protection": "それぞれのページの保護レベルを一覧表示する。",
        "apihelp-query+info-example-simple": "<kbd>Main Page</kbd> に関する情報を取得する。",
+       "apihelp-query+iwbacklinks-param-prefix": "インターウィキ接頭辞。",
+       "apihelp-query+iwbacklinks-param-title": "検索するウィキ間リンク。<var>$1blprefix</var>と同時に使用しなければなりません。",
+       "apihelp-query+iwbacklinks-param-limit": "返すページの総数。",
        "apihelp-query+iwbacklinks-param-prop": "取得するプロパティ:",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "インターウィキ接頭辞を追加します。",
        "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "ウィキ間リンクのページ名を追加します。",
+       "apihelp-query+iwbacklinks-param-dir": "一覧表示する方向。",
        "apihelp-query+iwbacklinks-example-simple": "[[wikibooks:Test]] へリンクしているページを取得する。",
        "apihelp-query+iwbacklinks-example-generator": "[[wikibooks:Test]] へリンクしているページの情報を取得する。",
+       "apihelp-query+iwlinks-description": "ページからのすべてのウィキ間リンクを返します。",
+       "apihelp-query+iwlinks-param-url": "完全なURLを取得するかどうか (<var>$1prop</var>とは同時に使用できません).",
+       "apihelp-query+iwlinks-param-prop": "各言語間リンクについて取得する追加のプロパティ:",
        "apihelp-query+iwlinks-paramvalue-prop-url": "完全なURLを追加します。",
        "apihelp-query+iwlinks-param-limit": "返すウィキ間リンクの数。",
        "apihelp-query+iwlinks-param-prefix": "この接頭辞のウィキ間リンクのみを返す。",
        "apihelp-query+iwlinks-param-title": "検索するウィキ間リンク。<var>$1</var> と同時に使用しなければなりません。",
+       "apihelp-query+iwlinks-param-dir": "一覧表示する方向。",
        "apihelp-query+iwlinks-example-simple": "<kbd>Main Page</kbd> にあるウィキ間リンクを取得する。",
        "apihelp-query+langbacklinks-param-lang": "言語間リンクの言語。",
        "apihelp-query+langbacklinks-param-title": "検索する言語間リンク。$1lang と同時に使用しなければなりません。",
        "apihelp-query+langbacklinks-param-limit": "返すページの総数。",
        "apihelp-query+langbacklinks-param-prop": "取得するプロパティ:",
+       "apihelp-query+langbacklinks-paramvalue-prop-lllang": "言語間リンクの言語コードを追加します。",
        "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "言語間リンクのページ名を追加します。",
+       "apihelp-query+langbacklinks-param-dir": "一覧表示する方向。",
        "apihelp-query+langbacklinks-example-simple": "[[:fr:Test]] へリンクしているページを取得する。",
        "apihelp-query+langbacklinks-example-generator": "[[:fr:Test]] へリンクしているページの情報を取得する。",
+       "apihelp-query+langlinks-description": "ページからのすべての言語間リンクを返します。",
        "apihelp-query+langlinks-param-limit": "返す言語間リンクの数。",
        "apihelp-query+langlinks-param-url": "完全なURLを取得するかどうか (<var>$1prop</var>とは同時に使用できません).",
+       "apihelp-query+langlinks-param-prop": "各言語間リンクについて取得する追加のプロパティ:",
        "apihelp-query+langlinks-paramvalue-prop-url": "完全なURLを追加します。",
        "apihelp-query+langlinks-paramvalue-prop-autonym": "ネイティブ言語名を追加します。",
        "apihelp-query+langlinks-param-lang": "この言語コードの言語間リンクのみを返す。",
index 59c008e..ca77d1c 100644 (file)
        "apihelp-upload-param-filename": "Nazwa pliku docelowego.",
        "apihelp-userrights-param-user": "Nazwa użytkownika.",
        "apihelp-userrights-param-reason": "Powód zmiany.",
-       "apihelp-dbg-description": "Dane wyjściowe w formacie <code>var_export()</code> (funkcji PHP).",
-       "apihelp-dbgfm-description": "Dane wyjściowe w formacie <code>var_export()</code> (funkcji PHP) (prawidłowo wyświetlane w HTML).",
        "apihelp-json-description": "Dane wyjściowe w formacie JSON.",
        "apihelp-jsonfm-description": "Dane wyjściowe w formacie JSON (prawidłowo wyświetlane w HTML).",
        "apihelp-php-description": "Dane wyjściowe w serializowany formacie PHP.",
        "apihelp-phpfm-description": "Dane wyjściowe w serializowanym formacie PHP (prawidłowo wyświetlane w HTML).",
-       "apihelp-txt-description": "Dane wyjściowe w formacie <code>print_r()</code> (funkcji PHP).",
-       "apihelp-txtfm-description": "Dane wyjściowe w formacie <code>print_r()</code> (funkcji PHP) (prawidłowo wyświetlane w HTML).",
        "apihelp-xml-description": "Dane wyjściowe w formacie XML.",
-       "apihelp-xml-param-xslt": "Jeśli określony, dodaje &lt;xslt&gt; jako arkusz styli. Powinna to być strona wiki w przestrzeni nazw MediaWiki, której nazwy stron kończą się na \".xsl\".",
+       "apihelp-xml-param-xslt": "Jeśli określony, dodaje podaną stronę jako arkusz styli XSL. Powinna to być strona wiki w przestrzeni nazw MediaWiki, której nazwa kończy się na <code>.xsl</code>.",
        "apihelp-xmlfm-description": "Dane wyjściowe w formacie XML (prawidłowo wyświetlane w HTML).",
-       "apihelp-yaml-description": "Dane wyjściowe w formacie YAML.",
-       "apihelp-yamlfm-description": "Dane wyjściowe w formacie YAML (prawidłowo wyświetlane w HTML).",
        "api-format-title": "Wynik MediaWiki API",
        "api-help-title": "Pomoc MediaWiki API",
        "api-help-lead": "To jest automatycznie wygenerowana strona dokumentacji MediaWiki API.\nDokumentacja i przykłady: https://www.mediawiki.org/wiki/API",
index bb3aa46..e94d13b 100644 (file)
@@ -5,6 +5,7 @@
                        "Macofe"
                ]
        },
+       "apihelp-main-param-action": "کومه کړنه ترسره کړم.",
        "apihelp-block-description": "په يو کارن بنديز لگول.",
        "apihelp-block-param-user": "کارن-نوم، IP پته، يا IP سيمې باندې بنديز لگول.",
        "apihelp-block-param-reason": "د بنديز سبب.",
        "apihelp-stashedit-param-sectiontitle": "د يوې نوې برخې سرليک.",
        "apihelp-tag-param-reason": "د بدلون سبب.",
        "apihelp-unblock-param-reason": "د بنديز ليرې کولو سبب.",
+       "apihelp-undelete-param-reason": "د بيازېرملو سبب.",
        "apihelp-upload-param-watch": "مخ کتل.",
        "apihelp-upload-param-file": "د دوتنې مېنځپانگه.",
        "apihelp-userrights-param-user": "کارن نوم.",
        "apihelp-userrights-param-userid": "کارن پېژند.",
        "apihelp-userrights-param-reason": "د بدلون سبب.",
+       "api-help-title": "د مېډياويکي API لارښود",
+       "api-help-main-header": "آر ماډيول",
        "api-help-source": "سرچينه: $1",
        "api-help-source-unknown": "سرچينه: <span class=\"apihelp-unknown\">ناجوت</span>",
        "api-help-license": "منښتليک: [[$1|$2]]",
        "api-help-license-noname": "منښتليک: [[$1|تړنه وڅارئ]]",
        "api-help-license-unknown": "منښتليک: <span class=\"apihelp-unknown\">ناجوت</span>",
+       "api-help-parameters": "{{PLURAL:$1|پاراميټر|پاراميټرونه}}:",
+       "api-help-param-required": "دې پاراميټر ته اړتيا ده.",
        "api-help-datatypes-header": "اومتوگ ډولونه",
        "api-help-param-default": "تلواليز: $1",
        "api-help-param-default-empty": "تلواليز: <span class=\"apihelp-empty\">(تش)</span>",
index 047a806..f4ec177 100644 (file)
        "apihelp-query+allusers-paramvalue-prop-rights": "{{doc-apihelp-paramvalue|query+allusers|prop|rights}}",
        "apihelp-query+allusers-paramvalue-prop-editcount": "{{doc-apihelp-paramvalue|query+allusers|prop|editcount}}",
        "apihelp-query+allusers-paramvalue-prop-registration": "{{doc-apihelp-paramvalue|query+allusers|prop|registration}}",
+       "apihelp-query+allusers-paramvalue-prop-centralids": "{{doc-apihelp-paramvalue|query+allusers|prop|centralids}}",
+       "apihelp-query+allusers-param-attachedwiki": "{{doc-apihelp-param|query+allusers|attachedwiki}}",
        "apihelp-query+allusers-param-limit": "{{doc-apihelp-param|query+allusers|limit}}",
        "apihelp-query+allusers-param-witheditsonly": "{{doc-apihelp-param|query+allusers|witheditsonly}}",
        "apihelp-query+allusers-param-activeusers": "{{doc-apihelp-param|query+allusers|activeusers|params=* $1 - Value of [[mw:Manual:$wgActiveUserDays]]|paramstart=2}}",
        "apihelp-query+userinfo-paramvalue-prop-acceptlang": "{{doc-apihelp-paramvalue|query+userinfo|prop|acceptlang}}",
        "apihelp-query+userinfo-paramvalue-prop-registrationdate": "{{doc-apihelp-paramvalue|query+userinfo|prop|registrationdate}}",
        "apihelp-query+userinfo-paramvalue-prop-unreadcount": "{{doc-apihelp-paramvalue|query+userinfo|prop|unreadcount|params=* $1 - Maximum value for the \"unreadcount\" property.\n* $2 - Return value when there are more unread pages.|paramstart=3}}",
+       "apihelp-query+userinfo-paramvalue-prop-centralids": "{{doc-apihelp-paramvalue|query+userinfo|prop|centralids}}",
+       "apihelp-query+userinfo-param-attachedwiki": "{{doc-apihelp-param|query+userinfo|attachedwiki}}",
        "apihelp-query+userinfo-example-simple": "{{doc-apihelp-example|query+userinfo}}",
        "apihelp-query+userinfo-example-data": "{{doc-apihelp-example|query+userinfo}}",
        "apihelp-query+users-description": "{{doc-apihelp-description|query+users}}",
        "apihelp-query+users-paramvalue-prop-registration": "{{doc-apihelp-paramvalue|query+users|prop|registration}}",
        "apihelp-query+users-paramvalue-prop-emailable": "{{doc-apihelp-paramvalue|query+users|prop|emailable}}",
        "apihelp-query+users-paramvalue-prop-gender": "{{doc-apihelp-paramvalue|query+users|prop|gender}}",
+       "apihelp-query+users-paramvalue-prop-centralids": "{{doc-apihelp-paramvalue|query+users|prop|centralids}}",
+       "apihelp-query+users-param-attachedwiki": "{{doc-apihelp-param|query+users|attachedwiki}}",
        "apihelp-query+users-param-users": "{{doc-apihelp-param|query+users|users}}",
        "apihelp-query+users-param-token": "{{doc-apihelp-param|query+users|token}}",
        "apihelp-query+users-example-simple": "{{doc-apihelp-example|query+users}}",
index 00a16d6..ad4bee4 100644 (file)
@@ -5,9 +5,9 @@
                        "Aursani"
                ]
        },
-       "apihelp-query+allrevisions-description": "سمورن مسودن جي فهرست پيش ڪريو.",
-       "apihelp-query+watchlist-param-type": "ڪهڙن قسمن جون تبديليون ڏيکارڻ لاءِ:",
-       "apihelp-query+watchlist-paramvalue-type-edit": "عام صفحي ترميمون.",
+       "apihelp-query+allrevisions-description": "سمورن ڀيرن جي فهرست پيش ڪريو.",
+       "apihelp-query+watchlist-param-type": "ڪهڙن قسمن جون تبديليون ڏيکارجن:",
+       "apihelp-query+watchlist-paramvalue-type-edit": "قاعديوار صفحاتي ترميمون.",
        "apihelp-query+watchlist-paramvalue-type-external": "خارجي تبديليون.",
        "apihelp-query+watchlist-paramvalue-type-new": "صفحن جون تخليقون.",
        "apihelp-query+watchlist-paramvalue-type-log": "لاگ داخلائون."
index ff26429..615ea26 100644 (file)
        "apihelp-parse-paramvalue-prop-limitreporthtml": "提供限制报告的HTML版本。当<var>$1disablelimitreport</var>被设置时不会提供数据。",
        "apihelp-parse-paramvalue-prop-parsetree": "修订内容的XML解析树(需要内容模型<code>$1</code>)",
        "apihelp-parse-param-pst": "在解析输入前,对输入做一次保存前变换处理。仅当使用文本时有效。",
+       "apihelp-parse-param-onlypst": "在输入内容中执行预保存转换(PST),但不解析它。在PST被应用后返回相同的wiki文本。只当与<var>$1text</var>一起使用时有效。",
        "apihelp-parse-param-effectivelanglinks": "包含由扩展提供的语言链接(用于与<kbd>$1prop=langlinks</kbd>一起使用)。",
        "apihelp-parse-param-section": "只解析此段数的内容。\n\n当<kbd>new</kbd>时,将<var>$1text</var>和<var>$1sectiontitle</var>解析为添加新段落至页面。\n\n<kbd>new</kbd>段落只当指定<var>text</var>时允许。",
        "apihelp-parse-param-sectiontitle": "当<var>section</var>为<kbd>new</kbd>时新段落标题。\n\n不像页面编辑,当省略或为空时将不会备选为<var>summary</var>。",
        "apihelp-parse-param-sectionpreview": "在段落预览模式下解析(同时要启用预览模式)。",
        "apihelp-parse-param-disabletoc": "在输出中省略目录。",
        "apihelp-parse-param-contentformat": "用于输入文本的内容序列化格式。只当与$1text一起使用时有效。",
+       "apihelp-parse-param-contentmodel": "输入文本的内容模型。如果省略,$1title必须指定,并且默认将为指定标题的模型。只当与$1text一起使用时有效。",
        "apihelp-parse-example-page": "解析一个页面。",
        "apihelp-parse-example-text": "解析wiki文本。",
        "apihelp-parse-example-texttitle": "解析wiki文本,指定页面标题。",
        "apihelp-query+blocks-param-end": "枚举的结束时间戳。",
        "apihelp-query+blocks-param-ids": "要列出的封禁ID列表(可选)。",
        "apihelp-query+blocks-param-users": "要搜索的用户列表(可选)。",
+       "apihelp-query+blocks-param-ip": "获取应用到此IP地址或者CIDR范围的所有封禁,包括范围封禁。不能与<var>$3users</var>一起使用。CIDR范围不允许比IPv4/$1或IPv6/$2更宽。",
        "apihelp-query+blocks-param-limit": "封禁列表的最大数量。",
        "apihelp-query+blocks-param-prop": "要获取的属性:",
        "apihelp-query+blocks-paramvalue-prop-id": "添加封禁ID。",
        "apihelp-query+blocks-paramvalue-prop-reason": "添加封禁原因。",
        "apihelp-query+blocks-paramvalue-prop-range": "添加受封禁影响的IP地址段。",
        "apihelp-query+blocks-paramvalue-prop-flags": "标记编辑禁止(自动封禁、仅限匿名用户等)。",
+       "apihelp-query+blocks-param-show": "只显示符合这些标准的项目。\n例如,要只查看IP地址的无限期封禁,设置<kbd>$1show=ip|!temp</kbd>。",
        "apihelp-query+blocks-example-simple": "封禁列表。",
        "apihelp-query+blocks-example-users": "列出用户<kbd>Alice</kbd>和<kbd>Bob</kbd>的封禁。",
        "apihelp-query+categories-description": "页面属于的所有分类列表。",
        "apihelp-query+categories-paramvalue-prop-hidden": "标记由<code>_&#95;HIDDENCAT_&#95;</code>隐藏的分类。",
        "apihelp-query+categories-param-show": "显示何种分类。",
        "apihelp-query+categories-param-limit": "返回多少分类。",
+       "apihelp-query+categories-param-categories": "只列出这些分类。对于检查某一页面使用某一分类很有用。",
        "apihelp-query+categories-param-dir": "罗列所采用的方向。",
        "apihelp-query+categories-example-simple": "获取属于<kbd>Albert Einstein</kbd>的分类列表。",
        "apihelp-query+categories-example-generator": "获得有关用于<kbd>Albert Einstein</kbd>的分类的信息。",
        "apihelp-query+recentchanges-paramvalue-prop-tags": "Lists tags for the entry.",
        "apihelp-query+recentchanges-paramvalue-prop-sha1": "Adds the content checksum for entries associated with a revision.",
        "apihelp-query+recentchanges-param-token": "请改用<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>。",
+       "apihelp-query+recentchanges-param-show": "只显示满足这些标准的项目。例如,要只查看由登录用户做出的小编辑,设置$1show=minor|!anon。",
        "apihelp-query+recentchanges-param-limit": "返回总计更新数。",
        "apihelp-query+recentchanges-param-type": "显示的更改类型。",
        "apihelp-query+recentchanges-param-generaterevisions": "当作为生成器使用时,生成修订ID而不是标题。不带关联修订ID的最近更改记录(例如大多数日志记录)将不会生成任何东西。",
        "apihelp-query+redirects-example-generator": "获取所有重定向至[[Main Page]]的信息。",
        "apihelp-query+revisions-paraminfo-singlepageonly": "可能只能与单一页面使用(模式#2)。",
        "apihelp-query+revisions-param-end": "列举直至此时间戳。",
+       "apihelp-query+revisions-param-user": "只包含由用户做出的修订。",
+       "apihelp-query+revisions-param-excludeuser": "不包括由用户做出的修订。",
        "apihelp-query+revisions-param-tag": "只列出被此标签标记的修订。",
        "apihelp-query+revisions-example-content": "获取带内容的数据,用于标题<kbd>API</kbd>和<kbd>Main Page</kbd>的最近修订。",
        "apihelp-query+revisions-example-last5": "获取<kbd>Main Page</kbd>的最近5次修订。",
        "apihelp-query+siteinfo-example-interwiki": "取得本地跨wiki前缀列表。",
        "apihelp-query+siteinfo-example-replag": "检查当前的响应延迟。",
        "apihelp-query+stashimageinfo-description": "返回用于藏匿文件的文件信息。",
+       "apihelp-query+stashimageinfo-param-filekey": "用于识别一次临时藏匿的早前上传的关键字。",
        "apihelp-query+stashimageinfo-param-sessionkey": "$1filekey的别名,用于向后兼容。",
        "apihelp-query+stashimageinfo-example-simple": "返回藏匿文件的信息。",
        "apihelp-query+tags-description": "列出更改标签。",
        "apihelp-query+users-param-token": "请改用<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>。",
        "apihelp-query+users-example-simple": "返回用户<kbd>Example</kbd>的信息。",
        "apihelp-query+watchlist-description": "在当前用户的监视列表中获取对页面的最近更改。",
+       "apihelp-query+watchlist-param-allrev": "将同一页面的多个修订包含于指定的时间表内。",
        "apihelp-query+watchlist-param-start": "枚举的起始时间戳。",
        "apihelp-query+watchlist-param-end": "枚举的结束时间戳。",
        "apihelp-query+watchlist-param-user": "只列出此用户的更改。",
        "apihelp-query+watchlist-paramvalue-prop-sizes": "添加页面的旧有长度和新长度。",
        "apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "添加最近被通知有关编辑的用户的时间戳。",
        "apihelp-query+watchlist-paramvalue-prop-loginfo": "在适当位置添加日志信息。",
+       "apihelp-query+watchlist-param-show": "只显示满足这些标准的项目。例如,要只查看由登录用户做出的小编辑,设置$1show=minor|!anon。",
        "apihelp-query+watchlist-param-type": "要显示的更改类型:",
        "apihelp-query+watchlist-paramvalue-type-edit": "普通页面编辑。",
        "apihelp-query+watchlist-paramvalue-type-external": "外部更改。",
        "apihelp-query+watchlist-paramvalue-type-new": "页面创建。",
        "apihelp-query+watchlist-paramvalue-type-log": "日志记录。",
        "apihelp-query+watchlist-paramvalue-type-categorize": "分类成员组更改。",
+       "apihelp-query+watchlist-param-owner": "与$1token一起使用以访问不同用户的监视列表。",
        "apihelp-query+watchlist-param-token": "允许访问其他用户监视列表的安全密钥(可通过用户的[[Special:Preferences#mw-prefsection-watchlist|参数设置]]找到)。",
        "apihelp-query+watchlist-example-simple": "在当前用户的监视列表中列出用于最近更改页面的最新修订。",
        "apihelp-query+watchlist-example-props": "在当前用户的监视列表中检索有关用于最近更改页面的最新修订的额外信息。",
        "apihelp-query+watchlistraw-param-prop": "要获取的额外属性:",
        "apihelp-query+watchlistraw-paramvalue-prop-changed": "添加最近被通知有关编辑的用户的时间戳。",
        "apihelp-query+watchlistraw-param-show": "只列出符合这些标准的项目。",
+       "apihelp-query+watchlistraw-param-owner": "与$1token一起使用以访问不同用户的监视列表。",
        "apihelp-query+watchlistraw-param-token": "允许访问其他用户监视列表的安全密钥(可通过用户的[[Special:Preferences#mw-prefsection-watchlist|参数设置]]找到)。",
        "apihelp-query+watchlistraw-param-fromtitle": "要列举的起始标题(带名字空间前缀)。",
        "apihelp-query+watchlistraw-param-totitle": "要列举的最终标题(带名字空间前缀)。",
        "apihelp-query+watchlistraw-example-simple": "列出当前用户的监视列表中的页面。",
        "apihelp-revisiondelete-description": "删除和恢复修订版本。",
+       "apihelp-revisiondelete-param-type": "正在执行的修订版本删除类型。",
+       "apihelp-revisiondelete-param-target": "要进行修订版本删除的页面标题,如果对某一类型需要。",
        "apihelp-revisiondelete-param-ids": "用于将被删除的修订的标识符。",
        "apihelp-revisiondelete-param-hide": "每次修订要隐藏的东西。",
        "apihelp-revisiondelete-param-show": "每次修订要恢复显示的东西。",
+       "apihelp-revisiondelete-param-suppress": "是否对管理员及其他人禁止数据。",
        "apihelp-revisiondelete-param-reason": "删除或恢复的原因。",
        "apihelp-revisiondelete-example-revision": "隐藏<kbd>首页</kbd>的修订版本<kbd>12345</kbd>的内容。",
        "apihelp-revisiondelete-example-log": "隐藏日志记录<kbd>67890</kbd>上的所有数据,原因<kbd>BLP violation</kbd>。",
        "apihelp-rollback-description": "撤销对页面的最近编辑。\n\n如果最近编辑页面的用户在一行中进行多次编辑,所有编辑将被回退。",
        "apihelp-rollback-param-title": "要回退的页面标题。不能与<var>$1pageid</var>一起使用。",
        "apihelp-rollback-param-pageid": "要回退的页面的页面 ID。不能与<var>$1title</var>一起使用。",
+       "apihelp-rollback-param-user": "做出要回退的编辑的用户名称。",
+       "apihelp-rollback-param-summary": "自定义编辑摘要。如果为空,将使用默认摘要。",
+       "apihelp-rollback-param-markbot": "将被回退的编辑和回退操作标记为机器人编辑。",
        "apihelp-rollback-param-watchlist": "无条件地将页面加入至当前用户的监视列表或将其移除,使用设置或不更改监视。",
        "apihelp-rollback-example-simple": "回退由用户<kbd>Example</kbd>对<kbd>Main Page</kbd>做出的最近编辑。",
        "apihelp-rollback-example-summary": "回退由IP用户<kbd>192.0.2.5</kbd>对页面<kbd>Main Page</kbd>做出的最近编辑,带编辑摘要<kbd>Reverting vandalism</kbd>,并将这些编辑和回退标记为机器人编辑。",
        "apihelp-undelete-param-fileids": "要恢复的文件修订ID。如果<var>$1timestamps</var>和<var>$1fileids</var>都为空,所有将被恢复。",
        "apihelp-undelete-example-page": "恢复页面<kbd>Main Page</kbd>。",
        "apihelp-undelete-example-revisions": "恢复<kbd>Main Page</kbd>的两个修订。",
-       "apihelp-upload-description": "上传一个文件,或获取正在等待中的上传的状态。\n\n可以使用的几种方法:\n* 直接上传文件内容,使用<var>$1file</var>参数。\n* 成批上传文件,使用<var>$1filesize</var>、<var>$1chunk</var>和<var>$1offset</var>参数。\n* 有MediaWiki服务器从URL检索一个文件,使用<var>$1url</var>参数。\n* Complete an earlier upload that failed due to warnings, using the <var>$1filekey</var> parameter.\nNote that the HTTP POST must be done as a file upload (i.e. using <code>multipart/form-data</code>) when sending the <var>$1file</var>.",
+       "apihelp-upload-description": "上传一个文件,或获取正在等待中的上传的状态。\n\n可以使用的几种方法:\n* 直接上传文件内容,使用<var>$1file</var>参数。\n* 成批上传文件,使用<var>$1filesize</var>、<var>$1chunk</var>和<var>$1offset</var>参数。\n* 有MediaWiki服务器从URL检索一个文件,使用<var>$1url</var>参数。\n* 完成一次由于警告而失败的早前上传,使用<var>$1filekey</var>参数。\n需要注意,当发送<var>$1file</var>时,HTTP POST必须做为一次文件上传(也就是使用<code>multipart/form-data</code>)完成。",
        "apihelp-upload-param-filename": "目标文件名。",
        "apihelp-upload-param-comment": "上传注释。如果没有指定<var>$1text</var>,那么它也被用于新文件的初始页面文本。",
+       "apihelp-upload-param-text": "用于新文件的初始页面文本。",
        "apihelp-upload-param-watch": "监视页面。",
        "apihelp-upload-param-watchlist": "无条件地将页面加入至当前用户的监视列表或将其移除,使用设置或不更改监视。",
        "apihelp-upload-param-ignorewarnings": "忽略任何警告。",
        "apihelp-upload-param-file": "文件内容。",
        "apihelp-upload-param-url": "要检索文件来源的URL。",
+       "apihelp-upload-param-filekey": "用于识别一次临时藏匿的早前上传的关键字。",
+       "apihelp-upload-param-sessionkey": "与$1filekey相同,基于向后兼容而维护。",
        "apihelp-upload-param-stash": "如果设置,服务器将临时藏匿文件而不是加入存储库。",
        "apihelp-upload-param-filesize": "全部上传的文件大小。",
        "apihelp-upload-param-offset": "块的偏移量(字节)。",
index 483eaa5..298f6e2 100644 (file)
@@ -96,12 +96,12 @@ class HTMLFileCache extends FileCacheBase {
         * @return bool
         */
        public static function useFileCache( IContextSource $context ) {
-               global $wgUseFileCache, $wgShowIPinHeader, $wgDebugToolbar, $wgContLang;
+               global $wgUseFileCache, $wgDebugToolbar, $wgContLang;
                if ( !$wgUseFileCache ) {
                        return false;
                }
-               if ( $wgShowIPinHeader || $wgDebugToolbar ) {
-                       wfDebug( "HTML file cache skipped. Either \$wgShowIPinHeader and/or \$wgDebugToolbar on\n" );
+               if ( $wgDebugToolbar ) {
+                       wfDebug( "HTML file cache skipped. \$wgDebugToolbar on\n" );
 
                        return false;
                }
index 1573d7b..b0a10ce 100644 (file)
@@ -96,7 +96,7 @@ class LoggerFactory {
        public static function getInstance( $channel ) {
                static $hasPSR3Interface = null;
                if ( $hasPSR3Interface === null ) {
-                       $hasPSR3Interface = interface_exists( '\Psr\Log\LoggerInterface' );
+                       $hasPSR3Interface = interface_exists( 'Psr\Log\LoggerInterface' );
                        if ( !$hasPSR3Interface ) {
                                $message = (
                                        'MediaWiki requires the <a href="https://github.com/php-fig/log">PSR-3 logging ' .
index a6290ed..c253e74 100644 (file)
@@ -948,8 +948,7 @@ class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate {
                                        $inv = array( $inv );
                                }
                                foreach ( $inv as $table ) {
-                                       $update = new HTMLCacheUpdate( $this->mTitle, $table );
-                                       $update->doUpdate();
+                                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this->mTitle, $table ) );
                                }
                        }
                }
index 264c87f..7401992 100644 (file)
@@ -296,9 +296,9 @@ class DiffEngine {
                        $this->xchanged = $this->ychanged = array();
                        $this->xv = $this->yv = array();
                        $this->xind = $this->yind = array();
-                       unset( $this->seq );
-                       unset( $this->in_seq );
-                       unset( $this->lcs );
+                       $this->seq = array();
+                       $this->in_seq = array();
+                       $this->lcs = 0;
 
                        // Skip leading common lines.
                        for ( $skip = 0; $skip < $n_from && $skip < $n_to; $skip++ ) {
index d58e92f..44c6b14 100644 (file)
@@ -12,7 +12,7 @@
        "config-desc": "Το πρόγραμμα εγκατάστασης για το MediaWiki",
        "config-title": "Εγκατάσταση MediaWiki $1",
        "config-information": "Πληροφορίες",
-       "config-localsettings-upgrade": "Î\88να  Î±Ï\81Ï\87είο <code>LocalSettings.php</code> Î­Ï\87ει ÎµÎ½Ï\84οÏ\80ιÏ\83Ï\84εί.\nÎ\93ια Î½Î± Î±Î½Î±Î²Î±Î¸Î¼Î¯Ï\83εÏ\84ε Î±Ï\85Ï\84ή Ï\84ην ÎµÎ³ÎºÎ±Ï\84άÏ\83Ï\84αÏ\83η, Ï\80αÏ\81ακαλοÏ\8dμε Î½Î± ÎµÎ¹Ï\83άγεÏ\84ε Ï\84ην Ï\84ιμή Ï\84Ï\89ν <code>$wgUpgradeKey</code> στο παρακάτω πλαίσιο.\nΘα το βρείτε στο <code>LocalSettings.php</code>.",
+       "config-localsettings-upgrade": "Î\95νÏ\84οÏ\80ίÏ\83Ï\84ηκε Î±Ï\81Ï\87είο <code>LocalSettings.php</code>.\nÎ\93ια Î½Î± Î±Î½Î±Î²Î±Î¸Î¼Î¯Ï\83εÏ\84ε Î±Ï\85Ï\84ή Ï\84ην ÎµÎ³ÎºÎ±Ï\84άÏ\83Ï\84αÏ\83η, Ï\80αÏ\81ακαλοÏ\8dμε Î½Î± ÎµÎ¹Ï\83αγάγεÏ\84ε Ï\84ην Ï\84ιμή Ï\84οÏ\85 <code>$wgUpgradeKey</code> στο παρακάτω πλαίσιο.\nΘα το βρείτε στο <code>LocalSettings.php</code>.",
        "config-localsettings-cli-upgrade": "Ένα αρχείο <code>LocalSettings.php</code> έχει εντοπιστεί.\nΓια να αναβαθμίσετε αυτή την εγκατάσταση, εκτελέστε το <code>update.php</code> αντ' αυτού.",
        "config-localsettings-key": "Κλειδί αναβάθμισης:",
        "config-localsettings-badkey": "Το κλειδί που δώσατε είναι εσφαλμένο.",
@@ -52,6 +52,7 @@
        "config-env-hhvm": "Το HHVM $1 είναι εγκατεστημένο.",
        "config-unicode-using-intl": "Χρησιμοποιώντας την [http://pecl.php.net/intl επέκταση intl PECL] για κανονικοποίηση Unicode.",
        "config-unicode-pure-php-warning": "<strong>Προειδοποίηση:</strong> Η [http://pecl.php.net/intl επέκταση intl PECL] δεν είναι διαθέσιμη για να χειριστεί την κανονικοποίηση Unicode, επιστρέφουμε στην αργή αμιγώς PHP εφαρμογή.\nΕάν λειτουργείτε έναν ιστότοπο υψηλής επισκεψιμότητας, θα πρέπει να ρίξετε μια ματιά στην [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations κανονικοποίηση Unicode].",
+       "config-memory-raised": "Το  <code>memory_limit</code> της PHP είναι  $1 και αυξήθηκε σε  $2.",
        "config-memory-bad": "<strong>Προειδοποίηση:</strong> η <code>memory_limit</code> της PHP είναι $1.\nΑυτό είναι πιθανώς πολύ χαμηλό.\n\nΗ εγκατάσταση ενδέχεται να αποτύχει!",
        "config-xcache": "[http://xcache.lighttpd.net/ Το XCache] είναι εγκατεστημένο",
        "config-apc": "Το [http://www.php.net/apc APC] είναι εγκατεστημένο",
@@ -59,6 +60,7 @@
        "config-diff3-bad": "Το GNU diff3 δεν βρέθηκε.",
        "config-git": "Βρέθηκε η Git έκδοση λογισμικού ελέγχου: <code>$1</code>.",
        "config-git-bad": "Η Git έκδοση του λογισμικού ελέγχου δε βρέθηκε.",
+       "config-no-uri": "<strong>Σφάλμα:</strong> Δεν μπόρεσε να καθορίσει το τρέχον URI.\nΗ εγκατάσταση ματαιώθηκε.",
        "config-using-server": "Χρησιμοποιώντας το όνομα του διακομιστή \"<nowiki>$1</nowiki>\".",
        "config-using-uri": "Χρησιμοποιώντας την διεύθυνση URL του διακομιστή \"<nowiki>$1$2</nowiki>\".",
        "config-brokenlibxml": "Το σύστημά σας έχει ένα συνδυασμό εκδόσεων της PHP και libxml2 που είναι προβληματικές και μπορεί να προκαλέσει κρυμμένα στοιχεία διαφθοράς στο MediaWiki και άλλες εφαρμογές web.\nΑναβαθμίστε σε libxml2 2.7.3 ή μεταγενέστερο ([https://bugs.php.net/bug.php?id=45996 bug κατατεθεί με την PHP]).\nΗ εγκατάσταση ματαιώθηκε.",
        "config-charset-mysql5-binary": "MySQL 4.1/5.0 δυαδικό",
        "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8",
        "config-charset-mysql4": "UTF-8 συμβατό προς τα πίσω με MySQL 4.0",
+       "config-mysql-old": "Απαιτείται Microsoft SQL Server $1 ή νεότερο. Εσείς έχετε $2.",
        "config-db-port": "Θύρα βάσης δεδομένων:",
+       "config-db-schema": "Σχήμα για MediaWiki:",
+       "config-db-schema-help": "Αυτό το σχήμα συνήθως θα είναι εντάξει.\nΆλλαξε το μόνο αν ξέρεις ότι το χρειάζεσαι.",
+       "config-pg-test-error": "Δεν μπορεί να συνδεθεί στη βάση δεδομένων <strong>$1</strong>: $2",
+       "config-oracle-temp-ts": "Προσωρινό tablespace:",
        "config-type-mysql": "MySQL (ή συμβατό)",
+       "config-type-postgres": "PostgreSQL",
+       "config-type-sqlite": "SQLite",
+       "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
+       "config-support-info": "To MediaWiki υποστηρίζει τα ακόλουθα συστήματα βάσεων δεδομένων:\n\n$1\n\nΑν δε βλέπεις στο σύστημα βάσεων δεδομένων που θέλεις να χρησιμοποιήσεις να υπάρχει παρακάτω, τότε ακολούθησε τις οδηγίες που δίνονται παραπάνω για να ενεργοποιήσεις την υποστήριξη.",
        "config-header-mysql": "Ρυθμίσεις MySQL",
        "config-header-postgres": "Ρυθμίσεις PostgreSQL",
        "config-header-sqlite": "Ρυθμίσεις SQLite",
        "config-missing-db-host": "Πρέπει να εισαγάγετε μια τιμή για \"{{int:config-db-host}}\".",
        "config-missing-db-server-oracle": "Πρέπει να εισαγάγετε μια τιμή για \"{{int:config-db-host-oracle}}\".",
        "config-connection-error": "$1.\n\nΕλέγξτε τη διεύθυνση, το όνομα χρήστη και τον κωδικό πρόσβασης και προσπαθήστε ξανά.",
-       "config-mssql-old": "Απαιτείται Microsoft SQL Server $1 ή νεώτερο. Εσείς έχετε $2.",
+       "config-db-sys-user-exists-oracle": "Ο λογαριασμός χρήστη \"$1\" υπάρχει ήδη. Το SYSDBA μπορεί να χρησιμοποιηθεί μόνο για τη δημιουργία ενός νέου λογαριασμού!",
+       "config-postgres-old": "Απαιτείται PostgreSQL $1 ή νεότερο. Εσείς έχετε $2.",
+       "config-mssql-old": "Απαιτείται Microsoft SQL Server $1 ή νεότερο. Εσείς έχετε $2.",
        "config-sqlite-readonly": "Το αρχείο <code>$1</code> δεν είναι εγγράψιμο.",
        "config-sqlite-cant-create-db": "Δεν ήταν δυνατή η δημιουργία του αρχείου βάσης δεδομένων <code>$1</code>.",
+       "config-upgrade-done-no-regenerate": "Η αναβάθμιση ολοκληρώθηκε.\n\nΜπορείτε τώρα να [$1 ξεκινήσετε να χρησιμοποιείτε το wiki σας].",
        "config-regenerate": "Αναδημιουργία LocalSettings.php →",
        "config-db-web-account": "Λογαριασμός βάσης δεδομένων για πρόσβαση ιστού",
+       "config-db-web-account-same": "Χρήση του ίδιου λογαριασμού για την εγκατάσταση",
        "config-mysql-engine": "Μηχανή αποθήκευσης:",
        "config-mysql-innodb": "InnoDB",
        "config-mysql-myisam": "MyISAM",
        "config-admin-password-confirm": "Επανάληψη κωδικού πρόσβασης:",
        "config-admin-name-blank": "Εισαγάγετε όνομα χρήστη διαχειριστή.",
        "config-admin-name-invalid": "Το συγκεκριμένο όνομα χρήστη  \"<nowiki>$1</nowiki>\" δεν είναι έγκυρο. Δώστε ένα διαφορετικό όνομα χρήστη.",
-       "config-admin-password-blank": "Î\95ιÏ\83άγεÏ\84ε Î­Î½Î±Î½ ÎºÏ\89δικÏ\8c Î³Î¹Î± Ï\84ον Î»Î¿Î³Î±Ï\81ιαÏ\83μÏ\8c Ï\84οÏ\85 διαχειριστή.",
+       "config-admin-password-blank": "Î\95ιÏ\83αγάγεÏ\84ε ÎºÏ\89δικÏ\8c Î³Î¹Î± Ï\84ο Î»Î¿Î³Î±Ï\81ιαÏ\83μÏ\8c διαχειριστή.",
        "config-admin-password-mismatch": "Οι δύο κωδικοί πρόσβασης που εισηγάγατε δεν ταιριάζουν.",
        "config-admin-email": "Διεύθυνση ηλεκτρονικού ταχυδρομείου:",
        "config-admin-error-bademail": "Έχετε εισαγάγει μη έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου.",
index 60d1f57..75475ad 100644 (file)
@@ -22,6 +22,7 @@
        "config-page-language": "Hizkuntza",
        "config-page-welcome": "Ongi etorri MediaWikira!",
        "config-page-dbconnect": "Datu-basera konektatu",
+       "config-page-upgrade": "Oraingo instalazioa eguneratu",
        "config-page-dbsettings": "Datu-basearen ezarpenak",
        "config-page-name": "Izena",
        "config-page-options": "Aukerak",
        "config-page-complete": "Bukatua!",
        "config-page-restart": "Instalazioa berriz hasi",
        "config-page-readme": "Irakur nazazu",
+       "config-page-releasenotes": "Bertsioko oharrak",
        "config-page-copying": "Kopiatzea",
        "config-page-upgradedoc": "Eguneratu",
+       "config-page-existingwiki": "Existitzen den wikia",
        "config-restart": "Bai, berriz hasi",
        "config-sidebar": "* [//www.mediawiki.org MediaWiki nagusia]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Erabiltzaileentzako Gida]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents Administratzaileentzako Gida]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MEG]\n----\n* <doclink href=Readme>Irakur nazazu</doclink>\n* <doclink href=ReleaseNotes>Oharren argitalpena</doclink>\n* <doclink href=Copying>Kopiaketa</doclink>\n* <doclink href=UpgradeDoc>Eguneratzea</doclink>",
        "config-env-php": "PHP $1 instalatuta dago.",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] instalatuta dago",
        "config-diff3-bad": "GNU diff3 ez da aurkitu.",
        "config-db-type": "Datu-base mota:",
+       "config-db-host-oracle": "Datu-baseko TNS:",
        "config-db-wiki-settings": "Wiki hau identifikatu",
        "config-db-name": "Datu-base izena:",
+       "config-db-name-oracle": "Datu-baseko eskema:",
        "config-db-username": "Datu-base lankide izena:",
        "config-db-password": "Datu-base pasahitza:",
        "config-charset-mysql5-binary": "MySQL 4.1/5.0 bitarra",
        "config-admin-password-confirm": "Pasahitza berriz:",
        "config-admin-password-mismatch": "Sartutako bi pasahitzak ez datoz bat.",
        "config-admin-email": "E-posta helbidea:",
+       "config-admin-error-bademail": "Helbide elektroniko okerra idatzi duzu.",
+       "config-optional-continue": "Galdera gehiago egin.",
+       "config-optional-skip": "Aspertuta nago, wikia instalatu bakarrik.",
        "config-profile-wiki": "Wikia ireki",
+       "config-profile-no-anon": "Kontua sortzea beharrezkoa da",
+       "config-profile-fishbowl": "Baimendutako editoreak bakarrik",
        "config-profile-private": "Wiki pribatua",
        "config-license": "Copyright eta lizentzia:",
+       "config-license-cc-by": "Creative Commons Aitorpena",
        "config-license-cc-0": "Creative Commons Zero (Jabari Publikoa)",
        "config-license-pd": "Domeinu Askea",
+       "config-license-cc-choose": "Aukeratu Creative Commons lizentzia pertsonalizatua",
        "config-email-settings": "E-posta hobespenak",
+       "config-upload-settings": "Irudi eta fitxategi igoerak",
+       "config-upload-enable": "Fitxategi igoera gaitu",
        "config-logo": "Logo URL:",
+       "config-instantcommons": "Instant Commons gaitu",
+       "config-cc-again": "Berriz aukeratu...",
        "config-advanced-settings": "Konfigurazio aurreratua",
        "config-extensions": "Luzapenak",
        "config-skins": "Itxurak",
        "config-install-step-done": "egina",
+       "config-install-extensions": "Luzapenak barne",
+       "config-install-database": "Datu-basea konfiguratu",
+       "config-install-schema": "Eskema sortu",
+       "config-install-user-alreadyexists": "\"$1\" erabiltzailea badago.",
+       "config-install-tables": "Taulak sortzen",
+       "config-install-interwiki-list": "Ezin izan da <code>interwiki.list</code> fitxategia irakurri.",
+       "config-install-stats": "Estatistikak hasten",
+       "config-install-keys": "Gako sekretuak sortzen",
+       "config-install-sysop": "Administratzaile kontua sortzen",
+       "config-download-localsettings": "Jaitsi <code>LocalSettings.php</code>",
        "config-help": "Laguntza",
+       "config-help-tooltip": "sakatu zabaltzeko",
        "mainpagetext": "'''MediaWiki arrakastaz instalatu da.'''",
        "mainpagedocfooter": "Ikus [//meta.wikimedia.org/wiki/Help:Contents Erabiltzaile Gida] wiki softwarea erabiltzen hasteko informazio gehiagorako.\n\n== Nola hasi ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Konfigurazio balioen zerrenda]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ (Maiz egindako galderak)]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWikiren argitalpenen posta zerrenda]"
 }
index ce15eac..17b5658 100644 (file)
@@ -1,5 +1,9 @@
 {
-       "@metadata": [],
+       "@metadata": {
+               "authors": [
+                       "Snævar"
+               ]
+       },
        "mainpagetext": "'''Uppsetning á MediaWiki heppnaðist.'''",
-       "mainpagedocfooter": "Ráðfærðu þig við [//meta.wikimedia.org/wiki/Help:Contents Notandahandbókina] fyrir frekari upplýsingar um notkun wiki-hugbúnaðarins.\n\n== Fyrir byrjendur ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Listi yfir uppsetningarstillingar]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki Algengar spurningar MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Póstlisti MediaWiki-útgáfa]"
+       "mainpagedocfooter": "Ráðfærðu þig við [//meta.wikimedia.org/wiki/Help:Contents Notandahandbókina] fyrir frekari upplýsingar um notkun wiki-hugbúnaðarins.\n\n== Fyrir byrjendur ==\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Listi yfir uppsetningarstillingar]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki Algengar spurningar MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Póstlisti MediaWiki-útgáfa]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Læra hvernig á að berjast við amapóst á þínum wiki]"
 }
index 76bfc04..5d4c5d7 100644 (file)
        "config-upload-deleted": "Папка за избришаните податотеки:",
        "config-upload-deleted-help": "Одберете во која папка да се архивираат избришаните податотеки.\nНајдобро би било ако таа не е достапна преку семрежјето.",
        "config-logo": "URL за логото:",
-       "config-logo-help": "Ð\9cаÑ\82иÑ\87ноÑ\82о Ñ\80Ñ\83во Ð½Ð° Ð\9cедиÑ\98аÐ\92ики Ð¸Ð¼Ð° Ð¿Ñ\80оÑ\81Ñ\82оÑ\80 Ð·Ð° Ð»Ð¾Ð³Ð¾ Ð¾Ð´ 135x160 Ð¿Ð¸ÐºÑ\81ели Ð½Ð°Ð´ Ñ\81Ñ\82Ñ\80аниÑ\87наÑ\82а Ð»ÐµÐ½Ñ\82а.\n\nМожете да употребите <code>$wgStylePath</code> или <code>$wgScriptPath</code> ако вашето лого е релативно на тие патеки.\n\nАко не сакате да имате лого, тогаш оставете го ова поле празно.",
+       "config-logo-help": "Ð\9cаÑ\82иÑ\87ноÑ\82о Ñ\80Ñ\83во Ð½Ð° Ð\9cедиÑ\98аÐ\92ики Ð¸Ð¼Ð° Ð¿Ñ\80оÑ\81Ñ\82оÑ\80 Ð·Ð° Ð»Ð¾Ð³Ð¾ Ð¾Ð´ 135x160 Ð¿Ð¸ÐºÑ\81ели Ð½Ð°Ð´ Ñ\81Ñ\82Ñ\80аниÑ\87никоÑ\82.\n\nМожете да употребите <code>$wgStylePath</code> или <code>$wgScriptPath</code> ако вашето лого е релативно на тие патеки.\n\nАко не сакате да имате лого, тогаш оставете го ова поле празно.",
        "config-instantcommons": "Овозможи Instant Commons",
        "config-instantcommons-help": "[//www.mediawiki.org/wiki/InstantCommons Instant Commons] е функција која им овозможува на викијата да користат слики, звучни записи и други мултимедијални содржини од [//commons.wikimedia.org/ Ризницата].\nЗа да може ова да работи, МедијаВики бара пристап до семрежјето.\n\nЗа повеќе информации за оваа функција и напатствија за нејзино поставување на вики (сите други освен Ризницата), коносултирајте го [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos прирачникот].",
        "config-cc-error": "Изборникот на лиценци од Криејтив комонс не даде резултати.\nВнесете го името на лиценцата рачно.",
        "config-install-tables": "Создавам табели",
        "config-install-tables-exist": "'''Предупредување''': Изгледа дека табелите за МедијаВики веќе постојат.\nГо прескокнувам создавањето.",
        "config-install-tables-failed": "'''Грешка''': Создавањето на табелата не успеа поради следнава грешка: $1",
-       "config-install-interwiki": "Ð\93и Ð¿Ð¾Ð¿Ð¾Ð»Ð½Ñ\83вам Ð¾Ñ\81новно Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸Ñ\82е Ð¼ÐµÑ\93Ñ\83вики-табели",
+       "config-install-interwiki": "Ð\93и Ð¿Ð¾Ð¿Ð¾Ð»Ð½Ñ\83вам Ð¾Ñ\81новно Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸Ñ\82е Ð¼ÐµÑ\93Ñ\83пÑ\80оекÑ\82ни табели",
        "config-install-interwiki-list": "Не можев да ја пронајдам податотеката <code>interwiki.list</code>.",
        "config-install-interwiki-exists": "'''Предупредување''': Табелата со интервикија веќе содржи ставки.\nГо прескокнувам основно-зададениот список.",
        "config-install-stats": "Ги подготвувам статистиките",
        "config-nofile": "Податотеката „$1“ не е пронајдена. Да не е избришана?",
        "config-extension-link": "Дали сте знаеле дека вашето вики поддржува [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions додатоци]?\n\nМожете да ги прелистате [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category по категории]",
        "mainpagetext": "'''МедијаВики е успешно воспоставен.'''",
-       "mainpagedocfooter": "Погледнете го [//meta.wikimedia.org/wiki/Help:Contents Упатството за корисници] за подетални иформации како се користи вики-програмот.\n\n==Од каде да почнете==\n* [//meta.wikimedia.org/wiki/Manual:Configuration_settings Список на нагодувања]\n* [//meta.wikimedia.org/wiki/Manual:FAQ ЧПП (често поставувани прашања) за МедијаВики].\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Поштенски список на МедијаВики за нови верзии]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Локализирајте го МедијаВики на вашиот јазик]"
+       "mainpagedocfooter": "Погледнете го [//meta.wikimedia.org/wiki/Help:Contents Упатството за корисници] за подетални иформации како се користи вики-програмот.\n\n==Од каде да почнете==\n* [//meta.wikimedia.org/wiki/Manual:Configuration_settings Список на нагодувања]\n* [//meta.wikimedia.org/wiki/Manual:FAQ ЧПП (често поставувани прашања) за МедијаВики].\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Поштенски список на МедијаВики за нови верзии]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Локализирајте го МедијаВики на вашиот јазик]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Дознајте како да се борите против спам на вашето вики]"
 }
index 6b3b8f2..33fa590 100644 (file)
@@ -13,7 +13,7 @@
        "config-continue": "اڳتي →",
        "config-page-language": "ٻولي",
        "config-page-welcome": "ذريعات‌وڪي تي ڀلي ڪري آيا!",
-       "config-page-dbconnect": "اعداد خاني سان جُڙو",
+       "config-page-dbconnect": "اعدادخاني سان جُڙو",
        "config-page-upgrade": "هاڻوڪي تنصيبڪاريءَ کي سڌاريو",
        "config-page-dbsettings": "اعدادخاني جون سيٽڱس",
        "config-page-name": "نالو",
index c4a230c..13cd520 100644 (file)
@@ -11,5 +11,5 @@
        "config-page-language": "Тел",
        "config-page-welcome": "MediaWiki проектына рәхим итегез!",
        "mainpagetext": "«MediaWiki» уңышлы куелды.",
-       "mainpagedocfooter": "Бу вики турында мәгълүматны [//meta.wikimedia.org/wiki/Help:Contents биредә] табып була.\n\n== Кайбер файдалы ресурслар ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Көйләнмәләр исемлеге (инг.)];\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki турында еш бирелгән сораулар һәм җаваплар (инг.)];\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki'ның яңа версияләре турында хәбәрләр яздырып алу];\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language]."
+       "mainpagedocfooter": "Бу вики турында мәгълүматны [//meta.wikimedia.org/wiki/Help:Contents биредә] табып була.\n\n== Кайбер файдалы ресурслар ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Көйләнмәләр исемлеге (инг.)];\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki турында еш бирелгән сораулар һәм җаваплар (инг.)];\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki'ның яңа версияләре турында хәбәрләр яздырып алу];\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Localise MediaWiki for your language].\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Learn how to combat spam on your wiki]"
 }
index 8abaa68..f77b211 100644 (file)
@@ -49,10 +49,15 @@ class SamplingStatsdClient extends StatsdClient {
                return $data;
        }
 
-       /**
+       /*
+        * Send the metrics over UDP
         * Sample the metrics according to their sample rate and send the remaining ones.
         *
-        * {@inheritDoc}
+        * @param StatsdDataInterface|StatsdDataInterface[] $data message(s) to sent
+        *        strings are not allowed here as sampleData requires a StatsdDataInterface
+        * @param int $sampleRate
+        *
+        * @return integer the data sent in bytes
         */
        public function send( $data, $sampleRate = 1 ) {
                if ( !is_array( $data ) ) {
@@ -74,12 +79,13 @@ class SamplingStatsdClient extends StatsdClient {
                }
                $data = $this->sampleData( $data );
 
-               $messages = array_map( 'strval', $data );
+               $data = array_map( 'strval', $data );
 
                // reduce number of packets
                if ( $this->getReducePacket() ) {
                        $data = $this->reduceCount( $data );
                }
+
                // failures in any of this should be silently ignored if ..
                $written = 0;
                try {
@@ -87,7 +93,7 @@ class SamplingStatsdClient extends StatsdClient {
                        if ( !$fp ) {
                                return;
                        }
-                       foreach ( $messages as $message ) {
+                       foreach ( $data as $message ) {
                                $written += $this->getSender()->write( $fp, $message );
                        }
                        $this->getSender()->close( $fp );
index 5cd57b7..4005abb 100644 (file)
@@ -115,6 +115,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
        const FLD_TTL = 2;
        const FLD_TIME = 3;
        const FLD_FLAGS = 4;
+       const FLD_HOLDOFF = 5;
 
        /** @var integer Treat this value as expired-on-arrival */
        const FLG_STALE = 1;
@@ -232,18 +233,18 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                $vPrefixLen = strlen( self::VALUE_KEY_PREFIX );
                $valueKeys = self::prefixCacheKeys( $keys, self::VALUE_KEY_PREFIX );
 
-               $checksForAll = array();
-               $checksByKey = array();
+               $checkKeysForAll = array();
+               $checkKeysByKey = array();
                $checkKeysFlat = array();
                foreach ( $checkKeys as $i => $keys ) {
                        $prefixed = self::prefixCacheKeys( (array)$keys, self::TIME_KEY_PREFIX );
                        $checkKeysFlat = array_merge( $checkKeysFlat, $prefixed );
                        // Is this check keys for a specific cache key, or for all keys being fetched?
                        if ( is_int( $i ) ) {
-                               $checksForAll = array_merge( $checksForAll, $prefixed );
+                               $checkKeysForAll = array_merge( $checkKeysForAll, $prefixed );
                        } else {
-                               $checksByKey[$i] = isset( $checksByKey[$i] )
-                                       ? array_merge( $checksByKey[$i], $prefixed )
+                               $checkKeysByKey[$i] = isset( $checkKeysByKey[$i] )
+                                       ? array_merge( $checkKeysByKey[$i], $prefixed )
                                        : $prefixed;
                        }
                }
@@ -253,10 +254,10 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                $now = microtime( true );
 
                // Collect timestamps from all "check" keys
-               $checkKeyTimesForAll = $this->processCheckKeys( $checksForAll, $wrappedValues, $now );
-               $checkKeyTimesByKey = array();
-               foreach ( $checksByKey as $cacheKey => $checks ) {
-                       $checkKeyTimesByKey[$cacheKey] =
+               $purgeValuesForAll = $this->processCheckKeys( $checkKeysForAll, $wrappedValues, $now );
+               $purgeValuesByKey = array();
+               foreach ( $checkKeysByKey as $cacheKey => $checks ) {
+                       $purgeValuesByKey[$cacheKey] =
                                $this->processCheckKeys( $checks, $wrappedValues, $now );
                }
 
@@ -274,14 +275,14 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
 
                                // Force dependant keys to be invalid for a while after purging
                                // to reduce race conditions involving stale data getting cached
-                               $checkKeyTimes = $checkKeyTimesForAll;
-                               if ( isset( $checkKeyTimesByKey[$key] ) ) {
-                                       $checkKeyTimes = array_merge( $checkKeyTimes, $checkKeyTimesByKey[$key] );
+                               $purgeValues = $purgeValuesForAll;
+                               if ( isset( $purgeValuesByKey[$key] ) ) {
+                                       $purgeValues = array_merge( $purgeValues, $purgeValuesByKey[$key] );
                                }
-                               foreach ( $checkKeyTimes as $checkKeyTime ) {
-                                       $safeTimestamp = $checkKeyTime + self::HOLDOFF_TTL;
+                               foreach ( $purgeValues as $purge ) {
+                                       $safeTimestamp = $purge[self::FLD_TIME] + $purge[self::FLD_HOLDOFF];
                                        if ( $safeTimestamp >= $wrappedValues[$vKey][self::FLD_TIME] ) {
-                                               $curTTL = min( $curTTL, $checkKeyTime - $now );
+                                               $curTTL = min( $curTTL, $purge[self::FLD_TIME] - $now );
                                        }
                                }
                        }
@@ -296,22 +297,25 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         * @param array $timeKeys List of prefixed time check keys
         * @param array $wrappedValues
         * @param float $now
-        * @return array List of timestamps
+        * @return array List of purge value arrays
         */
        private function processCheckKeys( array $timeKeys, array $wrappedValues, $now ) {
-               $times = array();
+               $purgeValues = array();
                foreach ( $timeKeys as $timeKey ) {
-                       $timestamp = isset( $wrappedValues[$timeKey] )
+                       $purge = isset( $wrappedValues[$timeKey] )
                                ? self::parsePurgeValue( $wrappedValues[$timeKey] )
                                : false;
-                       if ( !is_float( $timestamp ) ) {
+                       if ( $purge === false ) {
                                // Key is not set or invalid; regenerate
-                               $this->cache->add( $timeKey, self::PURGE_VAL_PREFIX . $now, self::CHECK_KEY_TTL );
-                               $timestamp = $now;
+                               $this->cache->add( $timeKey,
+                                       $this->makePurgeValue( $now, self::HOLDOFF_TTL ),
+                                       self::CHECK_KEY_TTL
+                               );
+                               $purge = array( self::FLD_TIME => $now, self::FLD_HOLDOFF => self::HOLDOFF_TTL );
                        }
-                       $times[] = $timestamp;
+                       $purgeValues[] = $purge;
                }
-               return $times;
+               return $purgeValues;
        }
 
        /**
@@ -479,9 +483,12 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                        $ok = $this->relayDelete( $key ) && $ok;
                } else {
                        // Update the local datacenter immediately
-                       $ok = $this->cache->set( $key, self::PURGE_VAL_PREFIX . microtime( true ), $ttl );
+                       $ok = $this->cache->set( $key,
+                               $this->makePurgeValue( microtime( true ), self::HOLDOFF_NONE ),
+                               $ttl
+                       );
                        // Publish the purge to all datacenters
-                       $ok = $this->relayPurge( $key, $ttl ) && $ok;
+                       $ok = $this->relayPurge( $key, $ttl, self::HOLDOFF_NONE ) && $ok;
                }
 
                return $ok;
@@ -504,17 +511,22 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         * Note that "check" keys won't collide with other regular keys.
         *
         * @param string $key
-        * @return float UNIX timestamp of the key
+        * @return float UNIX timestamp of the check key
         */
        final public function getCheckKeyTime( $key ) {
                $key = self::TIME_KEY_PREFIX . $key;
 
-               $time = self::parsePurgeValue( $this->cache->get( $key ) );
-               if ( $time === false ) {
+               $purge = self::parsePurgeValue( $this->cache->get( $key ) );
+               if ( $purge !== false ) {
+                       $time = $purge[self::FLD_TIME];
+               } else {
                        // Casting assures identical floats for the next getCheckKeyTime() calls
-                       $time = (string)microtime( true );
-                       $this->cache->add( $key, self::PURGE_VAL_PREFIX . $time, self::CHECK_KEY_TTL );
-                       $time = (float)$time;
+                       $now = (string)microtime( true );
+                       $this->cache->add( $key,
+                               $this->makePurgeValue( $now, self::HOLDOFF_TTL ),
+                               self::CHECK_KEY_TTL
+                       );
+                       $time = (float)$now;
                }
 
                return $time;
@@ -548,15 +560,18 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         * @see WANObjectCache::resetCheckKey()
         *
         * @param string $key Cache key
+        * @param int $holdoff HOLDOFF_TTL or HOLDOFF_NONE constant
         * @return bool True if the item was purged or not found, false on failure
         */
-       final public function touchCheckKey( $key ) {
+       final public function touchCheckKey( $key, $holdoff = self::HOLDOFF_TTL ) {
                $key = self::TIME_KEY_PREFIX . $key;
                // Update the local datacenter immediately
                $ok = $this->cache->set( $key,
-                       self::PURGE_VAL_PREFIX . microtime( true ), self::CHECK_KEY_TTL );
+                       $this->makePurgeValue( microtime( true ), $holdoff ),
+                       self::CHECK_KEY_TTL
+               );
                // Publish the purge to all datacenters
-               return $this->relayPurge( $key, self::CHECK_KEY_TTL ) && $ok;
+               return $this->relayPurge( $key, self::CHECK_KEY_TTL, $holdoff ) && $ok;
        }
 
        /**
@@ -904,17 +919,18 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
        /**
         * Do the actual async bus purge of a key
         *
-        * This must set the key to "PURGED:<UNIX timestamp>"
+        * This must set the key to "PURGED:<UNIX timestamp>:<holdoff>"
         *
         * @param string $key Cache key
         * @param integer $ttl How long to keep the tombstone [seconds]
+        * @param integer $holdoff HOLDOFF_* constant controlling how long to ignore sets for this key
         * @return bool Success
         */
-       protected function relayPurge( $key, $ttl ) {
+       protected function relayPurge( $key, $ttl, $holdoff ) {
                $event = $this->cache->modifySimpleRelayEvent( array(
                        'cmd' => 'set',
                        'key' => $key,
-                       'val' => 'PURGED:$UNIXTIME$',
+                       'val' => 'PURGED:$UNIXTIME$:' . (int)$holdoff,
                        'ttl' => max( $ttl, 1 ),
                        'sbt' => true, // substitute $UNIXTIME$ with actual microtime
                ) );
@@ -996,10 +1012,10 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         */
        protected function unwrap( $wrapped, $now ) {
                // Check if the value is a tombstone
-               $purgeTimestamp = self::parsePurgeValue( $wrapped );
-               if ( is_float( $purgeTimestamp ) ) {
+               $purge = self::parsePurgeValue( $wrapped );
+               if ( $purge !== false ) {
                        // Purged values should always have a negative current $ttl
-                       $curTTL = min( $purgeTimestamp - $now, self::TINY_NEGATIVE );
+                       $curTTL = min( $purge[self::FLD_TIME] - $now, self::TINY_NEGATIVE );
                        return array( false, $curTTL );
                }
 
@@ -1042,17 +1058,36 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
        }
 
        /**
-        * @param string $value String like "PURGED:<timestamp>"
-        * @return float|bool UNIX timestamp or false on failure
+        * @param string $value Wrapped value like "PURGED:<timestamp>:<holdoff>"
+        * @return array|bool Array containing a UNIX timestamp (float) and holdoff period (integer),
+        *  or false if value isn't a valid purge value
         */
        protected static function parsePurgeValue( $value ) {
-               $m = array();
-               if ( is_string( $value ) &&
-                       preg_match( '/^' . self::PURGE_VAL_PREFIX . '([^:]+)$/', $value, $m )
+               if ( !is_string( $value ) ) {
+                       return false;
+               }
+               $segments = explode( ':', $value, 3 );
+               if ( !isset( $segments[0] ) || !isset( $segments[1] )
+                       || "{$segments[0]}:" !== self::PURGE_VAL_PREFIX
                ) {
-                       return (float)$m[1];
-               } else {
                        return false;
                }
+               if ( !isset( $segments[2] ) ) {
+                       // Back-compat with old purge values without holdoff
+                       $segments[2] = self::HOLDOFF_TTL;
+               }
+               return array(
+                       self::FLD_TIME => (float)$segments[1],
+                       self::FLD_HOLDOFF => (int)$segments[2],
+               );
+       }
+
+       /**
+        * @param float $timestamp
+        * @param int $holdoff In seconds
+        * @return string Wrapped purge value
+        */
+       protected static function makePurgeValue( $timestamp, $holdoff ) {
+               return self::PURGE_VAL_PREFIX . (float)$timestamp . ':' . (int)$holdoff;
        }
 }
index 08e4885..8177371 100644 (file)
@@ -232,7 +232,7 @@ abstract class Skin extends ContextSource {
                $title = $this->getRelevantTitle();
 
                // User/talk link
-               if ( $user->isLoggedIn() || $this->showIPinHeader() ) {
+               if ( $user->isLoggedIn() ) {
                        $titles[] = $user->getUserPage();
                        $titles[] = $user->getTalkPage();
                }
@@ -725,12 +725,12 @@ abstract class Skin extends ContextSource {
        }
 
        /**
-        * Returns true if the IP should be shown in the header
-        * @return bool
+        * @deprecated since 1.27, feature removed
+        * @return bool Always false
         */
        function showIPinHeader() {
-               global $wgShowIPinHeader;
-               return $wgShowIPinHeader && session_id() != '';
+               wfDeprecated( __METHOD__, '1.27' );
+               return false;
        }
 
        /**
index 4d7c03a..163f3d5 100644 (file)
@@ -207,7 +207,7 @@ class SkinTemplate extends Skin {
                $this->loggedin = $user->isLoggedIn();
                $this->username = $user->getName();
 
-               if ( $this->loggedin || $this->showIPinHeader() ) {
+               if ( $this->loggedin ) {
                        $this->userpageUrlDetails = self::makeUrlDetails( $this->userpage );
                } else {
                        # This won't be used in the standard skins, but we define it to preserve the interface
@@ -660,21 +660,28 @@ class SkinTemplate extends Skin {
                                'active' => $title->isSpecial( 'Userlogin' ) && $is_signup,
                        );
 
-                       if ( $this->showIPinHeader() ) {
-                               $href = &$this->userpageUrlDetails['href'];
+                       // No need to show Talk and Contributions to anons if they can't contribute!
+                       if ( User::groupHasPermission( '*', 'edit' ) ) {
+                               // Show the text "Not logged in"
                                $personal_urls['anonuserpage'] = array(
-                                       'text' => $this->username,
-                                       'href' => $href,
-                                       'class' => $this->userpageUrlDetails['exists'] ? false : 'new',
-                                       'active' => ( $pageurl == $href )
+                                       'text' => $this->msg( 'notloggedin' )->text()
                                );
-                               $usertalkUrlDetails = $this->makeTalkUrlDetails( $this->userpage );
-                               $href = &$usertalkUrlDetails['href'];
+
+                               // Because of caching, we can't link directly to the IP talk and
+                               // contributions pages. Instead we use the special page shortcuts
+                               // (which work correctly regardless of caching). This means we can't
+                               // determine whether these links are active or not, but since major
+                               // skins (MonoBook, Vector) don't use this information, it's not a
+                               // huge loss.
                                $personal_urls['anontalk'] = array(
                                        'text' => $this->msg( 'anontalk' )->text(),
-                                       'href' => $href,
-                                       'class' => $usertalkUrlDetails['exists'] ? false : 'new',
-                                       'active' => ( $pageurl == $href )
+                                       'href' => self::makeSpecialUrlSubpage( 'Mytalk', false ),
+                                       'active' => false
+                               );
+                               $personal_urls['anoncontribs'] = array(
+                                       'text' => $this->msg( 'anoncontribs' )->text(),
+                                       'href' => self::makeSpecialUrlSubpage( 'Mycontributions', false ),
+                                       'active' => false
                                );
                        }
 
index 81668e1..5f7c587 100644 (file)
@@ -517,8 +517,13 @@ class SpecialContributions extends IncludableSpecialPage {
                                        'mw-ui-input-inline',
                                        'mw-autocomplete-user', // used by mediawiki.userSuggest
                                ),
-                       ) + ( $this->opts['target'] ? array() : array( 'autofocus' ) )
+                       ) + (
+                               // Only autofocus if target hasn't been specified or in non-newbies mode
+                               ( $this->opts['contribs'] === 'newbie' || $this->opts['target'] )
+                                       ? array() : array( 'autofocus' => true )
+                               )
                );
+
                $targetSelection = Html::rawElement(
                        'td',
                        array( 'colspan' => 2 ),
index 9133a88..e9fb75b 100644 (file)
@@ -146,6 +146,25 @@ class MovePageForm extends UnlistedSpecialPage {
                $out->addModuleStyles( 'mediawiki.special.movePage.styles' );
                $this->addHelpLink( 'Help:Moving a page' );
 
+               if ( $this->oldTitle->getNamespace() == NS_USER && !$this->oldTitle->isSubpage() ) {
+                       $out->wrapWikiMsg(
+                               "<div class=\"error mw-moveuserpage-warning\">\n$1\n</div>",
+                               'moveuserpage-warning'
+                       );
+               } elseif ( $this->oldTitle->getNamespace() == NS_CATEGORY ) {
+                       $out->wrapWikiMsg(
+                               "<div class=\"error mw-movecategorypage-warning\">\n$1\n</div>",
+                               'movecategorypage-warning'
+                       );
+               }
+
+               $out->addWikiMsg( $this->getConfig()->get( 'FixDoubleRedirects' ) ?
+                       'movepagetext' :
+                       'movepagetext-noredirectfixer'
+               );
+               $submitVar = 'wpMove';
+               $confirm = false;
+
                $newTitle = $this->newTitle;
 
                if ( !$newTitle ) {
@@ -168,30 +187,9 @@ class MovePageForm extends UnlistedSpecialPage {
                        && $newTitle->quickUserCan( 'delete', $user )
                ) {
                        $out->addWikiMsg( 'delete_and_move_text', $newTitle->getPrefixedText() );
-                       $movepagebtn = $this->msg( 'delete_and_move' )->text();
                        $submitVar = 'wpDeleteAndMove';
                        $confirm = true;
                        $err = array();
-               } else {
-                       if ( $this->oldTitle->getNamespace() == NS_USER && !$this->oldTitle->isSubpage() ) {
-                               $out->wrapWikiMsg(
-                                       "<div class=\"error mw-moveuserpage-warning\">\n$1\n</div>",
-                                       'moveuserpage-warning'
-                               );
-                       } elseif ( $this->oldTitle->getNamespace() == NS_CATEGORY ) {
-                               $out->wrapWikiMsg(
-                                       "<div class=\"error mw-movecategorypage-warning\">\n$1\n</div>",
-                                       'movecategorypage-warning'
-                               );
-                       }
-
-                       $out->addWikiMsg( $this->getConfig()->get( 'FixDoubleRedirects' ) ?
-                               'movepagetext' :
-                               'movepagetext-noredirectfixer'
-                       );
-                       $movepagebtn = $this->msg( 'movepagebtn' )->text();
-                       $submitVar = 'wpMove';
-                       $confirm = false;
                }
 
                if ( count( $err ) == 1 && isset( $err[0][0] ) && $err[0][0] == 'file-exists-sharedrepo'
@@ -446,8 +444,8 @@ class MovePageForm extends UnlistedSpecialPage {
                $fields[] = new OOUI\FieldLayout(
                        new OOUI\ButtonInputWidget( array(
                                'name' => $submitVar,
-                               'value' => $movepagebtn,
-                               'label' => $movepagebtn,
+                               'value' => $this->msg( 'movepagebtn' )->text(),
+                               'label' => $this->msg( 'movepagebtn' )->text(),
                                'flags' => array( 'constructive', 'primary' ),
                                'type' => 'submit',
                        ) ),
index 447c3ef..664205a 100644 (file)
@@ -636,8 +636,7 @@ class PageArchive {
                Hooks::run( 'ArticleUndelete', array( &$this->title, $created, $comment, $oldPageId ) );
 
                if ( $this->title->getNamespace() == NS_FILE ) {
-                       $update = new HTMLCacheUpdate( $this->title, 'imagelinks' );
-                       $update->doUpdate();
+                       DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this->title, 'imagelinks' ) );
                }
 
                return Status::newGood( $restored );
index a6fe1b5..1327972 100644 (file)
@@ -458,8 +458,10 @@ class UserrightsPage extends SpecialPage {
                                30,
                                str_replace( '_', ' ', $this->mTarget ),
                                array(
-                                       'autofocus' => '',
                                        'class' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
+                               ) + (
+                                       // Set autofocus on blank input and error input
+                                       $this->mFetchedUser === null ? array( 'autofocus' => '' ) : array()
                                )
                        ) . ' ' .
                        Xml::submitButton( $this->msg( 'editusergroup' )->text() ) .
diff --git a/includes/user/CentralIdLookup.php b/includes/user/CentralIdLookup.php
new file mode 100644 (file)
index 0000000..638a3e2
--- /dev/null
@@ -0,0 +1,208 @@
+<?php
+/**
+ * A central user id lookup service
+ *
+ * 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
+ */
+
+/**
+ * The CentralIdLookup service allows for connecting local users with
+ * cluster-wide IDs.
+ */
+abstract class CentralIdLookup implements IDBAccessObject {
+       // Audience options for accessors
+       const AUDIENCE_PUBLIC = 1;
+       const AUDIENCE_RAW = 2;
+
+       /** @var CentralIdLookup[][] */
+       private static $instances = array();
+
+       /** @var string */
+       private $providerId;
+
+       /**
+        * Fetch a CentralIdLookup
+        * @param string|null $providerId Provider ID from $wgCentralIdLookupProviders
+        * @return CentralIdLookup|null
+        */
+       public static function factory( $providerId = null ) {
+               global $wgCentralIdLookupProviders, $wgCentralIdLookupProvider;
+
+               if ( $providerId === null ) {
+                       $providerId = $wgCentralIdLookupProvider;
+               }
+
+               if ( !array_key_exists( $providerId, self::$instances ) ) {
+                       self::$instances[$providerId] = null;
+
+                       if ( isset( $wgCentralIdLookupProviders[$providerId] ) ) {
+                               $provider = ObjectFactory::getObjectFromSpec( $wgCentralIdLookupProviders[$providerId] );
+                               if ( $provider instanceof CentralIdLookup ) {
+                                       $provider->providerId = $providerId;
+                                       self::$instances[$providerId] = $provider;
+                               }
+                       }
+               }
+
+               return self::$instances[$providerId];
+       }
+
+       final public function getProviderId() {
+               return $this->providerId;
+       }
+
+       /**
+        * Check that the "audience" parameter is valid
+        * @param int|User $audience One of the audience constants, or a specific user
+        * @return User|null User to check against, or null if no checks are needed
+        * @throws InvalidArgumentException
+        */
+       protected function checkAudience( $audience ) {
+               if ( $audience instanceof User ) {
+                       return $audience;
+               }
+               if ( $audience === self::AUDIENCE_PUBLIC ) {
+                       return new User;
+               }
+               if ( $audience === self::AUDIENCE_RAW ) {
+                       return null;
+               }
+               throw new InvalidArgumentException( 'Invalid audience' );
+       }
+
+       /**
+        * Check that a User is attached on the specified wiki.
+        *
+        * If unattached local accounts don't exist in your extension, this comes
+        * down to a check whether the central account exists at all and that
+        * $wikiId is using the same central database.
+        *
+        * @param User $user
+        * @param string|null $wikiId Wiki to check attachment status. If null, check the current wiki.
+        * @return bool
+        */
+       abstract public function isAttached( User $user, $wikiId = null );
+
+       /**
+        * Given central user IDs, return the (local) user names
+        * @note There's no requirement that the user names actually exist locally,
+        *  or if they do that they're actually attached to the central account.
+        * @param array $idToName Array with keys being central user IDs
+        * @param int|User $audience One of the audience constants, or a specific user
+        * @param int $flags IDBAccessObject read flags
+        * @return array Copy of $idToName with values set to user names (or
+        *  empty-string if the user exists but $audience lacks the rights needed
+        *  to see it). IDs not corresponding to a user are unchanged.
+        */
+       abstract public function lookupCentralIds(
+               array $idToName, $audience = self::AUDIENCE_PUBLIC, $flags = self::READ_NORMAL
+       );
+
+       /**
+        * Given (local) user names, return the central IDs
+        * @note There's no requirement that the user names actually exist locally,
+        *  or if they do that they're actually attached to the central account.
+        * @param array $nameToId Array with keys being canonicalized user names
+        * @param int|User $audience One of the audience constants, or a specific user
+        * @param int $flags IDBAccessObject read flags
+        * @return array Copy of $nameToId with values set to central IDs.
+        *  Names not corresponding to a user (or $audience lacks the rights needed
+        *  to see it) are unchanged.
+        */
+       abstract public function lookupUserNames(
+               array $nameToId, $audience = self::AUDIENCE_PUBLIC, $flags = self::READ_NORMAL
+       );
+
+       /**
+        * Given a central user ID, return the (local) user name
+        * @note There's no requirement that the user name actually exists locally,
+        *  or if it does that it's actually attached to the central account.
+        * @param int $id Central user ID
+        * @param int|User $audience One of the audience constants, or a specific user
+        * @param int $flags IDBAccessObject read flags
+        * @return string|null User name, or empty string if $audience lacks the
+        *  rights needed to see it, or null if $id doesn't correspond to a user
+        */
+       public function nameFromCentralId(
+               $id, $audience = self::AUDIENCE_PUBLIC, $flags = self::READ_NORMAL
+       ) {
+               $idToName = $this->lookupCentralIds( array( $id => null ), $audience, $flags );
+               return $idToName[$id];
+       }
+
+       /**
+        * Given a (local) user name, return the central ID
+        * @note There's no requirement that the user name actually exists locally,
+        *  or if it does that it's actually attached to the central account.
+        * @param string $name Canonicalized user name
+        * @param int|User $audience One of the audience constants, or a specific user
+        * @param int $flags IDBAccessObject read flags
+        * @return int User ID; 0 if the name does not correspond to a user or
+        *  $audience lacks the rights needed to see it.
+        */
+       public function centralIdFromName(
+               $name, $audience = self::AUDIENCE_PUBLIC, $flags = self::READ_NORMAL
+       ) {
+               $nameToId = $this->lookupUserNames( array( $name => 0 ), $audience, $flags );
+               return $nameToId[$name];
+       }
+
+       /**
+        * Given a central user ID, return a local User object
+        * @note Unlike nameFromCentralId(), this does guarantee that the local
+        *  user exists and is attached to the central account.
+        * @param int $id Central user ID
+        * @param int|User $audience One of the audience constants, or a specific user
+        * @param int $flags IDBAccessObject read flags
+        * @return User|null Local user, or null if: $id doesn't correspond to a
+        *  user, $audience lacks the rights needed to see the user, the user
+        *  doesn't exist locally, or the user isn't locally attached.
+        */
+       public function localUserFromCentralId(
+               $id, $audience = self::AUDIENCE_PUBLIC, $flags = self::READ_NORMAL
+       ) {
+               $name = $this->nameFromCentralId( $id, $audience, $flags );
+               if ( $name !== null && $name !== '' ) {
+                       $user = User::newFromName( $name );
+                       if ( $user && $user->getId() && $this->isAttached( $user ) ) {
+                               return $user;
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Given a local User object, return the central ID
+        * @note Unlike centralIdFromName(), this does guarantee that the local
+        *  user is attached to the central account.
+        * @param User $user Local user
+        * @param int|User $audience One of the audience constants, or a specific user
+        * @param int $flags IDBAccessObject read flags
+        * @return int User ID; 0 if the local user does not correspond to a
+        *  central user, $audience lacks the rights needed to see it, or the
+        *  central user isn't locally attached.
+        */
+       public function centralIdFromLocalUser(
+               User $user, $audience = self::AUDIENCE_PUBLIC, $flags = self::READ_NORMAL
+       ) {
+               return $this->isAttached( $user )
+                       ? $this->centralIdFromName( $user->getName(), $audience, $flags )
+                       : 0;
+       }
+
+}
diff --git a/includes/user/LocalIdLookup.php b/includes/user/LocalIdLookup.php
new file mode 100644 (file)
index 0000000..04c5b90
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+/**
+ * A central user id lookup service implementation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * A CentralIdLookup provider that just uses local IDs. Useful if the wiki
+ * isn't part of a cluster or you're using shared user tables.
+ *
+ * @note Shared user table support expects that all wikis involved have
+ *  $wgSharedDB and $wgSharedTables set, and that all wikis involved in the
+ *  sharing are listed in $wgLocalDatabases, and that no wikis not involved in
+ *  the sharing are listed in $wgLocalDatabases.
+ */
+class LocalIdLookup extends CentralIdLookup {
+
+       public function isAttached( User $user, $wikiId = null ) {
+               global $wgSharedDB, $wgSharedTables, $wgLocalDatabases;
+
+               // If the user has no ID, it can't be attached
+               if ( !$user->getId() ) {
+                       return false;
+               }
+
+               // Easy case, we're checking locally
+               if ( $wikiId === null || $wikiId === wfWikiId() ) {
+                       return true;
+               }
+
+               // Assume that shared user tables are set up as described above, if
+               // they're being used at all.
+               return $wgSharedDB !== null &&
+                       in_array( 'user', $wgSharedTables, true ) &&
+                       in_array( $wikiId, $wgLocalDatabases, true );
+       }
+
+       public function lookupCentralIds(
+               array $idToName, $audience = self::AUDIENCE_PUBLIC, $flags = self::READ_NORMAL
+       ) {
+               if ( !$idToName ) {
+                       return array();
+               }
+
+               $audience = $this->checkAudience( $audience );
+               $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_SLAVE );
+               $options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
+                       ? array( 'LOCK IN SHARE MODE' )
+                       : array();
+
+               $tables = array( 'user' );
+               $fields = array( 'user_id', 'user_name' );
+               $where = array(
+                       'user_id' => array_map( 'intval', array_keys( $idToName ) ),
+               );
+               $join = array();
+               if ( $audience && !$audience->isAllowed( 'hideuser' ) ) {
+                       $tables[] = 'ipblocks';
+                       $join['ipblocks'] = array( 'LEFT JOIN', 'ipb_user=user_id' );
+                       $fields[] = 'ipb_deleted';
+               }
+
+               $res = $db->select( $tables, $fields, $where, __METHOD__, $options, $join );
+               foreach ( $res as $row ) {
+                       $idToName[$row->user_id] = empty( $row->ipb_deleted ) ? $row->user_name : '';
+               }
+
+               return $idToName;
+       }
+
+       public function lookupUserNames(
+               array $nameToId, $audience = self::AUDIENCE_PUBLIC, $flags = self::READ_NORMAL
+       ) {
+               if ( !$nameToId ) {
+                       return array();
+               }
+
+               $audience = $this->checkAudience( $audience );
+               $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_SLAVE );
+               $options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
+                       ? array( 'LOCK IN SHARE MODE' )
+                       : array();
+
+               $tables = array( 'user' );
+               $fields = array( 'user_id', 'user_name' );
+               $where = array(
+                       'user_name' => array_map( 'strval', array_keys( $nameToId ) ),
+               );
+               $join = array();
+               if ( $audience && !$audience->isAllowed( 'hideuser' ) ) {
+                       $tables[] = 'ipblocks';
+                       $join['ipblocks'] = array( 'LEFT JOIN', 'ipb_user=user_id' );
+                       $where[] = 'ipb_deleted = 0 OR ipb_deleted IS NULL';
+               }
+
+               $res = $db->select( $tables, $fields, $where, __METHOD__, $options, $join );
+               foreach ( $res as $row ) {
+                       $nameToId[$row->user_name] = (int)$row->user_id;
+               }
+
+               return $nameToId;
+       }
+}
diff --git a/includes/user/User.php b/includes/user/User.php
new file mode 100644 (file)
index 0000000..3d1aa7e
--- /dev/null
@@ -0,0 +1,5334 @@
+<?php
+/**
+ * Implements the User class for the %MediaWiki software.
+ *
+ * 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
+ */
+
+/**
+ * String Some punctuation to prevent editing from broken text-mangling proxies.
+ * @ingroup Constants
+ */
+define( 'EDIT_TOKEN_SUFFIX', '+\\' );
+
+/**
+ * The User object encapsulates all of the user-specific settings (user_id,
+ * name, rights, email address, options, last login time). Client
+ * classes use the getXXX() functions to access these fields. These functions
+ * do all the work of determining whether the user is logged in,
+ * whether the requested option can be satisfied from cookies or
+ * whether a database query is needed. Most of the settings needed
+ * for rendering normal pages are set in the cookie to minimize use
+ * of the database.
+ */
+class User implements IDBAccessObject {
+       /**
+        * @const int Number of characters in user_token field.
+        */
+       const TOKEN_LENGTH = 32;
+
+       /**
+        * Global constant made accessible as class constants so that autoloader
+        * magic can be used.
+        */
+       const EDIT_TOKEN_SUFFIX = EDIT_TOKEN_SUFFIX;
+
+       /**
+        * @const int Serialized record version.
+        */
+       const VERSION = 10;
+
+       /**
+        * Maximum items in $mWatchedItems
+        */
+       const MAX_WATCHED_ITEMS_CACHE = 100;
+
+       /**
+        * Exclude user options that are set to their default value.
+        * @since 1.25
+        */
+       const GETOPTIONS_EXCLUDE_DEFAULTS = 1;
+
+       /**
+        * Array of Strings List of member variables which are saved to the
+        * shared cache (memcached). Any operation which changes the
+        * corresponding database fields must call a cache-clearing function.
+        * @showinitializer
+        */
+       protected static $mCacheVars = array(
+               // user table
+               'mId',
+               'mName',
+               'mRealName',
+               'mEmail',
+               'mTouched',
+               'mToken',
+               'mEmailAuthenticated',
+               'mEmailToken',
+               'mEmailTokenExpires',
+               'mRegistration',
+               'mEditCount',
+               // user_groups table
+               'mGroups',
+               // user_properties table
+               'mOptionOverrides',
+       );
+
+       /**
+        * Array of Strings Core rights.
+        * Each of these should have a corresponding message of the form
+        * "right-$right".
+        * @showinitializer
+        */
+       protected static $mCoreRights = array(
+               'apihighlimits',
+               'applychangetags',
+               'autoconfirmed',
+               'autopatrol',
+               'bigdelete',
+               'block',
+               'blockemail',
+               'bot',
+               'browsearchive',
+               'changetags',
+               'createaccount',
+               'createpage',
+               'createtalk',
+               'delete',
+               'deletedhistory',
+               'deletedtext',
+               'deletelogentry',
+               'deleterevision',
+               'edit',
+               'editcontentmodel',
+               'editinterface',
+               'editprotected',
+               'editmyoptions',
+               'editmyprivateinfo',
+               'editmyusercss',
+               'editmyuserjs',
+               'editmywatchlist',
+               'editsemiprotected',
+               'editusercssjs', # deprecated
+               'editusercss',
+               'edituserjs',
+               'hideuser',
+               'import',
+               'importupload',
+               'ipblock-exempt',
+               'managechangetags',
+               'markbotedits',
+               'mergehistory',
+               'minoredit',
+               'move',
+               'movefile',
+               'move-categorypages',
+               'move-rootuserpages',
+               'move-subpages',
+               'nominornewtalk',
+               'noratelimit',
+               'override-export-depth',
+               'pagelang',
+               'passwordreset',
+               'patrol',
+               'patrolmarks',
+               'protect',
+               'proxyunbannable',
+               'purge',
+               'read',
+               'reupload',
+               'reupload-own',
+               'reupload-shared',
+               'rollback',
+               'sendemail',
+               'siteadmin',
+               'suppressionlog',
+               'suppressredirect',
+               'suppressrevision',
+               'unblockself',
+               'undelete',
+               'unwatchedpages',
+               'upload',
+               'upload_by_url',
+               'userrights',
+               'userrights-interwiki',
+               'viewmyprivateinfo',
+               'viewmywatchlist',
+               'viewsuppressed',
+               'writeapi',
+       );
+
+       /**
+        * String Cached results of getAllRights()
+        */
+       protected static $mAllRights = false;
+
+       /** Cache variables */
+       // @{
+       public $mId;
+       /** @var string */
+       public $mName;
+       /** @var string */
+       public $mRealName;
+
+       /** @var string */
+       public $mEmail;
+       /** @var string TS_MW timestamp from the DB */
+       public $mTouched;
+       /** @var string TS_MW timestamp from cache */
+       protected $mQuickTouched;
+       /** @var string */
+       protected $mToken;
+       /** @var string */
+       public $mEmailAuthenticated;
+       /** @var string */
+       protected $mEmailToken;
+       /** @var string */
+       protected $mEmailTokenExpires;
+       /** @var string */
+       protected $mRegistration;
+       /** @var int */
+       protected $mEditCount;
+       /** @var array */
+       public $mGroups;
+       /** @var array */
+       protected $mOptionOverrides;
+       // @}
+
+       /**
+        * Bool Whether the cache variables have been loaded.
+        */
+       // @{
+       public $mOptionsLoaded;
+
+       /**
+        * Array with already loaded items or true if all items have been loaded.
+        */
+       protected $mLoadedItems = array();
+       // @}
+
+       /**
+        * String Initialization data source if mLoadedItems!==true. May be one of:
+        *  - 'defaults'   anonymous user initialised from class defaults
+        *  - 'name'       initialise from mName
+        *  - 'id'         initialise from mId
+        *  - 'session'    log in from cookies or session if possible
+        *
+        * Use the User::newFrom*() family of functions to set this.
+        */
+       public $mFrom;
+
+       /**
+        * Lazy-initialized variables, invalidated with clearInstanceCache
+        */
+       protected $mNewtalk;
+       /** @var string */
+       protected $mDatePreference;
+       /** @var string */
+       public $mBlockedby;
+       /** @var string */
+       protected $mHash;
+       /** @var array */
+       public $mRights;
+       /** @var string */
+       protected $mBlockreason;
+       /** @var array */
+       protected $mEffectiveGroups;
+       /** @var array */
+       protected $mImplicitGroups;
+       /** @var array */
+       protected $mFormerGroups;
+       /** @var bool */
+       protected $mBlockedGlobally;
+       /** @var bool */
+       protected $mLocked;
+       /** @var bool */
+       public $mHideName;
+       /** @var array */
+       public $mOptions;
+
+       /**
+        * @var WebRequest
+        */
+       private $mRequest;
+
+       /** @var Block */
+       public $mBlock;
+
+       /** @var bool */
+       protected $mAllowUsertalk;
+
+       /** @var Block */
+       private $mBlockedFromCreateAccount = false;
+
+       /** @var array */
+       private $mWatchedItems = array();
+
+       /** @var integer User::READ_* constant bitfield used to load data */
+       protected $queryFlagsUsed = self::READ_NORMAL;
+
+       public static $idCacheByName = array();
+
+       /**
+        * Lightweight constructor for an anonymous user.
+        * Use the User::newFrom* factory functions for other kinds of users.
+        *
+        * @see newFromName()
+        * @see newFromId()
+        * @see newFromConfirmationCode()
+        * @see newFromSession()
+        * @see newFromRow()
+        */
+       public function __construct() {
+               $this->clearInstanceCache( 'defaults' );
+       }
+
+       /**
+        * @return string
+        */
+       public function __toString() {
+               return $this->getName();
+       }
+
+       /**
+        * Load the user table data for this object from the source given by mFrom.
+        *
+        * @param integer $flags User::READ_* constant bitfield
+        */
+       public function load( $flags = self::READ_NORMAL ) {
+               if ( $this->mLoadedItems === true ) {
+                       return;
+               }
+
+               // Set it now to avoid infinite recursion in accessors
+               $this->mLoadedItems = true;
+               $this->queryFlagsUsed = $flags;
+
+               switch ( $this->mFrom ) {
+                       case 'defaults':
+                               $this->loadDefaults();
+                               break;
+                       case 'name':
+                               // Make sure this thread sees its own changes
+                               if ( wfGetLB()->hasOrMadeRecentMasterChanges() ) {
+                                       $flags |= self::READ_LATEST;
+                                       $this->queryFlagsUsed = $flags;
+                               }
+
+                               $this->mId = self::idFromName( $this->mName, $flags );
+                               if ( !$this->mId ) {
+                                       // Nonexistent user placeholder object
+                                       $this->loadDefaults( $this->mName );
+                               } else {
+                                       $this->loadFromId( $flags );
+                               }
+                               break;
+                       case 'id':
+                               $this->loadFromId( $flags );
+                               break;
+                       case 'session':
+                               if ( !$this->loadFromSession() ) {
+                                       // Loading from session failed. Load defaults.
+                                       $this->loadDefaults();
+                               }
+                               Hooks::run( 'UserLoadAfterLoadFromSession', array( $this ) );
+                               break;
+                       default:
+                               throw new UnexpectedValueException(
+                                       "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
+               }
+       }
+
+       /**
+        * Load user table data, given mId has already been set.
+        * @param integer $flags User::READ_* constant bitfield
+        * @return bool False if the ID does not exist, true otherwise
+        */
+       public function loadFromId( $flags = self::READ_NORMAL ) {
+               if ( $this->mId == 0 ) {
+                       $this->loadDefaults();
+                       return false;
+               }
+
+               // Try cache (unless this needs data from the master DB).
+               // NOTE: if this thread called saveSettings(), the cache was cleared.
+               $latest = DBAccessObjectUtils::hasFlags( $flags, self::READ_LATEST );
+               if ( $latest || !$this->loadFromCache() ) {
+                       wfDebug( "User: cache miss for user {$this->mId}\n" );
+                       // Load from DB (make sure this thread sees its own changes)
+                       if ( wfGetLB()->hasOrMadeRecentMasterChanges() ) {
+                               $flags |= self::READ_LATEST;
+                       }
+                       if ( !$this->loadFromDatabase( $flags ) ) {
+                               // Can't load from ID, user is anonymous
+                               return false;
+                       }
+                       $this->saveToCache();
+               }
+
+               $this->mLoadedItems = true;
+               $this->queryFlagsUsed = $flags;
+
+               return true;
+       }
+
+       /**
+        * @since 1.27
+        * @param string $wikiId
+        * @param integer $userId
+        */
+       public static function purge( $wikiId, $userId ) {
+               $cache = ObjectCache::getMainWANInstance();
+               $cache->delete( $cache->makeGlobalKey( 'user', 'id', $wikiId, $userId ) );
+       }
+
+       /**
+        * @since 1.27
+        * @param WANObjectCache $cache
+        * @return string
+        */
+       protected function getCacheKey( WANObjectCache $cache ) {
+               return $cache->makeGlobalKey( 'user', 'id', wfWikiID(), $this->mId );
+       }
+
+       /**
+        * Load user data from shared cache, given mId has already been set.
+        *
+        * @return bool false if the ID does not exist or data is invalid, true otherwise
+        * @since 1.25
+        */
+       protected function loadFromCache() {
+               if ( $this->mId == 0 ) {
+                       $this->loadDefaults();
+                       return false;
+               }
+
+               $cache = ObjectCache::getMainWANInstance();
+               $data = $cache->get( $this->getCacheKey( $cache ) );
+               if ( !is_array( $data ) || $data['mVersion'] < self::VERSION ) {
+                       // Object is expired
+                       return false;
+               }
+
+               wfDebug( "User: got user {$this->mId} from cache\n" );
+
+               // Restore from cache
+               foreach ( self::$mCacheVars as $name ) {
+                       $this->$name = $data[$name];
+               }
+
+               return true;
+       }
+
+       /**
+        * Save user data to the shared cache
+        *
+        * This method should not be called outside the User class
+        */
+       public function saveToCache() {
+               $this->load();
+               $this->loadGroups();
+               $this->loadOptions();
+
+               if ( $this->isAnon() ) {
+                       // Anonymous users are uncached
+                       return;
+               }
+
+               $data = array();
+               foreach ( self::$mCacheVars as $name ) {
+                       $data[$name] = $this->$name;
+               }
+               $data['mVersion'] = self::VERSION;
+               $opts = Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) );
+
+               $cache = ObjectCache::getMainWANInstance();
+               $key = $this->getCacheKey( $cache );
+               $cache->set( $key, $data, $cache::TTL_HOUR, $opts );
+       }
+
+       /** @name newFrom*() static factory methods */
+       // @{
+
+       /**
+        * Static factory method for creation from username.
+        *
+        * This is slightly less efficient than newFromId(), so use newFromId() if
+        * you have both an ID and a name handy.
+        *
+        * @param string $name Username, validated by Title::newFromText()
+        * @param string|bool $validate Validate username. Takes the same parameters as
+        *  User::getCanonicalName(), except that true is accepted as an alias
+        *  for 'valid', for BC.
+        *
+        * @return User|bool User object, or false if the username is invalid
+        *  (e.g. if it contains illegal characters or is an IP address). If the
+        *  username is not present in the database, the result will be a user object
+        *  with a name, zero user ID and default settings.
+        */
+       public static function newFromName( $name, $validate = 'valid' ) {
+               if ( $validate === true ) {
+                       $validate = 'valid';
+               }
+               $name = self::getCanonicalName( $name, $validate );
+               if ( $name === false ) {
+                       return false;
+               } else {
+                       // Create unloaded user object
+                       $u = new User;
+                       $u->mName = $name;
+                       $u->mFrom = 'name';
+                       $u->setItemLoaded( 'name' );
+                       return $u;
+               }
+       }
+
+       /**
+        * Static factory method for creation from a given user ID.
+        *
+        * @param int $id Valid user ID
+        * @return User The corresponding User object
+        */
+       public static function newFromId( $id ) {
+               $u = new User;
+               $u->mId = $id;
+               $u->mFrom = 'id';
+               $u->setItemLoaded( 'id' );
+               return $u;
+       }
+
+       /**
+        * Factory method to fetch whichever user has a given email confirmation code.
+        * This code is generated when an account is created or its e-mail address
+        * has changed.
+        *
+        * If the code is invalid or has expired, returns NULL.
+        *
+        * @param string $code Confirmation code
+        * @param int $flags User::READ_* bitfield
+        * @return User|null
+        */
+       public static function newFromConfirmationCode( $code, $flags = 0 ) {
+               $db = ( $flags & self::READ_LATEST ) == self::READ_LATEST
+                       ? wfGetDB( DB_MASTER )
+                       : wfGetDB( DB_SLAVE );
+
+               $id = $db->selectField(
+                       'user',
+                       'user_id',
+                       array(
+                               'user_email_token' => md5( $code ),
+                               'user_email_token_expires > ' . $db->addQuotes( $db->timestamp() ),
+                       )
+               );
+
+               return $id ? User::newFromId( $id ) : null;
+       }
+
+       /**
+        * Create a new user object using data from session or cookies. If the
+        * login credentials are invalid, the result is an anonymous user.
+        *
+        * @param WebRequest|null $request Object to use; $wgRequest will be used if omitted.
+        * @return User
+        */
+       public static function newFromSession( WebRequest $request = null ) {
+               $user = new User;
+               $user->mFrom = 'session';
+               $user->mRequest = $request;
+               return $user;
+       }
+
+       /**
+        * Create a new user object from a user row.
+        * The row should have the following fields from the user table in it:
+        * - either user_name or user_id to load further data if needed (or both)
+        * - user_real_name
+        * - all other fields (email, etc.)
+        * It is useless to provide the remaining fields if either user_id,
+        * user_name and user_real_name are not provided because the whole row
+        * will be loaded once more from the database when accessing them.
+        *
+        * @param stdClass $row A row from the user table
+        * @param array $data Further data to load into the object (see User::loadFromRow for valid keys)
+        * @return User
+        */
+       public static function newFromRow( $row, $data = null ) {
+               $user = new User;
+               $user->loadFromRow( $row, $data );
+               return $user;
+       }
+
+       /**
+        * Static factory method for creation of a "system" user from username.
+        *
+        * A "system" user is an account that's used to attribute logged actions
+        * taken by MediaWiki itself, as opposed to a bot or human user. Examples
+        * might include the 'Maintenance script' or 'Conversion script' accounts
+        * used by various scripts in the maintenance/ directory or accounts such
+        * as 'MediaWiki message delivery' used by the MassMessage extension.
+        *
+        * This can optionally create the user if it doesn't exist, and "steal" the
+        * account if it does exist.
+        *
+        * @param string $name Username
+        * @param array $options Options are:
+        *  - validate: As for User::getCanonicalName(), default 'valid'
+        *  - create: Whether to create the user if it doesn't already exist, default true
+        *  - steal: Whether to reset the account's password and email if it
+        *    already exists, default false
+        * @return User|null
+        */
+       public static function newSystemUser( $name, $options = array() ) {
+               $options += array(
+                       'validate' => 'valid',
+                       'create' => true,
+                       'steal' => false,
+               );
+
+               $name = self::getCanonicalName( $name, $options['validate'] );
+               if ( $name === false ) {
+                       return null;
+               }
+
+               $dbw = wfGetDB( DB_MASTER );
+               $row = $dbw->selectRow(
+                       'user',
+                       array_merge(
+                               self::selectFields(),
+                               array( 'user_password', 'user_newpassword' )
+                       ),
+                       array( 'user_name' => $name ),
+                       __METHOD__
+               );
+               if ( !$row ) {
+                       // No user. Create it?
+                       return $options['create'] ? self::createNew( $name ) : null;
+               }
+               $user = self::newFromRow( $row );
+
+               // A user is considered to exist as a non-system user if it has a
+               // password set, or a temporary password set, or an email set.
+               $passwordFactory = new PasswordFactory();
+               $passwordFactory->init( RequestContext::getMain()->getConfig() );
+               try {
+                       $password = $passwordFactory->newFromCiphertext( $row->user_password );
+               } catch ( PasswordError $e ) {
+                       wfDebug( 'Invalid password hash found in database.' );
+                       $password = PasswordFactory::newInvalidPassword();
+               }
+               try {
+                       $newpassword = $passwordFactory->newFromCiphertext( $row->user_newpassword );
+               } catch ( PasswordError $e ) {
+                       wfDebug( 'Invalid password hash found in database.' );
+                       $newpassword = PasswordFactory::newInvalidPassword();
+               }
+               if ( !$password instanceof InvalidPassword || !$newpassword instanceof InvalidPassword
+                       || $user->mEmail
+               ) {
+                       // User exists. Steal it?
+                       if ( !$options['steal'] ) {
+                               return null;
+                       }
+
+                       $nopass = PasswordFactory::newInvalidPassword()->toString();
+
+                       $dbw->update(
+                               'user',
+                               array(
+                                       'user_password' => $nopass,
+                                       'user_newpassword' => $nopass,
+                                       'user_newpass_time' => null,
+                               ),
+                               array( 'user_id' => $user->getId() ),
+                               __METHOD__
+                       );
+                       $user->invalidateEmail();
+                       $user->saveSettings();
+               }
+
+               return $user;
+       }
+
+       // @}
+
+       /**
+        * Get the username corresponding to a given user ID
+        * @param int $id User ID
+        * @return string|bool The corresponding username
+        */
+       public static function whoIs( $id ) {
+               return UserCache::singleton()->getProp( $id, 'name' );
+       }
+
+       /**
+        * Get the real name of a user given their user ID
+        *
+        * @param int $id User ID
+        * @return string|bool The corresponding user's real name
+        */
+       public static function whoIsReal( $id ) {
+               return UserCache::singleton()->getProp( $id, 'real_name' );
+       }
+
+       /**
+        * Get database id given a user name
+        * @param string $name Username
+        * @param integer $flags User::READ_* constant bitfield
+        * @return int|null The corresponding user's ID, or null if user is nonexistent
+        */
+       public static function idFromName( $name, $flags = self::READ_NORMAL ) {
+               $nt = Title::makeTitleSafe( NS_USER, $name );
+               if ( is_null( $nt ) ) {
+                       // Illegal name
+                       return null;
+               }
+
+               if ( !( $flags & self::READ_LATEST ) && isset( self::$idCacheByName[$name] ) ) {
+                       return self::$idCacheByName[$name];
+               }
+
+               $db = ( $flags & self::READ_LATEST )
+                       ? wfGetDB( DB_MASTER )
+                       : wfGetDB( DB_SLAVE );
+
+               $s = $db->selectRow(
+                       'user',
+                       array( 'user_id' ),
+                       array( 'user_name' => $nt->getText() ),
+                       __METHOD__
+               );
+
+               if ( $s === false ) {
+                       $result = null;
+               } else {
+                       $result = $s->user_id;
+               }
+
+               self::$idCacheByName[$name] = $result;
+
+               if ( count( self::$idCacheByName ) > 1000 ) {
+                       self::$idCacheByName = array();
+               }
+
+               return $result;
+       }
+
+       /**
+        * Reset the cache used in idFromName(). For use in tests.
+        */
+       public static function resetIdByNameCache() {
+               self::$idCacheByName = array();
+       }
+
+       /**
+        * Does the string match an anonymous IPv4 address?
+        *
+        * This function exists for username validation, in order to reject
+        * usernames which are similar in form to IP addresses. Strings such
+        * as 300.300.300.300 will return true because it looks like an IP
+        * address, despite not being strictly valid.
+        *
+        * We match "\d{1,3}\.\d{1,3}\.\d{1,3}\.xxx" as an anonymous IP
+        * address because the usemod software would "cloak" anonymous IP
+        * addresses like this, if we allowed accounts like this to be created
+        * new users could get the old edits of these anonymous users.
+        *
+        * @param string $name Name to match
+        * @return bool
+        */
+       public static function isIP( $name ) {
+               return preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/', $name )
+                       || IP::isIPv6( $name );
+       }
+
+       /**
+        * Is the input a valid username?
+        *
+        * Checks if the input is a valid username, we don't want an empty string,
+        * an IP address, anything that contains slashes (would mess up subpages),
+        * is longer than the maximum allowed username size or doesn't begin with
+        * a capital letter.
+        *
+        * @param string $name Name to match
+        * @return bool
+        */
+       public static function isValidUserName( $name ) {
+               global $wgContLang, $wgMaxNameChars;
+
+               if ( $name == ''
+                       || User::isIP( $name )
+                       || strpos( $name, '/' ) !== false
+                       || strlen( $name ) > $wgMaxNameChars
+                       || $name != $wgContLang->ucfirst( $name )
+               ) {
+                       wfDebugLog( 'username', __METHOD__ .
+                               ": '$name' invalid due to empty, IP, slash, length, or lowercase" );
+                       return false;
+               }
+
+               // Ensure that the name can't be misresolved as a different title,
+               // such as with extra namespace keys at the start.
+               $parsed = Title::newFromText( $name );
+               if ( is_null( $parsed )
+                       || $parsed->getNamespace()
+                       || strcmp( $name, $parsed->getPrefixedText() ) ) {
+                       wfDebugLog( 'username', __METHOD__ .
+                               ": '$name' invalid due to ambiguous prefixes" );
+                       return false;
+               }
+
+               // Check an additional blacklist of troublemaker characters.
+               // Should these be merged into the title char list?
+               $unicodeBlacklist = '/[' .
+                       '\x{0080}-\x{009f}' . # iso-8859-1 control chars
+                       '\x{00a0}' .          # non-breaking space
+                       '\x{2000}-\x{200f}' . # various whitespace
+                       '\x{2028}-\x{202f}' . # breaks and control chars
+                       '\x{3000}' .          # ideographic space
+                       '\x{e000}-\x{f8ff}' . # private use
+                       ']/u';
+               if ( preg_match( $unicodeBlacklist, $name ) ) {
+                       wfDebugLog( 'username', __METHOD__ .
+                               ": '$name' invalid due to blacklisted characters" );
+                       return false;
+               }
+
+               return true;
+       }
+
+       /**
+        * Usernames which fail to pass this function will be blocked
+        * from user login and new account registrations, but may be used
+        * internally by batch processes.
+        *
+        * If an account already exists in this form, login will be blocked
+        * by a failure to pass this function.
+        *
+        * @param string $name Name to match
+        * @return bool
+        */
+       public static function isUsableName( $name ) {
+               global $wgReservedUsernames;
+               // Must be a valid username, obviously ;)
+               if ( !self::isValidUserName( $name ) ) {
+                       return false;
+               }
+
+               static $reservedUsernames = false;
+               if ( !$reservedUsernames ) {
+                       $reservedUsernames = $wgReservedUsernames;
+                       Hooks::run( 'UserGetReservedNames', array( &$reservedUsernames ) );
+               }
+
+               // Certain names may be reserved for batch processes.
+               foreach ( $reservedUsernames as $reserved ) {
+                       if ( substr( $reserved, 0, 4 ) == 'msg:' ) {
+                               $reserved = wfMessage( substr( $reserved, 4 ) )->inContentLanguage()->text();
+                       }
+                       if ( $reserved == $name ) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       /**
+        * Usernames which fail to pass this function will be blocked
+        * from new account registrations, but may be used internally
+        * either by batch processes or by user accounts which have
+        * already been created.
+        *
+        * Additional blacklisting may be added here rather than in
+        * isValidUserName() to avoid disrupting existing accounts.
+        *
+        * @param string $name String to match
+        * @return bool
+        */
+       public static function isCreatableName( $name ) {
+               global $wgInvalidUsernameCharacters;
+
+               // Ensure that the username isn't longer than 235 bytes, so that
+               // (at least for the builtin skins) user javascript and css files
+               // will work. (bug 23080)
+               if ( strlen( $name ) > 235 ) {
+                       wfDebugLog( 'username', __METHOD__ .
+                               ": '$name' invalid due to length" );
+                       return false;
+               }
+
+               // Preg yells if you try to give it an empty string
+               if ( $wgInvalidUsernameCharacters !== '' ) {
+                       if ( preg_match( '/[' . preg_quote( $wgInvalidUsernameCharacters, '/' ) . ']/', $name ) ) {
+                               wfDebugLog( 'username', __METHOD__ .
+                                       ": '$name' invalid due to wgInvalidUsernameCharacters" );
+                               return false;
+                       }
+               }
+
+               return self::isUsableName( $name );
+       }
+
+       /**
+        * Is the input a valid password for this user?
+        *
+        * @param string $password Desired password
+        * @return bool
+        */
+       public function isValidPassword( $password ) {
+               // simple boolean wrapper for getPasswordValidity
+               return $this->getPasswordValidity( $password ) === true;
+       }
+
+
+       /**
+        * Given unvalidated password input, return error message on failure.
+        *
+        * @param string $password Desired password
+        * @return bool|string|array True on success, string or array of error message on failure
+        */
+       public function getPasswordValidity( $password ) {
+               $result = $this->checkPasswordValidity( $password );
+               if ( $result->isGood() ) {
+                       return true;
+               } else {
+                       $messages = array();
+                       foreach ( $result->getErrorsByType( 'error' ) as $error ) {
+                               $messages[] = $error['message'];
+                       }
+                       foreach ( $result->getErrorsByType( 'warning' ) as $warning ) {
+                               $messages[] = $warning['message'];
+                       }
+                       if ( count( $messages ) === 1 ) {
+                               return $messages[0];
+                       }
+                       return $messages;
+               }
+       }
+
+       /**
+        * Check if this is a valid password for this user
+        *
+        * Create a Status object based on the password's validity.
+        * The Status should be set to fatal if the user should not
+        * be allowed to log in, and should have any errors that
+        * would block changing the password.
+        *
+        * If the return value of this is not OK, the password
+        * should not be checked. If the return value is not Good,
+        * the password can be checked, but the user should not be
+        * able to set their password to this.
+        *
+        * @param string $password Desired password
+        * @param string $purpose one of 'login', 'create', 'reset'
+        * @return Status
+        * @since 1.23
+        */
+       public function checkPasswordValidity( $password, $purpose = 'login' ) {
+               global $wgPasswordPolicy;
+
+               $upp = new UserPasswordPolicy(
+                       $wgPasswordPolicy['policies'],
+                       $wgPasswordPolicy['checks']
+               );
+
+               $status = Status::newGood();
+               $result = false; // init $result to false for the internal checks
+
+               if ( !Hooks::run( 'isValidPassword', array( $password, &$result, $this ) ) ) {
+                       $status->error( $result );
+                       return $status;
+               }
+
+               if ( $result === false ) {
+                       $status->merge( $upp->checkUserPassword( $this, $password, $purpose ) );
+                       return $status;
+               } elseif ( $result === true ) {
+                       return $status;
+               } else {
+                       $status->error( $result );
+                       return $status; // the isValidPassword hook set a string $result and returned true
+               }
+       }
+
+       /**
+        * Given unvalidated user input, return a canonical username, or false if
+        * the username is invalid.
+        * @param string $name User input
+        * @param string|bool $validate Type of validation to use:
+        *   - false        No validation
+        *   - 'valid'      Valid for batch processes
+        *   - 'usable'     Valid for batch processes and login
+        *   - 'creatable'  Valid for batch processes, login and account creation
+        *
+        * @throws InvalidArgumentException
+        * @return bool|string
+        */
+       public static function getCanonicalName( $name, $validate = 'valid' ) {
+               // Force usernames to capital
+               global $wgContLang;
+               $name = $wgContLang->ucfirst( $name );
+
+               # Reject names containing '#'; these will be cleaned up
+               # with title normalisation, but then it's too late to
+               # check elsewhere
+               if ( strpos( $name, '#' ) !== false ) {
+                       return false;
+               }
+
+               // Clean up name according to title rules,
+               // but only when validation is requested (bug 12654)
+               $t = ( $validate !== false ) ?
+                       Title::newFromText( $name ) : Title::makeTitle( NS_USER, $name );
+               // Check for invalid titles
+               if ( is_null( $t ) ) {
+                       return false;
+               }
+
+               // Reject various classes of invalid names
+               global $wgAuth;
+               $name = $wgAuth->getCanonicalName( $t->getText() );
+
+               switch ( $validate ) {
+                       case false:
+                               break;
+                       case 'valid':
+                               if ( !User::isValidUserName( $name ) ) {
+                                       $name = false;
+                               }
+                               break;
+                       case 'usable':
+                               if ( !User::isUsableName( $name ) ) {
+                                       $name = false;
+                               }
+                               break;
+                       case 'creatable':
+                               if ( !User::isCreatableName( $name ) ) {
+                                       $name = false;
+                               }
+                               break;
+                       default:
+                               throw new InvalidArgumentException(
+                                       'Invalid parameter value for $validate in ' . __METHOD__ );
+               }
+               return $name;
+       }
+
+       /**
+        * Count the number of edits of a user
+        *
+        * @param int $uid User ID to check
+        * @return int The user's edit count
+        *
+        * @deprecated since 1.21 in favour of User::getEditCount
+        */
+       public static function edits( $uid ) {
+               wfDeprecated( __METHOD__, '1.21' );
+               $user = self::newFromId( $uid );
+               return $user->getEditCount();
+       }
+
+       /**
+        * Return a random password.
+        *
+        * @deprecated since 1.27, use PasswordFactory::generateRandomPasswordString()
+        * @return string New random password
+        */
+       public static function randomPassword() {
+               global $wgMinimalPasswordLength;
+               return PasswordFactory::generateRandomPasswordString( $wgMinimalPasswordLength );
+       }
+
+       /**
+        * Set cached properties to default.
+        *
+        * @note This no longer clears uncached lazy-initialised properties;
+        *       the constructor does that instead.
+        *
+        * @param string|bool $name
+        */
+       public function loadDefaults( $name = false ) {
+               $this->mId = 0;
+               $this->mName = $name;
+               $this->mRealName = '';
+               $this->mEmail = '';
+               $this->mOptionOverrides = null;
+               $this->mOptionsLoaded = false;
+
+               $loggedOut = $this->getRequest()->getCookie( 'LoggedOut' );
+               if ( $loggedOut !== null ) {
+                       $this->mTouched = wfTimestamp( TS_MW, $loggedOut );
+               } else {
+                       $this->mTouched = '1'; # Allow any pages to be cached
+               }
+
+               $this->mToken = null; // Don't run cryptographic functions till we need a token
+               $this->mEmailAuthenticated = null;
+               $this->mEmailToken = '';
+               $this->mEmailTokenExpires = null;
+               $this->mRegistration = wfTimestamp( TS_MW );
+               $this->mGroups = array();
+
+               Hooks::run( 'UserLoadDefaults', array( $this, $name ) );
+       }
+
+       /**
+        * Return whether an item has been loaded.
+        *
+        * @param string $item Item to check. Current possibilities:
+        *   - id
+        *   - name
+        *   - realname
+        * @param string $all 'all' to check if the whole object has been loaded
+        *   or any other string to check if only the item is available (e.g.
+        *   for optimisation)
+        * @return bool
+        */
+       public function isItemLoaded( $item, $all = 'all' ) {
+               return ( $this->mLoadedItems === true && $all === 'all' ) ||
+                       ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] === true );
+       }
+
+       /**
+        * Set that an item has been loaded
+        *
+        * @param string $item
+        */
+       protected function setItemLoaded( $item ) {
+               if ( is_array( $this->mLoadedItems ) ) {
+                       $this->mLoadedItems[$item] = true;
+               }
+       }
+
+       /**
+        * Load user data from the session or login cookie.
+        *
+        * @return bool True if the user is logged in, false otherwise.
+        */
+       private function loadFromSession() {
+               $result = null;
+               Hooks::run( 'UserLoadFromSession', array( $this, &$result ) );
+               if ( $result !== null ) {
+                       return $result;
+               }
+
+               $request = $this->getRequest();
+
+               $cookieId = $request->getCookie( 'UserID' );
+               $sessId = $request->getSessionData( 'wsUserID' );
+
+               if ( $cookieId !== null ) {
+                       $sId = intval( $cookieId );
+                       if ( $sessId !== null && $cookieId != $sessId ) {
+                               wfDebugLog( 'loginSessions', "Session user ID ($sessId) and
+                                       cookie user ID ($sId) don't match!" );
+                               return false;
+                       }
+                       $request->setSessionData( 'wsUserID', $sId );
+               } elseif ( $sessId !== null && $sessId != 0 ) {
+                       $sId = $sessId;
+               } else {
+                       return false;
+               }
+
+               if ( $request->getSessionData( 'wsUserName' ) !== null ) {
+                       $sName = $request->getSessionData( 'wsUserName' );
+               } elseif ( $request->getCookie( 'UserName' ) !== null ) {
+                       $sName = $request->getCookie( 'UserName' );
+                       $request->setSessionData( 'wsUserName', $sName );
+               } else {
+                       return false;
+               }
+
+               $proposedUser = User::newFromId( $sId );
+               if ( !$proposedUser->isLoggedIn() ) {
+                       // Not a valid ID
+                       return false;
+               }
+
+               global $wgBlockDisablesLogin;
+               if ( $wgBlockDisablesLogin && $proposedUser->isBlocked() ) {
+                       // User blocked and we've disabled blocked user logins
+                       return false;
+               }
+
+               if ( $request->getSessionData( 'wsToken' ) ) {
+                       $passwordCorrect =
+                               ( $proposedUser->getToken( false ) === $request->getSessionData( 'wsToken' ) );
+                       $from = 'session';
+               } elseif ( $request->getCookie( 'Token' ) ) {
+                       # Get the token from DB/cache and clean it up to remove garbage padding.
+                       # This deals with historical problems with bugs and the default column value.
+                       $token = rtrim( $proposedUser->getToken( false ) ); // correct token
+                       // Make comparison in constant time (bug 61346)
+                       $passwordCorrect = strlen( $token )
+                               && hash_equals( $token, $request->getCookie( 'Token' ) );
+                       $from = 'cookie';
+               } else {
+                       // No session or persistent login cookie
+                       return false;
+               }
+
+               if ( ( $sName === $proposedUser->getName() ) && $passwordCorrect ) {
+                       $this->loadFromUserObject( $proposedUser );
+                       $request->setSessionData( 'wsToken', $this->mToken );
+                       wfDebug( "User: logged in from $from\n" );
+                       return true;
+               } else {
+                       // Invalid credentials
+                       wfDebug( "User: can't log in from $from, invalid credentials\n" );
+                       return false;
+               }
+       }
+
+       /**
+        * Load user and user_group data from the database.
+        * $this->mId must be set, this is how the user is identified.
+        *
+        * @param integer $flags User::READ_* constant bitfield
+        * @return bool True if the user exists, false if the user is anonymous
+        */
+       public function loadFromDatabase( $flags = self::READ_LATEST ) {
+               // Paranoia
+               $this->mId = intval( $this->mId );
+
+               // Anonymous user
+               if ( !$this->mId ) {
+                       $this->loadDefaults();
+                       return false;
+               }
+
+               list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
+               $db = wfGetDB( $index );
+
+               $s = $db->selectRow(
+                       'user',
+                       self::selectFields(),
+                       array( 'user_id' => $this->mId ),
+                       __METHOD__,
+                       $options
+               );
+
+               $this->queryFlagsUsed = $flags;
+               Hooks::run( 'UserLoadFromDatabase', array( $this, &$s ) );
+
+               if ( $s !== false ) {
+                       // Initialise user table data
+                       $this->loadFromRow( $s );
+                       $this->mGroups = null; // deferred
+                       $this->getEditCount(); // revalidation for nulls
+                       return true;
+               } else {
+                       // Invalid user_id
+                       $this->mId = 0;
+                       $this->loadDefaults();
+                       return false;
+               }
+       }
+
+       /**
+        * Initialize this object from a row from the user table.
+        *
+        * @param stdClass $row Row from the user table to load.
+        * @param array $data Further user data to load into the object
+        *
+        *      user_groups             Array with groups out of the user_groups table
+        *      user_properties         Array with properties out of the user_properties table
+        */
+       protected function loadFromRow( $row, $data = null ) {
+               $all = true;
+
+               $this->mGroups = null; // deferred
+
+               if ( isset( $row->user_name ) ) {
+                       $this->mName = $row->user_name;
+                       $this->mFrom = 'name';
+                       $this->setItemLoaded( 'name' );
+               } else {
+                       $all = false;
+               }
+
+               if ( isset( $row->user_real_name ) ) {
+                       $this->mRealName = $row->user_real_name;
+                       $this->setItemLoaded( 'realname' );
+               } else {
+                       $all = false;
+               }
+
+               if ( isset( $row->user_id ) ) {
+                       $this->mId = intval( $row->user_id );
+                       $this->mFrom = 'id';
+                       $this->setItemLoaded( 'id' );
+               } else {
+                       $all = false;
+               }
+
+               if ( isset( $row->user_id ) && isset( $row->user_name ) ) {
+                       self::$idCacheByName[$row->user_name] = $row->user_id;
+               }
+
+               if ( isset( $row->user_editcount ) ) {
+                       $this->mEditCount = $row->user_editcount;
+               } else {
+                       $all = false;
+               }
+
+               if ( isset( $row->user_email ) ) {
+                       $this->mEmail = $row->user_email;
+                       $this->mTouched = wfTimestamp( TS_MW, $row->user_touched );
+                       $this->mToken = $row->user_token;
+                       if ( $this->mToken == '' ) {
+                               $this->mToken = null;
+                       }
+                       $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
+                       $this->mEmailToken = $row->user_email_token;
+                       $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
+                       $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
+               } else {
+                       $all = false;
+               }
+
+               if ( $all ) {
+                       $this->mLoadedItems = true;
+               }
+
+               if ( is_array( $data ) ) {
+                       if ( isset( $data['user_groups'] ) && is_array( $data['user_groups'] ) ) {
+                               $this->mGroups = $data['user_groups'];
+                       }
+                       if ( isset( $data['user_properties'] ) && is_array( $data['user_properties'] ) ) {
+                               $this->loadOptions( $data['user_properties'] );
+                       }
+               }
+       }
+
+       /**
+        * Load the data for this user object from another user object.
+        *
+        * @param User $user
+        */
+       protected function loadFromUserObject( $user ) {
+               $user->load();
+               $user->loadGroups();
+               $user->loadOptions();
+               foreach ( self::$mCacheVars as $var ) {
+                       $this->$var = $user->$var;
+               }
+       }
+
+       /**
+        * Load the groups from the database if they aren't already loaded.
+        */
+       private function loadGroups() {
+               if ( is_null( $this->mGroups ) ) {
+                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
+                               ? wfGetDB( DB_MASTER )
+                               : wfGetDB( DB_SLAVE );
+                       $res = $db->select( 'user_groups',
+                               array( 'ug_group' ),
+                               array( 'ug_user' => $this->mId ),
+                               __METHOD__ );
+                       $this->mGroups = array();
+                       foreach ( $res as $row ) {
+                               $this->mGroups[] = $row->ug_group;
+                       }
+               }
+       }
+
+       /**
+        * Add the user to the group if he/she meets given criteria.
+        *
+        * Contrary to autopromotion by \ref $wgAutopromote, the group will be
+        *   possible to remove manually via Special:UserRights. In such case it
+        *   will not be re-added automatically. The user will also not lose the
+        *   group if they no longer meet the criteria.
+        *
+        * @param string $event Key in $wgAutopromoteOnce (each one has groups/criteria)
+        *
+        * @return array Array of groups the user has been promoted to.
+        *
+        * @see $wgAutopromoteOnce
+        */
+       public function addAutopromoteOnceGroups( $event ) {
+               global $wgAutopromoteOnceLogInRC, $wgAuth;
+
+               if ( wfReadOnly() || !$this->getId() ) {
+                       return array();
+               }
+
+               $toPromote = Autopromote::getAutopromoteOnceGroups( $this, $event );
+               if ( !count( $toPromote ) ) {
+                       return array();
+               }
+
+               if ( !$this->checkAndSetTouched() ) {
+                       return array(); // raced out (bug T48834)
+               }
+
+               $oldGroups = $this->getGroups(); // previous groups
+               foreach ( $toPromote as $group ) {
+                       $this->addGroup( $group );
+               }
+               // update groups in external authentication database
+               Hooks::run( 'UserGroupsChanged', array( $this, $toPromote, array(), false ) );
+               $wgAuth->updateExternalDBGroups( $this, $toPromote );
+
+               $newGroups = array_merge( $oldGroups, $toPromote ); // all groups
+
+               $logEntry = new ManualLogEntry( 'rights', 'autopromote' );
+               $logEntry->setPerformer( $this );
+               $logEntry->setTarget( $this->getUserPage() );
+               $logEntry->setParameters( array(
+                       '4::oldgroups' => $oldGroups,
+                       '5::newgroups' => $newGroups,
+               ) );
+               $logid = $logEntry->insert();
+               if ( $wgAutopromoteOnceLogInRC ) {
+                       $logEntry->publish( $logid );
+               }
+
+               return $toPromote;
+       }
+
+       /**
+        * Bump user_touched if it didn't change since this object was loaded
+        *
+        * On success, the mTouched field is updated.
+        * The user serialization cache is always cleared.
+        *
+        * @return bool Whether user_touched was actually updated
+        * @since 1.26
+        */
+       protected function checkAndSetTouched() {
+               $this->load();
+
+               if ( !$this->mId ) {
+                       return false; // anon
+               }
+
+               // Get a new user_touched that is higher than the old one
+               $oldTouched = $this->mTouched;
+               $newTouched = $this->newTouchedTimestamp();
+
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->update( 'user',
+                       array( 'user_touched' => $dbw->timestamp( $newTouched ) ),
+                       array(
+                               'user_id' => $this->mId,
+                               'user_touched' => $dbw->timestamp( $oldTouched ) // CAS check
+                       ),
+                       __METHOD__
+               );
+               $success = ( $dbw->affectedRows() > 0 );
+
+               if ( $success ) {
+                       $this->mTouched = $newTouched;
+                       $this->clearSharedCache();
+               } else {
+                       // Clears on failure too since that is desired if the cache is stale
+                       $this->clearSharedCache( 'refresh' );
+               }
+
+               return $success;
+       }
+
+       /**
+        * Clear various cached data stored in this object. The cache of the user table
+        * data (i.e. self::$mCacheVars) is not cleared unless $reloadFrom is given.
+        *
+        * @param bool|string $reloadFrom Reload user and user_groups table data from a
+        *   given source. May be "name", "id", "defaults", "session", or false for no reload.
+        */
+       public function clearInstanceCache( $reloadFrom = false ) {
+               $this->mNewtalk = -1;
+               $this->mDatePreference = null;
+               $this->mBlockedby = -1; # Unset
+               $this->mHash = false;
+               $this->mRights = null;
+               $this->mEffectiveGroups = null;
+               $this->mImplicitGroups = null;
+               $this->mGroups = null;
+               $this->mOptions = null;
+               $this->mOptionsLoaded = false;
+               $this->mEditCount = null;
+
+               if ( $reloadFrom ) {
+                       $this->mLoadedItems = array();
+                       $this->mFrom = $reloadFrom;
+               }
+       }
+
+       /**
+        * Combine the language default options with any site-specific options
+        * and add the default language variants.
+        *
+        * @return array Array of String options
+        */
+       public static function getDefaultOptions() {
+               global $wgNamespacesToBeSearchedDefault, $wgDefaultUserOptions, $wgContLang, $wgDefaultSkin;
+
+               static $defOpt = null;
+               if ( !defined( 'MW_PHPUNIT_TEST' ) && $defOpt !== null ) {
+                       // Disabling this for the unit tests, as they rely on being able to change $wgContLang
+                       // mid-request and see that change reflected in the return value of this function.
+                       // Which is insane and would never happen during normal MW operation
+                       return $defOpt;
+               }
+
+               $defOpt = $wgDefaultUserOptions;
+               // Default language setting
+               $defOpt['language'] = $wgContLang->getCode();
+               foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
+                       $defOpt[$langCode == $wgContLang->getCode() ? 'variant' : "variant-$langCode"] = $langCode;
+               }
+               foreach ( SearchEngine::searchableNamespaces() as $nsnum => $nsname ) {
+                       $defOpt['searchNs' . $nsnum] = !empty( $wgNamespacesToBeSearchedDefault[$nsnum] );
+               }
+               $defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin );
+
+               Hooks::run( 'UserGetDefaultOptions', array( &$defOpt ) );
+
+               return $defOpt;
+       }
+
+       /**
+        * Get a given default option value.
+        *
+        * @param string $opt Name of option to retrieve
+        * @return string Default option value
+        */
+       public static function getDefaultOption( $opt ) {
+               $defOpts = self::getDefaultOptions();
+               if ( isset( $defOpts[$opt] ) ) {
+                       return $defOpts[$opt];
+               } else {
+                       return null;
+               }
+       }
+
+       /**
+        * Get blocking information
+        * @param bool $bFromSlave Whether to check the slave database first.
+        *   To improve performance, non-critical checks are done against slaves.
+        *   Check when actually saving should be done against master.
+        */
+       private function getBlockedStatus( $bFromSlave = true ) {
+               global $wgProxyWhitelist, $wgUser, $wgApplyIpBlocksToXff;
+
+               if ( -1 != $this->mBlockedby ) {
+                       return;
+               }
+
+               wfDebug( __METHOD__ . ": checking...\n" );
+
+               // Initialize data...
+               // Otherwise something ends up stomping on $this->mBlockedby when
+               // things get lazy-loaded later, causing false positive block hits
+               // due to -1 !== 0. Probably session-related... Nothing should be
+               // overwriting mBlockedby, surely?
+               $this->load();
+
+               # We only need to worry about passing the IP address to the Block generator if the
+               # user is not immune to autoblocks/hardblocks, and they are the current user so we
+               # know which IP address they're actually coming from
+               if ( !$this->isAllowed( 'ipblock-exempt' ) && $this->equals( $wgUser ) ) {
+                       $ip = $this->getRequest()->getIP();
+               } else {
+                       $ip = null;
+               }
+
+               // User/IP blocking
+               $block = Block::newFromTarget( $this, $ip, !$bFromSlave );
+
+               // Proxy blocking
+               if ( !$block instanceof Block && $ip !== null && !$this->isAllowed( 'proxyunbannable' )
+                       && !in_array( $ip, $wgProxyWhitelist )
+               ) {
+                       // Local list
+                       if ( self::isLocallyBlockedProxy( $ip ) ) {
+                               $block = new Block;
+                               $block->setBlocker( wfMessage( 'proxyblocker' )->text() );
+                               $block->mReason = wfMessage( 'proxyblockreason' )->text();
+                               $block->setTarget( $ip );
+                       } elseif ( $this->isAnon() && $this->isDnsBlacklisted( $ip ) ) {
+                               $block = new Block;
+                               $block->setBlocker( wfMessage( 'sorbs' )->text() );
+                               $block->mReason = wfMessage( 'sorbsreason' )->text();
+                               $block->setTarget( $ip );
+                       }
+               }
+
+               // (bug 23343) Apply IP blocks to the contents of XFF headers, if enabled
+               if ( !$block instanceof Block
+                       && $wgApplyIpBlocksToXff
+                       && $ip !== null
+                       && !$this->isAllowed( 'proxyunbannable' )
+                       && !in_array( $ip, $wgProxyWhitelist )
+               ) {
+                       $xff = $this->getRequest()->getHeader( 'X-Forwarded-For' );
+                       $xff = array_map( 'trim', explode( ',', $xff ) );
+                       $xff = array_diff( $xff, array( $ip ) );
+                       $xffblocks = Block::getBlocksForIPList( $xff, $this->isAnon(), !$bFromSlave );
+                       $block = Block::chooseBlock( $xffblocks, $xff );
+                       if ( $block instanceof Block ) {
+                               # Mangle the reason to alert the user that the block
+                               # originated from matching the X-Forwarded-For header.
+                               $block->mReason = wfMessage( 'xffblockreason', $block->mReason )->text();
+                       }
+               }
+
+               if ( $block instanceof Block ) {
+                       wfDebug( __METHOD__ . ": Found block.\n" );
+                       $this->mBlock = $block;
+                       $this->mBlockedby = $block->getByName();
+                       $this->mBlockreason = $block->mReason;
+                       $this->mHideName = $block->mHideName;
+                       $this->mAllowUsertalk = !$block->prevents( 'editownusertalk' );
+               } else {
+                       $this->mBlockedby = '';
+                       $this->mHideName = 0;
+                       $this->mAllowUsertalk = false;
+               }
+
+               // Extensions
+               Hooks::run( 'GetBlockedStatus', array( &$this ) );
+
+       }
+
+       /**
+        * Whether the given IP is in a DNS blacklist.
+        *
+        * @param string $ip IP to check
+        * @param bool $checkWhitelist Whether to check the whitelist first
+        * @return bool True if blacklisted.
+        */
+       public function isDnsBlacklisted( $ip, $checkWhitelist = false ) {
+               global $wgEnableDnsBlacklist, $wgDnsBlacklistUrls, $wgProxyWhitelist;
+
+               if ( !$wgEnableDnsBlacklist ) {
+                       return false;
+               }
+
+               if ( $checkWhitelist && in_array( $ip, $wgProxyWhitelist ) ) {
+                       return false;
+               }
+
+               return $this->inDnsBlacklist( $ip, $wgDnsBlacklistUrls );
+       }
+
+       /**
+        * Whether the given IP is in a given DNS blacklist.
+        *
+        * @param string $ip IP to check
+        * @param string|array $bases Array of Strings: URL of the DNS blacklist
+        * @return bool True if blacklisted.
+        */
+       public function inDnsBlacklist( $ip, $bases ) {
+
+               $found = false;
+               // @todo FIXME: IPv6 ???  (http://bugs.php.net/bug.php?id=33170)
+               if ( IP::isIPv4( $ip ) ) {
+                       // Reverse IP, bug 21255
+                       $ipReversed = implode( '.', array_reverse( explode( '.', $ip ) ) );
+
+                       foreach ( (array)$bases as $base ) {
+                               // Make hostname
+                               // If we have an access key, use that too (ProjectHoneypot, etc.)
+                               $basename = $base;
+                               if ( is_array( $base ) ) {
+                                       if ( count( $base ) >= 2 ) {
+                                               // Access key is 1, base URL is 0
+                                               $host = "{$base[1]}.$ipReversed.{$base[0]}";
+                                       } else {
+                                               $host = "$ipReversed.{$base[0]}";
+                                       }
+                                       $basename = $base[0];
+                               } else {
+                                       $host = "$ipReversed.$base";
+                               }
+
+                               // Send query
+                               $ipList = gethostbynamel( $host );
+
+                               if ( $ipList ) {
+                                       wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $basename!" );
+                                       $found = true;
+                                       break;
+                               } else {
+                                       wfDebugLog( 'dnsblacklist', "Requested $host, not found in $basename." );
+                               }
+                       }
+               }
+
+               return $found;
+       }
+
+       /**
+        * Check if an IP address is in the local proxy list
+        *
+        * @param string $ip
+        *
+        * @return bool
+        */
+       public static function isLocallyBlockedProxy( $ip ) {
+               global $wgProxyList;
+
+               if ( !$wgProxyList ) {
+                       return false;
+               }
+
+               if ( !is_array( $wgProxyList ) ) {
+                       // Load from the specified file
+                       $wgProxyList = array_map( 'trim', file( $wgProxyList ) );
+               }
+
+               if ( !is_array( $wgProxyList ) ) {
+                       $ret = false;
+               } elseif ( array_search( $ip, $wgProxyList ) !== false ) {
+                       $ret = true;
+               } elseif ( array_key_exists( $ip, $wgProxyList ) ) {
+                       // Old-style flipped proxy list
+                       $ret = true;
+               } else {
+                       $ret = false;
+               }
+               return $ret;
+       }
+
+       /**
+        * Is this user subject to rate limiting?
+        *
+        * @return bool True if rate limited
+        */
+       public function isPingLimitable() {
+               global $wgRateLimitsExcludedIPs;
+               if ( in_array( $this->getRequest()->getIP(), $wgRateLimitsExcludedIPs ) ) {
+                       // No other good way currently to disable rate limits
+                       // for specific IPs. :P
+                       // But this is a crappy hack and should die.
+                       return false;
+               }
+               return !$this->isAllowed( 'noratelimit' );
+       }
+
+       /**
+        * Primitive rate limits: enforce maximum actions per time period
+        * to put a brake on flooding.
+        *
+        * The method generates both a generic profiling point and a per action one
+        * (suffix being "-$action".
+        *
+        * @note When using a shared cache like memcached, IP-address
+        * last-hit counters will be shared across wikis.
+        *
+        * @param string $action Action to enforce; 'edit' if unspecified
+        * @param int $incrBy Positive amount to increment counter by [defaults to 1]
+        * @return bool True if a rate limiter was tripped
+        */
+       public function pingLimiter( $action = 'edit', $incrBy = 1 ) {
+               // Call the 'PingLimiter' hook
+               $result = false;
+               if ( !Hooks::run( 'PingLimiter', array( &$this, $action, &$result, $incrBy ) ) ) {
+                       return $result;
+               }
+
+               global $wgRateLimits;
+               if ( !isset( $wgRateLimits[$action] ) ) {
+                       return false;
+               }
+
+               // Some groups shouldn't trigger the ping limiter, ever
+               if ( !$this->isPingLimitable() ) {
+                       return false;
+               }
+
+               $limits = $wgRateLimits[$action];
+               $keys = array();
+               $id = $this->getId();
+               $userLimit = false;
+
+               if ( isset( $limits['anon'] ) && $id == 0 ) {
+                       $keys[wfMemcKey( 'limiter', $action, 'anon' )] = $limits['anon'];
+               }
+
+               if ( isset( $limits['user'] ) && $id != 0 ) {
+                       $userLimit = $limits['user'];
+               }
+               if ( $this->isNewbie() ) {
+                       if ( isset( $limits['newbie'] ) && $id != 0 ) {
+                               $keys[wfMemcKey( 'limiter', $action, 'user', $id )] = $limits['newbie'];
+                       }
+                       if ( isset( $limits['ip'] ) ) {
+                               $ip = $this->getRequest()->getIP();
+                               $keys["mediawiki:limiter:$action:ip:$ip"] = $limits['ip'];
+                       }
+                       if ( isset( $limits['subnet'] ) ) {
+                               $ip = $this->getRequest()->getIP();
+                               $matches = array();
+                               $subnet = false;
+                               if ( IP::isIPv6( $ip ) ) {
+                                       $parts = IP::parseRange( "$ip/64" );
+                                       $subnet = $parts[0];
+                               } elseif ( preg_match( '/^(\d+\.\d+\.\d+)\.\d+$/', $ip, $matches ) ) {
+                                       // IPv4
+                                       $subnet = $matches[1];
+                               }
+                               if ( $subnet !== false ) {
+                                       $keys["mediawiki:limiter:$action:subnet:$subnet"] = $limits['subnet'];
+                               }
+                       }
+               }
+               // Check for group-specific permissions
+               // If more than one group applies, use the group with the highest limit
+               foreach ( $this->getGroups() as $group ) {
+                       if ( isset( $limits[$group] ) ) {
+                               if ( $userLimit === false
+                                       || $limits[$group][0] / $limits[$group][1] > $userLimit[0] / $userLimit[1]
+                               ) {
+                                       $userLimit = $limits[$group];
+                               }
+                       }
+               }
+               // Set the user limit key
+               if ( $userLimit !== false ) {
+                       list( $max, $period ) = $userLimit;
+                       wfDebug( __METHOD__ . ": effective user limit: $max in {$period}s\n" );
+                       $keys[wfMemcKey( 'limiter', $action, 'user', $id )] = $userLimit;
+               }
+
+               $cache = ObjectCache::getLocalClusterInstance();
+
+               $triggered = false;
+               foreach ( $keys as $key => $limit ) {
+                       list( $max, $period ) = $limit;
+                       $summary = "(limit $max in {$period}s)";
+                       $count = $cache->get( $key );
+                       // Already pinged?
+                       if ( $count ) {
+                               if ( $count >= $max ) {
+                                       wfDebugLog( 'ratelimit', "User '{$this->getName()}' " .
+                                               "(IP {$this->getRequest()->getIP()}) tripped $key at $count $summary" );
+                                       $triggered = true;
+                               } else {
+                                       wfDebug( __METHOD__ . ": ok. $key at $count $summary\n" );
+                               }
+                       } else {
+                               wfDebug( __METHOD__ . ": adding record for $key $summary\n" );
+                               if ( $incrBy > 0 ) {
+                                       $cache->add( $key, 0, intval( $period ) ); // first ping
+                               }
+                       }
+                       if ( $incrBy > 0 ) {
+                               $cache->incr( $key, $incrBy );
+                       }
+               }
+
+               return $triggered;
+       }
+
+       /**
+        * Check if user is blocked
+        *
+        * @param bool $bFromSlave Whether to check the slave database instead of
+        *   the master. Hacked from false due to horrible probs on site.
+        * @return bool True if blocked, false otherwise
+        */
+       public function isBlocked( $bFromSlave = true ) {
+               return $this->getBlock( $bFromSlave ) instanceof Block && $this->getBlock()->prevents( 'edit' );
+       }
+
+       /**
+        * Get the block affecting the user, or null if the user is not blocked
+        *
+        * @param bool $bFromSlave Whether to check the slave database instead of the master
+        * @return Block|null
+        */
+       public function getBlock( $bFromSlave = true ) {
+               $this->getBlockedStatus( $bFromSlave );
+               return $this->mBlock instanceof Block ? $this->mBlock : null;
+       }
+
+       /**
+        * Check if user is blocked from editing a particular article
+        *
+        * @param Title $title Title to check
+        * @param bool $bFromSlave Whether to check the slave database instead of the master
+        * @return bool
+        */
+       public function isBlockedFrom( $title, $bFromSlave = false ) {
+               global $wgBlockAllowsUTEdit;
+
+               $blocked = $this->isBlocked( $bFromSlave );
+               $allowUsertalk = ( $wgBlockAllowsUTEdit ? $this->mAllowUsertalk : false );
+               // If a user's name is suppressed, they cannot make edits anywhere
+               if ( !$this->mHideName && $allowUsertalk && $title->getText() === $this->getName()
+                       && $title->getNamespace() == NS_USER_TALK ) {
+                       $blocked = false;
+                       wfDebug( __METHOD__ . ": self-talk page, ignoring any blocks\n" );
+               }
+
+               Hooks::run( 'UserIsBlockedFrom', array( $this, $title, &$blocked, &$allowUsertalk ) );
+
+               return $blocked;
+       }
+
+       /**
+        * If user is blocked, return the name of the user who placed the block
+        * @return string Name of blocker
+        */
+       public function blockedBy() {
+               $this->getBlockedStatus();
+               return $this->mBlockedby;
+       }
+
+       /**
+        * If user is blocked, return the specified reason for the block
+        * @return string Blocking reason
+        */
+       public function blockedFor() {
+               $this->getBlockedStatus();
+               return $this->mBlockreason;
+       }
+
+       /**
+        * If user is blocked, return the ID for the block
+        * @return int Block ID
+        */
+       public function getBlockId() {
+               $this->getBlockedStatus();
+               return ( $this->mBlock ? $this->mBlock->getId() : false );
+       }
+
+       /**
+        * Check if user is blocked on all wikis.
+        * Do not use for actual edit permission checks!
+        * This is intended for quick UI checks.
+        *
+        * @param string $ip IP address, uses current client if none given
+        * @return bool True if blocked, false otherwise
+        */
+       public function isBlockedGlobally( $ip = '' ) {
+               if ( $this->mBlockedGlobally !== null ) {
+                       return $this->mBlockedGlobally;
+               }
+               // User is already an IP?
+               if ( IP::isIPAddress( $this->getName() ) ) {
+                       $ip = $this->getName();
+               } elseif ( !$ip ) {
+                       $ip = $this->getRequest()->getIP();
+               }
+               $blocked = false;
+               Hooks::run( 'UserIsBlockedGlobally', array( &$this, $ip, &$blocked ) );
+               $this->mBlockedGlobally = (bool)$blocked;
+               return $this->mBlockedGlobally;
+       }
+
+       /**
+        * Check if user account is locked
+        *
+        * @return bool True if locked, false otherwise
+        */
+       public function isLocked() {
+               if ( $this->mLocked !== null ) {
+                       return $this->mLocked;
+               }
+               global $wgAuth;
+               $authUser = $wgAuth->getUserInstance( $this );
+               $this->mLocked = (bool)$authUser->isLocked();
+               Hooks::run( 'UserIsLocked', array( $this, &$this->mLocked ) );
+               return $this->mLocked;
+       }
+
+       /**
+        * Check if user account is hidden
+        *
+        * @return bool True if hidden, false otherwise
+        */
+       public function isHidden() {
+               if ( $this->mHideName !== null ) {
+                       return $this->mHideName;
+               }
+               $this->getBlockedStatus();
+               if ( !$this->mHideName ) {
+                       global $wgAuth;
+                       $authUser = $wgAuth->getUserInstance( $this );
+                       $this->mHideName = (bool)$authUser->isHidden();
+                       Hooks::run( 'UserIsHidden', array( $this, &$this->mHideName ) );
+               }
+               return $this->mHideName;
+       }
+
+       /**
+        * Get the user's ID.
+        * @return int The user's ID; 0 if the user is anonymous or nonexistent
+        */
+       public function getId() {
+               if ( $this->mId === null && $this->mName !== null && User::isIP( $this->mName ) ) {
+                       // Special case, we know the user is anonymous
+                       return 0;
+               } elseif ( !$this->isItemLoaded( 'id' ) ) {
+                       // Don't load if this was initialized from an ID
+                       $this->load();
+               }
+               return $this->mId;
+       }
+
+       /**
+        * Set the user and reload all fields according to a given ID
+        * @param int $v User ID to reload
+        */
+       public function setId( $v ) {
+               $this->mId = $v;
+               $this->clearInstanceCache( 'id' );
+       }
+
+       /**
+        * Get the user name, or the IP of an anonymous user
+        * @return string User's name or IP address
+        */
+       public function getName() {
+               if ( $this->isItemLoaded( 'name', 'only' ) ) {
+                       // Special case optimisation
+                       return $this->mName;
+               } else {
+                       $this->load();
+                       if ( $this->mName === false ) {
+                               // Clean up IPs
+                               $this->mName = IP::sanitizeIP( $this->getRequest()->getIP() );
+                       }
+                       return $this->mName;
+               }
+       }
+
+       /**
+        * Set the user name.
+        *
+        * This does not reload fields from the database according to the given
+        * name. Rather, it is used to create a temporary "nonexistent user" for
+        * later addition to the database. It can also be used to set the IP
+        * address for an anonymous user to something other than the current
+        * remote IP.
+        *
+        * @note User::newFromName() has roughly the same function, when the named user
+        * does not exist.
+        * @param string $str New user name to set
+        */
+       public function setName( $str ) {
+               $this->load();
+               $this->mName = $str;
+       }
+
+       /**
+        * Get the user's name escaped by underscores.
+        * @return string Username escaped by underscores.
+        */
+       public function getTitleKey() {
+               return str_replace( ' ', '_', $this->getName() );
+       }
+
+       /**
+        * Check if the user has new messages.
+        * @return bool True if the user has new messages
+        */
+       public function getNewtalk() {
+               $this->load();
+
+               // Load the newtalk status if it is unloaded (mNewtalk=-1)
+               if ( $this->mNewtalk === -1 ) {
+                       $this->mNewtalk = false; # reset talk page status
+
+                       // Check memcached separately for anons, who have no
+                       // entire User object stored in there.
+                       if ( !$this->mId ) {
+                               global $wgDisableAnonTalk;
+                               if ( $wgDisableAnonTalk ) {
+                                       // Anon newtalk disabled by configuration.
+                                       $this->mNewtalk = false;
+                               } else {
+                                       $this->mNewtalk = $this->checkNewtalk( 'user_ip', $this->getName() );
+                               }
+                       } else {
+                               $this->mNewtalk = $this->checkNewtalk( 'user_id', $this->mId );
+                       }
+               }
+
+               return (bool)$this->mNewtalk;
+       }
+
+       /**
+        * Return the data needed to construct links for new talk page message
+        * alerts. If there are new messages, this will return an associative array
+        * with the following data:
+        *     wiki: The database name of the wiki
+        *     link: Root-relative link to the user's talk page
+        *     rev: The last talk page revision that the user has seen or null. This
+        *         is useful for building diff links.
+        * If there are no new messages, it returns an empty array.
+        * @note This function was designed to accomodate multiple talk pages, but
+        * currently only returns a single link and revision.
+        * @return array
+        */
+       public function getNewMessageLinks() {
+               $talks = array();
+               if ( !Hooks::run( 'UserRetrieveNewTalks', array( &$this, &$talks ) ) ) {
+                       return $talks;
+               } elseif ( !$this->getNewtalk() ) {
+                       return array();
+               }
+               $utp = $this->getTalkPage();
+               $dbr = wfGetDB( DB_SLAVE );
+               // Get the "last viewed rev" timestamp from the oldest message notification
+               $timestamp = $dbr->selectField( 'user_newtalk',
+                       'MIN(user_last_timestamp)',
+                       $this->isAnon() ? array( 'user_ip' => $this->getName() ) : array( 'user_id' => $this->getID() ),
+                       __METHOD__ );
+               $rev = $timestamp ? Revision::loadFromTimestamp( $dbr, $utp, $timestamp ) : null;
+               return array( array( 'wiki' => wfWikiID(), 'link' => $utp->getLocalURL(), 'rev' => $rev ) );
+       }
+
+       /**
+        * Get the revision ID for the last talk page revision viewed by the talk
+        * page owner.
+        * @return int|null Revision ID or null
+        */
+       public function getNewMessageRevisionId() {
+               $newMessageRevisionId = null;
+               $newMessageLinks = $this->getNewMessageLinks();
+               if ( $newMessageLinks ) {
+                       // Note: getNewMessageLinks() never returns more than a single link
+                       // and it is always for the same wiki, but we double-check here in
+                       // case that changes some time in the future.
+                       if ( count( $newMessageLinks ) === 1
+                               && $newMessageLinks[0]['wiki'] === wfWikiID()
+                               && $newMessageLinks[0]['rev']
+                       ) {
+                               /** @var Revision $newMessageRevision */
+                               $newMessageRevision = $newMessageLinks[0]['rev'];
+                               $newMessageRevisionId = $newMessageRevision->getId();
+                       }
+               }
+               return $newMessageRevisionId;
+       }
+
+       /**
+        * Internal uncached check for new messages
+        *
+        * @see getNewtalk()
+        * @param string $field 'user_ip' for anonymous users, 'user_id' otherwise
+        * @param string|int $id User's IP address for anonymous users, User ID otherwise
+        * @return bool True if the user has new messages
+        */
+       protected function checkNewtalk( $field, $id ) {
+               $dbr = wfGetDB( DB_SLAVE );
+
+               $ok = $dbr->selectField( 'user_newtalk', $field, array( $field => $id ), __METHOD__ );
+
+               return $ok !== false;
+       }
+
+       /**
+        * Add or update the new messages flag
+        * @param string $field 'user_ip' for anonymous users, 'user_id' otherwise
+        * @param string|int $id User's IP address for anonymous users, User ID otherwise
+        * @param Revision|null $curRev New, as yet unseen revision of the user talk page. Ignored if null.
+        * @return bool True if successful, false otherwise
+        */
+       protected function updateNewtalk( $field, $id, $curRev = null ) {
+               // Get timestamp of the talk page revision prior to the current one
+               $prevRev = $curRev ? $curRev->getPrevious() : false;
+               $ts = $prevRev ? $prevRev->getTimestamp() : null;
+               // Mark the user as having new messages since this revision
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->insert( 'user_newtalk',
+                       array( $field => $id, 'user_last_timestamp' => $dbw->timestampOrNull( $ts ) ),
+                       __METHOD__,
+                       'IGNORE' );
+               if ( $dbw->affectedRows() ) {
+                       wfDebug( __METHOD__ . ": set on ($field, $id)\n" );
+                       return true;
+               } else {
+                       wfDebug( __METHOD__ . " already set ($field, $id)\n" );
+                       return false;
+               }
+       }
+
+       /**
+        * Clear the new messages flag for the given user
+        * @param string $field 'user_ip' for anonymous users, 'user_id' otherwise
+        * @param string|int $id User's IP address for anonymous users, User ID otherwise
+        * @return bool True if successful, false otherwise
+        */
+       protected function deleteNewtalk( $field, $id ) {
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->delete( 'user_newtalk',
+                       array( $field => $id ),
+                       __METHOD__ );
+               if ( $dbw->affectedRows() ) {
+                       wfDebug( __METHOD__ . ": killed on ($field, $id)\n" );
+                       return true;
+               } else {
+                       wfDebug( __METHOD__ . ": already gone ($field, $id)\n" );
+                       return false;
+               }
+       }
+
+       /**
+        * Update the 'You have new messages!' status.
+        * @param bool $val Whether the user has new messages
+        * @param Revision $curRev New, as yet unseen revision of the user talk
+        *   page. Ignored if null or !$val.
+        */
+       public function setNewtalk( $val, $curRev = null ) {
+               if ( wfReadOnly() ) {
+                       return;
+               }
+
+               $this->load();
+               $this->mNewtalk = $val;
+
+               if ( $this->isAnon() ) {
+                       $field = 'user_ip';
+                       $id = $this->getName();
+               } else {
+                       $field = 'user_id';
+                       $id = $this->getId();
+               }
+
+               if ( $val ) {
+                       $changed = $this->updateNewtalk( $field, $id, $curRev );
+               } else {
+                       $changed = $this->deleteNewtalk( $field, $id );
+               }
+
+               if ( $changed ) {
+                       $this->invalidateCache();
+               }
+       }
+
+       /**
+        * Generate a current or new-future timestamp to be stored in the
+        * user_touched field when we update things.
+        * @return string Timestamp in TS_MW format
+        */
+       private function newTouchedTimestamp() {
+               global $wgClockSkewFudge;
+
+               $time = wfTimestamp( TS_MW, time() + $wgClockSkewFudge );
+               if ( $this->mTouched && $time <= $this->mTouched ) {
+                       $time = wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $this->mTouched ) + 1 );
+               }
+
+               return $time;
+       }
+
+       /**
+        * Clear user data from memcached
+        *
+        * Use after applying updates to the database; caller's
+        * responsibility to update user_touched if appropriate.
+        *
+        * Called implicitly from invalidateCache() and saveSettings().
+        *
+        * @param string $mode Use 'refresh' to clear now; otherwise before DB commit
+        */
+       public function clearSharedCache( $mode = 'changed' ) {
+               if ( !$this->getId() ) {
+                       return;
+               }
+
+               $cache = ObjectCache::getMainWANInstance();
+               $key = $this->getCacheKey( $cache );
+               if ( $mode === 'refresh' ) {
+                       $cache->delete( $key, 1 );
+               } else {
+                       wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $cache, $key ) {
+                               $cache->delete( $key );
+                       } );
+               }
+       }
+
+       /**
+        * Immediately touch the user data cache for this account
+        *
+        * Calls touch() and removes account data from memcached
+        */
+       public function invalidateCache() {
+               $this->touch();
+               $this->clearSharedCache();
+       }
+
+       /**
+        * Update the "touched" timestamp for the user
+        *
+        * This is useful on various login/logout events when making sure that
+        * a browser or proxy that has multiple tenants does not suffer cache
+        * pollution where the new user sees the old users content. The value
+        * of getTouched() is checked when determining 304 vs 200 responses.
+        * Unlike invalidateCache(), this preserves the User object cache and
+        * avoids database writes.
+        *
+        * @since 1.25
+        */
+       public function touch() {
+               $id = $this->getId();
+               if ( $id ) {
+                       $key = wfMemcKey( 'user-quicktouched', 'id', $id );
+                       ObjectCache::getMainWANInstance()->touchCheckKey( $key );
+                       $this->mQuickTouched = null;
+               }
+       }
+
+       /**
+        * Validate the cache for this account.
+        * @param string $timestamp A timestamp in TS_MW format
+        * @return bool
+        */
+       public function validateCache( $timestamp ) {
+               return ( $timestamp >= $this->getTouched() );
+       }
+
+       /**
+        * Get the user touched timestamp
+        *
+        * Use this value only to validate caches via inequalities
+        * such as in the case of HTTP If-Modified-Since response logic
+        *
+        * @return string TS_MW Timestamp
+        */
+       public function getTouched() {
+               $this->load();
+
+               if ( $this->mId ) {
+                       if ( $this->mQuickTouched === null ) {
+                               $key = wfMemcKey( 'user-quicktouched', 'id', $this->mId );
+                               $cache = ObjectCache::getMainWANInstance();
+
+                               $this->mQuickTouched = wfTimestamp( TS_MW, $cache->getCheckKeyTime( $key ) );
+                       }
+
+                       return max( $this->mTouched, $this->mQuickTouched );
+               }
+
+               return $this->mTouched;
+       }
+
+       /**
+        * Get the user_touched timestamp field (time of last DB updates)
+        * @return string TS_MW Timestamp
+        * @since 1.26
+        */
+       public function getDBTouched() {
+               $this->load();
+
+               return $this->mTouched;
+       }
+
+       /**
+        * @deprecated Removed in 1.27.
+        * @return Password
+        * @since 1.24
+        */
+       public function getPassword() {
+               throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
+       }
+
+       /**
+        * @deprecated Removed in 1.27.
+        * @return Password
+        * @since 1.24
+        */
+       public function getTemporaryPassword() {
+               throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' );
+       }
+
+       /**
+        * Set the password and reset the random token.
+        * Calls through to authentication plugin if necessary;
+        * will have no effect if the auth plugin refuses to
+        * pass the change through or if the legal password
+        * checks fail.
+        *
+        * As a special case, setting the password to null
+        * wipes it, so the account cannot be logged in until
+        * a new password is set, for instance via e-mail.
+        *
+        * @deprecated since 1.27. AuthManager is coming.
+        * @param string $str New password to set
+        * @throws PasswordError On failure
+        * @return bool
+        */
+       public function setPassword( $str ) {
+               global $wgAuth;
+
+               if ( $str !== null ) {
+                       if ( !$wgAuth->allowPasswordChange() ) {
+                               throw new PasswordError( wfMessage( 'password-change-forbidden' )->text() );
+                       }
+
+                       $status = $this->checkPasswordValidity( $str );
+                       if ( !$status->isGood() ) {
+                               throw new PasswordError( $status->getMessage()->text() );
+                       }
+               }
+
+               if ( !$wgAuth->setPassword( $this, $str ) ) {
+                       throw new PasswordError( wfMessage( 'externaldberror' )->text() );
+               }
+
+               $this->setToken();
+               $this->setOption( 'watchlisttoken', false );
+               $this->setPasswordInternal( $str );
+
+               return true;
+       }
+
+       /**
+        * Set the password and reset the random token unconditionally.
+        *
+        * @deprecated since 1.27. AuthManager is coming.
+        * @param string|null $str New password to set or null to set an invalid
+        *  password hash meaning that the user will not be able to log in
+        *  through the web interface.
+        */
+       public function setInternalPassword( $str ) {
+               global $wgAuth;
+
+               if ( $wgAuth->allowSetLocalPassword() ) {
+                       $this->setToken();
+                       $this->setOption( 'watchlisttoken', false );
+                       $this->setPasswordInternal( $str );
+               }
+       }
+
+       /**
+        * Actually set the password and such
+        * @since 1.27 cannot set a password for a user not in the database
+        * @param string|null $str New password to set or null to set an invalid
+        *  password hash meaning that the user will not be able to log in
+        *  through the web interface.
+        */
+       private function setPasswordInternal( $str ) {
+               $id = self::idFromName( $this->getName(), self::READ_LATEST );
+               if ( $id == 0 ) {
+                       throw new LogicException( 'Cannot set a password for a user that is not in the database.' );
+               }
+
+               $passwordFactory = new PasswordFactory();
+               $passwordFactory->init( RequestContext::getMain()->getConfig() );
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->update(
+                       'user',
+                       array(
+                               'user_password' => $passwordFactory->newFromPlaintext( $str )->toString(),
+                               'user_newpassword' => PasswordFactory::newInvalidPassword()->toString(),
+                               'user_newpass_time' => $dbw->timestampOrNull( null ),
+                       ),
+                       array(
+                               'user_id' => $id,
+                       ),
+                       __METHOD__
+               );
+       }
+
+       /**
+        * Get the user's current token.
+        * @param bool $forceCreation Force the generation of a new token if the
+        *   user doesn't have one (default=true for backwards compatibility).
+        * @return string Token
+        */
+       public function getToken( $forceCreation = true ) {
+               $this->load();
+               if ( !$this->mToken && $forceCreation ) {
+                       $this->setToken();
+               }
+               return $this->mToken;
+       }
+
+       /**
+        * Set the random token (used for persistent authentication)
+        * Called from loadDefaults() among other places.
+        *
+        * @param string|bool $token If specified, set the token to this value
+        */
+       public function setToken( $token = false ) {
+               $this->load();
+               if ( !$token ) {
+                       $this->mToken = MWCryptRand::generateHex( self::TOKEN_LENGTH );
+               } else {
+                       $this->mToken = $token;
+               }
+       }
+
+       /**
+        * Set the password for a password reminder or new account email
+        *
+        * @deprecated since 1.27, AuthManager is coming
+        * @param string $str New password to set or null to set an invalid
+        *  password hash meaning that the user will not be able to use it
+        * @param bool $throttle If true, reset the throttle timestamp to the present
+        */
+       public function setNewpassword( $str, $throttle = true ) {
+               $id = $this->getId();
+               if ( $id == 0 ) {
+                       throw new LogicException( 'Cannot set new password for a user that is not in the database.' );
+               }
+
+               $dbw = wfGetDB( DB_MASTER );
+
+               $passwordFactory = new PasswordFactory();
+               $passwordFactory->init( RequestContext::getMain()->getConfig() );
+               $update = array(
+                       'user_newpassword' => $passwordFactory->newFromPlaintext( $str )->toString(),
+               );
+
+               if ( $str === null ) {
+                       $update['user_newpass_time'] = null;
+               } elseif ( $throttle ) {
+                       $update['user_newpass_time'] = $dbw->timestamp();
+               }
+
+               $dbw->update( 'user', $update, array( 'user_id' => $id ), __METHOD__ );
+       }
+
+       /**
+        * Has password reminder email been sent within the last
+        * $wgPasswordReminderResendTime hours?
+        * @return bool
+        */
+       public function isPasswordReminderThrottled() {
+               global $wgPasswordReminderResendTime;
+
+               if ( !$wgPasswordReminderResendTime ) {
+                       return false;
+               }
+
+               $this->load();
+
+               $db = ( $this->queryFlagsUsed & self::READ_LATEST )
+                       ? wfGetDB( DB_MASTER )
+                       : wfGetDB( DB_SLAVE );
+               $newpassTime = $db->selectField(
+                       'user',
+                       'user_newpass_time',
+                       array( 'user_id' => $this->getId() ),
+                       __METHOD__
+               );
+
+               if ( $newpassTime === null ) {
+                       return false;
+               }
+               $expiry = wfTimestamp( TS_UNIX, $newpassTime ) + $wgPasswordReminderResendTime * 3600;
+               return time() < $expiry;
+       }
+
+       /**
+        * Get the user's e-mail address
+        * @return string User's email address
+        */
+       public function getEmail() {
+               $this->load();
+               Hooks::run( 'UserGetEmail', array( $this, &$this->mEmail ) );
+               return $this->mEmail;
+       }
+
+       /**
+        * Get the timestamp of the user's e-mail authentication
+        * @return string TS_MW timestamp
+        */
+       public function getEmailAuthenticationTimestamp() {
+               $this->load();
+               Hooks::run( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
+               return $this->mEmailAuthenticated;
+       }
+
+       /**
+        * Set the user's e-mail address
+        * @param string $str New e-mail address
+        */
+       public function setEmail( $str ) {
+               $this->load();
+               if ( $str == $this->mEmail ) {
+                       return;
+               }
+               $this->invalidateEmail();
+               $this->mEmail = $str;
+               Hooks::run( 'UserSetEmail', array( $this, &$this->mEmail ) );
+       }
+
+       /**
+        * Set the user's e-mail address and a confirmation mail if needed.
+        *
+        * @since 1.20
+        * @param string $str New e-mail address
+        * @return Status
+        */
+       public function setEmailWithConfirmation( $str ) {
+               global $wgEnableEmail, $wgEmailAuthentication;
+
+               if ( !$wgEnableEmail ) {
+                       return Status::newFatal( 'emaildisabled' );
+               }
+
+               $oldaddr = $this->getEmail();
+               if ( $str === $oldaddr ) {
+                       return Status::newGood( true );
+               }
+
+               $this->setEmail( $str );
+
+               if ( $str !== '' && $wgEmailAuthentication ) {
+                       // Send a confirmation request to the new address if needed
+                       $type = $oldaddr != '' ? 'changed' : 'set';
+                       $result = $this->sendConfirmationMail( $type );
+                       if ( $result->isGood() ) {
+                               // Say to the caller that a confirmation mail has been sent
+                               $result->value = 'eauth';
+                       }
+               } else {
+                       $result = Status::newGood( true );
+               }
+
+               return $result;
+       }
+
+       /**
+        * Get the user's real name
+        * @return string User's real name
+        */
+       public function getRealName() {
+               if ( !$this->isItemLoaded( 'realname' ) ) {
+                       $this->load();
+               }
+
+               return $this->mRealName;
+       }
+
+       /**
+        * Set the user's real name
+        * @param string $str New real name
+        */
+       public function setRealName( $str ) {
+               $this->load();
+               $this->mRealName = $str;
+       }
+
+       /**
+        * Get the user's current setting for a given option.
+        *
+        * @param string $oname The option to check
+        * @param string $defaultOverride A default value returned if the option does not exist
+        * @param bool $ignoreHidden Whether to ignore the effects of $wgHiddenPrefs
+        * @return string User's current value for the option
+        * @see getBoolOption()
+        * @see getIntOption()
+        */
+       public function getOption( $oname, $defaultOverride = null, $ignoreHidden = false ) {
+               global $wgHiddenPrefs;
+               $this->loadOptions();
+
+               # We want 'disabled' preferences to always behave as the default value for
+               # users, even if they have set the option explicitly in their settings (ie they
+               # set it, and then it was disabled removing their ability to change it).  But
+               # we don't want to erase the preferences in the database in case the preference
+               # is re-enabled again.  So don't touch $mOptions, just override the returned value
+               if ( !$ignoreHidden && in_array( $oname, $wgHiddenPrefs ) ) {
+                       return self::getDefaultOption( $oname );
+               }
+
+               if ( array_key_exists( $oname, $this->mOptions ) ) {
+                       return $this->mOptions[$oname];
+               } else {
+                       return $defaultOverride;
+               }
+       }
+
+       /**
+        * 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( $flags = 0 ) {
+               global $wgHiddenPrefs;
+               $this->loadOptions();
+               $options = $this->mOptions;
+
+               # We want 'disabled' preferences to always behave as the default value for
+               # users, even if they have set the option explicitly in their settings (ie they
+               # set it, and then it was disabled removing their ability to change it).  But
+               # we don't want to erase the preferences in the database in case the preference
+               # is re-enabled again.  So don't touch $mOptions, just override the returned value
+               foreach ( $wgHiddenPrefs as $pref ) {
+                       $default = self::getDefaultOption( $pref );
+                       if ( $default !== null ) {
+                               $options[$pref] = $default;
+                       }
+               }
+
+               if ( $flags & self::GETOPTIONS_EXCLUDE_DEFAULTS ) {
+                       $options = array_diff_assoc( $options, self::getDefaultOptions() );
+               }
+
+               return $options;
+       }
+
+       /**
+        * Get the user's current setting for a given option, as a boolean value.
+        *
+        * @param string $oname The option to check
+        * @return bool User's current value for the option
+        * @see getOption()
+        */
+       public function getBoolOption( $oname ) {
+               return (bool)$this->getOption( $oname );
+       }
+
+       /**
+        * Get the user's current setting for a given option, as an integer value.
+        *
+        * @param string $oname The option to check
+        * @param int $defaultOverride A default value returned if the option does not exist
+        * @return int User's current value for the option
+        * @see getOption()
+        */
+       public function getIntOption( $oname, $defaultOverride = 0 ) {
+               $val = $this->getOption( $oname );
+               if ( $val == '' ) {
+                       $val = $defaultOverride;
+               }
+               return intval( $val );
+       }
+
+       /**
+        * Set the given option for a user.
+        *
+        * You need to call saveSettings() to actually write to the database.
+        *
+        * @param string $oname The option to set
+        * @param mixed $val New value to set
+        */
+       public function setOption( $oname, $val ) {
+               $this->loadOptions();
+
+               // Explicitly NULL values should refer to defaults
+               if ( is_null( $val ) ) {
+                       $val = self::getDefaultOption( $oname );
+               }
+
+               $this->mOptions[$oname] = $val;
+       }
+
+       /**
+        * Get a token stored in the preferences (like the watchlist one),
+        * resetting it if it's empty (and saving changes).
+        *
+        * @param string $oname The option name to retrieve the token from
+        * @return string|bool User's current value for the option, or false if this option is disabled.
+        * @see resetTokenFromOption()
+        * @see getOption()
+        * @deprecated 1.26 Applications should use the OAuth extension
+        */
+       public function getTokenFromOption( $oname ) {
+               global $wgHiddenPrefs;
+
+               $id = $this->getId();
+               if ( !$id || in_array( $oname, $wgHiddenPrefs ) ) {
+                       return false;
+               }
+
+               $token = $this->getOption( $oname );
+               if ( !$token ) {
+                       // Default to a value based on the user token to avoid space
+                       // wasted on storing tokens for all users. When this option
+                       // is set manually by the user, only then is it stored.
+                       $token = hash_hmac( 'sha1', "$oname:$id", $this->getToken() );
+               }
+
+               return $token;
+       }
+
+       /**
+        * Reset a token stored in the preferences (like the watchlist one).
+        * *Does not* save user's preferences (similarly to setOption()).
+        *
+        * @param string $oname The option name to reset the token in
+        * @return string|bool New token value, or false if this option is disabled.
+        * @see getTokenFromOption()
+        * @see setOption()
+        */
+       public function resetTokenFromOption( $oname ) {
+               global $wgHiddenPrefs;
+               if ( in_array( $oname, $wgHiddenPrefs ) ) {
+                       return false;
+               }
+
+               $token = MWCryptRand::generateHex( 40 );
+               $this->setOption( $oname, $token );
+               return $token;
+       }
+
+       /**
+        * Return a list of the types of user options currently returned by
+        * User::getOptionKinds().
+        *
+        * Currently, the option kinds are:
+        * - 'registered' - preferences which are registered in core MediaWiki or
+        *                  by extensions using the UserGetDefaultOptions hook.
+        * - 'registered-multiselect' - as above, using the 'multiselect' type.
+        * - 'registered-checkmatrix' - as above, using the 'checkmatrix' type.
+        * - 'userjs' - preferences with names starting with 'userjs-', intended to
+        *              be used by user scripts.
+        * - 'special' - "preferences" that are not accessible via User::getOptions
+        *               or User::setOptions.
+        * - 'unused' - preferences about which MediaWiki doesn't know anything.
+        *              These are usually legacy options, removed in newer versions.
+        *
+        * The API (and possibly others) use this function to determine the possible
+        * option types for validation purposes, so make sure to update this when a
+        * new option kind is added.
+        *
+        * @see User::getOptionKinds
+        * @return array Option kinds
+        */
+       public static function listOptionKinds() {
+               return array(
+                       'registered',
+                       'registered-multiselect',
+                       'registered-checkmatrix',
+                       'userjs',
+                       'special',
+                       'unused'
+               );
+       }
+
+       /**
+        * Return an associative array mapping preferences keys to the kind of a preference they're
+        * used for. Different kinds are handled differently when setting or reading preferences.
+        *
+        * See User::listOptionKinds for the list of valid option types that can be provided.
+        *
+        * @see User::listOptionKinds
+        * @param IContextSource $context
+        * @param array $options Assoc. array with options keys to check as keys.
+        *   Defaults to $this->mOptions.
+        * @return array The key => kind mapping data
+        */
+       public function getOptionKinds( IContextSource $context, $options = null ) {
+               $this->loadOptions();
+               if ( $options === null ) {
+                       $options = $this->mOptions;
+               }
+
+               $prefs = Preferences::getPreferences( $this, $context );
+               $mapping = array();
+
+               // Pull out the "special" options, so they don't get converted as
+               // multiselect or checkmatrix.
+               $specialOptions = array_fill_keys( Preferences::getSaveBlacklist(), true );
+               foreach ( $specialOptions as $name => $value ) {
+                       unset( $prefs[$name] );
+               }
+
+               // Multiselect and checkmatrix options are stored in the database with
+               // one key per option, each having a boolean value. Extract those keys.
+               $multiselectOptions = array();
+               foreach ( $prefs as $name => $info ) {
+                       if ( ( isset( $info['type'] ) && $info['type'] == 'multiselect' ) ||
+                                       ( isset( $info['class'] ) && $info['class'] == 'HTMLMultiSelectField' ) ) {
+                               $opts = HTMLFormField::flattenOptions( $info['options'] );
+                               $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
+
+                               foreach ( $opts as $value ) {
+                                       $multiselectOptions["$prefix$value"] = true;
+                               }
+
+                               unset( $prefs[$name] );
+                       }
+               }
+               $checkmatrixOptions = array();
+               foreach ( $prefs as $name => $info ) {
+                       if ( ( isset( $info['type'] ) && $info['type'] == 'checkmatrix' ) ||
+                                       ( isset( $info['class'] ) && $info['class'] == 'HTMLCheckMatrix' ) ) {
+                               $columns = HTMLFormField::flattenOptions( $info['columns'] );
+                               $rows = HTMLFormField::flattenOptions( $info['rows'] );
+                               $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
+
+                               foreach ( $columns as $column ) {
+                                       foreach ( $rows as $row ) {
+                                               $checkmatrixOptions["$prefix$column-$row"] = true;
+                                       }
+                               }
+
+                               unset( $prefs[$name] );
+                       }
+               }
+
+               // $value is ignored
+               foreach ( $options as $key => $value ) {
+                       if ( isset( $prefs[$key] ) ) {
+                               $mapping[$key] = 'registered';
+                       } elseif ( isset( $multiselectOptions[$key] ) ) {
+                               $mapping[$key] = 'registered-multiselect';
+                       } elseif ( isset( $checkmatrixOptions[$key] ) ) {
+                               $mapping[$key] = 'registered-checkmatrix';
+                       } elseif ( isset( $specialOptions[$key] ) ) {
+                               $mapping[$key] = 'special';
+                       } elseif ( substr( $key, 0, 7 ) === 'userjs-' ) {
+                               $mapping[$key] = 'userjs';
+                       } else {
+                               $mapping[$key] = 'unused';
+                       }
+               }
+
+               return $mapping;
+       }
+
+       /**
+        * Reset certain (or all) options to the site defaults
+        *
+        * The optional parameter determines which kinds of preferences will be reset.
+        * Supported values are everything that can be reported by getOptionKinds()
+        * and 'all', which forces a reset of *all* preferences and overrides everything else.
+        *
+        * @param array|string $resetKinds Which kinds of preferences to reset. Defaults to
+        *  array( 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused' )
+        *  for backwards-compatibility.
+        * @param IContextSource|null $context Context source used when $resetKinds
+        *  does not contain 'all', passed to getOptionKinds().
+        *  Defaults to RequestContext::getMain() when null.
+        */
+       public function resetOptions(
+               $resetKinds = array( 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused' ),
+               IContextSource $context = null
+       ) {
+               $this->load();
+               $defaultOptions = self::getDefaultOptions();
+
+               if ( !is_array( $resetKinds ) ) {
+                       $resetKinds = array( $resetKinds );
+               }
+
+               if ( in_array( 'all', $resetKinds ) ) {
+                       $newOptions = $defaultOptions;
+               } else {
+                       if ( $context === null ) {
+                               $context = RequestContext::getMain();
+                       }
+
+                       $optionKinds = $this->getOptionKinds( $context );
+                       $resetKinds = array_intersect( $resetKinds, self::listOptionKinds() );
+                       $newOptions = array();
+
+                       // Use default values for the options that should be deleted, and
+                       // copy old values for the ones that shouldn't.
+                       foreach ( $this->mOptions as $key => $value ) {
+                               if ( in_array( $optionKinds[$key], $resetKinds ) ) {
+                                       if ( array_key_exists( $key, $defaultOptions ) ) {
+                                               $newOptions[$key] = $defaultOptions[$key];
+                                       }
+                               } else {
+                                       $newOptions[$key] = $value;
+                               }
+                       }
+               }
+
+               Hooks::run( 'UserResetAllOptions', array( $this, &$newOptions, $this->mOptions, $resetKinds ) );
+
+               $this->mOptions = $newOptions;
+               $this->mOptionsLoaded = true;
+       }
+
+       /**
+        * Get the user's preferred date format.
+        * @return string User's preferred date format
+        */
+       public function getDatePreference() {
+               // Important migration for old data rows
+               if ( is_null( $this->mDatePreference ) ) {
+                       global $wgLang;
+                       $value = $this->getOption( 'date' );
+                       $map = $wgLang->getDatePreferenceMigrationMap();
+                       if ( isset( $map[$value] ) ) {
+                               $value = $map[$value];
+                       }
+                       $this->mDatePreference = $value;
+               }
+               return $this->mDatePreference;
+       }
+
+       /**
+        * Determine based on the wiki configuration and the user's options,
+        * whether this user must be over HTTPS no matter what.
+        *
+        * @return bool
+        */
+       public function requiresHTTPS() {
+               global $wgSecureLogin;
+               if ( !$wgSecureLogin ) {
+                       return false;
+               } else {
+                       $https = $this->getBoolOption( 'prefershttps' );
+                       Hooks::run( 'UserRequiresHTTPS', array( $this, &$https ) );
+                       if ( $https ) {
+                               $https = wfCanIPUseHTTPS( $this->getRequest()->getIP() );
+                       }
+                       return $https;
+               }
+       }
+
+       /**
+        * Get the user preferred stub threshold
+        *
+        * @return int
+        */
+       public function getStubThreshold() {
+               global $wgMaxArticleSize; # Maximum article size, in Kb
+               $threshold = $this->getIntOption( 'stubthreshold' );
+               if ( $threshold > $wgMaxArticleSize * 1024 ) {
+                       // If they have set an impossible value, disable the preference
+                       // so we can use the parser cache again.
+                       $threshold = 0;
+               }
+               return $threshold;
+       }
+
+       /**
+        * Get the permissions this user has.
+        * @return array Array of String permission names
+        */
+       public function getRights() {
+               if ( is_null( $this->mRights ) ) {
+                       $this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() );
+                       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 ) );
+               }
+               return $this->mRights;
+       }
+
+       /**
+        * Get the list of explicit group memberships this user has.
+        * The implicit * and user groups are not included.
+        * @return array Array of String internal group names
+        */
+       public function getGroups() {
+               $this->load();
+               $this->loadGroups();
+               return $this->mGroups;
+       }
+
+       /**
+        * Get the list of implicit group memberships this user has.
+        * This includes all explicit groups, plus 'user' if logged in,
+        * '*' for all accounts, and autopromoted groups
+        * @param bool $recache Whether to avoid the cache
+        * @return array Array of String internal group names
+        */
+       public function getEffectiveGroups( $recache = false ) {
+               if ( $recache || is_null( $this->mEffectiveGroups ) ) {
+                       $this->mEffectiveGroups = array_unique( array_merge(
+                               $this->getGroups(), // explicit groups
+                               $this->getAutomaticGroups( $recache ) // implicit groups
+                       ) );
+                       // Hook for additional groups
+                       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 ) );
+               }
+               return $this->mEffectiveGroups;
+       }
+
+       /**
+        * Get the list of implicit group memberships this user has.
+        * This includes 'user' if logged in, '*' for all accounts,
+        * and autopromoted groups
+        * @param bool $recache Whether to avoid the cache
+        * @return array Array of String internal group names
+        */
+       public function getAutomaticGroups( $recache = false ) {
+               if ( $recache || is_null( $this->mImplicitGroups ) ) {
+                       $this->mImplicitGroups = array( '*' );
+                       if ( $this->getId() ) {
+                               $this->mImplicitGroups[] = 'user';
+
+                               $this->mImplicitGroups = array_unique( array_merge(
+                                       $this->mImplicitGroups,
+                                       Autopromote::getAutopromoteGroups( $this )
+                               ) );
+                       }
+                       if ( $recache ) {
+                               // Assure data consistency with rights/groups,
+                               // as getEffectiveGroups() depends on this function
+                               $this->mEffectiveGroups = null;
+                       }
+               }
+               return $this->mImplicitGroups;
+       }
+
+       /**
+        * Returns the groups the user has belonged to.
+        *
+        * The user may still belong to the returned groups. Compare with getGroups().
+        *
+        * The function will not return groups the user had belonged to before MW 1.17
+        *
+        * @return array Names of the groups the user has belonged to.
+        */
+       public function getFormerGroups() {
+               $this->load();
+
+               if ( is_null( $this->mFormerGroups ) ) {
+                       $db = ( $this->queryFlagsUsed & self::READ_LATEST )
+                               ? wfGetDB( DB_MASTER )
+                               : wfGetDB( DB_SLAVE );
+                       $res = $db->select( 'user_former_groups',
+                               array( 'ufg_group' ),
+                               array( 'ufg_user' => $this->mId ),
+                               __METHOD__ );
+                       $this->mFormerGroups = array();
+                       foreach ( $res as $row ) {
+                               $this->mFormerGroups[] = $row->ufg_group;
+                       }
+               }
+
+               return $this->mFormerGroups;
+       }
+
+       /**
+        * Get the user's edit count.
+        * @return int|null Null for anonymous users
+        */
+       public function getEditCount() {
+               if ( !$this->getId() ) {
+                       return null;
+               }
+
+               if ( $this->mEditCount === null ) {
+                       /* Populate the count, if it has not been populated yet */
+                       $dbr = wfGetDB( DB_SLAVE );
+                       // check if the user_editcount field has been initialized
+                       $count = $dbr->selectField(
+                               'user', 'user_editcount',
+                               array( 'user_id' => $this->mId ),
+                               __METHOD__
+                       );
+
+                       if ( $count === null ) {
+                               // it has not been initialized. do so.
+                               $count = $this->initEditCount();
+                       }
+                       $this->mEditCount = $count;
+               }
+               return (int)$this->mEditCount;
+       }
+
+       /**
+        * Add the user to the given group.
+        * This takes immediate effect.
+        * @param string $group Name of the group to add
+        * @return bool
+        */
+       public function addGroup( $group ) {
+               $this->load();
+
+               if ( !Hooks::run( 'UserAddGroup', array( $this, &$group ) ) ) {
+                       return false;
+               }
+
+               $dbw = wfGetDB( DB_MASTER );
+               if ( $this->getId() ) {
+                       $dbw->insert( 'user_groups',
+                               array(
+                                       'ug_user' => $this->getID(),
+                                       'ug_group' => $group,
+                               ),
+                               __METHOD__,
+                               array( 'IGNORE' ) );
+               }
+
+               $this->loadGroups();
+               $this->mGroups[] = $group;
+               // In case loadGroups was not called before, we now have the right twice.
+               // Get rid of the duplicate.
+               $this->mGroups = array_unique( $this->mGroups );
+
+               // Refresh the groups caches, and clear the rights cache so it will be
+               // refreshed on the next call to $this->getRights().
+               $this->getEffectiveGroups( true );
+               $this->mRights = null;
+
+               $this->invalidateCache();
+
+               return true;
+       }
+
+       /**
+        * Remove the user from the given group.
+        * This takes immediate effect.
+        * @param string $group Name of the group to remove
+        * @return bool
+        */
+       public function removeGroup( $group ) {
+               $this->load();
+               if ( !Hooks::run( 'UserRemoveGroup', array( $this, &$group ) ) ) {
+                       return false;
+               }
+
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->delete( 'user_groups',
+                       array(
+                               'ug_user' => $this->getID(),
+                               'ug_group' => $group,
+                       ), __METHOD__
+               );
+               // Remember that the user was in this group
+               $dbw->insert( 'user_former_groups',
+                       array(
+                               'ufg_user' => $this->getID(),
+                               'ufg_group' => $group,
+                       ),
+                       __METHOD__,
+                       array( 'IGNORE' )
+               );
+
+               $this->loadGroups();
+               $this->mGroups = array_diff( $this->mGroups, array( $group ) );
+
+               // Refresh the groups caches, and clear the rights cache so it will be
+               // refreshed on the next call to $this->getRights().
+               $this->getEffectiveGroups( true );
+               $this->mRights = null;
+
+               $this->invalidateCache();
+
+               return true;
+       }
+
+       /**
+        * Get whether the user is logged in
+        * @return bool
+        */
+       public function isLoggedIn() {
+               return $this->getID() != 0;
+       }
+
+       /**
+        * Get whether the user is anonymous
+        * @return bool
+        */
+       public function isAnon() {
+               return !$this->isLoggedIn();
+       }
+
+       /**
+        * Check if user is allowed to access a feature / make an action
+        *
+        * @param string ... Permissions to test
+        * @return bool True if user is allowed to perform *any* of the given actions
+        */
+       public function isAllowedAny() {
+               $permissions = func_get_args();
+               foreach ( $permissions as $permission ) {
+                       if ( $this->isAllowed( $permission ) ) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        *
+        * @param string ... Permissions to test
+        * @return bool True if the user is allowed to perform *all* of the given actions
+        */
+       public function isAllowedAll() {
+               $permissions = func_get_args();
+               foreach ( $permissions as $permission ) {
+                       if ( !$this->isAllowed( $permission ) ) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       /**
+        * Internal mechanics of testing a permission
+        * @param string $action
+        * @return bool
+        */
+       public function isAllowed( $action = '' ) {
+               if ( $action === '' ) {
+                       return true; // In the spirit of DWIM
+               }
+               // Patrolling may not be enabled
+               if ( $action === 'patrol' || $action === 'autopatrol' ) {
+                       global $wgUseRCPatrol, $wgUseNPPatrol;
+                       if ( !$wgUseRCPatrol && !$wgUseNPPatrol ) {
+                               return false;
+                       }
+               }
+               // Use strict parameter to avoid matching numeric 0 accidentally inserted
+               // by misconfiguration: 0 == 'foo'
+               return in_array( $action, $this->getRights(), true );
+       }
+
+       /**
+        * Check whether to enable recent changes patrol features for this user
+        * @return bool True or false
+        */
+       public function useRCPatrol() {
+               global $wgUseRCPatrol;
+               return $wgUseRCPatrol && $this->isAllowedAny( 'patrol', 'patrolmarks' );
+       }
+
+       /**
+        * Check whether to enable new pages patrol features for this user
+        * @return bool True or false
+        */
+       public function useNPPatrol() {
+               global $wgUseRCPatrol, $wgUseNPPatrol;
+               return (
+                       ( $wgUseRCPatrol || $wgUseNPPatrol )
+                               && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
+               );
+       }
+
+       /**
+        * Get the WebRequest object to use with this object
+        *
+        * @return WebRequest
+        */
+       public function getRequest() {
+               if ( $this->mRequest ) {
+                       return $this->mRequest;
+               } else {
+                       global $wgRequest;
+                       return $wgRequest;
+               }
+       }
+
+       /**
+        * Get the current skin, loading it if required
+        * @return Skin The current skin
+        * @todo FIXME: Need to check the old failback system [AV]
+        * @deprecated since 1.18 Use ->getSkin() in the most relevant outputting context you have
+        */
+       public function getSkin() {
+               wfDeprecated( __METHOD__, '1.18' );
+               return RequestContext::getMain()->getSkin();
+       }
+
+       /**
+        * Get a WatchedItem for this user and $title.
+        *
+        * @since 1.22 $checkRights parameter added
+        * @param Title $title
+        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
+        * @return WatchedItem
+        */
+       public function getWatchedItem( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
+               $key = $checkRights . ':' . $title->getNamespace() . ':' . $title->getDBkey();
+
+               if ( isset( $this->mWatchedItems[$key] ) ) {
+                       return $this->mWatchedItems[$key];
+               }
+
+               if ( count( $this->mWatchedItems ) >= self::MAX_WATCHED_ITEMS_CACHE ) {
+                       $this->mWatchedItems = array();
+               }
+
+               $this->mWatchedItems[$key] = WatchedItem::fromUserTitle( $this, $title, $checkRights );
+               return $this->mWatchedItems[$key];
+       }
+
+       /**
+        * Check the watched status of an article.
+        * @since 1.22 $checkRights parameter added
+        * @param Title $title Title of the article to look at
+        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
+        * @return bool
+        */
+       public function isWatched( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
+               return $this->getWatchedItem( $title, $checkRights )->isWatched();
+       }
+
+       /**
+        * Watch an article.
+        * @since 1.22 $checkRights parameter added
+        * @param Title $title Title of the article to look at
+        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
+        */
+       public function addWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
+               $this->getWatchedItem( $title, $checkRights )->addWatch();
+               $this->invalidateCache();
+       }
+
+       /**
+        * Stop watching an article.
+        * @since 1.22 $checkRights parameter added
+        * @param Title $title Title of the article to look at
+        * @param int $checkRights Whether to check 'viewmywatchlist'/'editmywatchlist' rights.
+        *     Pass WatchedItem::CHECK_USER_RIGHTS or WatchedItem::IGNORE_USER_RIGHTS.
+        */
+       public function removeWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
+               $this->getWatchedItem( $title, $checkRights )->removeWatch();
+               $this->invalidateCache();
+       }
+
+       /**
+        * Clear the user's notification timestamp for the given title.
+        * If e-notif e-mails are on, they will receive notification mails on
+        * the next change of the page if it's watched etc.
+        * @note If the user doesn't have 'editmywatchlist', this will do nothing.
+        * @param Title $title Title of the article to look at
+        * @param int $oldid The revision id being viewed. If not given or 0, latest revision is assumed.
+        */
+       public function clearNotification( &$title, $oldid = 0 ) {
+               global $wgUseEnotif, $wgShowUpdatedMarker;
+
+               // Do nothing if the database is locked to writes
+               if ( wfReadOnly() ) {
+                       return;
+               }
+
+               // Do nothing if not allowed to edit the watchlist
+               if ( !$this->isAllowed( 'editmywatchlist' ) ) {
+                       return;
+               }
+
+               // 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 ( !Hooks::run( 'UserClearNewTalkNotification', array( &$this, $oldid ) ) ) {
+                               return;
+                       }
+
+                       $that = $this;
+                       // Try to update the DB post-send and only if needed...
+                       DeferredUpdates::addCallableUpdate( function() use ( $that, $title, $oldid ) {
+                               if ( !$that->getNewtalk() ) {
+                                       return; // no notifications to clear
+                               }
+
+                               // Delete the last notifications (they stack up)
+                               $that->setNewtalk( false );
+
+                               // If there is a new, unseen, revision, use its timestamp
+                               $nextid = $oldid
+                                       ? $title->getNextRevisionID( $oldid, Title::GAID_FOR_UPDATE )
+                                       : null;
+                               if ( $nextid ) {
+                                       $that->setNewtalk( true, Revision::newFromId( $nextid ) );
+                               }
+                       } );
+               }
+
+               if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
+                       return;
+               }
+
+               if ( $this->isAnon() ) {
+                       // Nothing else to do...
+                       return;
+               }
+
+               // Only update the timestamp if the page is being watched.
+               // The query to find out if it is watched is cached both in memcached and per-invocation,
+               // and when it does have to be executed, it can be on a slave
+               // If this is the user's newtalk page, we always update the timestamp
+               $force = '';
+               if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
+                       $force = 'force';
+               }
+
+               $this->getWatchedItem( $title )->resetNotificationTimestamp(
+                       $force, $oldid, WatchedItem::DEFERRED
+               );
+       }
+
+       /**
+        * Resets all of the given user's page-change notification timestamps.
+        * If e-notif e-mails are on, they will receive notification mails on
+        * the next change of any watched page.
+        * @note If the user doesn't have 'editmywatchlist', this will do nothing.
+        */
+       public function clearAllNotifications() {
+               if ( wfReadOnly() ) {
+                       return;
+               }
+
+               // Do nothing if not allowed to edit the watchlist
+               if ( !$this->isAllowed( 'editmywatchlist' ) ) {
+                       return;
+               }
+
+               global $wgUseEnotif, $wgShowUpdatedMarker;
+               if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
+                       $this->setNewtalk( false );
+                       return;
+               }
+               $id = $this->getId();
+               if ( $id != 0 ) {
+                       $dbw = wfGetDB( DB_MASTER );
+                       $dbw->update( 'watchlist',
+                               array( /* SET */ 'wl_notificationtimestamp' => null ),
+                               array( /* WHERE */ 'wl_user' => $id, 'wl_notificationtimestamp IS NOT NULL' ),
+                               __METHOD__
+                       );
+                       // We also need to clear here the "you have new message" notification for the own user_talk page;
+                       // it's cleared one page view later in WikiPage::doViewUpdates().
+               }
+       }
+
+       /**
+        * Set a cookie on the user's client. Wrapper for
+        * WebResponse::setCookie
+        * @param string $name Name of the cookie to set
+        * @param string $value Value to set
+        * @param int $exp Expiration time, as a UNIX time value;
+        *                   if 0 or not specified, use the default $wgCookieExpiration
+        * @param bool $secure
+        *  true: Force setting the secure attribute when setting the cookie
+        *  false: Force NOT setting the secure attribute when setting the cookie
+        *  null (default): Use the default ($wgCookieSecure) to set the secure attribute
+        * @param array $params Array of options sent passed to WebResponse::setcookie()
+        * @param WebRequest|null $request WebRequest object to use; $wgRequest will be used if null
+        *        is passed.
+        */
+       protected function setCookie(
+               $name, $value, $exp = 0, $secure = null, $params = array(), $request = null
+       ) {
+               if ( $request === null ) {
+                       $request = $this->getRequest();
+               }
+               $params['secure'] = $secure;
+               $request->response()->setCookie( $name, $value, $exp, $params );
+       }
+
+       /**
+        * Clear a cookie on the user's client
+        * @param string $name Name of the cookie to clear
+        * @param bool $secure
+        *  true: Force setting the secure attribute when setting the cookie
+        *  false: Force NOT setting the secure attribute when setting the cookie
+        *  null (default): Use the default ($wgCookieSecure) to set the secure attribute
+        * @param array $params Array of options sent passed to WebResponse::setcookie()
+        */
+       protected function clearCookie( $name, $secure = null, $params = array() ) {
+               $this->setCookie( $name, '', time() - 86400, $secure, $params );
+       }
+
+       /**
+        * Set an extended login cookie on the user's client. The expiry of the cookie
+        * is controlled by the $wgExtendedLoginCookieExpiration configuration
+        * variable.
+        *
+        * @see User::setCookie
+        *
+        * @param string $name Name of the cookie to set
+        * @param string $value Value to set
+        * @param bool $secure
+        *  true: Force setting the secure attribute when setting the cookie
+        *  false: Force NOT setting the secure attribute when setting the cookie
+        *  null (default): Use the default ($wgCookieSecure) to set the secure attribute
+        */
+       protected function setExtendedLoginCookie( $name, $value, $secure ) {
+               global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
+
+               $exp = time();
+               $exp += $wgExtendedLoginCookieExpiration !== null
+                       ? $wgExtendedLoginCookieExpiration
+                       : $wgCookieExpiration;
+
+               $this->setCookie( $name, $value, $exp, $secure );
+       }
+
+       /**
+        * Set the default cookies for this session on the user's client.
+        *
+        * @param WebRequest|null $request WebRequest object to use; $wgRequest will be used if null
+        *        is passed.
+        * @param bool $secure Whether to force secure/insecure cookies or use default
+        * @param bool $rememberMe Whether to add a Token cookie for elongated sessions
+        */
+       public function setCookies( $request = null, $secure = null, $rememberMe = false ) {
+               global $wgExtendedLoginCookies;
+
+               if ( $request === null ) {
+                       $request = $this->getRequest();
+               }
+
+               $this->load();
+               if ( 0 == $this->mId ) {
+                       return;
+               }
+               if ( !$this->mToken ) {
+                       // When token is empty or NULL generate a new one and then save it to the database
+                       // This allows a wiki to re-secure itself after a leak of it's user table or $wgSecretKey
+                       // Simply by setting every cell in the user_token column to NULL and letting them be
+                       // regenerated as users log back into the wiki.
+                       $this->setToken();
+                       if ( !wfReadOnly() ) {
+                               $this->saveSettings();
+                       }
+               }
+               $session = array(
+                       'wsUserID' => $this->mId,
+                       'wsToken' => $this->mToken,
+                       'wsUserName' => $this->getName()
+               );
+               $cookies = array(
+                       'UserID' => $this->mId,
+                       'UserName' => $this->getName(),
+               );
+               if ( $rememberMe ) {
+                       $cookies['Token'] = $this->mToken;
+               } else {
+                       $cookies['Token'] = false;
+               }
+
+               Hooks::run( 'UserSetCookies', array( $this, &$session, &$cookies ) );
+
+               foreach ( $session as $name => $value ) {
+                       $request->setSessionData( $name, $value );
+               }
+               foreach ( $cookies as $name => $value ) {
+                       if ( $value === false ) {
+                               $this->clearCookie( $name );
+                       } elseif ( $rememberMe && in_array( $name, $wgExtendedLoginCookies ) ) {
+                               $this->setExtendedLoginCookie( $name, $value, $secure );
+                       } else {
+                               $this->setCookie( $name, $value, 0, $secure, array(), $request );
+                       }
+               }
+
+               /**
+                * If wpStickHTTPS was selected, also set an insecure cookie that
+                * will cause the site to redirect the user to HTTPS, if they access
+                * it over HTTP. Bug 29898. Use an un-prefixed cookie, so it's the same
+                * as the one set by centralauth (bug 53538). Also set it to session, or
+                * standard time setting, based on if rememberme was set.
+                */
+               if ( $request->getCheck( 'wpStickHTTPS' ) || $this->requiresHTTPS() ) {
+                       $this->setCookie(
+                               'forceHTTPS',
+                               'true',
+                               $rememberMe ? 0 : null,
+                               false,
+                               array( 'prefix' => '' ) // no prefix
+                       );
+               }
+       }
+
+       /**
+        * Log this user out.
+        */
+       public function logout() {
+               if ( Hooks::run( 'UserLogout', array( &$this ) ) ) {
+                       $this->doLogout();
+               }
+       }
+
+       /**
+        * Clear the user's cookies and session, and reset the instance cache.
+        * @see logout()
+        */
+       public function doLogout() {
+               $this->clearInstanceCache( 'defaults' );
+
+               $this->getRequest()->setSessionData( 'wsUserID', 0 );
+
+               $this->clearCookie( 'UserID' );
+               $this->clearCookie( 'Token' );
+               $this->clearCookie( 'forceHTTPS', false, array( 'prefix' => '' ) );
+
+               // Remember when user logged out, to prevent seeing cached pages
+               $this->setCookie( 'LoggedOut', time(), time() + 86400 );
+       }
+
+       /**
+        * Save this user's settings into the database.
+        * @todo Only rarely do all these fields need to be set!
+        */
+       public function saveSettings() {
+               if ( wfReadOnly() ) {
+                       // @TODO: caller should deal with this instead!
+                       // This should really just be an exception.
+                       MWExceptionHandler::logException( new DBExpectedError(
+                               null,
+                               "Could not update user with ID '{$this->mId}'; DB is read-only."
+                       ) );
+                       return;
+               }
+
+               $this->load();
+               if ( 0 == $this->mId ) {
+                       return; // anon
+               }
+
+               // Get a new user_touched that is higher than the old one.
+               // This will be used for a CAS check as a last-resort safety
+               // check against race conditions and slave lag.
+               $oldTouched = $this->mTouched;
+               $newTouched = $this->newTouchedTimestamp();
+
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->update( 'user',
+                       array( /* SET */
+                               'user_name' => $this->mName,
+                               'user_real_name' => $this->mRealName,
+                               'user_email' => $this->mEmail,
+                               'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
+                               'user_touched' => $dbw->timestamp( $newTouched ),
+                               'user_token' => strval( $this->mToken ),
+                               'user_email_token' => $this->mEmailToken,
+                               'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
+                       ), array( /* WHERE */
+                               'user_id' => $this->mId,
+                               'user_touched' => $dbw->timestamp( $oldTouched ) // CAS check
+                       ), __METHOD__
+               );
+
+               if ( !$dbw->affectedRows() ) {
+                       // Maybe the problem was a missed cache update; clear it to be safe
+                       $this->clearSharedCache( 'refresh' );
+                       // User was changed in the meantime or loaded with stale data
+                       $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'master' : 'slave';
+                       throw new MWException(
+                               "CAS update failed on user_touched for user ID '{$this->mId}' (read from $from);" .
+                               " the version of the user to be saved is older than the current version."
+                       );
+               }
+
+               $this->mTouched = $newTouched;
+               $this->saveOptions();
+
+               Hooks::run( 'UserSaveSettings', array( $this ) );
+               $this->clearSharedCache();
+               $this->getUserPage()->invalidateCache();
+       }
+
+       /**
+        * If only this user's username is known, and it exists, return the user ID.
+        *
+        * @param int $flags Bitfield of User:READ_* constants; useful for existence checks
+        * @return int
+        */
+       public function idForName( $flags = 0 ) {
+               $s = trim( $this->getName() );
+               if ( $s === '' ) {
+                       return 0;
+               }
+
+               $db = ( ( $flags & self::READ_LATEST ) == self::READ_LATEST )
+                       ? wfGetDB( DB_MASTER )
+                       : wfGetDB( DB_SLAVE );
+
+               $options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
+                       ? array( 'LOCK IN SHARE MODE' )
+                       : array();
+
+               $id = $db->selectField( 'user',
+                       'user_id', array( 'user_name' => $s ), __METHOD__, $options );
+
+               return (int)$id;
+       }
+
+       /**
+        * Add a user to the database, return the user object
+        *
+        * @param string $name Username to add
+        * @param array $params Array of Strings Non-default parameters to save to
+        *   the database as user_* fields:
+        *   - email: The user's email address.
+        *   - email_authenticated: The email authentication timestamp.
+        *   - real_name: The user's real name.
+        *   - options: An associative array of non-default options.
+        *   - token: Random authentication token. Do not set.
+        *   - registration: Registration timestamp. Do not set.
+        *
+        * @return User|null User object, or null if the username already exists.
+        */
+       public static function createNew( $name, $params = array() ) {
+               foreach ( array( 'password', 'newpassword', 'newpass_time', 'password_expires' ) as $field ) {
+                       if ( isset( $params[$field] ) ) {
+                               wfDeprecated( __METHOD__ . " with param '$field'", '1.27' );
+                               unset( $params[$field] );
+                       }
+               }
+
+               $user = new User;
+               $user->load();
+               $user->setToken(); // init token
+               if ( isset( $params['options'] ) ) {
+                       $user->mOptions = $params['options'] + (array)$user->mOptions;
+                       unset( $params['options'] );
+               }
+               $dbw = wfGetDB( DB_MASTER );
+               $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
+
+               $noPass = PasswordFactory::newInvalidPassword()->toString();
+
+               $fields = array(
+                       'user_id' => $seqVal,
+                       'user_name' => $name,
+                       'user_password' => $noPass,
+                       'user_newpassword' => $noPass,
+                       'user_email' => $user->mEmail,
+                       'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
+                       'user_real_name' => $user->mRealName,
+                       'user_token' => strval( $user->mToken ),
+                       'user_registration' => $dbw->timestamp( $user->mRegistration ),
+                       'user_editcount' => 0,
+                       'user_touched' => $dbw->timestamp( $user->newTouchedTimestamp() ),
+               );
+               foreach ( $params as $name => $value ) {
+                       $fields["user_$name"] = $value;
+               }
+               $dbw->insert( 'user', $fields, __METHOD__, array( 'IGNORE' ) );
+               if ( $dbw->affectedRows() ) {
+                       $newUser = User::newFromId( $dbw->insertId() );
+               } else {
+                       $newUser = null;
+               }
+               return $newUser;
+       }
+
+       /**
+        * Add this existing user object to the database. If the user already
+        * exists, a fatal status object is returned, and the user object is
+        * initialised with the data from the database.
+        *
+        * Previously, this function generated a DB error due to a key conflict
+        * if the user already existed. Many extension callers use this function
+        * in code along the lines of:
+        *
+        *   $user = User::newFromName( $name );
+        *   if ( !$user->isLoggedIn() ) {
+        *       $user->addToDatabase();
+        *   }
+        *   // do something with $user...
+        *
+        * However, this was vulnerable to a race condition (bug 16020). By
+        * initialising the user object if the user exists, we aim to support this
+        * calling sequence as far as possible.
+        *
+        * Note that if the user exists, this function will acquire a write lock,
+        * so it is still advisable to make the call conditional on isLoggedIn(),
+        * and to commit the transaction after calling.
+        *
+        * @throws MWException
+        * @return Status
+        */
+       public function addToDatabase() {
+               $this->load();
+               if ( !$this->mToken ) {
+                       $this->setToken(); // init token
+               }
+
+               $this->mTouched = $this->newTouchedTimestamp();
+
+               $noPass = PasswordFactory::newInvalidPassword()->toString();
+
+               $dbw = wfGetDB( DB_MASTER );
+               $inWrite = $dbw->writesOrCallbacksPending();
+               $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
+               $dbw->insert( 'user',
+                       array(
+                               'user_id' => $seqVal,
+                               'user_name' => $this->mName,
+                               'user_password' => $noPass,
+                               'user_newpassword' => $noPass,
+                               'user_email' => $this->mEmail,
+                               'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
+                               'user_real_name' => $this->mRealName,
+                               'user_token' => strval( $this->mToken ),
+                               'user_registration' => $dbw->timestamp( $this->mRegistration ),
+                               'user_editcount' => 0,
+                               'user_touched' => $dbw->timestamp( $this->mTouched ),
+                       ), __METHOD__,
+                       array( 'IGNORE' )
+               );
+               if ( !$dbw->affectedRows() ) {
+                       // The queries below cannot happen in the same REPEATABLE-READ snapshot.
+                       // Handle this by COMMIT, if possible, or by LOCK IN SHARE MODE otherwise.
+                       if ( $inWrite ) {
+                               // Can't commit due to pending writes that may need atomicity.
+                               // This may cause some lock contention unlike the case below.
+                               $options = array( 'LOCK IN SHARE MODE' );
+                               $flags = self::READ_LOCKING;
+                       } else {
+                               // Often, this case happens early in views before any writes when
+                               // using CentralAuth. It's should be OK to commit and break the snapshot.
+                               $dbw->commit( __METHOD__, 'flush' );
+                               $options = array();
+                               $flags = self::READ_LATEST;
+                       }
+                       $this->mId = $dbw->selectField( 'user', 'user_id',
+                               array( 'user_name' => $this->mName ), __METHOD__, $options );
+                       $loaded = false;
+                       if ( $this->mId ) {
+                               if ( $this->loadFromDatabase( $flags ) ) {
+                                       $loaded = true;
+                               }
+                       }
+                       if ( !$loaded ) {
+                               throw new MWException( __METHOD__ . ": hit a key conflict attempting " .
+                                       "to insert user '{$this->mName}' row, but it was not present in select!" );
+                       }
+                       return Status::newFatal( 'userexists' );
+               }
+               $this->mId = $dbw->insertId();
+               self::$idCacheByName[$this->mName] = $this->mId;
+
+               // Clear instance cache other than user table data, which is already accurate
+               $this->clearInstanceCache();
+
+               $this->saveOptions();
+               return Status::newGood();
+       }
+
+       /**
+        * If this user is logged-in and blocked,
+        * block any IP address they've successfully logged in from.
+        * @return bool A block was spread
+        */
+       public function spreadAnyEditBlock() {
+               if ( $this->isLoggedIn() && $this->isBlocked() ) {
+                       return $this->spreadBlock();
+               }
+               return false;
+       }
+
+       /**
+        * If this (non-anonymous) user is blocked,
+        * block the IP address they've successfully logged in from.
+        * @return bool A block was spread
+        */
+       protected function spreadBlock() {
+               wfDebug( __METHOD__ . "()\n" );
+               $this->load();
+               if ( $this->mId == 0 ) {
+                       return false;
+               }
+
+               $userblock = Block::newFromTarget( $this->getName() );
+               if ( !$userblock ) {
+                       return false;
+               }
+
+               return (bool)$userblock->doAutoblock( $this->getRequest()->getIP() );
+       }
+
+       /**
+        * Get whether the user is explicitly blocked from account creation.
+        * @return bool|Block
+        */
+       public function isBlockedFromCreateAccount() {
+               $this->getBlockedStatus();
+               if ( $this->mBlock && $this->mBlock->prevents( 'createaccount' ) ) {
+                       return $this->mBlock;
+               }
+
+               # bug 13611: if the IP address the user is trying to create an account from is
+               # blocked with createaccount disabled, prevent new account creation there even
+               # when the user is logged in
+               if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
+                       $this->mBlockedFromCreateAccount = Block::newFromTarget( null, $this->getRequest()->getIP() );
+               }
+               return $this->mBlockedFromCreateAccount instanceof Block
+                       && $this->mBlockedFromCreateAccount->prevents( 'createaccount' )
+                       ? $this->mBlockedFromCreateAccount
+                       : false;
+       }
+
+       /**
+        * Get whether the user is blocked from using Special:Emailuser.
+        * @return bool
+        */
+       public function isBlockedFromEmailuser() {
+               $this->getBlockedStatus();
+               return $this->mBlock && $this->mBlock->prevents( 'sendemail' );
+       }
+
+       /**
+        * Get whether the user is allowed to create an account.
+        * @return bool
+        */
+       public function isAllowedToCreateAccount() {
+               return $this->isAllowed( 'createaccount' ) && !$this->isBlockedFromCreateAccount();
+       }
+
+       /**
+        * Get this user's personal page title.
+        *
+        * @return Title User's personal page title
+        */
+       public function getUserPage() {
+               return Title::makeTitle( NS_USER, $this->getName() );
+       }
+
+       /**
+        * Get this user's talk page title.
+        *
+        * @return Title User's talk page title
+        */
+       public function getTalkPage() {
+               $title = $this->getUserPage();
+               return $title->getTalkPage();
+       }
+
+       /**
+        * Determine whether the user is a newbie. Newbies are either
+        * anonymous IPs, or the most recently created accounts.
+        * @return bool
+        */
+       public function isNewbie() {
+               return !$this->isAllowed( 'autoconfirmed' );
+       }
+
+       /**
+        * Check to see if the given clear-text password is one of the accepted passwords
+        * @deprecated since 1.27. AuthManager is coming.
+        * @param string $password User password
+        * @return bool True if the given password is correct, otherwise False
+        */
+       public function checkPassword( $password ) {
+               global $wgAuth, $wgLegacyEncoding;
+
+               $this->load();
+
+               // Some passwords will give a fatal Status, which means there is
+               // some sort of technical or security reason for this password to
+               // be completely invalid and should never be checked (e.g., T64685)
+               if ( !$this->checkPasswordValidity( $password )->isOK() ) {
+                       return false;
+               }
+
+               // Certain authentication plugins do NOT want to save
+               // domain passwords in a mysql database, so we should
+               // check this (in case $wgAuth->strict() is false).
+               if ( $wgAuth->authenticate( $this->getName(), $password ) ) {
+                       return true;
+               } elseif ( $wgAuth->strict() ) {
+                       // Auth plugin doesn't allow local authentication
+                       return false;
+               } elseif ( $wgAuth->strictUserAuth( $this->getName() ) ) {
+                       // Auth plugin doesn't allow local authentication for this user name
+                       return false;
+               }
+
+               $passwordFactory = new PasswordFactory();
+               $passwordFactory->init( RequestContext::getMain()->getConfig() );
+               $db = ( $this->queryFlagsUsed & self::READ_LATEST )
+                       ? wfGetDB( DB_MASTER )
+                       : wfGetDB( DB_SLAVE );
+
+               try {
+                       $mPassword = $passwordFactory->newFromCiphertext( $db->selectField(
+                               'user', 'user_password', array( 'user_id' => $this->getId() ), __METHOD__
+                       ) );
+               } catch ( PasswordError $e ) {
+                       wfDebug( 'Invalid password hash found in database.' );
+                       $mPassword = PasswordFactory::newInvalidPassword();
+               }
+
+               if ( !$mPassword->equals( $password ) ) {
+                       if ( $wgLegacyEncoding ) {
+                               // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
+                               // Check for this with iconv
+                               $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
+                               if ( $cp1252Password === $password || !$mPassword->equals( $cp1252Password ) ) {
+                                       return false;
+                               }
+                       } else {
+                               return false;
+                       }
+               }
+
+               if ( $passwordFactory->needsUpdate( $mPassword ) && !wfReadOnly() ) {
+                       $this->setPasswordInternal( $password );
+               }
+
+               return true;
+       }
+
+       /**
+        * Check if the given clear-text password matches the temporary password
+        * sent by e-mail for password reset operations.
+        *
+        * @deprecated since 1.27. AuthManager is coming.
+        * @param string $plaintext
+        * @return bool True if matches, false otherwise
+        */
+       public function checkTemporaryPassword( $plaintext ) {
+               global $wgNewPasswordExpiry;
+
+               $this->load();
+
+               $passwordFactory = new PasswordFactory();
+               $passwordFactory->init( RequestContext::getMain()->getConfig() );
+               $db = ( $this->queryFlagsUsed & self::READ_LATEST )
+                       ? wfGetDB( DB_MASTER )
+                       : wfGetDB( DB_SLAVE );
+
+               $row = $db->selectRow(
+                       'user',
+                       array( 'user_newpassword', 'user_newpass_time' ),
+                       array( 'user_id' => $this->getId() ),
+                       __METHOD__
+               );
+               try {
+                       $newPassword = $passwordFactory->newFromCiphertext( $row->user_newpassword );
+               } catch ( PasswordError $e ) {
+                       wfDebug( 'Invalid password hash found in database.' );
+                       $newPassword = PasswordFactory::newInvalidPassword();
+               }
+
+               if ( $newPassword->equals( $plaintext ) ) {
+                       if ( is_null( $row->user_newpass_time ) ) {
+                               return true;
+                       }
+                       $expiry = wfTimestamp( TS_UNIX, $row->user_newpass_time ) + $wgNewPasswordExpiry;
+                       return ( time() < $expiry );
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * Alias for getEditToken.
+        * @deprecated since 1.19, use getEditToken instead.
+        *
+        * @param string|array $salt Array of Strings Optional function-specific data for hashing
+        * @param WebRequest|null $request WebRequest object to use or null to use $wgRequest
+        * @return string The new edit token
+        */
+       public function editToken( $salt = '', $request = null ) {
+               wfDeprecated( __METHOD__, '1.19' );
+               return $this->getEditToken( $salt, $request );
+       }
+
+       /**
+        * Internal implementation for self::getEditToken() and
+        * self::matchEditToken().
+        *
+        * @param string|array $salt
+        * @param WebRequest $request
+        * @param string|int $timestamp
+        * @return string
+        */
+       private function getEditTokenAtTimestamp( $salt, $request, $timestamp ) {
+               if ( $this->isAnon() ) {
+                       return self::EDIT_TOKEN_SUFFIX;
+               } else {
+                       $token = $request->getSessionData( 'wsEditToken' );
+                       if ( $token === null ) {
+                               $token = MWCryptRand::generateHex( 32 );
+                               $request->setSessionData( 'wsEditToken', $token );
+                       }
+                       if ( is_array( $salt ) ) {
+                               $salt = implode( '|', $salt );
+                       }
+                       return hash_hmac( 'md5', $timestamp . $salt, $token, false ) .
+                               dechex( $timestamp ) .
+                               self::EDIT_TOKEN_SUFFIX;
+               }
+       }
+
+       /**
+        * Initialize (if necessary) and return a session token value
+        * which can be used in edit forms to show that the user's
+        * login credentials aren't being hijacked with a foreign form
+        * submission.
+        *
+        * @since 1.19
+        *
+        * @param string|array $salt Array of Strings Optional function-specific data for hashing
+        * @param WebRequest|null $request WebRequest object to use or null to use $wgRequest
+        * @return string The new edit token
+        */
+       public function getEditToken( $salt = '', $request = null ) {
+               return $this->getEditTokenAtTimestamp(
+                       $salt, $request ?: $this->getRequest(), wfTimestamp()
+               );
+       }
+
+       /**
+        * Generate a looking random token for various uses.
+        *
+        * @return string The new random token
+        * @deprecated since 1.20: Use MWCryptRand for secure purposes or
+        *   wfRandomString for pseudo-randomness.
+        */
+       public static function generateToken() {
+               return MWCryptRand::generateHex( 32 );
+       }
+
+       /**
+        * Get the embedded timestamp from a token.
+        * @param string $val Input token
+        * @return int|null
+        */
+       public static function getEditTokenTimestamp( $val ) {
+               $suffixLen = strlen( self::EDIT_TOKEN_SUFFIX );
+               if ( strlen( $val ) <= 32 + $suffixLen ) {
+                       return null;
+               }
+
+               return hexdec( substr( $val, 32, -$suffixLen ) );
+       }
+
+       /**
+        * Check given value against the token value stored in the session.
+        * A match should confirm that the form was submitted from the
+        * user's own login session, not a form submission from a third-party
+        * site.
+        *
+        * @param string $val Input value to compare
+        * @param string $salt Optional function-specific data for hashing
+        * @param WebRequest|null $request Object to use or null to use $wgRequest
+        * @param int $maxage Fail tokens older than this, in seconds
+        * @return bool Whether the token matches
+        */
+       public function matchEditToken( $val, $salt = '', $request = null, $maxage = null ) {
+               if ( $this->isAnon() ) {
+                       return $val === self::EDIT_TOKEN_SUFFIX;
+               }
+
+               $timestamp = self::getEditTokenTimestamp( $val );
+               if ( $timestamp === null ) {
+                       return false;
+               }
+               if ( $maxage !== null && $timestamp < wfTimestamp() - $maxage ) {
+                       // Expired token
+                       return false;
+               }
+
+               $sessionToken = $this->getEditTokenAtTimestamp(
+                       $salt, $request ?: $this->getRequest(), $timestamp
+               );
+
+               if ( $val != $sessionToken ) {
+                       wfDebug( "User::matchEditToken: broken session data\n" );
+               }
+
+               return hash_equals( $sessionToken, $val );
+       }
+
+       /**
+        * Check given value against the token value stored in the session,
+        * ignoring the suffix.
+        *
+        * @param string $val Input value to compare
+        * @param string $salt Optional function-specific data for hashing
+        * @param WebRequest|null $request Object to use or null to use $wgRequest
+        * @param int $maxage Fail tokens older than this, in seconds
+        * @return bool Whether the token matches
+        */
+       public function matchEditTokenNoSuffix( $val, $salt = '', $request = null, $maxage = null ) {
+               $val = substr( $val, 0, strspn( $val, '0123456789abcdef' ) ) . self::EDIT_TOKEN_SUFFIX;
+               return $this->matchEditToken( $val, $salt, $request, $maxage );
+       }
+
+       /**
+        * Generate a new e-mail confirmation token and send a confirmation/invalidation
+        * mail to the user's given address.
+        *
+        * @param string $type Message to send, either "created", "changed" or "set"
+        * @return Status
+        */
+       public function sendConfirmationMail( $type = 'created' ) {
+               global $wgLang;
+               $expiration = null; // gets passed-by-ref and defined in next line.
+               $token = $this->confirmationToken( $expiration );
+               $url = $this->confirmationTokenUrl( $token );
+               $invalidateURL = $this->invalidationTokenUrl( $token );
+               $this->saveSettings();
+
+               if ( $type == 'created' || $type === false ) {
+                       $message = 'confirmemail_body';
+               } elseif ( $type === true ) {
+                       $message = 'confirmemail_body_changed';
+               } else {
+                       // Messages: confirmemail_body_changed, confirmemail_body_set
+                       $message = 'confirmemail_body_' . $type;
+               }
+
+               return $this->sendMail( wfMessage( 'confirmemail_subject' )->text(),
+                       wfMessage( $message,
+                               $this->getRequest()->getIP(),
+                               $this->getName(),
+                               $url,
+                               $wgLang->timeanddate( $expiration, false ),
+                               $invalidateURL,
+                               $wgLang->date( $expiration, false ),
+                               $wgLang->time( $expiration, false ) )->text() );
+       }
+
+       /**
+        * Send an e-mail to this user's account. Does not check for
+        * confirmed status or validity.
+        *
+        * @param string $subject Message subject
+        * @param string $body Message body
+        * @param User|null $from Optional sending user; if unspecified, default
+        *   $wgPasswordSender will be used.
+        * @param string $replyto Reply-To address
+        * @return Status
+        */
+       public function sendMail( $subject, $body, $from = null, $replyto = null ) {
+               global $wgPasswordSender;
+
+               if ( $from instanceof User ) {
+                       $sender = MailAddress::newFromUser( $from );
+               } else {
+                       $sender = new MailAddress( $wgPasswordSender,
+                               wfMessage( 'emailsender' )->inContentLanguage()->text() );
+               }
+               $to = MailAddress::newFromUser( $this );
+
+               return UserMailer::send( $to, $sender, $subject, $body, array(
+                       'replyTo' => $replyto,
+               ) );
+       }
+
+       /**
+        * Generate, store, and return a new e-mail confirmation code.
+        * A hash (unsalted, since it's used as a key) is stored.
+        *
+        * @note Call saveSettings() after calling this function to commit
+        * this change to the database.
+        *
+        * @param string &$expiration Accepts the expiration time
+        * @return string New token
+        */
+       protected function confirmationToken( &$expiration ) {
+               global $wgUserEmailConfirmationTokenExpiry;
+               $now = time();
+               $expires = $now + $wgUserEmailConfirmationTokenExpiry;
+               $expiration = wfTimestamp( TS_MW, $expires );
+               $this->load();
+               $token = MWCryptRand::generateHex( 32 );
+               $hash = md5( $token );
+               $this->mEmailToken = $hash;
+               $this->mEmailTokenExpires = $expiration;
+               return $token;
+       }
+
+       /**
+        * Return a URL the user can use to confirm their email address.
+        * @param string $token Accepts the email confirmation token
+        * @return string New token URL
+        */
+       protected function confirmationTokenUrl( $token ) {
+               return $this->getTokenUrl( 'ConfirmEmail', $token );
+       }
+
+       /**
+        * Return a URL the user can use to invalidate their email address.
+        * @param string $token Accepts the email confirmation token
+        * @return string New token URL
+        */
+       protected function invalidationTokenUrl( $token ) {
+               return $this->getTokenUrl( 'InvalidateEmail', $token );
+       }
+
+       /**
+        * Internal function to format the e-mail validation/invalidation URLs.
+        * This uses a quickie hack to use the
+        * hardcoded English names of the Special: pages, for ASCII safety.
+        *
+        * @note Since these URLs get dropped directly into emails, using the
+        * short English names avoids insanely long URL-encoded links, which
+        * also sometimes can get corrupted in some browsers/mailers
+        * (bug 6957 with Gmail and Internet Explorer).
+        *
+        * @param string $page Special page
+        * @param string $token Token
+        * @return string Formatted URL
+        */
+       protected function getTokenUrl( $page, $token ) {
+               // Hack to bypass localization of 'Special:'
+               $title = Title::makeTitle( NS_MAIN, "Special:$page/$token" );
+               return $title->getCanonicalURL();
+       }
+
+       /**
+        * Mark the e-mail address confirmed.
+        *
+        * @note Call saveSettings() after calling this function to commit the change.
+        *
+        * @return bool
+        */
+       public function confirmEmail() {
+               // Check if it's already confirmed, so we don't touch the database
+               // and fire the ConfirmEmailComplete hook on redundant confirmations.
+               if ( !$this->isEmailConfirmed() ) {
+                       $this->setEmailAuthenticationTimestamp( wfTimestampNow() );
+                       Hooks::run( 'ConfirmEmailComplete', array( $this ) );
+               }
+               return true;
+       }
+
+       /**
+        * Invalidate the user's e-mail confirmation, and unauthenticate the e-mail
+        * address if it was already confirmed.
+        *
+        * @note Call saveSettings() after calling this function to commit the change.
+        * @return bool Returns true
+        */
+       public function invalidateEmail() {
+               $this->load();
+               $this->mEmailToken = null;
+               $this->mEmailTokenExpires = null;
+               $this->setEmailAuthenticationTimestamp( null );
+               $this->mEmail = '';
+               Hooks::run( 'InvalidateEmailComplete', array( $this ) );
+               return true;
+       }
+
+       /**
+        * Set the e-mail authentication timestamp.
+        * @param string $timestamp TS_MW timestamp
+        */
+       public function setEmailAuthenticationTimestamp( $timestamp ) {
+               $this->load();
+               $this->mEmailAuthenticated = $timestamp;
+               Hooks::run( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
+       }
+
+       /**
+        * Is this user allowed to send e-mails within limits of current
+        * site configuration?
+        * @return bool
+        */
+       public function canSendEmail() {
+               global $wgEnableEmail, $wgEnableUserEmail;
+               if ( !$wgEnableEmail || !$wgEnableUserEmail || !$this->isAllowed( 'sendemail' ) ) {
+                       return false;
+               }
+               $canSend = $this->isEmailConfirmed();
+               Hooks::run( 'UserCanSendEmail', array( &$this, &$canSend ) );
+               return $canSend;
+       }
+
+       /**
+        * Is this user allowed to receive e-mails within limits of current
+        * site configuration?
+        * @return bool
+        */
+       public function canReceiveEmail() {
+               return $this->isEmailConfirmed() && !$this->getOption( 'disablemail' );
+       }
+
+       /**
+        * Is this user's e-mail address valid-looking and confirmed within
+        * limits of the current site configuration?
+        *
+        * @note If $wgEmailAuthentication is on, this may require the user to have
+        * confirmed their address by returning a code or using a password
+        * sent to the address from the wiki.
+        *
+        * @return bool
+        */
+       public function isEmailConfirmed() {
+               global $wgEmailAuthentication;
+               $this->load();
+               $confirmed = true;
+               if ( Hooks::run( 'EmailConfirmed', array( &$this, &$confirmed ) ) ) {
+                       if ( $this->isAnon() ) {
+                               return false;
+                       }
+                       if ( !Sanitizer::validateEmail( $this->mEmail ) ) {
+                               return false;
+                       }
+                       if ( $wgEmailAuthentication && !$this->getEmailAuthenticationTimestamp() ) {
+                               return false;
+                       }
+                       return true;
+               } else {
+                       return $confirmed;
+               }
+       }
+
+       /**
+        * Check whether there is an outstanding request for e-mail confirmation.
+        * @return bool
+        */
+       public function isEmailConfirmationPending() {
+               global $wgEmailAuthentication;
+               return $wgEmailAuthentication &&
+                       !$this->isEmailConfirmed() &&
+                       $this->mEmailToken &&
+                       $this->mEmailTokenExpires > wfTimestamp();
+       }
+
+       /**
+        * Get the timestamp of account creation.
+        *
+        * @return string|bool|null Timestamp of account creation, false for
+        *  non-existent/anonymous user accounts, or null if existing account
+        *  but information is not in database.
+        */
+       public function getRegistration() {
+               if ( $this->isAnon() ) {
+                       return false;
+               }
+               $this->load();
+               return $this->mRegistration;
+       }
+
+       /**
+        * Get the timestamp of the first edit
+        *
+        * @return string|bool Timestamp of first edit, or false for
+        *  non-existent/anonymous user accounts.
+        */
+       public function getFirstEditTimestamp() {
+               if ( $this->getId() == 0 ) {
+                       return false; // anons
+               }
+               $dbr = wfGetDB( DB_SLAVE );
+               $time = $dbr->selectField( 'revision', 'rev_timestamp',
+                       array( 'rev_user' => $this->getId() ),
+                       __METHOD__,
+                       array( 'ORDER BY' => 'rev_timestamp ASC' )
+               );
+               if ( !$time ) {
+                       return false; // no edits
+               }
+               return wfTimestamp( TS_MW, $time );
+       }
+
+       /**
+        * Get the permissions associated with a given list of groups
+        *
+        * @param array $groups Array of Strings List of internal group names
+        * @return array Array of Strings List of permission key names for given groups combined
+        */
+       public static function getGroupPermissions( $groups ) {
+               global $wgGroupPermissions, $wgRevokePermissions;
+               $rights = array();
+               // grant every granted permission first
+               foreach ( $groups as $group ) {
+                       if ( isset( $wgGroupPermissions[$group] ) ) {
+                               $rights = array_merge( $rights,
+                                       // array_filter removes empty items
+                                       array_keys( array_filter( $wgGroupPermissions[$group] ) ) );
+                       }
+               }
+               // now revoke the revoked permissions
+               foreach ( $groups as $group ) {
+                       if ( isset( $wgRevokePermissions[$group] ) ) {
+                               $rights = array_diff( $rights,
+                                       array_keys( array_filter( $wgRevokePermissions[$group] ) ) );
+                       }
+               }
+               return array_unique( $rights );
+       }
+
+       /**
+        * Get all the groups who have a given permission
+        *
+        * @param string $role Role to check
+        * @return array Array of Strings List of internal group names with the given permission
+        */
+       public static function getGroupsWithPermission( $role ) {
+               global $wgGroupPermissions;
+               $allowedGroups = array();
+               foreach ( array_keys( $wgGroupPermissions ) as $group ) {
+                       if ( self::groupHasPermission( $group, $role ) ) {
+                               $allowedGroups[] = $group;
+                       }
+               }
+               return $allowedGroups;
+       }
+
+       /**
+        * Check, if the given group has the given permission
+        *
+        * If you're wanting to check whether all users have a permission, use
+        * User::isEveryoneAllowed() instead. That properly checks if it's revoked
+        * from anyone.
+        *
+        * @since 1.21
+        * @param string $group Group to check
+        * @param string $role Role to check
+        * @return bool
+        */
+       public static function groupHasPermission( $group, $role ) {
+               global $wgGroupPermissions, $wgRevokePermissions;
+               return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
+                       && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
+       }
+
+       /**
+        * Check if all users have the given permission
+        *
+        * @since 1.22
+        * @param string $right Right to check
+        * @return bool
+        */
+       public static function isEveryoneAllowed( $right ) {
+               global $wgGroupPermissions, $wgRevokePermissions;
+               static $cache = array();
+
+               // Use the cached results, except in unit tests which rely on
+               // being able change the permission mid-request
+               if ( isset( $cache[$right] ) && !defined( 'MW_PHPUNIT_TEST' ) ) {
+                       return $cache[$right];
+               }
+
+               if ( !isset( $wgGroupPermissions['*'][$right] ) || !$wgGroupPermissions['*'][$right] ) {
+                       $cache[$right] = false;
+                       return false;
+               }
+
+               // If it's revoked anywhere, then everyone doesn't have it
+               foreach ( $wgRevokePermissions as $rights ) {
+                       if ( isset( $rights[$right] ) && $rights[$right] ) {
+                               $cache[$right] = false;
+                               return false;
+                       }
+               }
+
+               // Allow extensions (e.g. OAuth) to say false
+               if ( !Hooks::run( 'UserIsEveryoneAllowed', array( $right ) ) ) {
+                       $cache[$right] = false;
+                       return false;
+               }
+
+               $cache[$right] = true;
+               return true;
+       }
+
+       /**
+        * Get the localized descriptive name for a group, if it exists
+        *
+        * @param string $group Internal group name
+        * @return string Localized descriptive group name
+        */
+       public static function getGroupName( $group ) {
+               $msg = wfMessage( "group-$group" );
+               return $msg->isBlank() ? $group : $msg->text();
+       }
+
+       /**
+        * Get the localized descriptive name for a member of a group, if it exists
+        *
+        * @param string $group Internal group name
+        * @param string $username Username for gender (since 1.19)
+        * @return string Localized name for group member
+        */
+       public static function getGroupMember( $group, $username = '#' ) {
+               $msg = wfMessage( "group-$group-member", $username );
+               return $msg->isBlank() ? $group : $msg->text();
+       }
+
+       /**
+        * Return the set of defined explicit groups.
+        * The implicit groups (by default *, 'user' and 'autoconfirmed')
+        * are not included, as they are defined automatically, not in the database.
+        * @return array Array of internal group names
+        */
+       public static function getAllGroups() {
+               global $wgGroupPermissions, $wgRevokePermissions;
+               return array_diff(
+                       array_merge( array_keys( $wgGroupPermissions ), array_keys( $wgRevokePermissions ) ),
+                       self::getImplicitGroups()
+               );
+       }
+
+       /**
+        * Get a list of all available permissions.
+        * @return string[] Array of permission names
+        */
+       public static function getAllRights() {
+               if ( self::$mAllRights === false ) {
+                       global $wgAvailableRights;
+                       if ( count( $wgAvailableRights ) ) {
+                               self::$mAllRights = array_unique( array_merge( self::$mCoreRights, $wgAvailableRights ) );
+                       } else {
+                               self::$mAllRights = self::$mCoreRights;
+                       }
+                       Hooks::run( 'UserGetAllRights', array( &self::$mAllRights ) );
+               }
+               return self::$mAllRights;
+       }
+
+       /**
+        * Get a list of implicit groups
+        * @return array Array of Strings Array of internal group names
+        */
+       public static function getImplicitGroups() {
+               global $wgImplicitGroups;
+
+               $groups = $wgImplicitGroups;
+               # Deprecated, use $wgImplicitGroups instead
+               Hooks::run( 'UserGetImplicitGroups', array( &$groups ), '1.25' );
+
+               return $groups;
+       }
+
+       /**
+        * Get the title of a page describing a particular group
+        *
+        * @param string $group Internal group name
+        * @return Title|bool Title of the page if it exists, false otherwise
+        */
+       public static function getGroupPage( $group ) {
+               $msg = wfMessage( 'grouppage-' . $group )->inContentLanguage();
+               if ( $msg->exists() ) {
+                       $title = Title::newFromText( $msg->text() );
+                       if ( is_object( $title ) ) {
+                               return $title;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Create a link to the group in HTML, if available;
+        * else return the group name.
+        *
+        * @param string $group Internal name of the group
+        * @param string $text The text of the link
+        * @return string HTML link to the group
+        */
+       public static function makeGroupLinkHTML( $group, $text = '' ) {
+               if ( $text == '' ) {
+                       $text = self::getGroupName( $group );
+               }
+               $title = self::getGroupPage( $group );
+               if ( $title ) {
+                       return Linker::link( $title, htmlspecialchars( $text ) );
+               } else {
+                       return htmlspecialchars( $text );
+               }
+       }
+
+       /**
+        * Create a link to the group in Wikitext, if available;
+        * else return the group name.
+        *
+        * @param string $group Internal name of the group
+        * @param string $text The text of the link
+        * @return string Wikilink to the group
+        */
+       public static function makeGroupLinkWiki( $group, $text = '' ) {
+               if ( $text == '' ) {
+                       $text = self::getGroupName( $group );
+               }
+               $title = self::getGroupPage( $group );
+               if ( $title ) {
+                       $page = $title->getFullText();
+                       return "[[$page|$text]]";
+               } else {
+                       return $text;
+               }
+       }
+
+       /**
+        * Returns an array of the groups that a particular group can add/remove.
+        *
+        * @param string $group The group to check for whether it can add/remove
+        * @return array Array( 'add' => array( addablegroups ),
+        *     'remove' => array( removablegroups ),
+        *     'add-self' => array( addablegroups to self),
+        *     'remove-self' => array( removable groups from self) )
+        */
+       public static function changeableByGroup( $group ) {
+               global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
+
+               $groups = array(
+                       'add' => array(),
+                       'remove' => array(),
+                       'add-self' => array(),
+                       'remove-self' => array()
+               );
+
+               if ( empty( $wgAddGroups[$group] ) ) {
+                       // Don't add anything to $groups
+               } elseif ( $wgAddGroups[$group] === true ) {
+                       // You get everything
+                       $groups['add'] = self::getAllGroups();
+               } elseif ( is_array( $wgAddGroups[$group] ) ) {
+                       $groups['add'] = $wgAddGroups[$group];
+               }
+
+               // Same thing for remove
+               if ( empty( $wgRemoveGroups[$group] ) ) {
+                       // Do nothing
+               } elseif ( $wgRemoveGroups[$group] === true ) {
+                       $groups['remove'] = self::getAllGroups();
+               } elseif ( is_array( $wgRemoveGroups[$group] ) ) {
+                       $groups['remove'] = $wgRemoveGroups[$group];
+               }
+
+               // Re-map numeric keys of AddToSelf/RemoveFromSelf to the 'user' key for backwards compatibility
+               if ( empty( $wgGroupsAddToSelf['user'] ) || $wgGroupsAddToSelf['user'] !== true ) {
+                       foreach ( $wgGroupsAddToSelf as $key => $value ) {
+                               if ( is_int( $key ) ) {
+                                       $wgGroupsAddToSelf['user'][] = $value;
+                               }
+                       }
+               }
+
+               if ( empty( $wgGroupsRemoveFromSelf['user'] ) || $wgGroupsRemoveFromSelf['user'] !== true ) {
+                       foreach ( $wgGroupsRemoveFromSelf as $key => $value ) {
+                               if ( is_int( $key ) ) {
+                                       $wgGroupsRemoveFromSelf['user'][] = $value;
+                               }
+                       }
+               }
+
+               // Now figure out what groups the user can add to him/herself
+               if ( empty( $wgGroupsAddToSelf[$group] ) ) {
+                       // Do nothing
+               } elseif ( $wgGroupsAddToSelf[$group] === true ) {
+                       // No idea WHY this would be used, but it's there
+                       $groups['add-self'] = User::getAllGroups();
+               } elseif ( is_array( $wgGroupsAddToSelf[$group] ) ) {
+                       $groups['add-self'] = $wgGroupsAddToSelf[$group];
+               }
+
+               if ( empty( $wgGroupsRemoveFromSelf[$group] ) ) {
+                       // Do nothing
+               } elseif ( $wgGroupsRemoveFromSelf[$group] === true ) {
+                       $groups['remove-self'] = User::getAllGroups();
+               } elseif ( is_array( $wgGroupsRemoveFromSelf[$group] ) ) {
+                       $groups['remove-self'] = $wgGroupsRemoveFromSelf[$group];
+               }
+
+               return $groups;
+       }
+
+       /**
+        * Returns an array of groups that this user can add and remove
+        * @return array Array( 'add' => array( addablegroups ),
+        *  'remove' => array( removablegroups ),
+        *  'add-self' => array( addablegroups to self),
+        *  'remove-self' => array( removable groups from self) )
+        */
+       public function changeableGroups() {
+               if ( $this->isAllowed( 'userrights' ) ) {
+                       // This group gives the right to modify everything (reverse-
+                       // compatibility with old "userrights lets you change
+                       // everything")
+                       // Using array_merge to make the groups reindexed
+                       $all = array_merge( User::getAllGroups() );
+                       return array(
+                               'add' => $all,
+                               'remove' => $all,
+                               'add-self' => array(),
+                               'remove-self' => array()
+                       );
+               }
+
+               // Okay, it's not so simple, we will have to go through the arrays
+               $groups = array(
+                       'add' => array(),
+                       'remove' => array(),
+                       'add-self' => array(),
+                       'remove-self' => array()
+               );
+               $addergroups = $this->getEffectiveGroups();
+
+               foreach ( $addergroups as $addergroup ) {
+                       $groups = array_merge_recursive(
+                               $groups, $this->changeableByGroup( $addergroup )
+                       );
+                       $groups['add'] = array_unique( $groups['add'] );
+                       $groups['remove'] = array_unique( $groups['remove'] );
+                       $groups['add-self'] = array_unique( $groups['add-self'] );
+                       $groups['remove-self'] = array_unique( $groups['remove-self'] );
+               }
+               return $groups;
+       }
+
+       /**
+        * Deferred version of incEditCountImmediate()
+        */
+       public function incEditCount() {
+               $that = $this;
+               wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $that ) {
+                       $that->incEditCountImmediate();
+               } );
+       }
+
+       /**
+        * Increment the user's edit-count field.
+        * Will have no effect for anonymous users.
+        * @since 1.26
+        */
+       public function incEditCountImmediate() {
+               if ( $this->isAnon() ) {
+                       return;
+               }
+
+               $dbw = wfGetDB( DB_MASTER );
+               // No rows will be "affected" if user_editcount is NULL
+               $dbw->update(
+                       'user',
+                       array( 'user_editcount=user_editcount+1' ),
+                       array( 'user_id' => $this->getId(), 'user_editcount IS NOT NULL' ),
+                       __METHOD__
+               );
+               // Lazy initialization check...
+               if ( $dbw->affectedRows() == 0 ) {
+                       // Now here's a goddamn hack...
+                       $dbr = wfGetDB( DB_SLAVE );
+                       if ( $dbr !== $dbw ) {
+                               // If we actually have a slave server, the count is
+                               // at least one behind because the current transaction
+                               // has not been committed and replicated.
+                               $this->initEditCount( 1 );
+                       } else {
+                               // But if DB_SLAVE is selecting the master, then the
+                               // count we just read includes the revision that was
+                               // just added in the working transaction.
+                               $this->initEditCount();
+                       }
+               }
+               // Edit count in user cache too
+               $this->invalidateCache();
+       }
+
+       /**
+        * Initialize user_editcount from data out of the revision table
+        *
+        * @param int $add Edits to add to the count from the revision table
+        * @return int Number of edits
+        */
+       protected function initEditCount( $add = 0 ) {
+               // Pull from a slave to be less cruel to servers
+               // Accuracy isn't the point anyway here
+               $dbr = wfGetDB( DB_SLAVE );
+               $count = (int)$dbr->selectField(
+                       'revision',
+                       'COUNT(rev_user)',
+                       array( 'rev_user' => $this->getId() ),
+                       __METHOD__
+               );
+               $count = $count + $add;
+
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->update(
+                       'user',
+                       array( 'user_editcount' => $count ),
+                       array( 'user_id' => $this->getId() ),
+                       __METHOD__
+               );
+
+               return $count;
+       }
+
+       /**
+        * Get the description of a given right
+        *
+        * @param string $right Right to query
+        * @return string Localized description of the right
+        */
+       public static function getRightDescription( $right ) {
+               $key = "right-$right";
+               $msg = wfMessage( $key );
+               return $msg->isBlank() ? $right : $msg->text();
+       }
+
+       /**
+        * Make a new-style password hash
+        *
+        * @param string $password Plain-text password
+        * @param bool|string $salt Optional salt, may be random or the user ID.
+        *  If unspecified or false, will generate one automatically
+        * @return string Password hash
+        * @deprecated since 1.24, use Password class
+        */
+       public static function crypt( $password, $salt = false ) {
+               wfDeprecated( __METHOD__, '1.24' );
+               $passwordFactory = new PasswordFactory();
+               $passwordFactory->init( RequestContext::getMain()->getConfig() );
+               $hash = $passwordFactory->newFromPlaintext( $password );
+               return $hash->toString();
+       }
+
+       /**
+        * Compare a password hash with a plain-text password. Requires the user
+        * ID if there's a chance that the hash is an old-style hash.
+        *
+        * @param string $hash Password hash
+        * @param string $password Plain-text password to compare
+        * @param string|bool $userId User ID for old-style password salt
+        *
+        * @return bool
+        * @deprecated since 1.24, use Password class
+        */
+       public static function comparePasswords( $hash, $password, $userId = false ) {
+               wfDeprecated( __METHOD__, '1.24' );
+
+               // Check for *really* old password hashes that don't even have a type
+               // The old hash format was just an md5 hex hash, with no type information
+               if ( preg_match( '/^[0-9a-f]{32}$/', $hash ) ) {
+                       global $wgPasswordSalt;
+                       if ( $wgPasswordSalt ) {
+                               $password = ":B:{$userId}:{$hash}";
+                       } else {
+                               $password = ":A:{$hash}";
+                       }
+               }
+
+               $passwordFactory = new PasswordFactory();
+               $passwordFactory->init( RequestContext::getMain()->getConfig() );
+               $hash = $passwordFactory->newFromCiphertext( $hash );
+               return $hash->equals( $password );
+       }
+
+       /**
+        * Add a newuser log entry for this user.
+        * Before 1.19 the return value was always true.
+        *
+        * @param string|bool $action Account creation type.
+        *   - String, one of the following values:
+        *     - 'create' for an anonymous user creating an account for himself.
+        *       This will force the action's performer to be the created user itself,
+        *       no matter the value of $wgUser
+        *     - 'create2' for a logged in user creating an account for someone else
+        *     - 'byemail' when the created user will receive its password by e-mail
+        *     - 'autocreate' when the user is automatically created (such as by CentralAuth).
+        *   - Boolean means whether the account was created by e-mail (deprecated):
+        *     - true will be converted to 'byemail'
+        *     - false will be converted to 'create' if this object is the same as
+        *       $wgUser and to 'create2' otherwise
+        *
+        * @param string $reason User supplied reason
+        *
+        * @return int|bool True if not $wgNewUserLog; otherwise ID of log item or 0 on failure
+        */
+       public function addNewUserLogEntry( $action = false, $reason = '' ) {
+               global $wgUser, $wgNewUserLog;
+               if ( empty( $wgNewUserLog ) ) {
+                       return true; // disabled
+               }
+
+               if ( $action === true ) {
+                       $action = 'byemail';
+               } elseif ( $action === false ) {
+                       if ( $this->equals( $wgUser ) ) {
+                               $action = 'create';
+                       } else {
+                               $action = 'create2';
+                       }
+               }
+
+               if ( $action === 'create' || $action === 'autocreate' ) {
+                       $performer = $this;
+               } else {
+                       $performer = $wgUser;
+               }
+
+               $logEntry = new ManualLogEntry( 'newusers', $action );
+               $logEntry->setPerformer( $performer );
+               $logEntry->setTarget( $this->getUserPage() );
+               $logEntry->setComment( $reason );
+               $logEntry->setParameters( array(
+                       '4::userid' => $this->getId(),
+               ) );
+               $logid = $logEntry->insert();
+
+               if ( $action !== 'autocreate' ) {
+                       $logEntry->publish( $logid );
+               }
+
+               return (int)$logid;
+       }
+
+       /**
+        * Add an autocreate newuser log entry for this user
+        * Used by things like CentralAuth and perhaps other authplugins.
+        * Consider calling addNewUserLogEntry() directly instead.
+        *
+        * @return bool
+        */
+       public function addNewUserLogEntryAutoCreate() {
+               $this->addNewUserLogEntry( 'autocreate' );
+
+               return true;
+       }
+
+       /**
+        * Load the user options either from cache, the database or an array
+        *
+        * @param array $data Rows for the current user out of the user_properties table
+        */
+       protected function loadOptions( $data = null ) {
+               global $wgContLang;
+
+               $this->load();
+
+               if ( $this->mOptionsLoaded ) {
+                       return;
+               }
+
+               $this->mOptions = self::getDefaultOptions();
+
+               if ( !$this->getId() ) {
+                       // For unlogged-in users, load language/variant options from request.
+                       // There's no need to do it for logged-in users: they can set preferences,
+                       // and handling of page content is done by $pageLang->getPreferredVariant() and such,
+                       // so don't override user's choice (especially when the user chooses site default).
+                       $variant = $wgContLang->getDefaultVariant();
+                       $this->mOptions['variant'] = $variant;
+                       $this->mOptions['language'] = $variant;
+                       $this->mOptionsLoaded = true;
+                       return;
+               }
+
+               // Maybe load from the object
+               if ( !is_null( $this->mOptionOverrides ) ) {
+                       wfDebug( "User: loading options for user " . $this->getId() . " from override cache.\n" );
+                       foreach ( $this->mOptionOverrides as $key => $value ) {
+                               $this->mOptions[$key] = $value;
+                       }
+               } else {
+                       if ( !is_array( $data ) ) {
+                               wfDebug( "User: loading options for user " . $this->getId() . " from database.\n" );
+                               // Load from database
+                               $dbr = ( $this->queryFlagsUsed & self::READ_LATEST )
+                                       ? wfGetDB( DB_MASTER )
+                                       : wfGetDB( DB_SLAVE );
+
+                               $res = $dbr->select(
+                                       'user_properties',
+                                       array( 'up_property', 'up_value' ),
+                                       array( 'up_user' => $this->getId() ),
+                                       __METHOD__
+                               );
+
+                               $this->mOptionOverrides = array();
+                               $data = array();
+                               foreach ( $res as $row ) {
+                                       $data[$row->up_property] = $row->up_value;
+                               }
+                       }
+                       foreach ( $data as $property => $value ) {
+                               $this->mOptionOverrides[$property] = $value;
+                               $this->mOptions[$property] = $value;
+                       }
+               }
+
+               $this->mOptionsLoaded = true;
+
+               Hooks::run( 'UserLoadOptions', array( $this, &$this->mOptions ) );
+       }
+
+       /**
+        * Saves the non-default options for this user, as previously set e.g. via
+        * setOption(), in the database's "user_properties" (preferences) table.
+        * Usually used via saveSettings().
+        */
+       protected function saveOptions() {
+               $this->loadOptions();
+
+               // Not using getOptions(), to keep hidden preferences in database
+               $saveOptions = $this->mOptions;
+
+               // Allow hooks to abort, for instance to save to a global profile.
+               // Reset options to default state before saving.
+               if ( !Hooks::run( 'UserSaveOptions', array( $this, &$saveOptions ) ) ) {
+                       return;
+               }
+
+               $userId = $this->getId();
+
+               $insert_rows = array(); // all the new preference rows
+               foreach ( $saveOptions as $key => $value ) {
+                       // Don't bother storing default values
+                       $defaultOption = self::getDefaultOption( $key );
+                       if ( ( $defaultOption === null && $value !== false && $value !== null )
+                               || $value != $defaultOption
+                       ) {
+                               $insert_rows[] = array(
+                                       'up_user' => $userId,
+                                       'up_property' => $key,
+                                       'up_value' => $value,
+                               );
+                       }
+               }
+
+               $dbw = wfGetDB( DB_MASTER );
+
+               $res = $dbw->select( 'user_properties',
+                       array( 'up_property', 'up_value' ), array( 'up_user' => $userId ), __METHOD__ );
+
+               // Find prior rows that need to be removed or updated. These rows will
+               // all be deleted (the later so that INSERT IGNORE applies the new values).
+               $keysDelete = array();
+               foreach ( $res as $row ) {
+                       if ( !isset( $saveOptions[$row->up_property] )
+                               || strcmp( $saveOptions[$row->up_property], $row->up_value ) != 0
+                       ) {
+                               $keysDelete[] = $row->up_property;
+                       }
+               }
+
+               if ( count( $keysDelete ) ) {
+                       // Do the DELETE by PRIMARY KEY for prior rows.
+                       // In the past a very large portion of calls to this function are for setting
+                       // 'rememberpassword' for new accounts (a preference that has since been removed).
+                       // Doing a blanket per-user DELETE for new accounts with no rows in the table
+                       // caused gap locks on [max user ID,+infinity) which caused high contention since
+                       // updates would pile up on each other as they are for higher (newer) user IDs.
+                       // It might not be necessary these days, but it shouldn't hurt either.
+                       $dbw->delete( 'user_properties',
+                               array( 'up_user' => $userId, 'up_property' => $keysDelete ), __METHOD__ );
+               }
+               // Insert the new preference rows
+               $dbw->insert( 'user_properties', $insert_rows, __METHOD__, array( 'IGNORE' ) );
+       }
+
+       /**
+        * Lazily instantiate and return a factory object for making passwords
+        *
+        * @deprecated since 1.27, create a PasswordFactory directly instead
+        * @return PasswordFactory
+        */
+       public static function getPasswordFactory() {
+               wfDeprecated( __METHOD__, '1.27' );
+               $ret = new PasswordFactory();
+               $ret->init( RequestContext::getMain()->getConfig() );
+               return $ret;
+       }
+
+       /**
+        * Provide an array of HTML5 attributes to put on an input element
+        * intended for the user to enter a new password.  This may include
+        * required, title, and/or pattern, depending on $wgMinimalPasswordLength.
+        *
+        * Do *not* use this when asking the user to enter his current password!
+        * Regardless of configuration, users may have invalid passwords for whatever
+        * reason (e.g., they were set before requirements were tightened up).
+        * Only use it when asking for a new password, like on account creation or
+        * ResetPass.
+        *
+        * Obviously, you still need to do server-side checking.
+        *
+        * NOTE: A combination of bugs in various browsers means that this function
+        * actually just returns array() unconditionally at the moment.  May as
+        * well keep it around for when the browser bugs get fixed, though.
+        *
+        * @todo FIXME: This does not belong here; put it in Html or Linker or somewhere
+        *
+        * @deprecated since 1.27
+        * @return array Array of HTML attributes suitable for feeding to
+        *   Html::element(), directly or indirectly.  (Don't feed to Xml::*()!
+        *   That will get confused by the boolean attribute syntax used.)
+        */
+       public static function passwordChangeInputAttribs() {
+               global $wgMinimalPasswordLength;
+
+               if ( $wgMinimalPasswordLength == 0 ) {
+                       return array();
+               }
+
+               # Note that the pattern requirement will always be satisfied if the
+               # input is empty, so we need required in all cases.
+
+               # @todo FIXME: Bug 23769: This needs to not claim the password is required
+               # if e-mail confirmation is being used.  Since HTML5 input validation
+               # is b0rked anyway in some browsers, just return nothing.  When it's
+               # re-enabled, fix this code to not output required for e-mail
+               # registration.
+               # $ret = array( 'required' );
+               $ret = array();
+
+               # We can't actually do this right now, because Opera 9.6 will print out
+               # the entered password visibly in its error message!  When other
+               # browsers add support for this attribute, or Opera fixes its support,
+               # we can add support with a version check to avoid doing this on Opera
+               # versions where it will be a problem.  Reported to Opera as
+               # DSK-262266, but they don't have a public bug tracker for us to follow.
+               /*
+               if ( $wgMinimalPasswordLength > 1 ) {
+                       $ret['pattern'] = '.{' . intval( $wgMinimalPasswordLength ) . ',}';
+                       $ret['title'] = wfMessage( 'passwordtooshort' )
+                               ->numParams( $wgMinimalPasswordLength )->text();
+               }
+               */
+
+               return $ret;
+       }
+
+       /**
+        * Return the list of user fields that should be selected to create
+        * a new user object.
+        * @return array
+        */
+       public static function selectFields() {
+               return array(
+                       'user_id',
+                       'user_name',
+                       'user_real_name',
+                       'user_email',
+                       'user_touched',
+                       'user_token',
+                       'user_email_authenticated',
+                       'user_email_token',
+                       'user_email_token_expires',
+                       'user_registration',
+                       'user_editcount',
+               );
+       }
+
+       /**
+        * Factory function for fatal permission-denied errors
+        *
+        * @since 1.22
+        * @param string $permission User right required
+        * @return Status
+        */
+       static function newFatalPermissionDeniedStatus( $permission ) {
+               global $wgLang;
+
+               $groups = array_map(
+                       array( 'User', 'makeGroupLinkWiki' ),
+                       User::getGroupsWithPermission( $permission )
+               );
+
+               if ( $groups ) {
+                       return Status::newFatal( 'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );
+               } else {
+                       return Status::newFatal( 'badaccess-group0' );
+               }
+       }
+
+       /**
+        * Checks if two user objects point to the same user.
+        *
+        * @since 1.25
+        * @param User $user
+        * @return bool
+        */
+       public function equals( User $user ) {
+               return $this->getName() === $user->getName();
+       }
+}
diff --git a/includes/user/UserArray.php b/includes/user/UserArray.php
new file mode 100644 (file)
index 0000000..31bd601
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+/**
+ * Class to walk into a list of User objects.
+ *
+ * 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
+ */
+
+abstract class UserArray implements Iterator {
+       /**
+        * @param ResultWrapper $res
+        * @return UserArrayFromResult
+        */
+       static function newFromResult( $res ) {
+               $userArray = null;
+               if ( !Hooks::run( 'UserArrayFromResult', array( &$userArray, $res ) ) ) {
+                       return null;
+               }
+               if ( $userArray === null ) {
+                       $userArray = self::newFromResult_internal( $res );
+               }
+               return $userArray;
+       }
+
+       /**
+        * @param array $ids
+        * @return UserArrayFromResult
+        */
+       static function newFromIDs( $ids ) {
+               $ids = array_map( 'intval', (array)$ids ); // paranoia
+               if ( !$ids ) {
+                       // Database::select() doesn't like empty arrays
+                       return new ArrayIterator( array() );
+               }
+               $dbr = wfGetDB( DB_SLAVE );
+               $res = $dbr->select(
+                       'user',
+                       User::selectFields(),
+                       array( 'user_id' => array_unique( $ids ) ),
+                       __METHOD__
+               );
+               return self::newFromResult( $res );
+       }
+
+       /**
+        * @since 1.25
+        * @param array $names
+        * @return UserArrayFromResult
+        */
+       static function newFromNames( $names ) {
+               $names = array_map( 'strval', (array)$names ); // paranoia
+               if ( !$names ) {
+                       // Database::select() doesn't like empty arrays
+                       return new ArrayIterator( array() );
+               }
+               $dbr = wfGetDB( DB_SLAVE );
+               $res = $dbr->select(
+                       'user',
+                       User::selectFields(),
+                       array( 'user_name' => array_unique( $names ) ),
+                       __METHOD__
+               );
+               return self::newFromResult( $res );
+       }
+
+       /**
+        * @param ResultWrapper $res
+        * @return UserArrayFromResult
+        */
+       protected static function newFromResult_internal( $res ) {
+               return new UserArrayFromResult( $res );
+       }
+}
diff --git a/includes/user/UserArrayFromResult.php b/includes/user/UserArrayFromResult.php
new file mode 100644 (file)
index 0000000..fb533d0
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Class to walk into a list of User objects.
+ *
+ * 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 UserArrayFromResult extends UserArray implements Countable {
+       /** @var ResultWrapper */
+       public $res;
+
+       /** @var int */
+       public $key;
+
+       /** @var bool|stdClass */
+       public $current;
+
+       /**
+        * @param ResultWrapper $res
+        */
+       function __construct( $res ) {
+               $this->res = $res;
+               $this->key = 0;
+               $this->setCurrent( $this->res->current() );
+       }
+
+       /**
+        * @param bool|stdClass $row
+        * @return void
+        */
+       protected function setCurrent( $row ) {
+               if ( $row === false ) {
+                       $this->current = false;
+               } else {
+                       $this->current = User::newFromRow( $row );
+               }
+       }
+
+       /**
+        * @return int
+        */
+       public function count() {
+               return $this->res->numRows();
+       }
+
+       /**
+        * @return User
+        */
+       function current() {
+               return $this->current;
+       }
+
+       function key() {
+               return $this->key;
+       }
+
+       function next() {
+               $row = $this->res->next();
+               $this->setCurrent( $row );
+               $this->key++;
+       }
+
+       function rewind() {
+               $this->res->rewind();
+               $this->key = 0;
+               $this->setCurrent( $this->res->current() );
+       }
+
+       /**
+        * @return bool
+        */
+       function valid() {
+               return $this->current !== false;
+       }
+}
diff --git a/includes/user/UserRightsProxy.php b/includes/user/UserRightsProxy.php
new file mode 100644 (file)
index 0000000..e686ae3
--- /dev/null
@@ -0,0 +1,287 @@
+<?php
+/**
+ * Representation of an user on a other locally-hosted wiki.
+ *
+ * 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
+ */
+
+/**
+ * Cut-down copy of User interface for local-interwiki-database
+ * user rights manipulation.
+ */
+class UserRightsProxy {
+
+       /**
+        * Constructor.
+        *
+        * @see newFromId()
+        * @see newFromName()
+        * @param IDatabase $db Db connection
+        * @param string $database Database name
+        * @param string $name User name
+        * @param int $id User ID
+        */
+       private function __construct( $db, $database, $name, $id ) {
+               $this->db = $db;
+               $this->database = $database;
+               $this->name = $name;
+               $this->id = intval( $id );
+               $this->newOptions = array();
+       }
+
+       /**
+        * Accessor for $this->database
+        *
+        * @return string Database name
+        */
+       public function getDBName() {
+               return $this->database;
+       }
+
+       /**
+        * Confirm the selected database name is a valid local interwiki database name.
+        *
+        * @param string $database Database name
+        * @return bool
+        */
+       public static function validDatabase( $database ) {
+               global $wgLocalDatabases;
+               return in_array( $database, $wgLocalDatabases );
+       }
+
+       /**
+        * Same as User::whoIs()
+        *
+        * @param string $database Database name
+        * @param int $id User ID
+        * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
+        * @return string User name or false if the user doesn't exist
+        */
+       public static function whoIs( $database, $id, $ignoreInvalidDB = false ) {
+               $user = self::newFromId( $database, $id, $ignoreInvalidDB );
+               if ( $user ) {
+                       return $user->name;
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * Factory function; get a remote user entry by ID number.
+        *
+        * @param string $database Database name
+        * @param int $id User ID
+        * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
+        * @return UserRightsProxy|null If doesn't exist
+        */
+       public static function newFromId( $database, $id, $ignoreInvalidDB = false ) {
+               return self::newFromLookup( $database, 'user_id', intval( $id ), $ignoreInvalidDB );
+       }
+
+       /**
+        * Factory function; get a remote user entry by name.
+        *
+        * @param string $database Database name
+        * @param string $name User name
+        * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
+        * @return UserRightsProxy|null If doesn't exist
+        */
+       public static function newFromName( $database, $name, $ignoreInvalidDB = false ) {
+               return self::newFromLookup( $database, 'user_name', $name, $ignoreInvalidDB );
+       }
+
+       /**
+        * @param string $database
+        * @param string $field
+        * @param string $value
+        * @param bool $ignoreInvalidDB
+        * @return null|UserRightsProxy
+        */
+       private static function newFromLookup( $database, $field, $value, $ignoreInvalidDB = false ) {
+               global $wgSharedDB, $wgSharedTables;
+               // If the user table is shared, perform the user query on it,
+               // but don't pass it to the UserRightsProxy,
+               // as user rights are normally not shared.
+               if ( $wgSharedDB && in_array( 'user', $wgSharedTables ) ) {
+                       $userdb = self::getDB( $wgSharedDB, $ignoreInvalidDB );
+               } else {
+                       $userdb = self::getDB( $database, $ignoreInvalidDB );
+               }
+
+               $db = self::getDB( $database, $ignoreInvalidDB );
+
+               if ( $db && $userdb ) {
+                       $row = $userdb->selectRow( 'user',
+                               array( 'user_id', 'user_name' ),
+                               array( $field => $value ),
+                               __METHOD__ );
+
+                       if ( $row !== false ) {
+                               return new UserRightsProxy( $db, $database,
+                                       $row->user_name,
+                                       intval( $row->user_id ) );
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Open a database connection to work on for the requested user.
+        * This may be a new connection to another database for remote users.
+        *
+        * @param string $database
+        * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
+        * @return IDatabase|null If invalid selection
+        */
+       public static function getDB( $database, $ignoreInvalidDB = false ) {
+               global $wgDBname;
+               if ( $ignoreInvalidDB || self::validDatabase( $database ) ) {
+                       if ( $database == $wgDBname ) {
+                               // Hmm... this shouldn't happen though. :)
+                               return wfGetDB( DB_MASTER );
+                       } else {
+                               return wfGetDB( DB_MASTER, array(), $database );
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * @return int
+        */
+       public function getId() {
+               return $this->id;
+       }
+
+       /**
+        * @return bool
+        */
+       public function isAnon() {
+               return $this->getId() == 0;
+       }
+
+       /**
+        * Same as User::getName()
+        *
+        * @return string
+        */
+       public function getName() {
+               return $this->name . '@' . $this->database;
+       }
+
+       /**
+        * Same as User::getUserPage()
+        *
+        * @return Title
+        */
+       public function getUserPage() {
+               return Title::makeTitle( NS_USER, $this->getName() );
+       }
+
+       /**
+        * Replaces User::getUserGroups()
+        * @return array
+        */
+       function getGroups() {
+               $res = $this->db->select( 'user_groups',
+                       array( 'ug_group' ),
+                       array( 'ug_user' => $this->id ),
+                       __METHOD__ );
+               $groups = array();
+               foreach ( $res as $row ) {
+                       $groups[] = $row->ug_group;
+               }
+               return $groups;
+       }
+
+       /**
+        * Replaces User::addUserGroup()
+        * @param string $group
+        *
+        * @return bool
+        */
+       function addGroup( $group ) {
+               $this->db->insert( 'user_groups',
+                       array(
+                               'ug_user' => $this->id,
+                               'ug_group' => $group,
+                       ),
+                       __METHOD__,
+                       array( 'IGNORE' ) );
+
+               return true;
+       }
+
+       /**
+        * Replaces User::removeUserGroup()
+        * @param string $group
+        *
+        * @return bool
+        */
+       function removeGroup( $group ) {
+               $this->db->delete( 'user_groups',
+                       array(
+                               'ug_user' => $this->id,
+                               'ug_group' => $group,
+                       ),
+                       __METHOD__ );
+
+               return true;
+       }
+
+       /**
+        * Replaces User::setOption()
+        * @param string $option
+        * @param mixed $value
+        */
+       public function setOption( $option, $value ) {
+               $this->newOptions[$option] = $value;
+       }
+
+       public function saveSettings() {
+               $rows = array();
+               foreach ( $this->newOptions as $option => $value ) {
+                       $rows[] = array(
+                               'up_user' => $this->id,
+                               'up_property' => $option,
+                               'up_value' => $value,
+                       );
+               }
+               $this->db->replace( 'user_properties',
+                       array( array( 'up_user', 'up_property' ) ),
+                       $rows, __METHOD__
+               );
+               $this->invalidateCache();
+       }
+
+       /**
+        * Replaces User::touchUser()
+        */
+       function invalidateCache() {
+               $this->db->update( 'user',
+                       array( 'user_touched' => $this->db->timestamp() ),
+                       array( 'user_id' => $this->id ),
+                       __METHOD__ );
+
+               $wikiId = $this->db->getWikiID();
+               $userId = $this->id;
+               $this->db->onTransactionPreCommitOrIdle( function() use ( $wikiId, $userId ) {
+                       User::purge( $wikiId, $userId );
+               } );
+       }
+}
index e70469e..f27094d 100644 (file)
        "createacct-reason": "ЗыпкъырыкIырэр:",
        "createacct-reason-ph": "Сыда пэмыкI аккаунт зэкIэублэрэр?",
        "createacct-submit": "Уи аккаунт бгъэпсын",
-       "createacct-another-submit": "Ð\9dÑ\8dмÑ\8bкI Ð°ÐºÐºÐ°Ñ\83нÑ\82 ÐºÑ\8aÑ\8dÑ\83бл",
+       "createacct-another-submit": "Ð\90ккаÑ\83нÑ\82 Ñ\83блÑ\8d",
        "createacct-benefit-heading": "{{SITENAME}}-м ощ фэдэхэр дэлажьэх.",
        "createacct-benefit-body1": "{{PLURAL:$1|еӀэзэныгъэ|еӀэзэныгъ}}",
        "createacct-benefit-body2": "{{PLURAL:$1|нэкӀубгъо|нэкӀубгъу}}",
        "passwordreset-email": "Емэйл адрес:",
        "passwordreset-emailtitle": "Аккаунт и гъэпсыкIэхэр, мий щыI {{SITENAME}}",
        "passwordreset-emailelement": "НэбгырацIэ: \n$1\n\nTemporary password: \n$2",
-       "passwordreset-emailsent": "ШÑ\8aÑ\8dÑ\84гÑ\83Ñ\89Ñ\8b\8dм Ð¸ Ð·Ñ\8dÑ\82едзÑ\8bм Ð¿Ð°Ðµ ÐµÐ¼Ñ\8dйл Ð°Ð³Ñ\8aÑ\8dÑ\85Ñ\8cÑ\8bгÑ\8a.",
+       "passwordreset-emailsent": "Ð\9cÑ\8bÑ\80 Ñ\80егиÑ\81Ñ\82Ñ\80Ñ\8bгÑ\8aÑ\8d ÐµÐ¼Ñ\8dйлÑ\8dÑ\83 Ñ\89Ñ\8bÑ\82мÑ\8d Ñ\83и Ð°ÐºÐºÐ°Ñ\83нÑ\82Ñ\8bм Ð¿Ð°Ðµ, Ñ\88Ñ\8aÑ\8dÑ\84гÑ\83Ñ\89Ñ\8b\8dм Ð¸ Ð·Ñ\8dÑ\82едз ÐµÐ¼Ñ\8dйл ÐºÑ\8aÑ\8bпÑ\84агÑ\8aÑ\8dÑ\85Ñ\8cÑ\8bÑ\89Ñ\82.",
        "passwordreset-emailsent-capture": "ШъэфгущыIэм изэтедз фэгъэхьыгъэ емэйлыр гъахьыгъэ, ычIэгъкIэ ар олъэгъу.",
-       "changeemail": "Зэблэхъу емэйл адресыр",
+       "changeemail": "Зэблэхъу е тегъэкI емэйл адресыр",
        "changeemail-no-info": "Мы нэкIубгъом занкIэу укIонэу уфаемэ, системэм ухэхьэгъэн фае.",
        "changeemail-oldemail": "Джырэ емэйл адрес:",
        "changeemail-newemail": "Емэйл адресыкIэр:",
        "prefs-watchlist-token": "Лъыплъэ купым и токен:",
        "prefs-misc": "ПэмыкI гъэпсыкIэхэр",
        "prefs-resetpass": "ШъэфгущыIэр зэблэхъу",
-       "prefs-changeemail": "Зэблэхъу емэйл адресыр",
+       "prefs-changeemail": "Зэблэхъу е тегъэкI емэйл адресыр",
        "prefs-setemail": "Игъахь уи емэйл адресыр",
        "prefs-email": "Емэйл гъэпсыкIэхэр",
        "prefs-rendering": "Ышъотеплъэ",
        "deletepage": "ТегъэкI нэкIубгъор",
        "confirm": "Теубыт",
        "excontent": "дэтхэгъагъэр: \"$1\"",
-       "excontentauthor": "дэтхэгъагъэр: \"$1\" (хэлэжьэкIо закъоэр \"[[Special:Contributions/$2|$2]]\")",
+       "excontentauthor": "дэтхагъэщтыгъэхэр: \"$1\", ыкIи хэлэжьэкIо закъощтыгъэр \"[[Special:Contributions/$2|$2]]\"([[User talk:$2|тегущыIэн]])",
        "delete-confirm": "ТегъэкI \"$1\"",
        "delete-legend": "ТегъэкI",
        "actioncomplete": "ЗэшIогъэкIыгъэ",
index 0a68c0d..51e930c 100644 (file)
        "movenosubpage": "Die bladsy het geen subbladsye nie.",
        "movereason": "Rede:",
        "revertmove": "rol terug",
-       "delete_and_move": "Skrap en skuif",
        "delete_and_move_text": "==Skrapping benodig==\n\nDie teikenartikel \"[[:$1]]\" bestaan reeds. Wil u dit skrap om plek te maak vir die skuif?",
        "delete_and_move_confirm": "Ja, skrap die bladsy",
        "delete_and_move_reason": "Geskrap om plek te maak vir skuif vanaf \"[[$1]]\"",
index 3df549d..d19ea49 100644 (file)
        "movenosubpage": "ليس لهذه الصفحة صفحات فرعية.",
        "movereason": "السبب:",
        "revertmove": "استرجع",
-       "delete_and_move": "حذف ونقل",
        "delete_and_move_text": "==الحذف مطلوب==\nالصفحة الهدف \"[[:$1]]\" موجودة بالفعل.\nهل تريد حذفها لإفساح المجال للنقل؟",
        "delete_and_move_confirm": "نعم، احذف الصفحة",
        "delete_and_move_reason": "حُذِفت لإفساح مجال لنقل \"[[$1]]\"",
index 29e39cb..acfcd1d 100644 (file)
        "rev-deleted-event": "(ল'গ সবিশেষ আঁতৰোৱা হ'ল)",
        "rev-deleted-user-contribs": "[সদস্যনাম বা আই-পি ঠিকনা আঁতৰোৱা হ'ল - সম্পাদনা বৰঙনিসমূহৰ পৰা আঁৰ কৰা হৈছে]",
        "rev-deleted-text-permission": "পৃষ্ঠাৰ এই সংশোধনটি '''বিলোপ''' কৰা হ'ল ।\nসবিশেষ পাব [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} অবলুপ্তি অভিলেখত]",
-       "rev-deleted-text-unhide": "পৃষ্ঠাখনৰ এই সংশোধনটো '''বিলোপ''' কৰা হৈছে | \nসবিশেষ পাব [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} অৱলুপ্তি অভিলেখত]।\nআপুনি মন কৰিলে [$1 এই সংশোধনটো চাব পাৰে]।",
+       "rev-deleted-text-unhide": "পৃষ্ঠাখনৰ এই সংশোধনটো <strong>বিলোপ</strong> কৰা হৈছে। \n[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} অৱলুপ্তি অভিলেখত ইয়াৰ সবিশেষ পাব]।\nআপুনি মন কৰিলে [$1 এই সংশোধনটো চাব পাৰে]।",
        "rev-suppressed-text-unhide": "পৃষ্ঠাটোৰ এই সংশোধনটো '''নিবাৰণ''' কৰা হৈছে ।\nসবিশেষ পাব [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} নিবাৰণ অভিলেখত]।\nআপুনি মন কৰিলে [$1 এই সংশোধনটো চাব পাৰে]।",
        "rev-deleted-text-view": "পৃষ্ঠাৰ এই সংশোধনটো '''বিলোপ''' কৰা হ'ল ।\nআপুনি এইটো চাব পাৰে; সবিশেষ পাব [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} অবলুপ্তি অভিলেখত]।",
        "rev-suppressed-text-view": "পৃষ্ঠাৰ এই সংশোধনটো '''নিবাৰণ''' কৰা হ’ল।\nআপুনি এইটো চাব পাৰে; সবিশেষ পাব [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} নিবাৰণ অভিলেখত]।",
        "speciallogtitlelabel": "গন্তব্য (title or user):",
        "log": "অভিলেখ/ল'গ",
        "all-logs-page": "সকলোবোৰ ৰাজহুৱা সূচী",
-       "alllogstext": "{{SITENAME}} à¦¸à¦\95লà§\8b à¦²â\80\99à¦\97ৰ à¦¸à¦¨à§\8dমিলিত à¦ªà§\8dৰদৰà§\8dশন à¥¤\nà¦\86পà§\81নি à¦²â\80\99à¦\97ৰ à¦ªà§\8dৰà¦\95াৰ, à¦¸à¦¦à¦¸à§\8dযৰ à¦¨à¦¾à¦® à¦¬à¦¾ à¦ªà§\83ষà§\8dঠাà¦\96নৰ নাম নিৰ্বাচন কৰি প্ৰদৰ্শনটোৰ আকাৰ সৰু কৰিব পাৰে ।",
+       "alllogstext": "{{SITENAME}} à¦¸à¦\95লà§\8b à¦²â\80\99à¦\97ৰ à¦¸à¦¨à§\8dমিলিত à¦ªà§\8dৰদৰà§\8dশন à¥¤\nà¦\86পà§\81নি à¦²â\80\99à¦\97ৰ à¦ªà§\8dৰà¦\95াৰ, à¦¸à¦¦à¦¸à§\8dযৰ à¦¨à¦¾à¦® à¦¬à¦¾ à¦ªà§\83ষà§\8dঠাà¦\9fà§\8bৰ নাম নিৰ্বাচন কৰি প্ৰদৰ্শনটোৰ আকাৰ সৰু কৰিব পাৰে ।",
        "logempty": "কোনো মিল থকা আইটেম লগত নাই ।",
        "log-title-wildcard": "এই পাঠেৰে আৰম্ভ হোৱা শিৰোনামাসমূহ অনুসন্ধান কৰক",
        "showhideselectedlogentries": "নিৰ্বাচিত ল'গ ভুক্তি দেখুৱাওক/লুকুৱাওক",
        "protect-text": "'''$1''' পৃষ্ঠাটোৰ সুৰক্ষা-স্তৰ আপুনি চাব আৰু সলনি কৰিব পাৰে।",
        "protect-locked-blocked": "বাধাপ্ৰাপ্ত অৱস্থাত আপুনি সুৰক্ষা স্তৰ সলাব নোৱাৰে ।\n'''$1''' পৃষ্ঠাৰ বৰ্তমান ছেটিং সমূহ ইয়াত দিয়া হ’ল:",
        "protect-locked-dblock": "এটা সক্ৰিয় অথ্যভঁৰাল প্ৰতিবন্ধকৰ বাবে সুৰক্ষা স্তৰ সলাব নোৱাৰি ।\n'''$1''' পৃষ্ঠাৰ বৰ্তমান ছেটিং সমূহ ইয়াত দিয়া হ’ল:",
-       "protect-locked-access": "এই পৃষ্ঠাটোৰ সুৰক্ষা-স্তৰ সলনি কৰাৰ অনুমতি আপোনাক দিয়া হোৱা নাই ।\n'''$1''' পৃষ্ঠাখনৰ সুৰক্ষা-স্তৰৰ গাঁথনি ইয়াত আছে:",
+       "protect-locked-access": "এই পৃষ্ঠাটোৰ সুৰক্ষা-স্তৰ সলনি কৰাৰ অনুমতি আপোনাক দিয়া হোৱা নাই ।\nপৃষ্ঠাটোৰ বৰ্তমান ছেটিংছ ইয়াত পাব:\n<strong>$1</strong>:",
        "protect-cascadeon": "এই পৃষ্ঠাটো বৰ্তমান সুৰক্ষিত কাৰণ ই {{PLURAL:$1|খন পৃষ্ঠাৰ|খন পৃষ্ঠাৰ}} অন্তৰ্গত য’ত প্ৰপাতাকাৰ সুৰক্ষা সক্ৰিয় ।\nএই পৃষ্ঠাৰ সুৰক্ষা স্তৰ সলালে প্ৰপাতাকাৰ সুৰক্ষাত কোনো প্ৰভাৱ নেপেলায় ।",
        "protect-default": "সকলো ব্যৱহাৰকাৰীৰ বাবে",
        "protect-fallback": "কেৱল \"$1\" অনুমতি থকা ব্যৱহাৰকাৰীকহে সুযোগ দিয়া হয়",
        "move-page-legend": "পৃষ্ঠাটো স্থানান্তৰ কৰক",
        "movepagetext": "তলৰ প্ৰপত্ৰ ব্যৱহাৰ কৰিলে এই পৃষ্ঠাৰ শিৰোনাম সলনি হ'ব, লগতে সমগ্ৰ ইতিহাস নতুন শিৰোনামলৈ স্থানান্তৰ কৰা হ'ব।\nপুৰণা শিৰোনামটো নতুন শিৰোনামালৈ এটা পুনৰ্নিৰ্দেশনা হৈ ৰ'ব।\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": "পà§\83ষà§\8dঠাà¦\96নৰ à¦²à¦\97তà§\87 à¦¸à¦\82শà§\8dলিষà§\8dà¦\9f à¦\86লà§\8bà¦\9aনা à¦ªà§\83ষà§\8dঠাà¦\96নà§\8b à¦¸à§\8dবয়à¦\82à¦\95à§\8dৰিয়ভাৱà§\87 à¦¸à§\8dথানানà§\8dতৰ à¦¹â\80\99ব; à¦\8fনà§\87 à¦¨à¦¹à¦¯à¦¼ '''যদিহà§\87:'''\n*নতà§\81ন à¦¶à¦¿à§°à§\8bনামাৰ à¦\85ধà§\80নত à¦\8fà¦\9fা à¦\96ালি à¦¨à§\8bহà§\8bৱা à¦\86লà§\8bà¦\9aনা à¦ªà§\83ষà§\8dঠা à¦\87তিমধà§\8dযà§\87à¦\87 à¦¥à¦¾à¦\95à§\87, à¦¬à¦¾\n*à¦\86পà§\81নি à¦¤à¦²à§° à¦\98ৰà¦\9fà§\8b à¦\85à¦\9aিহà§\8dনিত à¦\95ৰà§\87 à¥¤\n\nতà§\87নà§\87 à¦\95à§\8dষà§\87তà§\8dৰত à¦\86পà§\81নি à¦\86পà§\81নি à¦\87à¦\9aà§\8dà¦\9bা à¦\95ৰিলà§\87 à¦¨à¦¿à¦\9c à¦¹à¦¾à¦¤à§\87 à¦ªà§\83ষà§\8dঠাà¦\9fà§\8b à¦¸à§\8dথানানà§\8dতৰ à¦¬à¦¾ à¦\8fà¦\95তà§\8dৰà§\80à¦\95ৰণ à¦\95ৰিব à¦ªà¦¾à§°à§\87 ।",
+       "movepagetalktext": "à¦\8fà¦\87 à¦¬à¦¾à¦\95à¦\9bà¦\9fà§\8b à¦\9aিহà§\8dনিত à¦\95ৰিলà§\87 à¦ªà§\83ষà§\8dঠাà¦\9fà§\8bৰ à¦²à¦\97তà§\87 à¦¸à¦\82শà§\8dলিষà§\8dà¦\9f à¦\86লà§\8bà¦\9aনা à¦ªà§\83ষà§\8dঠাà¦\93 à¦¸à§\8dবয়à¦\82à¦\95à§\8dৰিয়ভাৱà§\87 à¦¸à§\8dথানানà§\8dতৰ à¦¹â\80\99ব; à¦\8fনà§\87 à¦¨à¦¹à¦¯à¦¼ à¦¯à¦¦à¦¿à¦¹à§\87 à¦\8fà¦\9fা à¦\96ালি à¦¨à§\8bহà§\8bৱা à¦\86লà§\8bà¦\9aনা à¦ªà§\83ষà§\8dঠা à¦\87তিমধà§\8dযà§\87à¦\87 à¦¥à¦¾à¦\95à§\87।\n\nতà§\87নà§\87 à¦\95à§\8dষà§\87তà§\8dৰত à¦\86পà§\81নি à¦\86পà§\81নি à¦\87à¦\9aà§\8dà¦\9bা à¦\95ৰিলà§\87 à¦¨à¦¿à¦\9c à¦¹à¦¾à¦¤à§\87 à¦ªà§\83ষà§\8dঠাà¦\9fà§\8b à¦¸à§\8dথানানà§\8dতৰ à¦¬à¦¾ à¦\8fà¦\95তà§\8dৰà§\80à¦\95ৰণ à¦\95ৰিব à¦ªà¦¾à§°à§\87।",
        "moveuserpage-warning": "'''সতৰ্কবাণী:''' আপুনি এখন সদস্যপৃষ্ঠা স্থানান্তৰ কৰিবলৈ বিছাৰিছে । অনুগ্ৰহ কৰি মন কৰক যে কেৱল সদস্যপৃষ্ঠাখনহে স্থানান্তৰ হ’ব আৰু সদস্যজনৰ পুনঃনামাকৰণ নহ’ব ।",
        "movenologintext": "পৃষ্ঠা স্থানান্তৰ কৰিবলৈ আপুনি ভুক্ত সদস্য হৈ [[Special:UserLogin|প্ৰৱেশ]] কৰিব লাগিব ।",
        "movenotallowed": "পৃষ্ঠা স্থানান্তৰ কৰিবলৈ আপোনাৰ অনুমতি নাই ।",
        "movenosubpage": "এই পৃষ্ঠাৰ কোনো উপপৃষ্ঠা নাই ।",
        "movereason": "কাৰণ:",
        "revertmove": "আগৰ অৱস্থালৈ ঘূৰি যাওক",
-       "delete_and_move": "বিলোপ আৰু স্থানান্তৰ কৰক",
        "delete_and_move_text": "== বিলোপন আৱশ্যক ==\nলক্ষ্য পৃষ্ঠা \"[[:$1]]\" ইতিমেধ্যে আছেই ।\nআপুনি স্থানান্তৰ কৰিবলৈ এইখন বিলোপ কৰিব খুজিছে নেকি ?",
        "delete_and_move_confirm": "হয়, পৃষ্ঠাটো বিলোপ কৰক",
        "delete_and_move_reason": "\"[[$1]]\"ৰ পৰা স্থানান্তৰৰ স্বাৰ্থত বিলোপ কৰা হৈছে",
        "tooltip-pt-logout": "প্ৰস্থান",
        "tooltip-pt-createaccount": "আপোনাক এটা একাউণ্ট সৃষ্টি কৰি প্ৰৱেশ কৰিবলৈ অনুৰোধ জনোৱা হৈছে, কিন্তু এয়া বাধ্যতামূলক নহয়",
        "tooltip-ca-talk": "সংশ্লিষ্ট প্ৰবন্ধ সম্পৰ্কীয় আলোচনা",
-       "tooltip-ca-edit": "এই পৃষ্ঠাখন সম্পাদনা কৰক",
+       "tooltip-ca-edit": "এই পৃষ্ঠা সম্পাদনা কৰক",
        "tooltip-ca-addsection": "নতুন অনুচ্ছেদ আৰম্ভ কৰক",
        "tooltip-ca-viewsource": "এই পৃষ্ঠাটো সুৰক্ষিত কৰা হৈছে, আপুনি ইয়াৰ উৎস চাব পাৰে।",
        "tooltip-ca-history": "এই পৃষ্ঠাৰ যোৱা সংস্কৰণসমূহ",
        "tooltip-ca-nstab-main": "এই ৱিকিৰ সূচী চাওক",
        "tooltip-ca-nstab-user": "সদস্য পৃষ্ঠা চাওক",
        "tooltip-ca-nstab-media": "মিডিয়া পৃষ্ঠাটো চাওক",
-       "tooltip-ca-nstab-special": "এইটো এটা বিশেষ পৃষ্ঠা, আপুনি সম্পাদনা কৰিব নোৱাৰে",
+       "tooltip-ca-nstab-special": "à¦\8fà¦\87à¦\9fà§\8b à¦\8fà¦\9fা à¦¬à¦¿à¦¶à§\87ষ à¦ªà§\83ষà§\8dঠা, à¦\86ৰà§\81 à¦\8fà¦\87à¦\9fà§\8b à¦\86পà§\81নি à¦¸à¦®à§\8dপাদনা à¦\95ৰিব à¦¨à§\8bৱাৰà§\87",
        "tooltip-ca-nstab-project": "প্ৰকল্প পৃষ্ঠা চাওক",
        "tooltip-ca-nstab-image": "নথিৰ পৃষ্ঠা চাওক",
        "tooltip-ca-nstab-mediawiki": "প্ৰণালী বাৰ্তা চাওক",
index 954255b..47ea930 100644 (file)
        "movenosubpage": "Esta páxina nun tien subpáxines.",
        "movereason": "Motivu:",
        "revertmove": "revertir",
-       "delete_and_move": "Esborrar y treslladar",
        "delete_and_move_text": "==Necesítase esborrar==\n\nLa páxina de destín \"[[:$1]]\" yá esiste. ¿Quies esborrala pa dexar sitiu pal treslláu?",
        "delete_and_move_confirm": "Sí, esborrar la páxina",
        "delete_and_move_reason": "Desaniciada pa facer sitiu pa treslladar dende «[[$1]]»",
index e805a73..3e5d53d 100644 (file)
        "movenosubpage": "Bu səhifənin altsəhifəsi yoxdur.",
        "movereason": "Səbəb:",
        "revertmove": "Əvvəlki vəziyyətinə",
-       "delete_and_move": "Sil və apar",
        "delete_and_move_text": "==Hazırki məqalənin silinməsi lazımdır==\n\n\"[[$1]]\" məqaləsi mövcuddur. Bu dəyişikliyin yerinə yetirilə bilməsi üçün həmin məqalənin silinməsini istəyirsinizmi?",
        "delete_and_move_confirm": "Bəli, səhifəni sil",
        "delete_and_move_reason": "[[$1]] Ad dəyişməyə yer açmaq üçün silinmişdir",
index 720adeb..390022b 100644 (file)
        "morenotlisted": "Гэта ня поўны сьпіс.",
        "mypage": "Старонка",
        "mytalk": "Гутаркі",
-       "anontalk": "Гутаркі для гэтага IP-адрасу",
+       "anontalk": "Гутаркі",
        "navigation": "Навігацыя",
        "and": "&#32;і",
        "qbfind": "Знайсьці",
        "contributions": "Унёсак {{GENDER:$1|удзельніка|удзельніцы}}",
        "contributions-title": "Унёсак {{GENDER:$1|удзельніка|удзельніцы}} $1",
        "mycontris": "Унёсак",
+       "anoncontribs": "Унёсак",
        "contribsub2": "Для {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Рахунак удзельніка «$1» не зарэгістраваны.",
        "nocontribs": "Ня знойдзена зьменаў, якія адпавядаюць гэтым крытэрыям.",
        "movenosubpage": "Гэтая старонка ня мае падстаронак.",
        "movereason": "Прычына:",
        "revertmove": "адкат",
-       "delete_and_move": "Выдаліць і перанесьці",
        "delete_and_move_text": "==Патрабуецца выдаленьне==\nМэтавая старонка «[[:$1]]» ужо існуе.\nЦі жадаеце Вы яе выдаліць, каб вызваліць месца для пераносу?",
        "delete_and_move_confirm": "Так, выдаліць старонку",
        "delete_and_move_reason": "Выдаленая, каб вызваліць месца для пераносу «[[$1]]»",
index 44f6654..f503418 100644 (file)
        "movenosubpage": "Старонка не мае пад-старонак.",
        "movereason": "Прычына:",
        "revertmove": "адкат",
-       "delete_and_move": "Сцерці і перанесці",
        "delete_and_move_text": "==Патрабуецца сціранне==\n\nУжо існуе артыкул з мэтавай назвай \"[[:$1]]\". Дык ці жадаеце сцерці яго, каб зрабіць месца для пераносу?",
        "delete_and_move_confirm": "Так, сцерці старонку",
        "delete_and_move_reason": "Сцёрта, каб зрабіць месца для пераносу \"[[$1]]\"",
index 7f4ed54..e12ecce 100644 (file)
@@ -30,7 +30,8 @@
                        "Macofe",
                        "V111P",
                        "Лорд Бъмбъри",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Xð"
                ]
        },
        "tog-underline": "Подчертаване на препратките:",
        "enhancedrc-history": "история",
        "recentchanges": "Последни промени",
        "recentchanges-legend": "Настройки на списъка с последни промени",
-       "recentchanges-summary": "Проследяване на последните промени в {{SITENAME}}.\n\nЛегенда: '''тек''' = разлика на текущата версия,\n'''ист''' = история на версиите",
+       "recentchanges-summary": "Проследяване на последните промени в {{SITENAME}}.\n\nЛегенда: '''{{int:diff}}''' = разлика на текущата версия,\n'''{{int:hist}}''' = история на версиите",
        "recentchanges-noresult": "За дадения период не бяха намерени промени, които да отговарят на критериите.",
        "recentchanges-feed-description": "Проследяване на последните промени в {{SITENAME}}.",
        "recentchanges-label-newpage": "Нова страница",
        "wlheader-showupdated": "Страниците, които са били променени след последния път, когато сте ги посетили, са показани в '''получер'''.",
        "wlnote": "{{PLURAL:$1|Показана е последната промяна|Показани са последните '''$1''' промени}} през {{PLURAL:$2|последния час|последните '''$2''' часа}}.",
        "wlshowlast": "Показване на последните $1 часа $2 дни",
+       "watchlistall2": "всички",
        "watchlist-options": "Опции на списъка за наблюдение",
        "watching": "Наблюдение…",
        "unwatching": "Спиране на наблюдение…",
        "movenosubpage": "Тази страница няма подстраници.",
        "movereason": "Причина:",
        "revertmove": "връщане",
-       "delete_and_move": "Изтриване и преместване",
        "delete_and_move_text": "== Наложително изтриване ==\n\nЦелевата страница „[[:$1]]“ вече съществува. Искате ли да я изтриете, за да освободите място за преместването?",
        "delete_and_move_confirm": "Да, искам да изтрия тази страница.",
        "delete_and_move_reason": "Изтрита, за да се освободи място за преместване от „[[$1]]“",
index c49cded..ac0204f 100644 (file)
        "contributions": "{{GENDER:$1|کار زوروک}} ئی شراکت ئان",
        "contributions-title": "$1 ئی کار زوروکئ شراکت ئان",
        "mycontris": "شراکت ئان",
+       "anoncontribs": "شراکت ئان",
        "contribsub2": "په {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "«$1» ئی کار زوروکین حساب راجستر نه بوته.",
        "nocontribs": "هیچ تغیری گۆ ای مشخصات ئان ودێ نه بوت",
        "movenosubpage": "ای تاکدیم هیچ گۆنڈدیم ئی نداریت.",
        "movereason": "دلیل:",
        "revertmove": "بیرگردینتین",
-       "delete_and_move": "پاک کورتین یا جابیجا",
        "delete_and_move_confirm": "هان،تاکدیم پاک بیئت",
        "delete_and_move_reason": "پاک کورتین  «[[$1]]» جابجایی امکانا",
        "immobile-source-page": "ای دیم جابیجا ئه نه بیئت.",
index d11c197..b8ba0e2 100644 (file)
        "movenosubpage": "এই পাতাটির কোনো উপপাতা নেই।",
        "movereason": "কারণ:",
        "revertmove": "পূর্বাবস্থায় ফেরত নেওয়া হোক",
-       "delete_and_move": "মুছে ফেলা হোক ও সরানো হোক",
        "delete_and_move_text": "==মুছে ফেলা আবশ্যক==\n\n\"[[:$1]]\" শিরোনামের গন্তব্য পাতাটি ইতিমধ্যেই বিদ্যমান। আপনি কি স্থানান্তর সফল করার জন্য পাতাটি মুছে দিতে চান?",
        "delete_and_move_confirm": "হ্যাঁ, পাতাটি মুছে ফেলা হোক",
        "delete_and_move_reason": "\"[[$1]]\" থেকে স্থানান্তরের স্বার্থে মুছে ফেলা হয়েছে",
index c62206b..c83b250 100644 (file)
        "sp-contributions-blocked-notice-anon": "Ova IP adresa je trenutno blokirana.\nPosljednje stavke zapisnika blokiranja možete pogledati ispod:",
        "sp-contributions-search": "Pretraži doprinose",
        "sp-contributions-username": "IP adresa ili korisničko ime:",
-       "sp-contributions-toponly": "Prikaži samo izmjene koje su posljednje revizije",
+       "sp-contributions-toponly": "Prikaži samo najnovije izmjene",
        "sp-contributions-newonly": "Prikaži samo izmjene kojima su napravljene nove stranice",
        "sp-contributions-submit": "Traži",
        "whatlinkshere": "Šta vodi ovamo",
        "movenosubpage": "Ova stranica nema podstranica.",
        "movereason": "Razlog:",
        "revertmove": "vrati",
-       "delete_and_move": "Obriši i premjesti",
        "delete_and_move_text": "==Potebno brisanje==\nOdredišna stranica \"[[:$1]]\" već postoji.\nDa li je želite obrisati kako bi ste mogli izvršiti premještanje?",
        "delete_and_move_confirm": "Da, obriši stranicu",
        "delete_and_move_reason": "Obrisano da bi se napravio prostor za premještanje iz \"[[$1]]\"",
index 9cc6cd1..dcb761e 100644 (file)
@@ -52,7 +52,8 @@
                        "Pginer",
                        "Eduardo Martinez",
                        "Matma Rex",
-                       "KRLS"
+                       "KRLS",
+                       "Jaumeortola"
                ]
        },
        "tog-underline": "Subratlla els enllaços:",
        "morenotlisted": "Aquesta llista no és completa.",
        "mypage": "Pàgina",
        "mytalk": "Discussió",
-       "anontalk": "Discussió d'aquesta IP",
+       "anontalk": "Discussió",
        "navigation": "Navegació",
        "and": "&#32;i",
        "qbfind": "Cerca",
        "privacy": "Política de privadesa",
        "privacypage": "Project:Política de privadesa",
        "badaccess": "Error de permisos",
-       "badaccess-group0": "No teniu permís per a executar l'acció que heu soŀlicitat.",
-       "badaccess-groups": "L'acció que heu soŀlicitat es limita als usuaris {{PLURAL:$2|del grup|dels grups}}: $1.",
+       "badaccess-group0": "No teniu permís per a executar l'acció que heu solicitat.",
+       "badaccess-groups": "L'acció que heu solicitat es limita als usuaris {{PLURAL:$2|del grup|dels grups}}: $1.",
        "versionrequired": "Cal la versió $1 del MediaWiki",
        "versionrequiredtext": "Cal la versió $1 del MediaWiki per a utilitzar aquesta pàgina. Vegeu [[Special:Version]]",
        "ok": "D’acord",
        "nstab-category": "Categoria",
        "mainpage-nstab": "Pàgina principal",
        "nosuchaction": "No es reconeix aquesta operació",
-       "nosuchactiontext": "L'acció especificada per la URL no és vàlida.\nPotser heu escrit malament la URL o heu seguit un enllaç incorrecte.\nAixò també pot ser causat per un error al programari utilitzat pel projecte {{SITENAME}}.",
+       "nosuchactiontext": "L'acció especificada per l'URL no és vàlida.\nPotser heu escrit malament l'URL o heu seguit un enllaç incorrecte.\nAixò també pot ser causat per un error en el programari utilitzat pel projecte {{SITENAME}}.",
        "nosuchspecialpage": "No es troba la pàgina especial que busqueu",
        "nospecialpagetext": "<strong>La pàgina especial que demaneu no és vàlida.</strong>\n\nVegeu la llista de pàgines especials a [[Special:SpecialPages]].",
        "error": "Error",
        "userlogin-signwithsecure": "Connexió segura",
        "yourdomainname": "El vostre domini",
        "password-change-forbidden": "No podeu canviar les contrasenyes en aquest wiki.",
-       "externaldberror": "Hi ha hagut una fallida en el servidor d'autenticació externa de la base de dades i no teniu permís per a actualitzar el vostre compte d'accès extern.",
+       "externaldberror": "Hi ha hagut un error en la base de dades d'autenticació o bé no teniu permís per a actualitzar el vostre compte extern.",
        "login": "Inici de sessió",
        "nav-login-createaccount": "Inicia una sessió / crea un compte",
        "userlogin": "Inicia una sessió / crea un compte",
        "wrongpasswordempty": "La contrasenya que s'ha introduït estava en blanc. Torneu-ho a provar.",
        "passwordtooshort": "La contrasenya ha de tenir un mínim {{PLURAL:$1|d'un caràcter|de $1 caràcters}}.",
        "passwordtoolong": "La contrasenya ha de tenir un màxim {{PLURAL:$1|d'un caràcter|de $1 caràcters}}.",
-       "password-name-match": "La contrasenya ha de ser diferent al vostre nom d'usuari.",
+       "password-name-match": "La contrasenya ha de ser diferent del vostre nom d'usuari.",
        "password-login-forbidden": "No és permès d'utilitzar aquest nom d'usuari i contrasenya.",
        "mailmypassword": "Restableix la contrasenya",
        "passwordremindertitle": "Nova contrasenya temporal per al projecte {{SITENAME}}",
-       "passwordremindertext": "Algú (vós mateix segurament, des de l'adreça l'IP $1) ha soŀlicitat que us enviéssim una nova contrasenya per a iniciar la sessió al projecte {{SITENAME}} ($4).\nLa nova contrasenya temporal per a l'usuari «$2» és ara «$3». Si aquesta fou la vostra intenció, ara hauríeu d'iniciar la sessió i canviar-la. Tingueu present que és temporal i caducarà d'aquí {{PLURAL:$5|un dia|$5 dies}}.\n\nSi algú altre hagués fet aquesta soŀlicitud o si ja haguéssiu recordat la vostra contrasenya i\nno volguéssiu canviar-la, ignoreu aquest missatge i continueu utilitzant\nla vostra antiga contrasenya.",
+       "passwordremindertext": "Algú (vós mateix segurament, des de l'adreça l'IP $1) ha sol·licitat que us enviéssim una nova contrasenya per a iniciar la sessió al projecte {{SITENAME}} ($4).\nLa nova contrasenya temporal per a l'usuari «$2» és ara «$3». Si aquesta fou la vostra intenció, ara hauríeu d'iniciar la sessió i canviar-la. Tingueu present que és temporal i caducarà d'aquí {{PLURAL:$5|un dia|$5 dies}}.\n\nSi algú altre hagués fet aquesta sol·licitud o si ja haguéssiu recordat la vostra contrasenya i\nno volguéssiu canviar-la, ignoreu aquest missatge i continueu utilitzant\nla vostra antiga contrasenya.",
        "noemail": "No hi ha cap adreça electrònica registrada de l'usuari «$1».",
        "noemailcreate": "Heu d’indicar una adreça electrònica vàlida.",
        "passwordsent": "S'ha enviat una nova contrasenya a l'adreça electrònica registrada per «$1».\nInicieu una sessió després que la rebeu.",
        "accountcreated": "S'ha creat el compte",
        "accountcreatedtext": "S'ha creat el compte d'usuari de [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|discussió]]).",
        "createaccount-title": "Creació d'un compte a {{SITENAME}}",
-       "createaccount-text": "Algú ha creat un compte d'usuari anomenat $2 al projecte {{SITENAME}}\n($4) amb la vostra adreça de correu electrònic. La contrasenya per a l'usuari «$2» és «$3». Hauríeu d'accedir al compte i canviar-vos aquesta contrasenya quan abans millor.\n\nSi no hi teniu cap relació i aquest compte s'ha creat per error, simplement ignoreu el missatge.",
+       "createaccount-text": "Algú ha creat un compte d'usuari anomenat $2 en el projecte {{SITENAME}}\n($4) amb la vostra adreça de correu electrònic. La contrasenya per a l'usuari «$2» és «$3». Hauríeu d'accedir al compte i canviar-vos aquesta contrasenya com més aviat millor.\n\nSi no hi teniu cap relació i aquest compte s'ha creat per error, simplement ignoreu el missatge.",
        "login-throttled": "Heu realitzat massa intents d'accés a la sessió.\nEspereu $1 abans de tornar-ho a provar.",
-       "login-abort-generic": "L'entrada al compte d'usuari no ha reeixit - Abortada",
+       "login-abort-generic": "L'entrada al compte d'usuari no ha reeixit - S'ha interromput.",
        "login-migrated-generic": "S'ha migrat el vostre compte, i el vostre nom d'usuari ja no existeix en aquest wiki.",
        "loginlanguagelabel": "Llengua: $1",
-       "suspicious-userlogout": "S'ha denegat la vostra petició per tancar la sessió ja què sembla que va ser enviada per un navegador defectuós o un proxy cau.",
+       "suspicious-userlogout": "S'ha denegat la vostra petició per a tancar la sessió, ja que sembla que va ser enviada per un navegador defectuós o un servidor intermediari.",
        "createacct-another-realname-tip": "El nom real és opcional.\nSi decidiu proporcionar-lo, s'utilitzarà per a reconèixer a l'usuari el seu treball.",
        "pt-login": "Inicia la sessió",
        "pt-login-button": "Inicia sessió",
        "resetpass_forbidden": "No poden canviar-se les contrasenyes",
        "resetpass-no-info": "Heu d'estar registrats en un compte per a poder accedir directament a aquesta pàgina.",
        "resetpass-submit-loggedin": "Canvia la contrasenya",
-       "resetpass-submit-cancel": "Canceŀla",
+       "resetpass-submit-cancel": "Cancela",
        "resetpass-wrong-oldpass": "Contrasenya actual o temporal no vàlida.\nDeveu haver canviat la vostra contrasenya o demanat una nova contrasenya temporal.",
        "resetpass-recycled": "Restabliu la contrasenya amb un text diferent que el de la contrasenya actual.",
        "resetpass-temp-emailed": "Heu iniciat una sessió amb un codi temporal enviat per correu.\nPer completar l'inici de sessió heu de definir una contrasenya nova a continuació:",
        "note": "'''Nota:'''",
        "previewnote": "'''Recorda que això és només una previsualització.'''\nEls vostres canvis encara no s'han desat!",
        "continue-editing": "Aneu a l'àrea d'edició",
-       "previewconflict": "Aquesta previsualització reflecteix, a l'àrea\nd'edició superior, el text tal com apareixerà si trieu desar-lo.",
+       "previewconflict": "Aquesta previsualització reflecteix, a l'àrea\nd'edició superior, el text tal com apareixerà si trieu desar-lo.",
        "session_fail_preview": "'''No s'ha pogut processar la vostra modificació a causa d'una pèrdua de dades de la sessió.\nSi us plau, proveu-ho una altra vegada. Si continués sense funcionar, proveu de [[Special:UserLogout|finalitzar la sessió]] i torneu a iniciar-ne una.'''",
        "session_fail_preview_html": "'''Ho sentim, no s'han pogut processar les vostres modificacions a causa d'una pèrdua de dades de la sessió.'''\n\n''Com que el projecte {{SITENAME}} té habilitat l'ús de codi HTML cru, s'ha amagat la previsualització com a prevenció contra atacs mitjançant codis JavaScript.''\n\n'''Si es tracta d'una contribució legítima, si us plau, intenteu-ho una altra vegada. Si continua havent-hi problemes, [[Special:UserLogout|finalitzeu la sessió]] i torneu a iniciar-ne una.'''",
        "token_suffix_mismatch": "'''S'ha rebutjat la vostra modificació perquè el vostre client ha fet malbé els caràcters de puntuació en el testimoni d'edició. S'ha rebutjat la modificació per a evitar la corrupció del text de la pàgina. Açò passa a vegades quan s'utilitza un servei web de servidor intermediari anònim amb problemes.'''",
        "defaultmessagetext": "Missatge per defecte",
        "content-failed-to-parse": "Ha fallat l'anàlisi del contingut de $2 per al model $1: $3",
        "invalid-content-data": "Dades de contingut no vàlides",
-       "content-not-allowed-here": "No Ã©s permés el contingut \"$1\" a la pàgina [[$2]]",
+       "content-not-allowed-here": "No Ã©s permès el contingut \"$1\" a la pàgina [[$2]]",
        "editwarning-warning": "Si sortiu d'aquesta pàgina perdreu tots els canvis que hàgiu fet.\nSi teniu un compte d'usuari, podeu eliminar aquest avís a la secció «{{int:prefs-editing}}» de les vostres preferències.",
        "editpage-notsupportedcontentformat-title": "No s'admet el format del contingut",
        "editpage-notsupportedcontentformat-text": "No s'admet el format del contingut $1 pel model de contingut $2.",
        "parser-unstrip-recursion-limit": "S'ha excedit el límit ($1) de recursivitat no desmuntable",
        "converter-manual-rule-error": "Error detectat a la norma de conversió de llengua manual",
        "undo-success": "Pot desfer-se la modificació. Si us plau, reviseu la comparació de sota per a assegurar-vos que és el que voleu fer; llavors deseu els canvis per a finalitzar la desfeta de l'edició.",
-       "undo-failure": "No pot desfer-se la modificació perquè hi ha edicions entre mig que hi entren en conflicte.",
+       "undo-failure": "No pot desfer-se la modificació perquè hi ha edicions intermèdies en conflicte.",
        "undo-norev": "No s'ha pogut desfer l'edició perquè no existeix o s'ha suprimit.",
        "undo-nochange": "Sembla que ja s'ha desfet la modificació.",
        "undo-summary": "Es desfà la revisió $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|Discussió]])",
        "undo-summary-username-hidden": "Desfés la revisió $1 d'un usuari ocult",
        "cantcreateaccounttitle": "No es pot crear el compte",
        "cantcreateaccount-text": "[[User:$3|$3]] ha bloquejat la creació de comptes des d'aquesta adreça IP ('''$1''').\n\nEl motiu donat per $3 és ''$2''",
-       "cantcreateaccount-range-text": "La creació de comptes des de les adreces IP en el rang '''$1''', que inclou la vostra adreça IP ('''$4'''), ha esta blocada per [[User:$3|$3]].\n\nEl motiu donat per $3 és ''$2''",
+       "cantcreateaccount-range-text": "La creació de comptes des de les adreces IP en el rang '''$1''', que inclou la vostra adreça IP ('''$4'''), ha estat blocada per [[User:$3|$3]].\n\nEl motiu donat per $3 és ''$2''",
        "viewpagelogs": "Visualitza els registres d'aquesta pàgina",
        "nohistory": "No hi ha un historial de revisions per a aquesta pàgina.",
        "currentrev": "Revisió actual",
        "rev-deleted-no-diff": "No podeu veure aquesta comparativa perquè s'ha '''suprimit''' una de les versions.\nPotser trobareu detalls al [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registre d'esborrats].",
        "rev-suppressed-no-diff": "No podeu veure aquesta diferència perquè s'ha '''suprimit''' una de les revisions.",
        "rev-deleted-unhide-diff": "S'ha '''eliminat''' una de les revisions d'aquesta comparativa.\nVegeu-ne més detalls al [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registre de supressions].\nEncara podeu [$1 veure aquesta comparativa] si així ho desitgeu.",
-       "rev-suppressed-unhide-diff": "S¡ha '''suprimit''' una de les revisions d'aquesta comparativa.\nPodeu veure'n més detalls al [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} registre de supressions].\nPodeu seguir [$1 veient aquesta comparativa] si així ho desitgeu.",
+       "rev-suppressed-unhide-diff": "S'ha <strong>suprimit</strong> una de les revisions d'aquesta comparativa.\nPodeu veure'n més detalls en el [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} registre de supressions].\nEncara podeu [$1 veure aquesta comparativa] si així ho desitgeu.",
        "rev-deleted-diff-view": "S'ha '''suprimit'' una de les revisions d'aquesta comparativa.\nPodeu veure aquesta comparativa; poden haver-hi més detalls al [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registre d'esborraments].",
        "rev-suppressed-diff-view": "S'ha '''suprimit'' una de les revisions d'aquesta comparativa.\nVegeu-ne més detalls al [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} registre de supressions].",
        "rev-delundel": "mostra/amaga",
        "mergehistory-empty": "No pot fusionar-se cap revisió.",
        "mergehistory-done": "{{PLURAL:$3|S’ha|S’han}} fusionat correctament $3 {{PLURAL:$3|revisió|revisions}} de $1 a [[:$2]].",
        "mergehistory-fail": "No s'ha pogut realitzar la fusió de l'historial, comproveu la pàgina i els paràmetres horaris.",
-       "mergehistory-fail-toobig": "No s'ha pogut realitzar la fusió de l'historial perquè es mourien més del limit de $1 {{PLURAL:$1|revisió|revisions}}.",
+       "mergehistory-fail-toobig": "No s'ha pogut fer la fusió de l'historial perquè es mourien més del límit de $1 {{PLURAL:$1|revisió|revisions}}.",
        "mergehistory-no-source": "La pàgina d'origen $1 no existeix.",
        "mergehistory-no-destination": "La pàgina de destinació $1 no existeix.",
        "mergehistory-invalid-source": "La pàgina d'origen ha de tenir un títol vàlid.",
        "right-upload": "Carregar fitxers",
        "right-reupload": "Carregar al damunt d'un fitxer existent",
        "right-reupload-own": "Carregar al damunt d'un fitxer que havia carregat el propi usuari",
-       "right-reupload-shared": "Carregar localment fitxers amb un nom usat en el repostori multimèdia compartit",
+       "right-reupload-shared": "Sobreescriure localment fitxers presents al repositori multimèdia compartit",
        "right-upload_by_url": "Carregar un fitxer des de l'adreça URL",
        "right-purge": "Purgar la memòria cau del lloc web sense pàgina de confirmació",
        "right-autoconfirmed": "Modificar pàgines semiprotegides",
        "action-undelete": "recuperar aquesta pàgina",
        "action-suppressrevision": "revisar i recuperar aquesta revisió oculta",
        "action-suppressionlog": "visualitzar aquest registre privat",
-       "action-block": "blocar aquest usuari per a què no pugui editar",
+       "action-block": "blocar aquest usuari perquè no pugui editar",
        "action-protect": "canviar els nivells de protecció d'aquesta pàgina",
        "action-rollback": "desfer ràpidament les modificacions de l'últim usuari que va editar una determinada pàgina",
        "action-import": "importa pàgines des d'un altre wiki",
        "action-editcontentmodel": "editar el model de contingut d'una pàgina",
        "action-managechangetags": "crear i suprimir etiquetes de la base de dades",
        "action-applychangetags": "aplica les etiquetes juntament amb els canvis",
-       "action-changetags": "afegeix i elimina etiquetes a les revisions y entrades de registre individuals",
+       "action-changetags": "afegeix i elimina etiquetes a les revisions i les entrades de registre individuals",
        "nchanges": "$1 {{PLURAL:$1|canvi|canvis}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|des de la darrera visita}}",
        "enhancedrc-history": "historial",
        "fileexists-thumbnail-yes": "Aquest fitxer sembla ser una imatge en mida reduïda (<em>miniatura</em>). [[$1|thumb]]\nComproveu si us plau el fitxer <strong>[[:$1]]</strong>.\nSi el fitxer és la mateixa imatge a mida original, no cal carregar cap miniatura més.",
        "file-thumbnail-no": "El nom del fitxer comença per <strong>$1</strong>.\nSembla ser una imatge de mida reduïda ''(miniatura)''.\nSi teniu la imatge en resolució completa, pugeu-la, sinó mireu de canviar-li el nom, si us plau.",
        "fileexists-forbidden": "Ja hi existeix un fitxer amb aquest nom i no es pot sobreescriure.\nSi us plau, torneu enrere i carregueu aquest fitxer sota un altre nom. [[File:$1|thumb|center|$1]]",
-       "fileexists-shared-forbidden": "Ja hi ha un fitxer amb aquest nom al fons comú de fitxers.\nSi us plau, si encara desitgeu carregar el vostre fitxer, torneu enrera i carregueu-ne una còpia amb un altre nom. [[File:$1|thumb|center|$1]]",
+       "fileexists-shared-forbidden": "Ja hi ha un fitxer amb aquest nom en el fons comú de fitxers.\nSi encara voleu pujar el fitxer, torneu enrere i pugeu-ne una còpia amb un altre nom. [[File:$1|thumb|center|$1]]",
        "file-exists-duplicate": "Aquest fitxer és un duplicat {{PLURAL:$1|del fitxer |dels següents fitxers:}}",
        "file-deleted-duplicate": "S'ha suprimit anteriorment un fitxer idèntic a aquest ([[:$1]]). Hauríeu de comprovar el registre de supressions del fitxer abans de tornar-lo a carregar.",
        "file-deleted-duplicate-notitle": "Un fitxer idèntic a aquest fitxer havia estat suprimit abans, i també el títol. Hauríeu de demanar a algú que pugui veure les dades suprimides del fitxer que revisi la situació abans de procedir a tornar a carregar-lo.",
        "upload-file-error-text": "S'ha produït un error de càrrega desconegut quan s'intentava crear un fitxer temporal al servidor. Poseu-vos en contacte amb un [[Special:ListUsers/sysop|administrador]].",
        "upload-misc-error": "S'ha produït un error de càrrega desconegut",
        "upload-misc-error-text": "S'ha produït un error desconegut durant la càrrega. Verifiqueu que l'URL és vàlid i accessible, i torneu-ho a provar. Si el problema persisteix, adreceu-vos a un [[Special:ListUsers/sysop|administrador]].",
-       "upload-too-many-redirects": "LURL conté massa redireccions",
+       "upload-too-many-redirects": "L'URL conté massa redireccions",
        "upload-http-error": "Ha ocorregut un error HTTP: $1",
        "upload-copy-upload-invalid-domain": "Les càrregues de còpia no són disponibles des d'aquest domini.",
        "upload-dialog-title": "Carrega un fitxer",
        "backend-fail-stream": "No s'ha pogut transmetre el fitxer $1.",
        "backend-fail-backup": "No s'ha pogut fer una còpia de seguretat del fitxer $1.",
        "backend-fail-notexists": "El fitxer $1 no existeix.",
-       "backend-fail-hashes": "No s'han pogut obtenir els resums dels fitxer per fer-ne comparació.",
+       "backend-fail-hashes": "No s'han pogut obtenir els codis hash dels fitxers per a fer-ne comparació.",
        "backend-fail-notsame": "Ja existeix un fitxer no idèntic a $1.",
        "backend-fail-invalidpath": "$1 no és un camí d'emmagatzemament vàlid.",
        "backend-fail-delete": "No s'ha pogut suprimir el fitxer $1.",
        "img-auth-streaming": "Lectura corrent de \"$1\".",
        "img-auth-public": "La funció de img_auth.php és de sortida de fitxers d'un lloc wiki privat.\nAquest wiki està configurat com a wiki públic.\nPer seguretat, img_auth.php està desactivat.",
        "img-auth-noread": "L'usuari no té accés a la lectura de \"$1\".",
-       "http-invalid-url": "URL incorrecta: $1",
+       "http-invalid-url": "URL incorrecte: $1",
        "http-invalid-scheme": "Les URLs amb l'esquema \"$1\" no són compatibles.",
        "http-request-error": "La petició HTTP ha fallat per un error desconegut.",
        "http-read-error": "Error de lectura HTTP.",
        "filehist-comment": "Comentari",
        "imagelinks": "Ús del fitxer",
        "linkstoimage": "{{PLURAL:$1|La pàgina següent enllaça|Les $1 pàgines següents enllacen}} a aquest fitxer:",
-       "linkstoimage-more": "Hi ha més de $1 {{PLURAL:$1|pàgina que enllaça|pàgines que enllaçen}} a aquest fitxer.\nLa següent llista només mostra {{PLURAL:$1|la primera d'elles|les primeres $1 d'aquestes pàgines}}.\nPodeu consultar la [[Special:WhatLinksHere/$2|llista completa]].",
+       "linkstoimage-more": "Hi ha més de $1 {{PLURAL:$1|pàgina que enllaça|pàgines que enllacen}} a aquest fitxer.\nLa següent llista només mostra {{PLURAL:$1|la primera d'aquestes pàgines|les primeres $1 d'aquestes pàgines}}.\nPodeu consultar la [[Special:WhatLinksHere/$2|llista completa]].",
        "nolinkstoimage": "No hi ha pàgines que enllacin a aquesta imatge.",
        "morelinkstoimage": "Visualitza [[Special:WhatLinksHere/$1|més enllaços]] que porten al fitxer.",
        "linkstoimage-redirect": "$1 (fitxer redirigit) $2",
        "statistics-header-hooks": "Altres estadístiques",
        "statistics-articles": "Pàgines de contingut",
        "statistics-pages": "Pàgines",
-       "statistics-pages-desc": "Totes les pàgines del wiki, incloent les pàgines de discussió, redireccions, etc.",
+       "statistics-pages-desc": "Totes les pàgines del wiki, incloses les pàgines de discussió, redireccions, etc.",
        "statistics-files": "Fitxers carregats",
        "statistics-edits": "Edicions en pàgines des que el projecte {{SITENAME}} fou instal·lat",
        "statistics-edits-average": "Edicions per pàgina de mitjana",
        "pageswithprop-prophidden-long": "valor de propietat text llarg ocult ($1)",
        "pageswithprop-prophidden-binary": "valor de propietat binària oculta ($1)",
        "doubleredirects": "Redireccions dobles",
-       "doubleredirectstext": "Aquesta pàgina llista les pàgines que redirigeixen a altres pàgines de redirecció.\nCada fila conté enllaços a la primera i segona redireccions, així com el destí de la segona redirecció, què generalment és la pàgina destí \"real\", a la què hauria d'apuntar la primera redirecció.\nLes entrades <del>ratllades</del> s'han resolt.",
+       "doubleredirectstext": "Aquesta pàgina llista les pàgines que redirigeixen a altres pàgines de redirecció.\nCada fila conté enllaços a la primera i segona redireccions, així com la destinació de la segona redirecció, que generalment és la pàgina de destinació \"real\" a la qual hauria d'apuntar la primera redirecció.\nLes entrades <del>ratllades</del> s'han resolt.",
        "double-redirect-fixed-move": "S'ha reanomenat [[$1]].\nS'ha actualitzat automàticament i ara redirigeix a [[$2]].",
        "double-redirect-fixed-maintenance": "S'ha arreglat automàticament la redirecció doble de [[$1]] a [[$2]] en un treball de manteniment.",
        "double-redirect-fixer": "Supressor de dobles redireccions",
        "wantedfiles": "Fitxers demanats",
        "wantedfiletext-cat": "Els fitxers següents s'utilitzen per no existeixen. Els fitxers de repositoris aliens poden ser llistats encara que existeixin. Aquells que siguin fals positius es <del>ratllaran</del>. A més, les pàgines que tinguin fitxers incrustats que no existeixin es llistaran a [[:$1]].",
        "wantedfiletext-cat-noforeign": "Els fitxers següents s'utilitzen, però no existeixen. Addicionalment, s'enumeren a [[:$1]] les pàgines que tenen fitxers inserits que no existeixen.",
-       "wantedfiletext-nocat": "Els fitxers següents es fan servir però no existeixen. Els fitxers d'un repositori aliè poden ser llistats encara que existeixin. Tots aquells fals positius es <del>tatxaran</del>.",
+       "wantedfiletext-nocat": "Els fitxers següents es fan servir però no existeixen. Els fitxers d'un repositori aliè poden ser llistats encara que existeixin. Tots aquests falsos positius es <del>ratllaran</del>.",
        "wantedfiletext-nocat-noforeign": "Els fitxers següents s'utilitzen però no existeixen.",
        "wantedtemplates": "Plantilles demanades",
        "mostlinked": "Pàgines més enllaçades",
        "shortpages": "Pàgines curtes",
        "longpages": "Pàgines llargues",
        "deadendpages": "Pàgines atzucac",
-       "deadendpagestext": "Aquestes pàgines no tenen enllaços a d'altres pàgines del projecte {{SITENAME}}.",
+       "deadendpagestext": "Aquestes pàgines no tenen enllaços a altres pàgines del projecte {{SITENAME}}.",
        "protectedpages": "Pàgines protegides",
        "protectedpages-indef": "Només proteccions indefinides",
        "protectedpages-summary": "Aquesta pàgina llista les pàgines existents que estan protegides actualment. Per consultar la llista de títols protegits per tal que no puguin crear-se'n pàgines, vegeu [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
        "deletereason-dropdown": "*Motius freqüents d'esborrat\n** Brossa\n** Vandalisme\n** Violació del copyright\n** Demanada per l'autor\n** Redirecció trencada",
        "delete-edit-reasonlist": "Edita els motius d'eliminació",
        "delete-toobig": "Aquesta pàgina té un historial d'edicions molt gran, amb més de $1 {{PLURAL:$1|canvi|canvis}}. L'eliminació d'aquestes pàgines està restringida per a prevenir que hi pugui haver un desajustament seriós de la base de dades de tot el projecte {{SITENAME}} per accident.",
-       "delete-warning-toobig": "Aquesta pàgina té un historial d'edicions molt gran, amb més de $1 {{PLURAL:$1|canvi|canvis}}. Eliminar-la podria suposar un seriós desajustament de la base de dades de tot el projecte {{SITENAME}}; aneu en compte abans dur a terme l'acció.",
+       "delete-warning-toobig": "Aquesta pàgina té un historial d'edicions molt gran, amb més de $1 {{PLURAL:$1|canvi|canvis}}. Eliminar-la podria suposar un seriós desajustament de la base de dades de tot el projecte {{SITENAME}}; aneu amb compte abans dur a terme l'acció.",
        "deleteprotected": "No podeu eliminar la pàgina perquè ha estat protegida.",
        "deleting-backlinks-warning": "'''Avís:''' [[Special:WhatLinksHere/{{FULLPAGENAME}}|Altres pàgines]] enllacen o transclouen de la pàgina que esteu a punt de suprimir.",
        "rollback": "Reverteix edicions",
        "prot_1movedto2": "[[$1]] mogut a [[$2]]",
        "protect-badnamespace-title": "Espai de nom no-protectable",
        "protect-badnamespace-text": "Les pàgines en aquest espai de nom no pot ser protegit.",
-       "protect-norestrictiontypes-text": "Aquesta pàgina no es pot protegir ja que no hi ha cap tipus de restricció disponible.",
+       "protect-norestrictiontypes-text": "Aquesta pàgina no es pot protegir, ja que no hi ha cap tipus de restricció disponible.",
        "protect-norestrictiontypes-title": "Pàgina no protegible",
        "protect-legend": "Confirmeu la protecció",
        "protectcomment": "Motiu:",
        "mycontris": "Contribucions",
        "contribsub2": "Per a {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "El compte d'usuari «$1» no està registrat.",
-       "nocontribs": "No s’ha trobat cap canvi que encaixessi amb aquests criteris.",
+       "nocontribs": "No s’ha trobat cap canvi que encaixés amb aquests criteris.",
        "uctop": "(actual)",
        "month": "Mes (i anteriors):",
        "year": "Any (i anteriors):",
        "sp-contributions-logs": "registres",
        "sp-contributions-talk": "discussió",
        "sp-contributions-userrights": "gestió de drets d'usuari",
-       "sp-contributions-blocked-notice": "En aquests moments, aquest compte d'usuari es troba blocat.\nPer més detalls, la última entrada del registre es mostra a continuació:",
+       "sp-contributions-blocked-notice": "En aquests moments aquest compte d'usuari està blocat.\nPer a més informació, a continuació es mostra l'última entrada del registre:",
        "sp-contributions-blocked-notice-anon": "En aquests moments, aquesta adreça IP es troba blocada.\nPer més detalls, la última entrada del registre es mostra a continuació:",
        "sp-contributions-search": "Cerca les contribucions",
        "sp-contributions-username": "Adreça IP o nom d'usuari:",
        "autoblockid": "Autoblocatge #$1",
        "block": "Blocatge d'usuaris",
        "unblock": "Desblocatge d'usuaris",
-       "blockip": "Bloca {{GENDER:$1|l'usuari|l'usuària}}",
+       "blockip": "Bloca {{GENDER:$1|l'usuari|lusuària}}",
        "blockip-legend": "Bloca l'usuari",
        "blockiptext": "Empreu el següent formulari per blocar l'accés\nd'escriptura des d'una adreça IP específica o des d'un usuari determinat.\naixò només s'hauria de fer per prevenir el vandalisme, i\nd'acord amb la [[{{MediaWiki:Policy-url}}|política del projecte]].\nEmpleneu el diàleg de sota amb un motiu específic (per exemple, citant\nquines pàgines en concret estan sent vandalitzades).",
        "ipaddressorusername": "Adreça IP o nom de l'usuari",
        "emailblock": "s'ha blocat l'enviament de correus electrònics",
        "blocklist-nousertalk": "no podeu modificar la pàgina de discussió pròpia",
        "ipblocklist-empty": "La llista de bloqueigs està buida.",
-       "ipblocklist-no-results": "L'adreça IP o nom d'usuari soŀlicitat no està bloquejat.",
+       "ipblocklist-no-results": "L'adreça IP o nom d'usuari solicitat no està bloquejat.",
        "blocklink": "bloqueja",
        "unblocklink": "desbloca",
        "change-blocklink": "canvia el blocatge",
        "ipb_cant_unblock": "Errada: No s'ha trobat el núm. ID de bloqueig $1. És possible que ja s'haguera desblocat.",
        "ipb_blocked_as_range": "Error: L'adreça IP $1 no està blocada directament i per tant no pot ésser desbloquejada. Ara bé, sí que ho està per formar part del rang $2 que sí que pot ser desblocat.",
        "ip_range_invalid": "Rang de IP no vàlid.",
-       "ip_range_toolarge": "No estan permesos el bloquejos de rangs més grans que /$1.",
+       "ip_range_toolarge": "No són permesos els bloquejos de rangs més grans que /$1.",
        "proxyblocker": "Bloqueig de proxy",
        "proxyblockreason": "S'ha blocat la vostra adreça IP perquè és un proxy obert. Contactau el vostre proveïdor d'Internet o servei tècnic i informau-los d'aquest seriós problema de seguretat.",
        "sorbsreason": "La vostra adreça IP està llistada com a servidor intermediari (''proxy'') obert dins la llista negra de DNS que fa servir el projecte {{SITENAME}}.",
        "lockdbtext": "Si es bloca la base de dades impedirà la capacitat a tots els usuaris d'editar pàgines, canviar les preferències, editar la llista de seguiment i altres canvis que calen de modificacions a la base de dades.\nConfirmeu que això és el que voleu fer, i sobretot no us oblideu de desblocar la base de dades quan acabeu el manteniment.",
        "unlockdbtext": "Desblocant la base de dades es restaurarà l'habilitat de tots\nels usuaris d'editar pàgines, canviar les preferències, editar els llistats de seguiment, i\naltres accions que requereixen canvis en la base de dades.\nConfirmeu que això és el que voleu fer.",
        "lockconfirm": "Sí, realment vull blocar la base de dades.",
-       "unlockconfirm": "Sí, realment vull desblocar la base dades.",
+       "unlockconfirm": "Sí, realment vull desblocar la base de dades.",
        "lockbtn": "Bloca la base de dades",
        "unlockbtn": "Desbloca la base de dades",
        "locknoconfirm": "No heu respost al diàleg de confirmació.",
        "movenosubpage": "Aquesta pàgina no té subpàgines.",
        "movereason": "Motiu:",
        "revertmove": "reverteix",
-       "delete_and_move": "Elimina i trasllada",
        "delete_and_move_text": "==Cal l'eliminació==\n\nLa pàgina de destinació, «[[:$1]]», ja existeix. Voleu eliminar-la per a fer lloc al trasllat?",
        "delete_and_move_confirm": "Sí, esborra la pàgina",
        "delete_and_move_reason": "S'ha eliminat per a permetre el reanomenament de \" [[$1]] \"",
        "importuploaderrorsize": "La càrrega del fitxer d'importació ha fallat. El fitxer és més gran que la mida de càrrega permesa.",
        "importuploaderrorpartial": "La càrrega del fitxer d'importació ha fallat. El fitxer s'ha penjat només parcialment.",
        "importuploaderrortemp": "La càrrega del fitxer d'importació ha fallat. Manca una carpeta temporal.",
-       "import-parse-failure": "error en importar l'XML",
+       "import-parse-failure": "error en importar l'XML",
        "import-noarticle": "No hi ha cap pàgina per importar!",
        "import-nonewrevisions": "No s'ha importat cap revisió (ja hi eren abans o s'han omès a causa d'errors).",
        "xml-error-string": "$1 a la línia $2, columna $3 (byte $4): $5",
        "tooltip-pt-mytalk": "La vostra pàgina de discussió.",
        "tooltip-pt-anontalk": "Discussió sobre les edicions per aquesta adreça ip.",
        "tooltip-pt-preferences": "Les vostres preferències.",
-       "tooltip-pt-watchlist": "La llista de pàgines de les que estau vigilant els canvis.",
+       "tooltip-pt-watchlist": "La llista de pàgines de les quals vigileu els canvis.",
        "tooltip-pt-mycontris": "Llista de les vostres contribucions.",
        "tooltip-pt-login": "Us animem a registrar-vos, però no és obligatori",
        "tooltip-pt-logout": "Finalitza la sessió d'usuari",
        "tooltip-ca-protect": "Protegeix aquesta pàgina.",
        "tooltip-ca-unprotect": "Desprotegeix aquesta pàgina",
        "tooltip-ca-delete": "Elimina aquesta pàgina",
-       "tooltip-ca-undelete": "Restaura les edicions fetes a aquesta pàgina abans de que fos esborrada.",
+       "tooltip-ca-undelete": "Restaura les edicions fetes en aquesta pàgina abans que fos esborrada.",
        "tooltip-ca-move": "Reanomena aquesta pàgina",
        "tooltip-ca-watch": "Afegiu aquesta pàgina a la vostra llista de seguiment",
        "tooltip-ca-unwatch": "Suprimiu aquesta pàgina de la vostra llista de seguiment",
        "group-bureaucrat.css": "/* El CSS d'aquí només afectarà els buròcrates */",
        "common.js": "/* Es carregarà per a tots els usuaris, i per a qualsevol pàgina, el codi JavaScript que hi haja després d'aquesta línia. */",
        "group-autoconfirmed.js": "/* Qualsevol JavaScript d'aquí es carregarà només per als usuaris autoconfirmats */",
-       "group-user.js": "/* Qualsevol JavaScript d'aquí es carregarà només per als usuaris rgistrats */",
+       "group-user.js": "/* Qualsevol JavaScript d'aquí es carregarà només per als usuaris registrats */",
        "group-bot.js": "/* Qualsevol JavaScript d'aquí es carregarà només per als bots */",
        "group-sysop.js": "/* Qualsevol JavaScript d'aquí es carregarà només per als sysops */",
        "group-bureaucrat.js": "/* Qualsevol JavaScript d'aquí es carregarà només per als buròcrates */",
        "pageinfo-robot-policy": "Indexació per robots",
        "pageinfo-robot-index": "Permès",
        "pageinfo-robot-noindex": "No permès",
-       "pageinfo-watchers": "Número d'usuaris que vigilen la pàgina",
+       "pageinfo-watchers": "Nombre d'usuaris que vigilen la pàgina",
        "pageinfo-visiting-watchers": "Nombre de vigilants de la pàgina que han visitat els canvis recents",
        "pageinfo-few-watchers": "Menys de $1 {{PLURAL:$1|observador|observadors}}",
        "pageinfo-redirects-name": "Nombre de redireccions a aquesta pàgina",
        "pageinfo-redirects-value": "$1",
        "pageinfo-subpages-name": "Subpàgines d'aquesta pàgina",
-       "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|redirecció|redireccions}}; $3 {{PLURAL:$3|no redireció|no redireccions}})",
+       "pageinfo-subpages-value": "$1 ($2 {{PLURAL:$2|redirecció|redireccions}}; $3 {{PLURAL:$3|no redirecció|no redireccions}})",
        "pageinfo-firstuser": "Creador de la pàgina",
        "pageinfo-firsttime": "Data de la creació de la pàgina",
        "pageinfo-lastuser": "Últim editor",
        "pageinfo-lasttime": "Data de l'última edició",
-       "pageinfo-edits": "Número total d'edicions",
-       "pageinfo-authors": "Número total d'autors diferents",
-       "pageinfo-recent-edits": "Número d'edicions recents (en els darrers $1)",
-       "pageinfo-recent-authors": "Número recent d'autors diferents",
+       "pageinfo-edits": "Nombre total d'edicions",
+       "pageinfo-authors": "Nombre total d'autors diferents",
+       "pageinfo-recent-edits": "Nombre d'edicions recents (en els darrers $1)",
+       "pageinfo-recent-authors": "Nombre recent d'autors diferents",
        "pageinfo-magic-words": "{{PLURAL:$1|Paraula clau|Paraules clau}} ($1)",
        "pageinfo-hidden-categories": "{{PLURAL:$1|Categoria oculta|Categories ocultes}} ($1)",
        "pageinfo-templates": "{{PLURAL:$1|plantilla inclosa|plantilles incloses}} ($1)",
        "file-info-png-looped": "embuclat",
        "file-info-png-repeat": "s'ha reproduït $1 {{PLURAL:$1|vegada|vegades}}",
        "file-info-png-frames": "$1 {{PLURAL:$1|fotograma|fotogrames}}",
-       "file-no-thumb-animation": "'''Nota: degut a limitacions tècniques no s'animaran les miniatures per aquest fitxer.'''",
-       "file-no-thumb-animation-gif": "''' Nota: degut a limitacions tècniques no s'animaran les miniatures d'alta resolució d'imatges GIF com aquesta.'''",
+       "file-no-thumb-animation": "<strong>Nota: per limitacions tècniques no s'animaran les miniatures per aquest fitxer.</strong>",
+       "file-no-thumb-animation-gif": "<strong>Nota: per limitacions tècniques no s'animaran les miniatures d'alta resolució d'imatges GIF com aquesta.</strong>",
        "newimages": "Galeria de fitxers nous",
        "imagelisttext": "Llista {{PLURAL:$1|d'un sol fitxer|de '''$1''' fitxers ordenats $2}}.",
        "newimages-summary": "Aquesta pàgina especial mostra els darrers fitxers carregats.",
        "exif-cameraownername": "Propietari de la càmera",
        "exif-label": "Etiqueta",
        "exif-datetimemetadata": "Data que s'ha modificat les metadades per última vegada",
-       "exif-nickname": "Nom informal de l'imatge",
+       "exif-nickname": "Nom informal de limatge",
        "exif-rating": "Valoració (sobre 5)",
        "exif-rightscertificate": "Certificat de gestió de drets",
        "exif-copyrighted": "Estat dels drets d'autor",
        "exif-originaldocumentid": "ID únic del document original",
        "exif-licenseurl": "Direcció de llicències de drets d'autor",
        "exif-morepermissionsurl": "Alternativa informació de llicència",
-       "exif-attributionurl": "Quan re-utilitzis aquest treball, si us plau posa un enllaç a",
-       "exif-preferredattributionname": "Quan re-utilitzis aquest treball, si us plau posa un credit a",
+       "exif-attributionurl": "Quan reutilitzeu aquest treball, si us plau, poseu un enllaç a",
+       "exif-preferredattributionname": "Quan reutilitzeu aquest treball, si us plau posa un credit a",
        "exif-pngfilecomment": "Comentari del fitxer PNG",
        "exif-disclaimer": "Avís general",
        "exif-contentwarning": "Advertència de contingut",
        "exif-orientation-2": "Invertit horitzontalment",
        "exif-orientation-3": "Girat 180°",
        "exif-orientation-4": "Invertit verticalment",
-       "exif-orientation-5": "Rotat 90° en sentit antihorari i invertit verticalment",
-       "exif-orientation-6": "Rotat 90° en sentit antihorari",
-       "exif-orientation-7": "Rotat 90° en sentit horari i invertit verticalment",
-       "exif-orientation-8": "Rotat 90° en sentit horari",
+       "exif-orientation-5": "Girat 90° en sentit antihorari i invertit verticalment",
+       "exif-orientation-6": "Girat 90° en sentit antihorari",
+       "exif-orientation-7": "Girat 90° en sentit horari i invertit verticalment",
+       "exif-orientation-8": "Girat 90° en sentit horari",
        "exif-planarconfiguration-1": "a blocs densos (chunky)",
        "exif-planarconfiguration-2": "format pla",
        "exif-xyresolution-i": "$1 ppp",
        "confirmemail_pending": "Ja s'ha enviat el vostre codi de confirmació per correu electrònic; si\nfa poc hi heu creat el vostre compte, abans de mirar de demanar un nou\ncodi, primer hauríeu d'esperar alguns minuts per a rebre'l.",
        "confirmemail_send": "Envia per correu electrònic un codi de confirmació",
        "confirmemail_sent": "S'ha enviat un missatge de confirmació.",
-       "confirmemail_oncreate": "S'ha enviat un codi de confirmació a la vostra adreça de correu electrònic.\nNo es requereix aquest codi per a autenticar-s'hi, però vos caldrà proporcionar-lo\nabans d'activar qualsevol funcionalitat del wiki basada en missatges\nde correu electrònic.",
+       "confirmemail_oncreate": "S'ha enviat un codi de confirmació a la vostra adreça de correu electrònic.\nAquest codi no cal per a autenticar-se, però haureu de proporcionar-lo abans d'activar qualsevol funcionalitat del wiki basada en missatges de correu electrònic.",
        "confirmemail_sendfailed": "{{SITENAME}} no ha pogut enviar el vostre missatge de confirmació.\nComproveu que l'adreça no tingui caràcters no vàlids.\n\nEl programari de correu retornà el següent missatge: $1",
        "confirmemail_invalid": "El codi de confirmació no és vàlid. Aquest podria haver vençut.",
        "confirmemail_needlogin": "Necessiteu $1 per a confirmar la vostra adreça electrònica.",
        "confirmemail_body": "Algú, segurament vós, ha registrat el compte «$2» al projecte {{SITENAME}}\namb aquesta adreça electrònica des de l'adreça IP $1.\n\nPer a confirmar que aquesta adreça electrònica us pertany realment\ni així activar les opcions de correu del programari, seguiu aquest enllaç:\n\n$3\n\nSi *no* heu estat qui ho ha fet, seguiu aquest altre enllaç per a canceŀlar la confirmació demanada:\n\n$5\n\nAquest codi de confirmació caducarà a $4.",
        "confirmemail_body_changed": "Algú, segurament vós, des de l'adreça IP $1, ha canviat al projecte {{SITENAME}} l'adreça de correu del compte \"$2\" a aquesta adreça.\n\nPer confirmar que aquest compte realment us pertany i per reactivar\nles opcions de correu a {{SITENAME}}, obriu el següent enllaç al vostre navegador:\n\n$3\n\nSi el compte *no* us pertany, seguiu l'enllaç següent\nper a cancel·lar la confirmació d'adreça de correu:\n\n$5\n\nAquest codi de confirmació expirarà el $4.",
        "confirmemail_body_set": "Algú, probablement vós, des de l'adreça IP $1, \nha establert aquesta adreça de correu electrònic com la del compte «$2» del lloc {{SITENAME}}. \n\nPer confirmar que aquest compte realment us pertany i reactivar \nles facilitats de correu electrònic a {{SITENAME}}, cal que obriu al navegador aquest enllaç:\n\n$3\n\nSi el compte *no* us pertany, cancel·leu l'adreça de correu electrònic seguint aquest enllaç: \n\n$5\n\nAquest codi de confirmació caducarà el $4.",
-       "confirmemail_invalidated": "Confirmació d'adreça electrònica canceŀlada",
+       "confirmemail_invalidated": "Confirmació d'adreça electrònica cancelada",
        "invalidateemail": "Canceŀlació d'adreça electrònica",
        "scarytranscludedisabled": "[S'ha inhabilitat la transclusió interwiki]",
        "scarytranscludefailed": "[Ha fallat la recuperació de la plantilla per a $1]",
        "duplicate-displaytitle": "<strong>Avís:</strong> El títol a mostrar «$2» sobreescriu l'anterior títol a mostrar «$1».",
        "invalid-indicator-name": "<strong>Error:</strong> No pot estar buit l'atribut <code>name</code> dels indicadors d'estat de la pàgina.",
        "version": "Versió",
-       "version-extensions": "Extensions instaŀlades",
+       "version-extensions": "Extensions instalades",
        "version-skins": "Temes instal·lats",
        "version-specialpages": "Pàgines especials",
        "version-parserhooks": "Extensions de l'analitzador",
        "tag-filter-submit": "Filtra",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Etiqueta|Etiquetes}}]]: $2)",
        "tags-title": "Etiquetes",
-       "tags-intro": "Aquesta pàgina llista les etiquetes amb les què el programari pot marcar una modificació, i llur significat.",
+       "tags-intro": "Aquesta pàgina llista les etiquetes amb què el programari pot marcar una modificació, i el seu significat.",
        "tags-tag": "Nom de l'etiqueta",
        "tags-display-header": "Aparença de la llista de canvis",
        "tags-description-header": "Descripció completa del significat",
        "tags-apply-not-allowed-multi": "No es permet aplicar manualment {{PLURAL:$2|l'etiqueta següent|les etiquetes següents}}: $1",
        "tags-update-no-permission": "No teniu permisos per a afegir o suprimir etiquetes de canvi de revisions individuals o entrades de registre.",
        "tags-update-add-not-allowed-one": "No es permet afegir manualment l'etiqueta «$1».",
-       "tags-update-add-not-allowed-multi": "No es permet afegir manualment {{PLURAL:$2|letiqueta següent|les etiquetes següents}}: $1",
+       "tags-update-add-not-allowed-multi": "No es permet afegir manualment {{PLURAL:$2|l'etiqueta següent|les etiquetes següents}}: $1",
        "tags-update-remove-not-allowed-one": "No es permet treure l’etiqueta «$1».",
-       "tags-update-remove-not-allowed-multi": "No es permet eliminar manualment {{PLURAL:$2|letiqueta següent|les etiquetes següents}}: $1",
+       "tags-update-remove-not-allowed-multi": "No es permet eliminar manualment {{PLURAL:$2|l'etiqueta següent|les etiquetes següents}}: $1",
        "tags-edit-title": "Modifica les etiquetes",
        "tags-edit-manage-link": "Gestiona les etiquetes",
        "tags-edit-revision-selected": "{{PLURAL:$1|Revisió seleccionada|Revisions seleccionades}} de [[:$2]]:",
        "htmlform-select-badoption": "El valor que heu especificat no és una opció vàlida.",
        "htmlform-int-invalid": "El valor que heu especificat no és un nombre enter.",
        "htmlform-float-invalid": "El valor especificat no és un nombre.",
-       "htmlform-int-toolow": "El valor que heu especifcat està per sota del mínim de $1",
+       "htmlform-int-toolow": "El valor que heu especificat està per sota del mínim de $1.",
        "htmlform-int-toohigh": "El valor que heu especificat està per sobre del màxim de $1",
        "htmlform-required": "Aquest valor és necessari",
        "htmlform-submit": "Tramet",
        "htmlform-title-not-exists": "$1 no existeix.",
        "htmlform-user-not-exists": "<strong>$1</strong> no existeix.",
        "htmlform-user-not-valid": "<strong>$1</strong> no és nom d'usuari vàlid.",
-       "sqlite-has-fts": "$1, amb suport de búsqueda de text íntegre",
-       "sqlite-no-fts": "$1, sense supor de búsqueda de text íntegre",
+       "sqlite-has-fts": "$1, amb suport de cerca de text íntegre",
+       "sqlite-no-fts": "$1, sense supor de cerca de text íntegre",
        "logentry-delete-delete": "$1 {{GENDER:$2|ha esborrat}} la pàgina $3",
        "logentry-delete-restore": "$1 ha restaurat $3",
        "logentry-delete-event": "$1 {{GENDER:$2|ha canviat}} la visibilitat {{PLURAL:$5|d'un esdeveniment al registre|de $5 esdeveniments al registre}} de $3: $4",
        "feedback-bugcheck": "Fantàstic! Comproveu que no sigui un dels [$1 problemes ja coneguts].",
        "feedback-bugnew": "Ja ho he comprovat. Informeu d'un nou problema",
        "feedback-bugornote": "Si podeu descriure un problema tècnic en detall, [$1 informeu-ne].\nAltrament, podeu fer servir un senzill formulari a continuació. El vostre comentari s'afegirà a la pàgina «[$3 $2]», juntament amb el vostre nom d'usuari i el navegador que esteu emprant.",
-       "feedback-cancel": "Canceŀla",
+       "feedback-cancel": "Cancela",
        "feedback-close": "Fet",
        "feedback-external-bug-report-button": "Arxiva una tasca tècnica",
        "feedback-dialog-title": "Envia el comentari",
        "api-error-publishfailed": "Error intern: el servidor no ha pogut publicar el fitxer temporal.",
        "api-error-stasherror": "S'ha produït un error en carregar el fitxer al dipòsit.",
        "api-error-stashedfilenotfound": "No s'ha trobat el fitxer de l'espai temporal quan es provava de carregar-lo d'allà.",
-       "api-error-stashpathinvalid": "El camí on s'havia trobar el fitxer de l'espai temporal no és vàlid.",
+       "api-error-stashpathinvalid": "El camí on s'havia de trobar el fitxer de l'espai temporal no és vàlid.",
        "api-error-stashfilestorage": "S'ha produït un error en emmagatzemar el fitxer en l'espai temporal.",
        "api-error-stashzerolength": "El servidor no ha pogut desar el fitxer a l'espai temporal perquè tenia longitud zero.",
        "api-error-stashnotloggedin": "Cal haver iniciat una sessió per desar fitxers en l'espai temporal de càrrega.",
        "limitreport-templateargumentsize": "Mida de l'argument de plantilla",
        "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|byte|bytes}}",
        "limitreport-expansiondepth": "Profunditat màxima d'expansió",
-       "limitreport-expensivefunctioncount": "Número de funcions d'anàlisi dispendioses",
+       "limitreport-expensivefunctioncount": "Nombre de funcions d'anàlisi dispendioses",
        "expandtemplates": "Expansió de plantilles",
        "expand_templates_intro": "Aquesta pàgina especial expandeix de forma recursiva totes les plantilles d'un text donat.\nTambé expandeix les funcions sintàctiques, com ara <code><nowiki>{{</nowiki>#language:…}}</code>, i les variables predefinides, com <code><nowiki>{{</nowiki>CURRENTDAY}}</code> &mdash;de fet, gairebé tot que estigui entre claus dobles.",
        "expand_templates_title": "Títol per contextualitzar ({{FULLPAGENAME}}, etc):",
        "special-characters-group-ipa": "AFI",
        "special-characters-group-symbols": "Símbols",
        "special-characters-group-greek": "Grec",
-       "special-characters-group-cyrillic": "Ciríŀlic",
+       "special-characters-group-cyrillic": "Cirílic",
        "special-characters-group-arabic": "Aràbic",
        "special-characters-group-arabicextended": "Aràbic estès",
        "special-characters-group-persian": "Persa",
index 9a851bc..02e0f61 100644 (file)
@@ -50,7 +50,7 @@
        "tog-showhiddencats": "Гайта къайлаха йолу категореш",
        "tog-norollbackdiff": "Юха яьккхиначул тӀаьхьа ма гайта версийн башхо",
        "tog-useeditwarning": "Хаамбе бина хийцамаш дӀаязцабеш аса болх дӀатосучу хенахь",
-       "tog-prefershttps": "Ð\94аима Ð»ÐµÐ»Ð° Ð¹Ðµ Ð»Ð°Ñ\80дина Ñ\81иÑ\81Ñ\82емин Ñ\87Ñ\83далар",
+       "tog-prefershttps": "СиÑ\81Ñ\82емин Ð´Ð¾Ð²Ð·Ð¸Ð¹Ñ\82ина Ñ\87Ñ\83л Ñ\82Ó\80еÑ\85Ñ\8cа Ð´Ð°Ð¸Ð¼Ð°Ð½ Ð»ÐµÐ»Ð°Ð´Ðµ Ð»Ð°Ñ\80дина Ð²Ð¾Ð²Ñ\88аÑ\85Ñ\82аÑ\81ар",
        "underline-always": "Даимна",
        "underline-never": "Цкъа а",
        "underline-default": "Лелае браузеран нисярца",
        "resettokens-watchlist-token": "Веб-каналан (Atom/RSS) токен  [[Special:Watchlist|хьан тергаме могӀанан чура агӀонашна хийцамаш бар]]",
        "resettokens-done": "Токенаш кхиссина.",
        "resettokens-resetbutton": "Къастина токенаш кхоссар",
-       "bold_sample": "Ӏаьржа до йоза",
-       "bold_tip": "Ӏаьржа до йоза",
-       "italic_sample": "СеÑ\82Ñ\82ан Ð´Ð¾ Ð¹Ð¾Ð·Ð°",
-       "italic_tip": "СеÑ\82Ñ\82ан Ð´Ð¾ Ð¹Ð¾Ð·Ð°",
+       "bold_sample": "Йоза Ӏаьржа къастор",
+       "bold_tip": "Йоза Ӏаьржа къастор",
+       "italic_sample": "Ð\9aÑ\83Ñ\80Ñ\81иваÑ\86а ÐºÑ\8aаÑ\81Ñ\82оÑ\80",
+       "italic_tip": "Ð\9aÑ\83Ñ\80Ñ\81иваÑ\86а ÐºÑ\8aаÑ\81Ñ\82оÑ\80",
        "link_sample": "Хьажориган коьрта могlа",
        "link_tip": "Чоьхьа хьажорг",
        "extlink_sample": "http://www.example.com хьажорг корта",
        "prefs-help-email-others": "Кхин дӀа цо кхечу декъашхошна йиш хуьлуьйту хьога электронан кехат даийта хьан агӀона чохь йолу хьажориган гӀоьнца.",
        "prefs-help-email-required": "Электронан поштан адрес яздан деза.",
        "prefs-info": "Коьрта хаам",
-       "prefs-i18n": "ЮкÑ\8aаÑ\80декÑ\8aа Ð¼Ð¾Ñ\82Ñ\82",
+       "prefs-i18n": "Ð\9aÑ\85ин Ð¿Ð°Ñ\80амеÑ\82Ñ\80аÑ\88",
        "prefs-signature": "КуьгтаӀор",
        "prefs-dateformat": "Терахьан формат",
        "prefs-timeoffset": "Хенан  гӀирс",
        "movenosubpage": "ХӀокху агӀона бухара агӀонаш яц.",
        "movereason": "Бахьана:",
        "revertmove": "юхаяккха",
-       "delete_and_move": "Цle а хуьйцуш дӀаяккха",
        "delete_and_move_text": "== ДӀаяккха хьокъ ю ==\nИ цӀе йолу аг1о «[[:$1]]» йолуш ю. \nЛаьий хьуна и дӀаяккха, цӀе хийца таро хилийта?",
        "delete_and_move_confirm": "ХӀаъ, дӀаяккха хӀара агӀо",
        "delete_and_move_reason": "ДӀаяьккхина цӀе хийца я таро хилийта  «[[$1]]»",
index 5d5f538..386b55e 100644 (file)
        "movenosubpage": "ئەم پەڕەیە ھیچ ژێرپەڕەیەکی نییە.",
        "movereason": "ھۆکار:",
        "revertmove": "پێچەوانەکردنەوە",
-       "delete_and_move": "بیسڕەوە و بیگوازەوە",
        "delete_and_move_text": "== پێویستییەکانی سڕینەوە ==\nلاپەڕەی مەبەست \"[[:$1]]\" لە پێش‌دا هەیە.\nئایا دەتەوێ ئەوە بسڕیتەوە تا ڕێگە بۆ گواستنەوەی بکەیتەوە؟",
        "delete_and_move_confirm": "بەڵێ، پەڕەکە بسڕەوه",
        "delete_and_move_reason": "سڕایەوە بۆ کردنەوەی ڕیگە بۆ گواستنەوە لە «[[$1]]»ەوە",
        "tooltip-ca-nstab-main": "بینینی پەڕەی ناوەڕۆک",
        "tooltip-ca-nstab-user": "پەڕەی بەکارھێنەر تەماشا بکە",
        "tooltip-ca-nstab-media": "پەڕەی میدیا چاو لێ بکە",
-       "tooltip-ca-nstab-special": "ئەمە پەڕەیەکی تایبەتە، ناتوانی خودی ئەم پەڕە دەستکاری بکەیت",
+       "tooltip-ca-nstab-special": "ئەمە پەڕەیەکی تایبەتە و دەستکاری ناکرێت",
        "tooltip-ca-nstab-project": "بینینی پەڕەی پرۆژە",
        "tooltip-ca-nstab-image": "بینینی پەڕەی پەڕگە",
        "tooltip-ca-nstab-mediawiki": "بینینی پەیامی سیستەم",
index 522ff95..f811fcf 100644 (file)
        "movenosubpage": "Tato stránka nemá žádné podstránky.",
        "movereason": "Důvod:",
        "revertmove": "vrátit",
-       "delete_and_move": "Smazat a přesunout",
        "delete_and_move_text": "==Je potřeba smazání==\n\nCílová stránka „[[:$1]]“ již existuje. Přejete si ji smazat pro uvolnění místa pro přesun?",
        "delete_and_move_confirm": "Ano, smazat cílovou stránku",
        "delete_and_move_reason": "Smazáno pro umožnění přesunu z „[[$1]]“",
        "logentry-suppress-block": "$1 {{GENDER:$2|zablokoval|zablokovala|blokuje}} {{GENDER:$4|uživatele|uživatelku}} „$3“ s časem vypršení $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|změnil|změnila|mění}} nastavení bloku {{GENDER:$4|uživatele|uživatelky}} „$3“ s časem vypršení $5 $6",
        "logentry-import-upload": "$1 {{GENDER:$2|naimportoval|naimportovala}} $3 načtením souboru",
+       "logentry-import-upload-details": "$1 {{GENDER:$2|naimportoval|naimportovala}} $3 načtením souboru ($4 {{PLURAL:$4|revize|revize|revizí}})",
        "logentry-import-interwiki": "$1 {{GENDER:$2|naimportoval|naimportovala}} $3 z jiné wiki",
+       "logentry-import-interwiki-details": "$1 {{GENDER:$2|naimportoval|naimportovala}} $3 z $5 ($4 {{PLURAL:$4|revize|revize|revizí}})",
        "logentry-merge-merge": "$1 {{GENDER:$2|sloučil|sloučila}} stránku $3 do $4 (revize po $5)",
        "logentry-move-move": "$1 {{GENDER:$2|přesunul|přesunula}} stránku $3 na $4",
        "logentry-move-move-noredirect": "$1 {{GENDER:$2|přesunul|přesunula}} stránku $3 na $4 bez založení přesměrování",
index 3d7f124..5b8d6d5 100644 (file)
        "morenotlisted": "Diese Liste ist nicht vollständig.",
        "mypage": "Eigene Seite",
        "mytalk": "Diskussion",
-       "anontalk": "Diskussionsseite dieser IP",
+       "anontalk": "Diskussionsseite",
        "navigation": "Navigation",
        "and": "&#32;und",
        "qbfind": "Finden",
        "contributions": "{{GENDER:$1|Benutzerbeiträge}}",
        "contributions-title": "Benutzerbeiträge von „$1“",
        "mycontris": "Beiträge",
+       "anoncontribs": "Beiträge",
        "contribsub2": "Von {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Das Benutzerkonto „$1“ ist nicht vorhanden.",
        "nocontribs": "Es wurden keine Benutzerbeiträge mit diesen Kriterien gefunden.",
        "movenosubpage": "Diese Seite hat keine Unterseiten.",
        "movereason": "Grund:",
        "revertmove": "zurück verschieben",
-       "delete_and_move": "Löschen und verschieben",
        "delete_and_move_text": "== Löschung erforderlich ==\n\nDie Seite „[[:$1]]“ existiert bereits. Möchtest du diese löschen, um die Seite verschieben zu können?",
        "delete_and_move_confirm": "Ja, Seite löschen",
        "delete_and_move_reason": "gelöscht, um Platz für die Verschiebung von „[[$1]]“ zu machen",
        "tooltip-pt-preferences": "Deine Einstellungen",
        "tooltip-pt-watchlist": "Liste der von dir beobachteten Seiten",
        "tooltip-pt-mycontris": "Liste eigener Beiträge",
+       "tooltip-pt-anoncontribs": "Eine Liste der Bearbeitungen, die von dieser IP-Adresse gemacht wurden",
        "tooltip-pt-login": "Sich anzumelden wird gerne gesehen, ist jedoch nicht zwingend erforderlich.",
        "tooltip-pt-logout": "Abmelden",
        "tooltip-pt-createaccount": "Wir ermutigen dich dazu, ein Benutzerkonto zu erstellen und dich anzumelden. Es ist jedoch nicht zwingend erforderlich.",
index 8a87b23..bb60473 100644 (file)
        "october-date": "Tışrino Verên $1",
        "november-date": "Tışrino Peyên $1",
        "december-date": "Kanun $1",
-       "pagecategories": "{{PLURAL:$1|Kategoriye|Kategoriy}}",
-       "category_header": "Pelê ke kategoriya \"$1\" derê",
+       "pagecategories": "{{PLURAL:$1|Red|Redey}}",
+       "category_header": "Pelê ke kategoriya \"$1\" tede derê",
        "subcategories": "Kategoriyê bınêni",
        "category-media-header": "Dosyeyê ke kategoriya \"$1\" derê",
        "category-empty": "''Ena kategoriye de hewna qet nuştey ya zi medya çıniyê.''",
        "morenotlisted": "Vêşi lista nêbi...",
        "mypage": "Per",
        "mytalk": "Mesac",
-       "anontalk": "Pela werênayışê nê IPy",
+       "anontalk": "Mesac",
        "navigation": "Pusula",
        "and": "&#32;u",
        "qbfind": "Bıvêne",
        "aboutpage": "Project:Heqa {{SITENAME}} de",
        "copyright": "Zerrekacı $1 bındı not biya.",
        "copyrightpage": "{{ns:project}}:Heqa telifi",
-       "currentevents": "Veng û vac",
+       "currentevents": "Hadiseyé rocaniyey",
        "currentevents-url": "Project:Rocani hadisey",
        "disclaimers": "Redê mesuliyeti",
        "disclaimerpage": "Project:Reddê mesuliyetê bıngey",
        "invalidtitle-knownnamespace": "Canemey \"$2\" u metnê \"$3\" xırabo",
        "invalidtitle-unknownnamespace": "Sernameye nêşınasiya yana amraiya canameyo  $1 u metno \"$2\" xırab",
        "exception-nologin": "Şıma cıkewtış nêvıraşto",
-       "exception-nologin-text": "Na pera ya zi na karkerdışi de  na wiki de cı kewtış icab keno.",
+       "exception-nologin-text": "Na pele ya zi nê karkerdışi rê nê wiki de cıkewtış icab keno.",
        "exception-nologin-text-manual": "Na pele resayışi re $1 bıgire.",
        "virus-badscanner": "Eyaro şaş: no virus-cıgerayox nêzanyeno: ''$1''",
        "virus-scanfailed": "cıgerayiş tamam nêbı (kod $1)",
        "createacct-reason": "Sebeb",
        "createacct-reason-ph": "Şımaye çı xo re zewbi hesab vırazeni?",
        "createacct-submit": "Hesabê xo vıraze",
-       "createacct-another-submit": "Hesab vıraz",
+       "createacct-another-submit": "Hesab vıraze",
        "createacct-benefit-heading": "{{SITENAME}} meş de merduman şi",
        "createacct-benefit-body1": "{{PLURAL:$1|vurnayış|vurnayışi}}",
        "createacct-benefit-body2": "{{PLURAL:$1|pele|peli}}",
        "nonunicodebrowser": "'''DİQET: Browserê şıma u unicode yewbini nêgeni. Qey izin dayişê vurnayişê pelan: Karakteri ke ASCII niyê; zerreyê qutiyê vurnayişi de kodi (cod) şiyes-şiyes aseni.'''",
        "editingold": "'''İkaz: Şımayé rewizyon da kehan da perer d vırnayış kené.'''\nVanése qeyd k,lakin rewziyoné veréni dé vınibé.",
        "yourdiff": "pêverronayiş",
-       "copyrightwarning": "'''Recayê ikazi:''' Sita da {{SITENAME}} ra iştıraqi pêro umışin da $2 zerredeyo (teferruata rê $1'i bıvinê).\nİştıraqê şıma, şıma kayıl niyê ke yewna merdumi kerpeyina bıvurnê yana yewna caya ra vılakerê se, iştıraq mekewê.<br />\nFına zi qayılê ke  iştıraq kewê, Şıma qayılê kê şar vaco eno nuşte felani nuşnayo yana resmi meqeman ra zanayışê cı  u malumatê cı esto/ Xoseri cayan ra groti rê şıma qerenti danê. '''Tiya dı, şıma wêrê telifira mısade nêgroto se eserê cı tiya vıla mekerê! '''",
-       "copyrightwarning2": "Ney bızane ke nuşteyê ke şıma ruşneni (şaweni) keyepelê {{SITENAME}} herkes eşkeno nê nuşteyanê şıma ser kay bıkero. Eke şıma qayil niye kes bıvurno, nuşetyanê xo meerze ita. <br />\nWexta ke şıma nuşte zi erzeni ita; şıma gani taahhud bıde koti ra ardo (qey teferruati referans: $1).",
+       "copyrightwarning": "'''Recaya iqazi:'''Sita {{SITENAME}} ra iştıraqi pêro umışiya $2 zerredeyo (teferuatan rê $1 bıvênê).\n\nİştıraqê şıma, şıma qayıl niyê ke yewna merdumi kerpeyina bıvurnê ya zi yewna cayi ra vıla kerê ke, iştıraq mekewê.<br />\nFına zi qayılê ke iştıraq kewê, şıma qayılê ke şar vaco eno nuşte fılan kesi nusnayo ya zi meqemanê resmiyan ra zanayışê cı û malumatê cı esto / cayanê xoseran ra gırewtışi rê şıma garanti danê. '''Tiya de şıma werê telifi ra ke mısade nêgırewto, eserê cı tiya vıla mekerê! '''",
+       "copyrightwarning2": "Ney bızanê ke nuşteyê ke şıma ruşnenê (şawenê) keyepela {{SITENAME}} herkes eşkeno nê nuşteyanê şıma ser kay bıkero. Eke şıma qayil niyê kes bıvurno, nuşteyanê xo meerzê ita. <br />\nWexto ke şıma nuşteyi zi erzenê ita; şıma gani teahud bıdê koti ra ardo (qandê teferuati ra referans: $1).",
        "longpageerror": "'''Xırab: Dergeya nuşte dê şıma nezdi {{PLURAL:$1|kilobayto|$1 kilobayto}}, feqet {{PLURAL:$2|kilobayt|$2 kilobayt}} ra vêşiyo. Qeyd biyayişê cı nêbeno'''",
        "readonlywarning": "'''Diqet: Semedê mıqayti, database kılit biyo. No sebeb ra vurnayişê şıma qayd nêbeno. Nuşteyanê şıma yewna serkar eşkeno wedaro u pey ra şıma eşkeni reyna ita de qayd bıker'''\n\nSerkar o ke kılit kerdo; no beyanat dayo: $1",
        "protectedpagewarning": "'''Diqet: No pel pawyeno, teyna serkari eşkeni bıvurni.'''\nWexta ke şıma no pel vurneni diqet bıkeri:",
        "upload-copy-upload-invalid-domain": "Na domain ra kopyayê barkerdışanê nêbenê.",
        "upload-dialog-title": "Dosya bar ke",
        "upload-dialog-button-cancel": "Bıtexelne",
-       "upload-dialog-button-done": "Qeyd ke",
-       "upload-dialog-button-save": "Star ke",
+       "upload-dialog-button-done": "Temam",
+       "upload-dialog-button-save": "Bışevekne",
        "upload-dialog-button-upload": "Bar ke",
        "upload-form-label-select-file": "Dosya weçine",
-       "upload-form-label-infoform-title": "Teferruati",
+       "upload-form-label-infoform-title": "Teferuati",
        "upload-form-label-infoform-name": "Name",
        "upload-form-label-infoform-description": "Şınasnayış",
-       "upload-form-label-usage-title": "Karfinayış",
-       "upload-form-label-usage-filename": "Namey dosya",
-       "foreign-structured-upload-form-label-own-work": "Ena aite mına",
-       "foreign-structured-upload-form-label-infoform-categories": "Kategoriy",
+       "upload-form-label-usage-title": "Gurenayış",
+       "upload-form-label-usage-filename": "Nameyê dosya",
+       "foreign-structured-upload-form-label-own-work": "No karê mıno",
+       "foreign-structured-upload-form-label-infoform-categories": "Kategoriyi",
        "foreign-structured-upload-form-label-infoform-date": "Tarix",
        "backend-fail-stream": "$1 nê vırazeyê",
        "backend-fail-backup": "$1 nê wendeyê",
        "nopagetext": "pelê hedefi ke şıma nişane kerdo çin o.",
        "pager-newer-n": "{{PLURAL:$1|newiyer 1|newiyer $1}}",
        "pager-older-n": "{{PLURAL:$1|deha kehan 1|deha kehan $1}}",
-       "suppress": "Vındardış",
+       "suppress": "Fetesnayene",
        "querypage-disabled": "Na pelaya xısusi,sebeb de performansi ra qefılneyê.",
-       "apihelp": "API desteg",
-       "apihelp-no-such-module": "$1 deyne modul çınya.",
+       "apihelp": "Peştiya APIyi",
+       "apihelp-no-such-module": "Modulê \"$1\" çıniyo.",
        "booksources": "Çımeyê kıtaban",
        "booksources-search-legend": "Seba çımeyanê kıtaban cı geyre",
        "booksources-isbn": "ISBN:",
        "booksources-text": "listeya cêrıni, keyepelê kitap rotoxan o.",
        "booksources-invalid-isbn": "ISBN raşt nêasena bıewnê çımeyê orjinali, raşt kopya biya nê nêbiyaya?",
        "specialloguserlabel": "Kerdoğ:",
-       "speciallogtitlelabel": "Etiket (sername yana {{ns:user}}:namey karberi semedi karberi):",
+       "speciallogtitlelabel": "Meqsed (sername ya zi {{ns:user}}:karberi rê nameyê karberi):",
        "log": "Qeydi",
        "all-logs-page": "Umumi qeydi pêro",
        "alllogstext": "qey {{SITENAME}}i mocnayişê heme rocaneyani.\ntipa rocaneyi, nameyê karberi (herfa pil u qıci re hessas a), ya zi peli (reyna hessasiyê herfa pil u qıciyi) bıweçine u esayiş qıc kerê.",
        "wlshowlast": "Peyni de vurnayışan ra  $1 seata u $2 roca  bımocnê",
        "watchlistall2": "pêro",
        "watchlist-hide": "Bınımne",
-       "wlshowtime": "Peyni bıvin:",
+       "wlshowtime": "Peyênan bımocne:",
        "wlshowhideminor": "vurnayışê werdiyi",
        "wlshowhidebots": "boti",
        "wlshowhideliu": "karberê qeydıni",
        "deletepage": "Pele bestere",
        "confirm": "Tesdiq ke",
        "excontent": "Zerreko verén: '$1'",
-       "excontentauthor": "zerrekê cı: \"$1\", û iştıraqkerê cı tenya \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|talk]]) bi",
+       "excontentauthor": "Zerreko verên: \"$1\", (teyna \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|vatış]]) iştiraq kerd bı.",
        "exbeforeblank": "behsê verê esteriyayişi: '$1'",
        "delete-confirm": "\"$1\" bestere",
        "delete-legend": "Bestere",
        "contributions": "İştıraqê {{GENDER:$1|karber}}i",
        "contributions-title": "Dekerdenê karber de $1",
        "mycontris": "İştıraqi",
+       "anoncontribs": "İştıraqi",
        "contribsub2": "Qandê {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Hesabê karberi \"$1\" qeyd nêbiyo.",
        "nocontribs": "Ena kriteriya de vurnayîş çini yo.",
        "ipb-unblock-addr": "$1 a bik",
        "ipb-unblock": "Yew adresê IPî ya zi nameyê karberî blok bike",
        "ipb-blocklist": "Blokî ke hama estê ey bivîne",
-       "ipb-blocklist-contribs": "Ser $1 îştîrakî",
+       "ipb-blocklist-contribs": "Qandê {{GENDER:$1|}} iştiraqi",
        "unblockip": "Hesabê karberî a bike",
        "unblockiptext": "Cıreştışê nuştışê IP ya zi karberio ke ver ra gêriyayo, seba peyser barkerdışi dey rê formê cêrêni bıgurenên.",
        "ipusubmit": "Enê kılitkerdışi wedare",
        "movenotallowedfile": "desturê şıma çino, şıma pelan bıkırışi",
        "cant-move-user-page": "desturê şıma çino, şıma pelanê karberani bıkırışi (bê pelê cerıni).",
        "cant-move-to-user-page": "desturê şıma çino, şıma yew peli bıkırışi pelê yew karberi.",
-       "newtitle": "Nameyê newi:",
+       "newtitle": "Sernameyo newe:",
        "move-watch": "Peler seyr ke",
        "movepagebtn": "Pele bere",
        "pagemovedsub": "Berdışi kerd temam",
        "movenosubpage": "pelê bınıni yê no peli çino.",
        "movereason": "Sebeb:",
        "revertmove": "peyser biya",
-       "delete_and_move": "Bestere û bere",
        "delete_and_move_text": "==gani hewn a bıbıo/bıesteriyo==\n\n\" no [[:$1]]\" name de yew pel ca ra esto. şıma wazeni pê hewn a kerdışê ey peli vurnayişê nameyi bıkeri?",
        "delete_and_move_confirm": "Eya, na pele bestere",
        "delete_and_move_reason": "\"[[$1]]\" qande nami re ca akerdışi re besteriyaye",
        "thumbnail_gd-library": "Configurasyonê katalog ê GDî tam niyo:funksiyonê $1î vînî biyo",
        "thumbnail_image-missing": "Dosya vînî biyo: $1",
        "import": "Peleyi import bik",
-       "importinterwiki": "Împortê transwîkî",
+       "importinterwiki": "Jewna wiki ra azere ke",
        "import-interwiki-text": "qey kırıştışê zerreyi yew wiki u pel bıvıcinê.\ntarixê revizyon u nameyê nuştoxi pawyene.\nkarê zerredayişê benateyê wikiyani[[Special:Log/import|zerreyê rocaneyê kırıştî de]] qeyd beno.",
        "import-interwiki-history": "Qeydanê pele pêrune kopya ke",
        "import-interwiki-templates": "Şablonan pêro zerre ke",
        "duplicate-defaultsort": "'''Tembe:''' Hesıbyaye sırmey ratnayış de \"$2\" sırmey ratnayış de \"$1\"i nêhesıbneno.",
        "version": "Versiyon",
        "version-extensions": "Ekstensiyonî ke ronaye",
-       "version-skins": "Cıldi",
+       "version-skins": "Bar kerde bejni",
        "version-specialpages": "Pelanê xasiyan",
        "version-parserhooks": "Çengelê Parserî",
        "version-variables": "Vurnayeyî",
index 75c4b7d..bc4207c 100644 (file)
        "welcomecreation-msg": "Ο λογαριασμός σας έχει δημιουργηθεί.\nΜην ξεχάσετε να αλλάξετε τις [[Special:Preferences|{{SITENAME}} προτιμήσεις]] σας.",
        "yourname": "Όνομα χρήστη:",
        "userlogin-yourname": "Όνομα χρήστη",
-       "userlogin-yourname-ph": "Εισάγετε το όνομα χρήστη σας",
-       "createacct-another-username-ph": "Εισάγετε το όνομα χρήστη",
+       "userlogin-yourname-ph": "Î\95ιÏ\83αγάγεÏ\84ε Ï\84ο Ï\8cνομα Ï\87Ï\81ήÏ\83Ï\84η Ï\83αÏ\82",
+       "createacct-another-username-ph": "Î\95ιÏ\83αγάγεÏ\84ε Ï\84ο Ï\8cνομα Ï\87Ï\81ήÏ\83Ï\84η",
        "yourpassword": "Κωδικός:",
        "userlogin-yourpassword": "Κωδικός",
-       "userlogin-yourpassword-ph": "Εισάγετε τον κωδικό σας",
+       "userlogin-yourpassword-ph": "Î\95ιÏ\83αγάγεÏ\84ε Ï\84ον ÎºÏ\89δικÏ\8c Ï\83αÏ\82",
        "createacct-yourpassword-ph": "Εισαγωγή κωδικού",
        "yourpasswordagain": "Επαναπληκτρολόγηση κωδικού:",
        "createacct-yourpasswordagain": "Επιβεβαίωση κωδικού",
        "userlogin-createanother": "Δημιουργήστε άλλο λογαριασμό",
        "createacct-emailrequired": "Διεύθυνση ηλεκτρονικού ταχυδρομείου",
        "createacct-emailoptional": "Διεύθυνση ηλεκτρονικού ταχυδρομείου (προαιρετικό)",
-       "createacct-email-ph": "Î\95ιÏ\83άγεÏ\84ε Ï\84ο email Ï\83αÏ\82",
-       "createacct-another-email-ph": "Εισάγετε τη διεύθυνση ηλεκτρονικού ταχυδρομείου",
+       "createacct-email-ph": "Î\95ιÏ\83αγάγεÏ\84ε Ï\84η Î´Î¹ÎµÏ\8dθÏ\85νÏ\83η Î·Î»ÎµÎºÏ\84Ï\81ονικοÏ\8d Ï\83αÏ\82 Ï\84αÏ\87Ï\85δÏ\81ομείοÏ\85",
+       "createacct-another-email-ph": "Î\95ιÏ\83αγάγεÏ\84ε Ï\84η Î´Î¹ÎµÏ\8dθÏ\85νÏ\83η Î·Î»ÎµÎºÏ\84Ï\81ονικοÏ\8d Ï\84αÏ\87Ï\85δÏ\81ομείοÏ\85",
        "createaccountmail": "Χρήση τυχαίου προσωρινού κωδικού πρόσβασης και αποστολή του στην καθοριζόμενη διεύθυνση ηλεκτρονικού ταχυδρομείου",
        "createacct-realname": "Πραγματικό όνομα (προαιρετικό)",
        "createaccountreason": "Αιτία:",
        "passwordreset-emailerror-capture": "Ένα email επαναφοράς κωδικού έχει δημιουργηθεί, το οποίο φαίνεται πιο κάτω, αλλά απέτυχε η αποστολή του στο  {{GENDER:$2|χρήστη}}: $1",
        "changeemail": "Αλλαγή ή αφαίρεση της διεύθυνσης ηλεκτρονικού ταχυδρομείου",
        "changeemail-header": "Συμπληρώστε αυτήν τη φόρμα για να αλλάξετε τη διεύθυνσή σας ηλεκτρονικού ταχυδρομείου. Αν θέλετε να καταργήσετε τη σύνδεση οποιασδήποτε διεύθυνσης ηλεκτρονικού ταχυδρομείου με το λογαριασμό σας, αφήστε τη νέα διεύθυνση ηλεκτρονικού ταχυδρομείου κενή κατά την υποβολή της φόρμας.",
-       "changeemail-passwordrequired": "Θα χρειαστεί να εισάγετε τον κωδικό σας για να επιβεβαιώσετε την αλλαγή αυτή.",
+       "changeemail-passwordrequired": "Î\98α Ï\87Ï\81ειαÏ\83Ï\84εί Î½Î± ÎµÎ¹Ï\83αγάγεÏ\84ε Ï\84ον ÎºÏ\89δικÏ\8c Ï\83αÏ\82 Î³Î¹Î± Î½Î± ÎµÏ\80ιβεβαιÏ\8eÏ\83εÏ\84ε Ï\84ην Î±Î»Î»Î±Î³Î® Î±Ï\85Ï\84ή.",
        "changeemail-no-info": "Πρέπει να έχετε συνδεθεί για άμεση πρόσβαση σε αυτήν τη σελίδα.",
        "changeemail-oldemail": "Τρέχουσα διεύθυνση ηλεκτρονικού ταχυδρομείου:",
        "changeemail-newemail": "Νέα διεύθυνση ηλεκτρονικού ταχυδρομείου:",
        "changeemail-password": "Ο κωδικός πρόσβασής σας στο εγχείρημα {{SITENAME}}:",
        "changeemail-submit": "Αλλαγή διεύθυνσης ηλεκτρονικού ταχυδρομείου",
        "changeemail-throttled": "Κάνατε πάρα πολλές απόπειρες σύνδεσης.\nΠαρακαλούμε περιμένετε $1 προτού ξαναδοκιμάσετε.",
-       "changeemail-nochange": "Παρακαλώ εισάγετε μια διαφορετική νέα διεύθυνση ηλεκτρονικού ταχυδρομείου.",
+       "changeemail-nochange": "Παρακαλούμε εισαγάγετε διαφορετική νέα διεύθυνση ηλεκτρονικού ταχυδρομείου.",
        "resettokens": "Επαναφορά των κλειδιών",
        "resettokens-text": "Μπορείτε να επαναφέρετε τα κλειδιά, τα οποία επιτρέπουν την πρόσβαση σε ορισμένα ιδιωτικά δεδομένα που συνδέονται με τον λογαριασμό σας εδώ.\n\nΠρέπει να το κάνετε εάν κατά λάθος τα μοιραστήκατε με κάποιον ή αν ο λογαριασμός σας έχει παραβιαστεί.",
        "resettokens-no-tokens": "Δεν υπάρχουν κλειδιά για επαναφορά.",
        "anonpreviewwarning": "''Δεν έχετε συνδεθεί. Η αποθήκευση θα καταγράψει την διεύθυνσή IP σας στο ιστορικό επεξεργασίας αυτής της σελίδας.''",
        "missingsummary": "'''Υπενθύμιση:''' Δεν έχετε συμπληρώσει τη σύνοψη επεξεργασίας. Αν κάνετε κλικ στο κουμπί Αποθήκευση πάλι, η επεξεργασία σας θα αποθηκευτεί χωρίς σύνοψη.",
        "selfredirect": "<strong>Προσοχή:</strong> Ανακατευθύνετε αυτή τη σελίδα στον εαυτό της. Μπορεί να δώσατε λάθος στόχο για την ανακατεύθυνση, ή μπορεί να επεξεργάζεστε λάθος σελίδα.\nΑν κάνε κλίκ στο \"{{int:savearticle}}\" ξανά, η ανακατεύθυνση θα δημιουργηθεί ούτως ή άλλως.",
-       "missingcommenttext": "Παρακαλώ εισάγετε ένα σχόλιο παρακάτω.",
+       "missingcommenttext": "Παρακαλούμε εισαγάγετε σχόλιο παρακάτω.",
        "missingcommentheader": "<strong>Υπενθύμιση:</strong> δεν έχετε δώσει ένα θέμα γι' αυτό το σχόλιο.\nΕάν κάνετε κλικ στο κουμπί \"{{int:savearticle}}\" ξανά, η επεξεργασία σας θα αποθηκευτεί χωρίς αυτό.",
        "summary-preview": "Προεπισκόπηση σύνοψης:",
        "subject-preview": "Προεπισκόπηση θέματος:",
        "permissionserrorstext-withaction": "Δεν έχετε την άδεια να $2, για {{PLURAL:$1|τον ακόλουθο λόγο|τους ακόλουθους λόγους}}:",
        "recreate-moveddeleted-warn": "'''Προειδοποίηση: Ξαναδημιουργείτε μια σελίδα που είχε προηγουμένως διαγραφεί.'''\n\nΘα πρέπει να σκεφτείτε σοβαρά αν είναι σωστό να συνεχίσετε να επεξεργάζεστε αυτή τη σελίδα.\nΟι καταγραφές διαγραφών και μετακινήσεων παρέχονται εδώ για διευκόλυνση:",
        "moveddeleted-notice": "Αυτή η σελίδα έχει διαγραφεί.\nΤο αρχείο καταγραφών διαγραφών και μετακινήσεων της σελίδας παρέχεται παρακάτω για αναφορά.",
+       "moveddeleted-notice-recent": "Συγγνώμη, η σελίδα έχει διαγραφεί πρόσφατα (μέσα στις τελευταίες 24 ώρες).\nΗ διαγραφή και μετακίνηση του αρχείου καταγραφής της σελίδας παρέχεται παρακάτω για αναφορά.",
        "log-fulllog": "Εμφάνιση πλήρους αρχείου",
        "edit-hook-aborted": "Η επεξεργασία ματαιώθηκε από το hook.\nΔεν έδωσε εξήγηση.",
        "edit-gone-missing": "Δεν ήταν εφικτό να ενημερωθεί η σελίδα.\nΦαίνεται πως έχει διαγραφεί.",
        "revisionasof": "Αναθεώρηση της $1",
        "revision-info": "Αναθεώρηση ως προς $1 από {{GENDER:$6|τον|την}} $2 $7",
        "previousrevision": "← Παλαιότερη αναθεώρηση",
-       "nextrevision": "Î\9dεÏ\8eÏ\84εÏ\81η Î±Î½Î±Î¸ÎµÏ\8eÏ\81ηÏ\83η &rarr;",
+       "nextrevision": "Î\9dεÏ\8cÏ\84εÏ\81η Î±Î½Î±Î¸ÎµÏ\8eÏ\81ηÏ\83η â\86\92",
        "currentrevisionlink": "Τελευταία αναθεώρηση",
        "cur": "τρέχουσα",
        "next": "επόμενη",
        "suppressionlog": "Κατάλογος διαγραφών",
        "suppressionlogtext": "Παρακάτω βρίσκεται μία λίστα με τις διαγραφές και τις φραγές σχετικό  με περιεχόμενο που έχει αποκρυβεί από τους διαχειριστές.\nΔείτε την [[Special:BlockList|λίστα φραγών IP]] για τις τρέχουσες λειτουργικές απαγορεύσεις και φραγές.",
        "mergehistory": "Συγχώνευση ιστορικών σελίδων",
-       "mergehistory-header": "Αυτή η σελίδα σας επιτρέπει να συγχωνεύσετε τις εκδόσεις από το ιστορικό μίας σελίδας πηγής σε μια νεώτερη σελίδα.\nΣιγουρευτείτε ότι αυτή η αλλαγή θα διατηρήσει την συνοχή του ιστορικού της σελίδας.",
+       "mergehistory-header": "Αυτή η σελίδα σας επιτρέπει να συγχωνεύσετε αναθεωρήσεις από το ιστορικό κάποιας σελίδας προέλευσης σε νεότερη σελίδα.\nΣιγουρευτείτε ότι αυτή η αλλαγή θα διατηρήσει τη συνοχή του ιστορικού της σελίδας.",
        "mergehistory-box": "Συγχώνευση εκδόσεων δυο σελίδων:",
        "mergehistory-from": "Σελίδα πηγής:",
        "mergehistory-into": "Σελίδα προορισμού:",
        "prefswarning-warning": "Έχετε κάνει αλλαγές στις προτιμήσεις σας που δεν έχουν αποθηκευτεί ακόμα.\nΕάν αφήσετε αυτή τη σελίδα χωρίς να κάνετε κλικ στο \"$1\" οι προτιμήσεις σας δεν θα ενημερωθούν.",
        "prefs-tabs-navigation-hint": "Συμβουλή: Μπορείτε να χρησιμοποιήσετε τα πλήκτρα διευθύνσεων αριστερά και δεξιά για να πλοηγηθείτε μεταξύ των καρτελών στη λίστα καρτελών.",
        "email-address-validity-valid": "Η διεύθυνση ηλεκτρονικού ταχυδρομείου φαίνεται έγκυρη",
-       "email-address-validity-invalid": "Î\95ιÏ\83άγεÏ\84ε  Î¼Î¹Î± έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου",
+       "email-address-validity-invalid": "Î\95ιÏ\83αγάγεÏ\84ε έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου",
        "userrights": "Διαχείριση δικαιωμάτων χρηστών",
        "userrights-lookup-user": "Διαχείριση ομάδων χρηστών",
        "userrights-user-editname": "Δηλώστε όνομα χρήστη:",
        "recentchanges-legend-plusminus": "(<em>±123</em>)",
        "rcnotefrom": "Παρακάτω {{PLURAL:$5|είναι η αλλαγή|είναι οι αλλαγές}} από <strong>$3, $4</strong> (έως <strong>$1</strong> που εμφανίζεται).",
        "rclistfrom": "Εμφάνιση νέων αλλαγών αρχίζοντας από τις $3 στις $2",
-       "rcshowhideminor": "$1 μικρών επεξεργασιών",
+       "rcshowhideminor": "$1 μικρών τροποποιήσεων",
        "rcshowhideminor-show": "Εμφάνιση",
        "rcshowhideminor-hide": "Απόκρυψη",
        "rcshowhidebots": "$1 ρομπότ",
        "emptyfile": "Το αρχείο που φορτώσατε φαίνεται να είναι κενό. Αυτό μπορεί να οφείλεται σε λάθος πληκτρολόγησης του ονόματος του αρχείου. Παρακαλούμε ελέγξτε εαν αυτό είναι πραγματικά το αρχείο που θέλετε να φορτώσετε.",
        "windows-nonascii-filename": "Αυτό το wiki δεν υποστηρίζει ονόματα αρχείων με ειδικούς χαρακτήρες.",
        "fileexists": "Υπάρχει ήδη αρχείο με αυτό το όνομα, παρακαλούμε ελέγξτε το <strong>[[:$1]]</strong> εάν δεν είστε {{GENDER:|σίγουρος|σίγουρη}} αν θέλετε να το αλλάξετε.\n[[$1|thumb]]",
-       "filepageexists": "Î\97 Ï\83ελίδα Ï\80εÏ\81ιγÏ\81αÏ\86ήÏ\82 Î³Î¹Î± Î±Ï\85Ï\84Ï\8c Ï\84ο Î±Ï\81Ï\87είο Î´Î·Î¼Î¹Î¿Ï\85Ï\81γήθηκε Î®Î´Î· Ï\83Ï\84ο <strong>[[:$1]]</strong>, Î±Î»Î»Î¬ ÎºÎ±Î½Î­Î½Î± Î±Ï\81Ï\87είο Î¼Îµ Î±Ï\85Ï\84Ï\8c Ï\84ο Ï\8cνομα Î´ÎµÎ½ Ï\85Ï\80άÏ\81Ï\87ει Î±Ï\85Ï\84ή Ï\84η Ï\83Ï\84ιγμή.\nÎ\97 Ï\80εÏ\81ιγÏ\81αÏ\86á¼  Ï\80οÏ\85 Î¸Î± ÎµÎ¹Ï\83άγεÏ\84ε Î´ÎµÎ½ Î¸Î± ÎµÎ¼Ï\86ανιÏ\83Ï\84εί Ï\83Ï\84η Ï\83ελίδα Ï\80εÏ\81ιγÏ\81αÏ\86ήÏ\82.\nÎ\93ια Î½Î± ÎµÎ¼Ï\86ανιÏ\83Ï\84εί Î· Ï\80εÏ\81ιγÏ\81αÏ\86ή Ï\83αÏ\82 ÎµÎºÎµÎ¯, Î¸Î± Ï\80Ï\81έÏ\80ει Î½Î± Ï\84ην ÎµÏ\80εξεÏ\81γαÏ\83Ï\84είÏ\84ε Ï\87ειÏ\81οκίνηÏ\84α.\n[[$1|thumb]]",
+       "filepageexists": "Î\97 Ï\83ελίδα Ï\80εÏ\81ιγÏ\81αÏ\86ήÏ\82 Î³Î¹Î± Î±Ï\85Ï\84Ï\8c Ï\84ο Î±Ï\81Ï\87είο Î´Î·Î¼Î¹Î¿Ï\85Ï\81γήθηκε Î®Î´Î· Ï\83Ï\84ο <strong>[[:$1]]</strong>, Î±Î»Î»Î¬ Î±Ï\85Ï\84ήν Ï\84η Ï\83Ï\84ιγμή Î´ÎµÎ½ Ï\85Ï\80άÏ\81Ï\87ει Î±Ï\81Ï\87είο Î¼Îµ Î±Ï\85Ï\84Ï\8c Ï\84ο Ï\8cνομα.\nÎ\97 Ï\83Ï\8dνοÏ\88η Ï\80οÏ\85 ÎµÎ¹Ï\83αγάγεÏ\84ε Î´ÎµÎ½ Î¸Î± ÎµÎ¼Ï\86ανιÏ\83Ï\84εί Ï\83Ï\84η Ï\83ελίδα Ï\80εÏ\81ιγÏ\81αÏ\86ήÏ\82.\nÎ\93ια Î½Î± ÎµÎ¼Ï\86ανιÏ\83Ï\84εί Î· Ï\83Ï\8dνοÏ\88ή Ï\83αÏ\82 ÎµÎºÎµÎ¯, Î¸Î± Ï\87Ï\81ειαÏ\83Ï\84εί Î½Î± Ï\84ην ÎµÏ\80εξεÏ\81γαÏ\83Ï\84είÏ\84ε Î¼Îµ Ï\84ο Ï\87έÏ\81ι.\n[[$1|thumb]]",
        "fileexists-extension": "Υπάρχει ένα αρχείο με παρόμοιο όνομα: [[$2|thumb]]\n* Όνομα του προς ανέβασμα αρχείου: <strong>[[:$1]]</strong>\n* Όνομα υπάρχοντος αρχείου: <strong>[[:$2]]</strong>\nΜήπως θα θέλατε να χρησιμοποιήσετε κάποιο όνομα που να ξεχωρίζει περισσότερο;",
        "fileexists-thumbnail-yes": "Το αρχείο φαίνεται ότι είναι μια εικόνα μειωμένου μεγέθους ''(μικρογραφία)''. [[$1|thumb]]\nΠαρακαλώ ελέγξτε το αρχείο <strong>[[:$1]]</strong>.\nΑν το ελεγμένο αρχείο είναι η ίδια εικόνα στο αρχικό μέγεθος δεν είναι απαραίτητο να επιφορτώσετε μια επιπλέον μικρογραφία.",
        "file-thumbnail-no": "Το όνομα αρχείου αρχίζει με <strong>$1</strong>.\nΦαίνεται πως είναι μια εικόνα μειωμένου μεγέθους ''(μικρογραφία)''.\nΑν έχετε αυτή την εικόνα σε πλήρη ανάλυση, επιφορτώστε τη, αλλιώς αλλάξτε παρακαλώ το όνομα του αρχείου.",
        "upload-options": "Επιλογές ανεβάσματος",
        "watchthisupload": "Παρακολούθηση αυτού του αρχείου",
        "filewasdeleted": "Ένα αρχείο με αυτό το όνομα είχε επιφορτωθεί προηγουμένως και επακολούθως διαγράφηκε. Θα έπρεπε να ελέγξετε το $1 πριν προσπαθήσετε να το επιφορτώσετε ξανά.",
+       "filename-thumb-name": "Αυτό μοιάζει με έναν τίτλο μικρογραφίας. Παρακαλούμε μην ανεβάζετε εικόνες μικρογραφίας και πάλι στο ίδιο wiki. Διαφορετικά, παρακαλούμε να διορθώσετε το όνομα του αρχείου έτσι ώστε να έχει περισσότερο νόημα, και να μην έχει πρόθεμα μικρογραφίας.",
        "filename-bad-prefix": "Το όνομα του αρχείου που ανεβάζετε ξεκινά με '''\"$1\"''', που είναι ένα μη περιγραφικό όνομα που συνήθως εκχωρείται αυτόματα από ψηφιακές φωτογραφικές μηχανές. Παρακαλώ διαλέξτε ένα πιο περιγραφικό όνομα για το αρχείο σας.",
        "filename-prefix-blacklist": " #<!-- leave this line exactly as it is --> <pre>\n# Η σύνταξη είναι ως ακολούθως:\n#   * Οτιδήποτε από ένα χαρακτήρα «#» μέχρι το τέλος της γραμμής είναι ένα σχόλιο\n#   * Οποιαδήποτε μη κενή γραμμή είναι ένα πρόθεμα για τυπικά ονόματα αρχείων ορισμένα\n#     αυτόματα από ψηφιακές φωτογραφικές μηχανές\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # μερικά κινητά τηλέφωνα\nIMG # γενικά\nJD # Jenoptik\nMGP # Pentax\nPICT # διάφορα\n #</pre> <!-- leave this line exactly as it is -->",
        "upload-success-subj": "Επιτυχής φόρτωση",
        "foreign-structured-upload-form-label-infoform-categories": "Κατηγορίες",
        "foreign-structured-upload-form-label-infoform-date": "Ημερομηνία",
        "foreign-structured-upload-form-label-own-work-message-local": "Επιβεβαιώνω ότι επιφορτώνω  αυτό το αρχείο κατά τους όρους της υπηρεσίας και πολιτικές αδειοδότησης για τον ιστότοπο {{SITENAME}}.",
+       "foreign-structured-upload-form-label-not-own-work-message-local": "Εάν δεν είστε σε θέση να ανεβάσετε αυτό το αρχείο στο πλαίσιο των πολιτικών της  {{SITENAME}}, παρακαλώ κλείστε αυτό το παράθυρο διαλόγου και να επιχειρήσετε μια άλλη μέθοδος.",
        "foreign-structured-upload-form-label-not-own-work-local-local": "Επίσης, μπορεί να θέλετε να δοκιμάσετε [[Special:Upload|την προεπιλεγμένη σελίδα επιφόρτωσης]].",
        "foreign-structured-upload-form-label-own-work-message-default": "Καταλαβαίνω ότι είμαι φόρτωμα αυτό το αρχείο σε ένα κοινόχρηστο αρχείο. Επιβεβαιώνω ότι είμαι τόσο ακόλουθες τους όρους της υπηρεσίας και πολιτικές αδειοδότησης.",
        "foreign-structured-upload-form-label-not-own-work-message-default": "Εάν δεν είστε σε θέση να ανεβάσετε αυτό το αρχείο στο πλαίσιο των πολιτικών της shared repository, παρακαλώ κλείστε αυτό το παράθυρο διαλόγου και να επιχειρήσετε μια άλλη μέθοδος.",
+       "foreign-structured-upload-form-label-not-own-work-message-shared": "Αν δεν κατέχει τα πνευματικά δικαιώματα για αυτό το αρχείο, ή επιθυμείτε να το δημοσιεύσετε υπό μια διαφορετική άδεια χρήσης, μπορείτε να χρησιμοποιήσετε τον [https://commons.wikimedia.org/wiki/Special:UploadWizard Οδηγό Ανεβάσματος των Κοινών].",
        "backend-fail-stream": "Αδύνατη η μετάδοση του αρχείου $1.",
        "backend-fail-backup": "Αδύνατη η δημιουργία αντίγραφου ασφαλείας του αρχείου $1.",
        "backend-fail-notexists": "Το αρχείο $1 δεν υπάρχει.",
        "notargettext": "Δεν έχετε καθορίσει ένα χρήστη ή μια σελίδα προορισμού για να εκτελεσθεί αυτή η λειτουργία.",
        "nopagetitle": "Δεν υπάρχει τέτοια σελίδα στόχος",
        "nopagetext": "Η σελίδα στόχος που καταχωρίσατε δεν υπάρχει.",
-       "pager-newer-n": "{{PLURAL:$1|1 Î½ÎµÏ\8eÏ\84εÏ\81οÏ\85|$1 Î½ÎµÏ\8eτερων}}",
+       "pager-newer-n": "{{PLURAL:$1|1 Î½ÎµÏ\8cÏ\84εÏ\81οÏ\85|$1 Î½ÎµÏ\8cτερων}}",
        "pager-older-n": "{{PLURAL:$1|1 παλαιότερο|$1 παλαιότερα}}",
        "suppress": "Περιορισμός",
        "querypage-disabled": "Αυτή η ειδική σελίδα είναι απενεργοποιημένη για λόγους απόδοσης.",
        "wlshowhidebots": "bots",
        "wlshowhideliu": "εγγεγραμμένοι χρήστες",
        "wlshowhideanons": "ανώνυμοι χρήστες",
+       "wlshowhidepatr": "επιτηρούμενες επεξεργασίες",
        "wlshowhidemine": "οι επεξεργασίες μου",
        "watchlist-options": "Επιλογές λίστας παρακολούθησης",
        "watching": "Παρακολούθηση...",
        "movenosubpage": "Αυτή η σελίδα δεν έχει υποσελίδες.",
        "movereason": "Αιτία:",
        "revertmove": "επαναφορά",
-       "delete_and_move": "Διαγραφή και μετακίνηση",
        "delete_and_move_text": "==Χρειάζεται διαγραφή.==\n\nΤο άρθρο [[:$1]] υπάρχει ήδη. Θέλετε να το διαγράψετε για να εκτελεσθεί η μετακίνηση;",
        "delete_and_move_confirm": "Ναι, να διαγραφεί η σελίδα.",
        "delete_and_move_reason": "Διαγράφηκε για να δημιουργήσει χώρο για μετακίνηση από το \"[[$1]]\"",
        "filedelete-current-unregistered": "Το συγκεκριμένο αρχείο \"$1\" δεν υπάρχει στη βάση δεδομένων.",
        "filedelete-archive-read-only": "Το αρχείο καταλόγου \"$1\" είναι μη εγγράψιμο από τον διακομιστή.",
        "previousdiff": "← Παλαιότερη επεξεργασία",
-       "nextdiff": "Î\9dεÏ\8eτερη επεξεργασία →",
+       "nextdiff": "Î\9dεÏ\8cτερη επεξεργασία →",
        "mediawarning": "'''Προειδοποίηση''': Το αρχείο αυτό μπορεί να περιέχει κακοπροαίρετο κώδικα.\nΕκτελώντας το, μπορεί να βλάψει το σύστημα του υπολογιστή σας.",
        "imagemaxsize": "Όριο μεγέθους εικόνων:<br />''(στις σελίδες περιγραφής εικόνων)''",
        "thumbsize": "Μέγεθος μικρογραφίας:",
        "logentry-managetags-delete": "{{GENDER:$2|Ο|Η}} $1 διέγραψε την ετικέτα «$4» (αφαιρέθηκε από $5 {{PLURAL:$5|αναθεώρηση ή καταχώρηση αρχείου καταγραφής|αναθεωρήσεις και/ή καταχωρήσεις του αρχείου καταγραφής}})",
        "logentry-managetags-deactivate": "{{GENDER:$2|Ο|Η}} $1 απενεργοποίησε την ετικέτα «$4» για χρήση από χρήστες και bots",
        "log-name-tag": "Αρχείο καταγραφών ετικετών",
+       "log-description-tag": "Αυτή η σελίδα εμφανίζεται όταν οι χρήστες έχουν προσθέσει ή αφαιρέσει  [[Special:Tags|ετικέτες]] από επιμέρους αναθεωρήσεις ή καταχωρήσεις του αρχείου καταγραφής. Το αρχείο καταγραφής δεν δημιουργεί κατάλογο ενεργειών ετικετών  όταν αυτές συμβαίνουν ως μέρος κάποιας επεξεργασίας, διαγραφής, ή παρόμοιας ενέργειας.",
        "logentry-tag-update-add-revision": "{{GENDER:$2|Ο|Η}} $1 πρόσθεσε {{PLURAL:$7|την ετικέτα|τις ετικέτες}} $6 στην αναθεώρηση $4 της σελίδας $3",
        "logentry-tag-update-remove-revision": "{{GENDER:$2|Ο|Η}} $1 αφαίρεσε {{PLURAL:$9|την ετικέτα|τις ετικέτες}} $8 από την αναθεώρηση $4 της σελίδας $3",
+       "logentry-tag-update-remove-logentry": "{{GENDER:$2|Ο|Η}} $1 αφαίρεσε {{PLURAL:$9|την ετικέτα|τις ετικέτες}} $8 από το αρχείο καταγραφής $5 της σελίδας $3",
        "logentry-tag-update-revision": "{{GENDER:$2|Ο|Η}} $1 ενημέρωσε ετικέτες στην αναθεώρηση $4 της σελίδας $3 (πρόσθεσε {{PLURAL:$7|την|τις}} $6• αφαίρεσε {{PLURAL:$9|την|τις}} $8)",
        "rightsnone": "(κανένα)",
        "revdelete-summary": "επεξεργασία σύνοψης",
index a274fac..0092ada 100644 (file)
        "morenotlisted": "This list is not complete.",
        "mypage": "Page",
        "mytalk": "Talk",
-       "anontalk": "Talk for this IP address",
+       "anontalk": "Talk",
        "navigation": "Navigation",
        "and": "&#32;and",
        "qbfind": "Find",
        "contributions-summary": "",
        "contributions-title": "User contributions for $1",
        "mycontris": "Contributions",
+       "anoncontribs": "Contributions",
        "contribsub2": "For {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "User account \"$1\" is not registered.",
        "nocontribs": "No changes were found matching these criteria.",
        "move-redirect-text": "",
        "category-move-redirect-override": "-",
        "revertmove": "revert",
-       "delete_and_move": "Delete and move",
        "delete_and_move_text": "== Deletion required ==\nThe destination page \"[[:$1]]\" already exists.\nDo you want to delete it to make way for the move?",
        "delete_and_move_confirm": "Yes, delete the page",
        "delete_and_move_reason": "Deleted to make way for move from \"[[$1]]\"",
        "accesskey-pt-preferences": "",
        "accesskey-pt-watchlist": "l",
        "accesskey-pt-mycontris": "y",
+       "accesskey-pt-anoncontribs": "y",
        "accesskey-pt-login": "o",
        "accesskey-pt-logout": "",
        "accesskey-pt-createaccount": "",
        "tooltip-pt-preferences": "Your preferences",
        "tooltip-pt-watchlist": "A list of pages you are monitoring for changes",
        "tooltip-pt-mycontris": "A list of your contributions",
+       "tooltip-pt-anoncontribs": "A list of edits made from this IP address",
        "tooltip-pt-login": "You are encouraged to log in; however, it is not mandatory",
        "tooltip-pt-logout": "Log out",
        "tooltip-pt-createaccount": "You are encouraged to create an account and log in; however, it is not mandatory",
index 314b1b1..3d34763 100644 (file)
@@ -42,7 +42,8 @@
                        "Sudastelaro",
                        "Ochilov",
                        "Macofe",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Xð"
                ]
        },
        "tog-underline": "Substreki ligilojn",
        "viewhelppage": "Vidi helpopaĝon",
        "categorypage": "Vidi kategorian paĝon",
        "viewtalkpage": "Vidi diskuton",
-       "otherlanguages": "Aliaj lingvoj",
+       "otherlanguages": "En aliaj lingvoj",
        "redirectedfrom": "(Alidirektita el $1)",
        "redirectpagesub": "Alidirektilo",
        "redirectto": "Alidirektas al:",
        "movenosubpage": "Ĉi tiu paĝo havas neniujn subpaĝojn.",
        "movereason": "Kialo:",
        "revertmove": "restarigi",
-       "delete_and_move": "Forigi kaj alinomi",
        "delete_and_move_text": "==Forigo nepras==\n\nLa celartikolo \"[[:$1]]\" jam ekzistas. Ĉu vi volas forigi ĝin por krei spacon por la movo?",
        "delete_and_move_confirm": "Jes, forigu la paĝon",
        "delete_and_move_reason": "Forigita por ebligi movadon de \"[[$1]]\"",
index 695d5b4..613a831 100644 (file)
        "qbpageoptions": "Opciones de página",
        "qbmyoptions": "Mis páginas",
        "faq": "Preguntas frecuentes",
-       "faqpage": "Project:PP. FF.",
+       "faqpage": "Project:Preguntas frecuentes",
        "actions": "Acciones",
        "namespaces": "Espacios de nombres",
        "variants": "Variantes",
        "virus-scanfailed": "ha fallado el análisis (código $1)",
        "virus-unknownscanner": "antivirus desconocido:",
        "logouttext": "<strong>Tu sesión ha finalizado.</strong>\n\nPuede que algunas páginas continúen mostrándose como si la sesión estuviera iniciada hasta que actualices la caché de tu navegador.",
-       "welcomeuser": "¡Bienvenido, $1!",
+       "welcomeuser": "¡Bienvenido/a, $1!",
        "welcomecreation-msg": "Se ha creado tu cuenta.\nSi lo deseas, puedes cambiar tus [[Special:Preferences|preferencias]] para {{SITENAME}}.",
        "yourname": "Usuario:",
        "userlogin-yourname": "Usuario",
        "movenosubpage": "Esta página no tiene subpáginas.",
        "movereason": "Motivo:",
        "revertmove": "revertir",
-       "delete_and_move": "Borrar y trasladar",
        "delete_and_move_text": "==Se necesita borrado==\n\nLa página de destino (\"[[:$1]]\") ya existe. ¿Quiere borrarla para permitir al traslado?",
        "delete_and_move_confirm": "Sí, borrar la página",
        "delete_and_move_reason": "Borrada para permitir el traslado de \"[[$1]]\"",
index 76ef032..e7a059d 100644 (file)
        "movenosubpage": "Sellel leheküljel pole alamlehekülgi.",
        "movereason": "Põhjus:",
        "revertmove": "taasta",
-       "delete_and_move": "Kustuta ja teisalda",
        "delete_and_move_text": "== Vajalik kustutamine ==\nSihtlehekülg \"[[:$1]]\" on juba olemas.\nKas kustutad selle, et luua võimalus teisaldamiseks?",
        "delete_and_move_confirm": "Jah, kustuta lehekülg",
        "delete_and_move_reason": "Kustutatud, et tõsta asemele lehekülg \"[[$1]]\"",
index fb93d0d..d0854ce 100644 (file)
                        "Joxemai",
                        "Arkaitz Barnetik",
                        "Sator",
-                       "Macofe"
+                       "Macofe",
+                       "Xð"
                ]
        },
        "tog-underline": "Azpimarratu loturak:",
        "tog-hideminor": "Ezkutatu azken aldaketetan aldaketa txikiak",
        "tog-hidepatrolled": "Ezkutatu patruilatutako aldaketa azken aldaketetan",
        "tog-newpageshidepatrolled": "Ezkutatu patruilatutako orriak, orri-zerrenda berritik",
-       "tog-hidecategorization": "Orrialdeen kategorizazioa ezkutatu",
+       "tog-hidecategorization": "Ezkutatu orrien kategorizazioa",
        "tog-extendwatchlist": "Jarraipen-zerrenda zabaldu aldaketa guztiak ikusteko, ez bakarrik azken aldaketak",
        "tog-usenewrc": "Azken aldaketetan eta jarraipen-zerrendan aldaketak orrialdearen arabera taldekatu",
-       "tog-numberheadings": "Goiburukoak automatikoki zenbakitu",
+       "tog-numberheadings": "Zenbakitu automatikoki goiburuak",
        "tog-showtoolbar": "Aldaketen tresna-barra erakutsi",
        "tog-editondblclick": "Klik bikoitzaren bitartez orrialdeak aldatu",
        "tog-editsectiononrightclick": "Atalen izenburuetan eskuin klik eginez aldatzea gaitu",
        "morenotlisted": "Zerrenda hau ez dago osorik.",
        "mypage": "Orrialdea",
        "mytalk": "Eztabaida",
-       "anontalk": "IP honen eztabaida",
+       "anontalk": "Eztabaida",
        "navigation": "Nabigazioa",
        "and": "&#32;eta",
        "qbfind": "Aurkitu",
        "viewhelppage": "Laguntza orrialdea ikusi",
        "categorypage": "Kategoria orrialdea ikusi",
        "viewtalkpage": "Eztabaida ikusi",
-       "otherlanguages": "Erdaretan",
+       "otherlanguages": "Beste hizkuntza batzuetan",
        "redirectedfrom": "($1(e)tik birzuzenduta)",
        "redirectpagesub": "Birbideratze orria",
        "redirectto": "Hona birzuzentzen du:",
        "passwordreset-email": "E-mail helbidea:",
        "passwordreset-emailtitle": "{{SITENAME}}-rako kontuaren xehetasunak",
        "passwordreset-emailelement": "Erabiltzaile izena: \n$1\n\nBehin-behineko pasahitza: \n$2",
-       "passwordreset-emailsent": "Pasahitza berrezartzeko e-posta bidali da.",
+       "passwordreset-emailsent": "Hau zure konturako erregistratuta dagoen helbide elektronikoa baldin bada, mezu elektronikoa bidaliko da zure pasahitza berrezartzeko.",
        "passwordreset-emailsent-capture": "Pasahitza berrezartzeko e-posta bat bidali dizugu, behean erakusten dena.",
        "changeemail": "Aldatu edo kendu e-mail helbidea",
-       "changeemail-header": "Aldatu kontuko e-posta helbidea",
+       "changeemail-header": "Bete ezazu inprimaki hau, zure helbide elektronikoa aldatzeko. Zure kontuari helbide elektronikorik elkartuta ez izatea nahi baduzu, utz ezazu hutsik helbide elektroniko berria, inprimakia bidaltzen duzunean.",
        "changeemail-no-info": "Orrialde honetara zuzenean sartzeko izena eman behar duzu.",
        "changeemail-oldemail": "Egungo e-mail helbidea:",
        "changeemail-newemail": "E-posta helbide berria:",
        "anonpreviewwarning": "''Ez duzu saioa hasi. Gordez gero, zure IP helbidea grabatuko da orri honen edizio historian.''",
        "missingsummary": "'''Gogorarazpena:''' Ez duzu aldaketa laburpen bat zehaztu. Berriz ere gordetzeko aukeratzen baduzu, laburpen mezurik gordeko da.",
        "missingcommenttext": "Mesedez, iruzkin bat idatzi jarraian.",
-       "missingcommentheader": "'''Oharra:''' Ez duzu iruzkin honetarako gairik edo goiburukorik ezarri. «{{int:Savearticle}}» klikatzen baduzu, hutsune horrekin gordeko da.",
+       "missingcommentheader": "<strong>Oharra:</strong> Ez duzu iruzkin honetarako gairik ezarri. «{{int:Savearticle}}» berriro klikatzen baduzu, gairik gabe gordeko da zure edizioa.",
        "summary-preview": "Laburpenaren aurreikuspena:",
        "subject-preview": "Gaiaren aurrebista:",
        "blockedtitle": "Erabiltzailea blokeatuta dago",
        "creating": "«$1» sortzen",
        "editingsection": "«$1» aldatzen (atala)",
        "editingcomment": "«$1» aldatzen (atal berria)",
-       "editconflict": "Zure aldaketak ezin izan dira gorde, edizio gatazka bat izan delako. Gatazka eskuz konpondu nahi {{GENDER:|duzu}}?",
+       "editconflict": "Edizio gatazka: $1",
        "explainconflict": "Zu orrialdea aldatzen hasi ondoren beste norbaitek ere aldaketak egin ditu.\nGoiko testu koadroan ikus daiteke orrialdeak uneotan duen edukia.\nZure aldaketak beheko testu koadroan ikus daitezke.\nZure testua dagoenarekin elkartu beharko duzu.\nOrrialdea gordetzeko erabakitzen duzun unean goiko koadroko edukia '''bakarrik''' gordeko da.",
        "yourtext": "Zure testua",
        "storedversion": "Gordetako bertsioa",
        "parser-template-recursion-depth-warning": "Txantiloaren rekurtsio sakoneraren muga gainditu da ($1)",
        "language-converter-depth-warning": "Hizkuntza-bihurgailuaren sakonerak ($1) muga gainditu du",
        "node-count-exceeded-category": "Nodo-zenbaketa gainditu den orrialdeak",
-       "node-count-exceeded-warning": "Orrialdeak nodo-zenbaketa gainditu du",
+       "node-count-exceeded-warning": "Orriak nodo-kopuruaren muga gainditu du",
        "expansion-depth-exceeded-category": "Orrialdearen espantsio sakonera gainditu da",
        "expansion-depth-exceeded-warning": "Espantsio sakonera gainditu duten orrialdeak",
        "parser-unstrip-loop-warning": "Loop unstrip bat aurkitu da",
        "rev-deleted-user": "(erabiltzailea ezabatu da)",
        "rev-deleted-event": "(log xehetasunak ezabatu dira)",
        "rev-deleted-user-contribs": "[lankide izena edo Ip helbidea ezabatua - aldatu ezkutapena ekarpenetatik]",
-       "rev-deleted-text-permission": "Orrialdearen berrikuspen hau '''ezabatua''' izan da.\nXehetasunak [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ezabaketa erregistroan] ikus daitezke.",
+       "rev-deleted-text-permission": "Orrialdearen berrikuspen hau <strong>ezabatua</strong> izan da.\nXehetasunak [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ezabaketa erregistroan] ikus daitezke.",
        "rev-deleted-text-unhide": "Orriaren bertsio hau '''ezabatu''' da.\nXehetasunak ikusgai daude [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ezabatze erregistroan].\nAdministratzailea zarenez, oraindik [$1 bertsio hau ikus dezakezu], nahi izanez gero.",
        "rev-suppressed-text-unhide": "Orriaren bertsio hau '''ezeztatu''' da.\nXehetasunak ikusgai daude [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} ezeztatze erregistroan].\nAdministratzailea zarenez, oraindik [$1 bertsio hau ikus dezakezu], nahi izanez gero.",
        "rev-deleted-text-view": "Orriaren berrikuspen hau '''ezabatua''' izan da.\nZuk ikusteko aukera daukazu; xehetasunak [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ezabaketa erregistroan] ikus ditzakezu.",
        "rev-showdeleted": "erakutsi",
        "revisiondelete": "Berrikuspenak ezabatu/leheneratu",
        "revdelete-nooldid-title": "Helburu berrikuspenik ez",
-       "revdelete-nooldid-text": "Ez d(it)uzu eragiketa hau burutzeko helburu berrikuspena(k) zehaztu.",
+       "revdelete-nooldid-text": "Ez duzu eragiketa hau burutzeko helburu berrikuspenik zehaztu, edo berrikuspen hori ez da existitzen, edo oraingo berrikuspena ezkutatzen ari zara.",
        "revdelete-no-file": "Zehazturiko fitxategia ez da existitzen.",
        "revdelete-show-file-confirm": "\"<nowiki>$1</nowiki>\" fitxategiaren bertsio ezabatua (eguna: $2; ordua: $3) ikusi nahi duzu?",
        "revdelete-show-file-submit": "Bai",
        "logdelete-selected": "{{PLURAL:$1|Aukeratutako log gertakaria|Aukeratutako log gertakariak}}:",
        "revdelete-confirm": "Baiezta ezazu hori dela zure asmoa, ulertzen dituzula ondorioak, eta [[{{MediaWiki:Policy-url}}|irizpideak]] errespetatuz egiten ari zarela hau.",
-       "revdelete-suppress-text": "Ezabaketa '''bakarrik''' arrazoi hauek direla eta erabili beharko litzateke:\n* Informazio pertsonal desegokia\n*: ''etxeko helbideak eta telefono zenbakiak, segurtasun sozial zenbakiak, etab.''",
+       "revdelete-suppress-text": "Ezabaketa <strong>bakarrik</strong> arrazoi hauek direla eta erabili beharko litzateke:\n* Iraingarria izan daiteken informazioa\n* Informazio pertsonal desegokia\n*: <em>etxeko helbideak eta telefono zenbakiak, nortasun zenbaki nazionalak, etab.</em>",
        "revdelete-legend": "Berrikuspen mugapenak ezarri:",
        "revdelete-hide-text": "Berrikuspenaren testua ezkutatu",
        "revdelete-hide-image": "Fitxategiaren edukia ezkutatu",
        "search-relatedarticle": "Erlazionatua",
        "searchrelated": "erlazionatua",
        "searchall": "guztia",
-       "showingresults": "Jarraian {{PLURAL:$1|emaitza '''1''' ikus daiteke|'''$1''' emaitza ikus daitezke}}, #'''$2'''.etik hasita.",
-       "showingresultsinrange": "Jarraian {{PLURAL:$1|emaitza '''1''' ikus daiteke|'''$1''' emaitza ikus daitezke}}, #'''$2'''.etik hasi eta #<strong>$3</strong>.eraino.",
+       "showingresults": "Jarraian {{PLURAL:$1|emaitza <strong>bat</strong> ageri da.|<strong>$1</strong> emaitza ageri dira, #'''$2'''.etik hasita.}}",
+       "showingresultsinrange": "Jarraian {{PLURAL:$1|emaitza <strong>bat</strong> ageri da.|<strong>$1</strong> emaitza ageri dira, </strong>$2</strong>.etik hasi eta <strong>$3</strong>.eraino.}}",
        "search-showingresults": "{{PLURAL:$4|<strong>$1.</strong> emaitza (guztira <strong>$3</strong> dira)|<strong>$1 - $2.</strong> emaitzak (guztira <strong>$3</strong> dira)}}",
        "search-nonefound": "Ez dago eskaerarekin bat egiten duten emaitzarik.",
        "powersearch-legend": "Bilaketa aurreratua",
        "group-bot": "Bot-ak",
        "group-sysop": "Administratzaileak",
        "group-bureaucrat": "Burokratak",
-       "group-suppress": "Gainikupsenak",
+       "group-suppress": "Gainikupenak",
        "group-all": "(guztiak)",
        "group-user-member": "{{GENDER:$1|lankidea}}",
        "group-autoconfirmed-member": "{{GENDER:$1|baieztatutako lankidea}}",
        "listgrouprights-addgroup-self-all": "Talde guztiak norbere kontura gehitu",
        "listgrouprights-removegroup-self-all": "Talde guztiak norbere kontutik ezabatu",
        "listgrouprights-namespaceprotection-namespace": "Izen-tartea",
+       "trackingcategories-name": "Mezuaren izena",
        "trackingcategories-nodesc": "Ez dago deskribapenik eskuragarri.",
        "trackingcategories-disabled": "Kategoria desgaitua dago",
        "mailnologin": "Bidalketa helbiderik ez",
        "wlheader-showupdated": "Bisitatu zenituen azken alditik aldaketak izan dituzten orrialdeak '''beltzez''' nabarmenduta daude.",
        "wlnote": "Jarraian {{PLURAL:$2|ikus daiteke azken orduko|ikus daitezke azken '''$2''' orduetako}} azken {{PLURAL:$1|aldaketa|'''$1''' aldaketak}}, $3, $4 gisa.",
        "wlshowlast": "Erakutsi azken $1 orduak, azken $2 egunak",
-       "watchlistall2": "guztiak",
+       "watchlistall2": "guztia",
        "watchlist-hide": "Ezkutatu",
        "wlshowtime": "Erakutsi azkenak:",
        "wlshowhideminor": "aldaketa txikiak",
        "wlshowhidebots": "bot-ak",
+       "wlshowhideliu": "Erregistratutako erabiltzaileak",
        "wlshowhideanons": "erabiltzaile anonimoak",
+       "wlshowhidepatr": "Patruilatutako aldaketak",
        "wlshowhidemine": "nire edizioak",
        "watchlist-options": "Jarraitze-zerrendaren aukerak",
        "watching": "Zerrendan gehitzen...",
        "deletecomment": "Arrazoia:",
        "deleteotherreason": "Arrazoi gehigarria:",
        "deletereasonotherlist": "Beste arrazoi bat",
-       "deletereason-dropdown": "*Ezabatzeko ohiko arrazoiak\n** Egileak eskatuta\n** Egile eskubideak urratzea\n** Bandalismoa",
+       "deletereason-dropdown": "*Ezabatzeko ohiko arrazoiak\n** Egileak eskatuta\n** Egile eskubideak urratzea\n** Bandalismoa\n** Hautsitako birzuzenketa \n** Spama",
        "delete-edit-reasonlist": "Ezabaketa arrazoiak aldatu",
        "delete-toobig": "Orrialde honek aldaketa historia luzea du, {{PLURAL:$1|berrikuspen batetik|$1 berrikuspenetik}} gorakoa.\nOrrialde horien ezabaketa mugatua dago {{SITENAME}}n ezbeharrak saihesteko.",
        "delete-warning-toobig": "Orrialde honek aldaketa historia luzea du, {{PLURAL:$1|berrikuspen batetik|$1 berrikuspenetik}} gorakoa.\nEzabatzeak ezbeharrak eragin ditzake {{SITENAME}}ren datu-basean;\nkontu izan.",
        "contributions": "{{GENDER:$1|Lankidearen}} ekarpenak",
        "contributions-title": "$1(r)entzat lankidearen ekarpenak",
        "mycontris": "Ekarpenak",
+       "anoncontribs": "Ekarpenak",
        "contribsub2": "{{GENDER:$3|$1(r)entzat}} ($2)",
+       "contributions-userdoesnotexist": "\"$1\" erabiltzaile-kontua ez dago erregistraturik.",
        "nocontribs": "Ez da ezaugarri horiekin bat datorren aldaketarik aurkitu.",
        "uctop": "(azken aldaketa)",
        "month": "Hilabetea (eta lehenagokoak):",
        "sp-contributions-newbies-sub": "Hasiberrientzako",
        "sp-contributions-newbies-title": "Lankideen ekarpenak lankide berrietn",
        "sp-contributions-blocklog": "Blokeaketa erregistroa",
+       "sp-contributions-suppresslog": "lankide-ekarpen ezabatuak",
        "sp-contributions-deleted": "lankide-ekarpen ezabatuak",
        "sp-contributions-uploads": "igoerak",
        "sp-contributions-logs": "erregistroak",
        "sp-contributions-talk": "eztabaida",
        "sp-contributions-userrights": "erabiltzaile-baimenen kudeaketa",
        "sp-contributions-blocked-notice": "Lankide hau une honetan blokeatuta dago.\nBlokeo erregistroa azken sarrera ematen da azpian erreferentziarako:",
+       "sp-contributions-blocked-notice-anon": "Erabiltzaile hau blokeatuta dago une honetan.\nAzken blokeoaren erregistroa ageri da behean, erreferentzia gisa:",
        "sp-contributions-search": "Ekarpenentzako bilaketa",
        "sp-contributions-username": "IP helbidea edo erabiltzaile izena:",
        "sp-contributions-toponly": "Azken aldaketak direnak soilik erakutsi",
        "unblocked": "[[User:$1|$1]] desblokeatu egin da",
        "unblocked-range": "$1 desblokeatuta izan da.",
        "unblocked-id": "$1 blokeaketa ezabatu da",
+       "unblocked-ip": "[[Special:Contributions/$1|$1]] desblokeatua izan da.",
        "blocklist": "Blokeatutako erabiltzaileak",
        "ipblocklist": "Blokeatutako erabiltzaileak",
        "ipblocklist-legend": "Blokeatutako erabiltzaile bat bilatu",
        "movenosubpage": "Orrialde honek ez du azpiorrialderik.",
        "movereason": "Arrazoia:",
        "revertmove": "desegin",
-       "delete_and_move": "Ezabatu eta mugitu",
        "delete_and_move_text": "== Ezabatzeko beharra ==\n\n\"[[:$1]]\" helburua existitzen da. Lekua egiteko ezabatu nahi al duzu?",
        "delete_and_move_confirm": "Bai, orrialdea ezabatu",
        "delete_and_move_reason": "[[$1]] mugitzeko ezabatu da",
        "thumbnail_gd-library": "GD liburutegiaren konfigurazio osagabea: $1 funtzioa falta da",
        "thumbnail_image-missing": "Fitxategirik ez dagoela dirudi: $1",
        "import": "Orrialdeak inportatu",
-       "importinterwiki": "Wikien arteko inportazioa",
+       "importinterwiki": "Beste wiki batetik inportatu",
        "import-interwiki-text": "Aukeratu inportatzeko wiki eta orrialde izenburu bat. Berrikuspenen datak eta egileak gorde egingo dira. Inportazio ekintza guzti hauek [[Special:Log/import|inportazio erregistroan]] gordetzen dira.",
        "import-interwiki-sourcewiki": "Jatorrizko wikia:",
        "import-interwiki-sourcepage": "Jatorrizko orria:",
        "tooltip-pt-preferences": "Nire hobespenak",
        "tooltip-pt-watchlist": "Jarraitzen dituzun orrialdeen zerrenda.",
        "tooltip-pt-mycontris": "Nire ekarpenen zerrenda",
+       "tooltip-pt-anoncontribs": "IP helbide honetatik egindako aldaketen zerrenda",
        "tooltip-pt-login": "Izen ematera gonbidatzen zaitugu.",
        "tooltip-pt-logout": "Saioa itxi",
        "tooltip-pt-createaccount": "Kontu bat sortu eta horrekin saioa hastea eskatu nahi genizuke; ez da ezinbestekoa, ordea.",
        "pageinfo-protect-cascading-yes": "Bai",
        "pageinfo-protect-cascading-from": "Serieko babesak aktibatuta. Sorburua:",
        "pageinfo-category-info": "Kategoria informazioa",
+       "pageinfo-category-total": "Erabiltzaile kopurua, guztira",
        "pageinfo-category-pages": "Orrialde kopurua",
        "pageinfo-category-subcats": "Azpikategorien zenbakia",
        "pageinfo-category-files": "Fitxategi kopurua",
        "patrol-log-page": "Patrullatze loga",
        "patrol-log-header": "Hau patruliatutako aldaketen log bat da.",
        "log-show-hide-patrol": "$1 patruilatze loga",
+       "log-show-hide-tag": "$1 etiketa erregistroa",
        "deletedrevision": "$1 berrikuspen zaharra ezabatu da",
        "filedeleteerror-short": "Errorea fitxategia ezabatzerakoan: $1",
        "filedeleteerror-long": "Erroreak gertatu dira fitxategia ezabatzerakoan:\n\n$1",
        "file-info-size-pages": "$1 × $2 pixel, fitxategi tamaina: $3, MIME mota: $4, {{PLURAL:$5|orrialde $5|$5 orrialde}}",
        "file-nohires": "Ez dago bereizmen handiagorik.",
        "svg-long-desc": "SVG fitxategia, nominaldi $1 × $2 pixel, fitxategiaren tamaina: $3",
+       "svg-long-desc-animated": "SVG fitxategi animatua, nominalki $1 × $2 pixel, fitxategiaren tamaina: $3",
        "svg-long-error": "SVG fitxategi ez baliagarria: $1",
        "show-big-image": "Jatorrizko fitxategia",
        "show-big-image-preview": "Aurreikuspen honen neurria: $1.",
        "autosumm-replace": "Orriaren edukiaren ordez, «$1» jarri da",
        "autoredircomment": "[[$1]] orrialdera birzuzentzentzen",
        "autosumm-new": "Orria sortu da. Edukia: $1",
+       "autosumm-newblank": "Orrialde zuria sortu da",
        "lag-warn-normal": "{{PLURAL:$1|segundu $1|$1 segundu}} baino berriagoak diren aldaketak ez dira zerrenda honetan agertuko.",
        "lag-warn-high": "Zerbitzariaren atzerapen handia dela eta, {{PLURAL:$1|segundu $1|$1 segundu}} baino berriagoak diren aldaketak baliteke zerrenda honetan ez azaltzea.",
        "watchlistedit-normal-title": "Jarraitze zerrenda aldatu",
        "watchlistedit-clear-submit": "Garbitu jarraipen zerrenda (Behin betiko da!)",
        "watchlistedit-clear-done": "Zure jarraipen-zerrenda garbitu da.",
        "watchlistedit-clear-removed": "{{PLURAL:$1|Izenburu 1 kendu da|$1 izenburu kendu dira}}:",
+       "watchlistedit-too-many": " Orrialde gehiegi, hemen erakusteko.",
        "watchlisttools-clear": "Garbitu jarraipen-zerrenda",
        "watchlisttools-view": "Aldaketa garrantzitsuak ikusi",
        "watchlisttools-edit": "Zerrenda ikusi eta aldatu",
        "version-ext-colheader-license": "Lizentzia",
        "version-ext-colheader-description": "Deskribapena",
        "version-ext-colheader-credits": "Egileak",
+       "version-license-title": "$1-entzako lizentzia",
+       "version-credits-title": "$1-entzako aitorpena",
        "version-poweredby-credits": "Wiki hau '''[https://www.mediawiki.org/ MediaWiki]'''k sustatzen du (copyright © 2001-$1 $2).",
        "version-poweredby-others": "beste batzuk",
        "version-poweredby-translators": "translatewiki.net itzultzaileak",
        "version-entrypoints": "Sarrera puntuko URLa",
        "version-entrypoints-header-entrypoint": "Sarrera puntua",
        "version-entrypoints-header-url": "URL",
+       "version-libraries": "Instalatutako bibliotekak",
        "version-libraries-library": "Liburutegia",
        "version-libraries-version": "Bertsioa",
        "version-libraries-license": "Lizentzia",
        "tags-actions-header": "Ekintzak",
        "tags-active-yes": "Bai",
        "tags-active-no": "Ez",
+       "tags-source-extension": "Luzapenak definitua",
+       "tags-source-none": "Ez da gehiago erabiltzen",
        "tags-edit": "aldatu",
        "tags-delete": "ezabatu",
        "tags-activate": "aktibatu",
        "tags-deactivate": "desaktibatu",
        "tags-hitcount": "$1 {{PLURAL:$1|aldaketa|aldaketa}}",
+       "tags-manage-no-permission": "Ez duzu etiketa aldaketak kudeatzeko baimenik.",
        "tags-create-heading": "Etiketa berria sortu",
        "tags-create-tag-name": "Etiketaren izena:",
        "tags-create-reason": "Arrazoia:",
        "tags-create-submit": "Sortu",
+       "tags-create-already-exists": "\"$1\" etiketa badago.",
+       "tags-create-warnings-below": "Etiketaren sorrerarekin jarraitu nahi duzu?",
        "tags-delete-title": "Etiketa ezabatu",
+       "tags-delete-explanation-initial": "Datu-basetik \"$1\" etiketa ezabatzera zoaz",
        "tags-delete-reason": "Arrazoia:",
        "tags-delete-not-found": "\"$1\" etiketa  ez da existitzen.",
        "tags-activate-title": "Etiketa aktibatu",
        "compare-revision-not-exists": "Zehazturiko berrikuspena ez da existitzen.",
        "dberr-problems": "Barkatu! Webgune honek zailtasun teknikoak jasaten ari da.",
        "dberr-again": "Saiatu pare bat minutu itxaroten edo kargatu ezazu orrialdea berriro.",
-       "dberr-info": "($1: Ezin da datu-base zerbitzariarekin konektatu)",
-       "dberr-info-hidden": "(Ezin da konektatu datubasearen zerbitzariarekin)",
+       "dberr-info": "($1: Ezin da datu-basera konektatu)",
+       "dberr-info-hidden": "(Ezin da konektatu datu-basera)",
        "dberr-usegoogle": "Bitartean Google bidez bilatzen saiatu zintezke.",
        "dberr-outofdate": "Eduki hauek aurkibideak eguneratu gabe egon daitezke.",
        "dberr-cachederror": "Ondorengoa eskatutako orriaren katxedun kopia da, eta eguneratu gabe egon daiteke.",
        "logentry-newusers-create": "$1 erabiltzaile kontua {{GENDER:$2|sortu da}}",
        "logentry-newusers-create2": "$1 wikilariak $3 erabiltzaile kontua sortu du",
        "logentry-upload-upload": "$1(e)k $3 {{GENDER:$2|igo du}}",
+       "log-name-tag": "Etiketen erregistroa",
        "rightsnone": "(bat ere ez)",
        "revdelete-summary": "aldaketaren laburpena",
        "feedback-adding": "Orriari feedbacka gehitzen...",
        "feedback-bugnew": "Txekeatu dut. Bug berria bidaliko",
        "feedback-cancel": "Utzi",
        "feedback-close": "Egina",
+       "feedback-dialog-title": "Feedbacka bidali",
        "feedback-error-title": "Errorea",
        "feedback-error1": "Akatsa: APIaren emaitza ez ezagunak",
        "feedback-error2": "Akatsa: Aldaketa ez da egin",
        "expand_templates_remove_comments": "Iruzkinak kendu",
        "expand_templates_remove_nowiki": "Ezabatu <nowiki> etiketen emaitzak",
        "expand_templates_generate_xml": "Erakutsi XML parse zuhaitza",
+       "expand_templates_generate_rawhtml": "Erakutsi HTML gordina",
        "expand_templates_preview": "Aurreikusi",
        "pagelanguage": "Orriaren hizkuntza aukeratu",
        "pagelang-name": "Orria",
        "special-characters-title-emdash": "em lerroa",
        "special-characters-title-minus": "minus zeinua",
        "mw-widgets-dateinput-no-date": "Ez duzu datarik aukeratu",
-       "mw-widgets-titleinput-description-new-page": "orrialde hori oraindik ez da existitzen",
+       "mw-widgets-titleinput-description-new-page": "orri hori oraindik ez da existitzen",
        "mw-widgets-titleinput-description-redirect": "$1ra birzuzendu",
        "api-error-blacklisted": "Aukera ezazu, mesedez, izenburu ezberdin eta deskriptiboago bat."
 }
index dd02823..30183a4 100644 (file)
        "movenosubpage": "Tällä sivulla ei ole alasivuja.",
        "movereason": "Syy:",
        "revertmove": "kumoa siirto",
-       "delete_and_move": "Poista kohdesivu ja siirrä",
        "delete_and_move_text": "==Poistamista edellyttävä siirto==\nKohdesivu [[:$1]] on jo olemassa. \nHaluatko poistaa sen, jotta nykyinen sivu voitaisiin siirtää?",
        "delete_and_move_confirm": "Kyllä, poista kohdesivu",
        "delete_and_move_reason": "Sivu on sivun [[$1]] siirron tiellä.",
index fdc460e..ced2458 100644 (file)
        "morenotlisted": "Cette liste n’est pas complète.",
        "mypage": "Page",
        "mytalk": "Discussion",
-       "anontalk": "Discussion avec cette adresse IP",
+       "anontalk": "Discussion",
        "navigation": "Navigation",
        "and": "&#32;et",
        "qbfind": "Rechercher",
        "contributions": "Contributions de l’{{GENDER:$1|utilisateur|utilisatrice}}",
        "contributions-title": "Liste des contributions de l’utilisat{{GENDER:$1|eur|rice|eur}} $1",
        "mycontris": "Contributions",
+       "anoncontribs": "Contributions",
        "contribsub2": "Pour {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Le compte utilisateur « $1 » n’est pas enregistré.",
        "nocontribs": "Aucune modification correspondant à ces critères n'a été trouvée.",
        "movenosubpage": "Cette page n'a aucune sous-page.",
        "movereason": "Motif :",
        "revertmove": "rétablir",
-       "delete_and_move": "Supprimer et renommer",
        "delete_and_move_text": "== Suppression requise ==\nLa page de destination « [[:$1]] » existe déjà.\nÊtes-vous certain{{GENDER:||e|}} de vouloir la supprimer pour permettre ce renommage ?",
        "delete_and_move_confirm": "Oui, supprimer la page de destination",
        "delete_and_move_reason": "Page supprimée pour permettre le renommage depuis « [[$1]] »",
        "tooltip-pt-preferences": "Vos préférences",
        "tooltip-pt-watchlist": "La liste des pages dont vous suivez les modifications",
        "tooltip-pt-mycontris": "La liste de vos contributions",
+       "tooltip-pt-anoncontribs": "Une liste des modifications effectuées depuis cette adresse IP",
        "tooltip-pt-login": "Il est recommandé de vous identifier ; ce n'est cependant pas obligatoire.",
        "tooltip-pt-logout": "Se déconnecter",
        "tooltip-pt-createaccount": "Il vous est conseillé de créer un compte et de vous connecter ; cependant, ce n’est pas obligatoire",
index ea547c5..2876ef2 100644 (file)
@@ -13,7 +13,8 @@
                        "לערי ריינהארט",
                        "아라",
                        "Robin0van0der0vliet",
-                       "Macofe"
+                       "Macofe",
+                       "Xð"
                ]
        },
        "tog-underline": "Keppelings ûnderstreekje:",
        "viewhelppage": "Helpside sjen litte",
        "categorypage": "Besjoch kategoryside",
        "viewtalkpage": "Oerlisside",
-       "otherlanguages": "Oare talen",
+       "otherlanguages": "In oare talen",
        "redirectedfrom": "(Trochwiisd fan \"$1\")",
        "redirectpagesub": "Trochferwiis-side",
        "lastmodifiedat": "Lêste kear bewurke op $2, $1.",
        "createaccountreason": "Reden:",
        "createacct-reason": "Reden",
        "createacct-reason-ph": "Wêrom makkesto in oare akkount?",
-       "createacct-captcha": "Feiligenshifking",
-       "createacct-imgcaptcha-ph": "Nim de tekst fan hjirboppe oer",
        "createacct-submit": "Meitsje in akkount",
        "createacct-another-submit": "Meitsje in oare akkount",
        "createacct-benefit-heading": "{{SITENAME}} is makke troch minsken krekt as dy.",
        "watchlist-details": "Jo folchlist hat {{PLURAL:$1|$1 side|$1 siden}}, oerlissiden net meiteld.",
        "wlnote": "Dit {{PLURAL:$1|is de lêste feroaring|binne de lêste '''$1''' feroarings}} yn de lêste {{PLURAL:$2|oer|'''$2''' oeren}}.",
        "wlshowlast": "Lit feroarings sjen fan de lêste $1 oeren $2 dagen",
+       "watchlistall2": "alles",
        "watching": "Dwaande mei op'e folchlist te setten ...",
        "unwatching": "Dwaande mei fan'e folchlist ôf te heljen ...",
        "enotif_impersonal_salutation": "meidogger fan {{SITENAME}}",
        "movelogpagetext": "Dit is in list fan feroare titels.",
        "movereason": "Reden:",
        "revertmove": "werom sette",
-       "delete_and_move": "Fuortsmite en omneame",
        "delete_and_move_text": "== Wiskjen nedich ==\nDe doelside \"[[:$1]]\" is der al.\nMoat dy wiske wurde om plak te meitsjen foar it werneamen?",
        "delete_and_move_confirm": "Ja, wiskje de side",
        "delete_and_move_reason": "Wiske om plak te meitsjen foar in werneamde side",
index 0eeaf98..fce4d42 100644 (file)
        "nstab-template": "Teamplaid",
        "nstab-help": "Cuideachadh",
        "nstab-category": "Roinn-seòrsa",
+       "mainpage-nstab": "Prìomh-dhuilleag",
        "nosuchaction": "Chan eil a leithid de ghnìomh ann",
        "nosuchactiontext": "Tha an gnìomh a shònraich an t-URL mì-dhligheach.\nFaodaidh gun do chuir thu a-steach URL mearachdach no gun do lean thu ri ceangal mearachdach.\nCuideachd, faodaidh gu bheil seo 'na chomharradh air buga sa bhathar-bhog aig {{SITENAME}}",
        "nosuchspecialpage": "Chan eil duilleag shònraichte d' a leithid ann",
        "createaccountreason": "Adhbhar:",
        "createacct-reason": "Adhbhar",
        "createacct-reason-ph": "Carson a tha thu a' cruthachadh cunntas eile?",
-       "createacct-captcha": "Sgrùdadh tèarainteachd",
-       "createacct-imgcaptcha-ph": "Cuir a-steach an teacsa a chì thu gu h-àrd",
        "createacct-submit": "Cruthaich an cunntas agad",
        "createacct-another-submit": "Cruthaich cunntas eile",
        "createacct-benefit-heading": "Tha {{SITENAME}} 'ga chruthachadh le daoine mar thu fhèin.",
        "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",
+       "watchlistall2": "na h-uile",
        "watchlist-options": "Roghainnean mo chlàir-faire",
        "watching": "'Ga chur air a' chlàr-fhaire...",
        "unwatching": "A' toirt far a' chlàir-fhaire...",
        "movenosubpage": "Chan eil fo-dhuilleag aig an duilleag seo.",
        "movereason": "Adhbhar:",
        "revertmove": "till",
-       "delete_and_move": "Sguab às agus gluais",
        "delete_and_move_text": "== Tha sguabadh às a dhìth ==\nTha an duilleag-uidhe \"[[:$1]]\" ann mar-thà.\nA bheil thu airson a sguabadh às ach am bidh rum airson a' ghluasaid ann?",
        "delete_and_move_confirm": "Siuthad, sguab às an duilleag",
        "delete_and_move_reason": "Chaidh a sguabadh às gus rum a airson a' ghluasaid o \"[[$1]]\" a chruthachadh",
        "tooltip-ca-nstab-main": "Seall duilleag na susbainte",
        "tooltip-ca-nstab-user": "Seall duilleag a' chleachdaiche",
        "tooltip-ca-nstab-media": "Seall duilleag a' mheadhain",
-       "tooltip-ca-nstab-special": "Seo duilleag shònraichte, chan urrainn dhut an duilleag fhèin a dheasachadh",
+       "tooltip-ca-nstab-special": "Seo duilleag shònraichte ’s cha ghabh a dheasachadh",
        "tooltip-ca-nstab-project": "Seall duilleag a' phròiseict",
        "tooltip-ca-nstab-image": "Seall duilleag an fhaidhle",
        "tooltip-ca-nstab-mediawiki": "Seall teachdaireachd an t-siostaim",
        "spam_reverting": "A' tilleadh dhan mhùthadh mu dheireadh anns nach eil ceangal gu $1",
        "spam_blanking": "Cha ceangal gu $1 anns gach mùthadh, 'ga bhànachadh",
        "spam_deleting": "Cha ceangal gu $1 anns gach mùthadh, 'ga sguabadh às",
-       "simpleantispam-label": "Dearbhadh an aghaidh spama.\n<strong>NA</strong> lìon seo!",
+       "simpleantispam-label": "Sgrùdadh an aghaidh spama.\n<strong>NA</strong> lìon seo!",
        "pageinfo-title": "Fiosrachadh airson \"$1\"",
        "pageinfo-not-current": "Duilich, ach cha ghabh am fiosrachadh seo a thoirt seachad airson seann mhùthaidhean.",
        "pageinfo-header-basic": "Fiosrachadh bunasach",
index ae43f1e..bf2acf4 100644 (file)
        "morenotlisted": "Esta lista non está completa.",
        "mypage": "Páxina",
        "mytalk": "Conversa",
-       "anontalk": "Conversa con este enderezo IP",
+       "anontalk": "Conversa",
        "navigation": "Navegación",
        "and": "&#32;e",
        "qbfind": "Procurar",
        "contributions": "Contribucións {{GENDER:$1|do usuario|da usuaria}}",
        "contributions-title": "Contribucións de $1",
        "mycontris": "Contribucións",
+       "anoncontribs": "Contribucións",
        "contribsub2": "De {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "A conta de usuario \"$1\" non está rexistrada.",
        "nocontribs": "Non se deron atopado cambios con eses criterios.",
        "movenosubpage": "Esta páxina non ten subpáxinas.",
        "movereason": "Motivo:",
        "revertmove": "reverter",
-       "delete_and_move": "Borrar e mover",
        "delete_and_move_text": "== Cómpre borrar ==\nA páxina de destino, chamada \"[[:$1]]\", xa existe.\nQuérea borrar para deixar sitio para facer o traslado?",
        "delete_and_move_confirm": "Si, borrar a páxina",
        "delete_and_move_reason": "Eliminado para facer sitio para mover \"[[$1]]\"",
        "tooltip-pt-preferences": "As miñas preferencias",
        "tooltip-pt-watchlist": "A lista de páxinas cuxas modificacións está a seguir",
        "tooltip-pt-mycontris": "Lista das súas contribucións",
+       "tooltip-pt-anoncontribs": "Unha lista de modificacións feitas desde esta dirección IP",
        "tooltip-pt-login": "Recoméndaselle rexistrarse, se ben non é obrigatorio",
        "tooltip-pt-logout": "Saír ao anonimato",
        "tooltip-pt-createaccount": "Recoméndaselle crear unha conta e acceder ao sistema, se ben non é obrigatorio",
index 394f47f..28200bf 100644 (file)
@@ -20,7 +20,8 @@
                        "לערי ריינהארט",
                        "80686",
                        "아라",
-                       "Macofe"
+                       "Macofe",
+                       "Xð"
                ]
        },
        "tog-underline": "Links unterstryche:",
        "viewhelppage": "D Hilf aazeige",
        "categorypage": "Kategoriesyte aazeige",
        "viewtalkpage": "Diskussion",
-       "otherlanguages": "Anderi Sproche",
+       "otherlanguages": "In andere Sprooche",
        "redirectedfrom": "(Witergleitet vun $1)",
        "redirectpagesub": "Umgleiteti Syte",
        "redirectto": "Wyterleitig uf:",
        "movenosubpage": "Die Syte het kei Untersyte.",
        "movereason": "Grund:",
        "revertmove": "Zrugg verschiebe",
-       "delete_and_move": "Lösche un Verschiebe",
        "delete_and_move_text": "== D Ziilsyte isch scho vorhande, lösche?==\n\nD Syte „[[:$1]]“ gits scho. Wottsch du si lösche, zume Platz zum verschiebe mache?",
        "delete_and_move_confirm": "D Ziilsyte für d Verschiebig lösche",
        "delete_and_move_reason": "glöscht, zume Platz für s Verschiebe vo „[[$1]]“ z mache",
index a69a693..18fe01e 100644 (file)
        "morenotlisted": "רשימה זו אינה מלאה.",
        "mypage": "דף משתמש",
        "mytalk": "שיחה",
-       "anontalk": "×\93×£ ×\94ש×\99×\97×\94 ×¢×\91×\95ר ×\9bת×\95×\91ת IP ×\96×\95",
+       "anontalk": "ש×\99×\97×\94",
        "navigation": "ניווט",
        "and": "&#32;וגם",
        "qbfind": "חיפוש",
        "contributions": "תרומות {{GENDER:$1|המשתמש|המשתמשת}}",
        "contributions-title": "תרומות של ה{{GENDER:$1|משתמש|משתמשת}} $1",
        "mycontris": "תרומות",
+       "anoncontribs": "תרומות",
        "contribsub2": "עבור {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "החשבון \"$1\" אינו רשום.",
        "nocontribs": "לא נמצאו שינויים המתאימים לקריטריונים אלו.",
        "movenosubpage": "לדף זה אין דפי משנה.",
        "movereason": "סיבה:",
        "revertmove": "החזרה",
-       "delete_and_move": "מחיקה והעברה",
        "delete_and_move_text": "== בקשת מחיקה ==\nדף היעד, \"[[:$1]]\", כבר קיים.\nהאם ברצונך למחוק אותו כדי לאפשר את ההעברה?",
        "delete_and_move_confirm": "אישור מחיקת הדף",
        "delete_and_move_reason": "מחיקה כדי לאפשר העברה מהשם \"[[$1]]\"",
        "tooltip-pt-preferences": "ההעדפות שלך",
        "tooltip-pt-watchlist": "רשימת הדפים שאתם עוקבים אחרי השינויים בהם",
        "tooltip-pt-mycontris": "רשימת התרומות שלך",
+       "tooltip-pt-anoncontribs": "רשימת העריכות שנעשו מכתובת ה־IP הזאת",
        "tooltip-pt-login": "מומלץ להירשם, אך אין חובה לעשות כן",
        "tooltip-pt-logout": "יציאה מהחשבון",
        "tooltip-pt-createaccount": "מומלץ ליצור חשבון ולהיכנס אליו; עם זאת, זו אינה חובה",
index 51d6fa1..319a29f 100644 (file)
        "movenosubpage": "Ii panna me koi subpages nai hai.",
        "movereason": "Kaaran:",
        "revertmove": "purana copy pe lae jao",
-       "delete_and_move": "Mitao aur hatao",
        "delete_and_move_text": "== Mitae ke jaruri hai ==\nDestination panna \"[[:$1]]\" abhi hai.\nKa aap mangta hai ki iske mitae dewa jaae, jisse ki ii naam se duusra paana ke save karaa jaae sake?",
        "delete_and_move_confirm": "Haan, panna ke mitao",
        "delete_and_move_reason": "\"[[$1]]\" se move kare ke khatir isk mitaya",
index 2a2f2f7..e5edb1c 100644 (file)
        "wlnote": "Ovdje {{PLURAL:$1|je posljednja $1 promjena|su posljednje $1 promjene|je posljednjih $1 promjena}} u {{PLURAL:$2|posljednjem <strong>$2</strong> satu|posljednja '''$2''' sata|posljednjih <strong>$2</strong> sati}}, od $3, $4.",
        "wlshowlast": "Prikaži posljednjih $1 sati $2 dana",
        "watchlistall2": "sve",
+       "wlshowtime": "Prikaži posljednjih:",
+       "wlshowhideminor": "manje promjene",
+       "wlshowhidebots": "botove",
+       "wlshowhideliu": "prijavljene suradnike",
+       "wlshowhideanons": "neprijavljene suradnike",
+       "wlshowhidemine": "moje promjene",
        "watchlist-options": "Izbornik popisa praćenja",
        "watching": "Pratim...",
        "unwatching": "Prestajem pratiti...",
        "movenosubpage": "Ova stranica nema podstranica.",
        "movereason": "Razlog:",
        "revertmove": "vrati",
-       "delete_and_move": "Izbriši i premjesti",
        "delete_and_move_text": "==Nužno brisanje==\n\nOdredišni članak \"[[:$1]]\" već postoji. Želite li ga obrisati da biste napravili mjesto za premještaj?",
        "delete_and_move_confirm": "Da, izbriši stranicu",
        "delete_and_move_reason": "obrisano kako bi se napravilo mjesto za premještaj, stari naziv \"[[$1]]\"",
index 9862dfe..1e733cf 100644 (file)
        "movenosubpage": "Այս էջը ենթաէջեր չունի",
        "movereason": "Պատճառ.",
        "revertmove": "հետ շրջել",
-       "delete_and_move": "Ջնջել և տեղափոխել",
        "delete_and_move_text": "==Պահանջվում է ջնջում==\n\n«[[:$1]]» անվանմամբ էջ արդեն գոյություն ունի։ Ուզո՞ւմ եք այն ջնջել՝ տեղափոխումը իրականացնելու համար։",
        "delete_and_move_confirm": "Այո, ջնջել էջը",
        "delete_and_move_reason": "Ջնջված է՝ տեղափոխման տեղ ազատելու համար",
index 5be6bd8..1064dbc 100644 (file)
        "movenosubpage": "Iste pagina non ha subpaginas.",
        "movereason": "Motivo:",
        "revertmove": "reverter",
-       "delete_and_move": "Deler e renominar",
        "delete_and_move_text": "==Deletion requirite==\nLe pagina de destination \"[[:$1]]\" existe ja.\nEsque tu vole deler lo pro permitter le renomination?",
        "delete_and_move_confirm": "Si, deler le pagina",
        "delete_and_move_reason": "Delite pro permitter le renomination de \"[[$1]]\"",
index a147dc9..5e0fabc 100644 (file)
        "morenotlisted": "Daytoy a listaan ket saan a kompleto.",
        "mypage": "Panid",
        "mytalk": "Tungtungan",
-       "anontalk": "Tungtungan para iti daytoy a pagtaengan ti IP",
+       "anontalk": "Tungtungan",
        "navigation": "Pagdaliasatan",
        "and": "&#32;ken",
        "qbfind": "Biruken",
        "viewsource": "Kitaen ti taudan",
        "viewsource-title": "Kitaen ti taudan para iti $1",
        "actionthrottled": "Napabuntog ti aramid",
-       "actionthrottledtext": "Para iti pagkontra ti spam, naipatinggaka nga agramid iti daytoy a tignay iti adu unay a beses iti nasiket nga oras, ken nalabsamon daytoy a patingga.\nPangngaasi nga ipadasmo manen no madamdama.",
+       "actionthrottledtext": "Kas pangkontra iti spam, naipatinggaka nga agaramid iti daytoy a tignay iti adu unay a beses iti nabiit a panawen, ken nalabsamon daytoy a patingga.\nPangngaasi nga ipadasmo manen intono madamdama.",
        "protectedpagetext": "Nasalakniban daytoy a panid tapno mapawilan ti panagurnos wenno dagiti dadduma pay a tignay.",
        "viewsourcetext": "Mabalinmo a kitaen ken tuladen ti taudan daytoy a panid.",
        "viewyourtext": "Mabalinmo a makita ken tuladen ti taudan dagiti <strong>inurnosmo</strong> iti daytoy panid.",
        "passwordreset-emailtext-ip": "Adda (baka sika, ti naggapuan ti IP a pagtaengan $1) a nagkiddaw ti maysa a panangisaad manen ti kontrasenias para iti {{SITNAME}} ($4) . {{PLURAL:$3|Ti |Dagiti}} sumaganad a pakabilangan ti agar-aramat ket\nmainaig iti daytoy nga esurat a pagtaengan:\n\n$2\n\n{{PLURAL:$3|Daytoy temporario a kontrasenias|Dagitoy temporario a kontrasenias}} ket agpaso {{PLURAL:$5|iti maysa nga aldaw|kadagiti $5 nga aldaw}}.\nSumrekka koman tapno agpilika ti baro a kontraseniasmo tattan. No adda met sabali a nagaramid daytoy a \npanagkiddaw, wenno malagipmo ti dati a kontraseniasmo, ket saanmo a kayaten a sukatan, saanmo nga ikaskaso daytoy a mensahe ken \nagtuloyka nga agusar ti daan a kontrasenias.",
        "passwordreset-emailtext-user": "Daytoy nga agar-aramat $1 iti {{SITENAME}} ket nagkiddaw ti maysa a panangisaad manen ti bukod a kontrasenias para iti {{SITENAME}}\n($4) . {{PLURAL:$3|Ti|Dagiti}} sumaganad a pakabilangan ti agar-aramat ket\nmainaig iti daytoy nga esurat a pagtaengan:\n\n$2\n\n{{PLURAL:$3|Daytoy temporario a kontrasenias|Dagitoy temporario a kontrasenias}} ket agpaso {{PLURAL:$5|iti maysa nga aldaw|kadagiti $5 nga aldaw}}.\nSumrekka koman tapno agpilika ti baro a kontraseniasmo tattan. No adda met sabali a nagaramid daytoy a \npanagkiddaw, wenno malagipmo ti dati a kontraseniasmo, ken saanmo a kayaten a sukatan, saanmo nga ikaskaso daytoy a mensahe ken \nagtuloykan nga agusar ti daan a kontraseniasmo.",
        "passwordreset-emailelement": "Nagan ti agar-aramat: \n$1\n\nTemporario a kontrasenias: \n$2",
-       "passwordreset-emailsent": "Ti maysa nga esurat ti panangisaad manen ti kontrasenias ket naipatuloden.",
+       "passwordreset-emailsent": "No daytoy ket nairehistro nga adres ti esurat para iti pakabilangam, maipatulodto ti maysa nga esurat iti panangisaad manen ti kontrasenias.",
        "passwordreset-emailsent-capture": "Ti maysa nga esurat ti panangisaad manen ti kontrasenias ket naipatuloden, a naipakita dita baba.",
        "passwordreset-emailerror-capture": "Naaramid ti maysa nga esurat a panangisaad manen ti kontrasenias, a napaikita dita baba, ngem ti panangitulod kenni {{GENDER:$2|agar-aramat}} ket napaay: $1",
-       "changeemail": "Sukatan ti esurat a pagtaengan",
-       "changeemail-header": "Sukatan ti esurat a pagtaengan ti pakabilangan",
+       "changeemail": "Sukatan wenno ikkaten ti adres ti esurat",
+       "changeemail-header": "Kompletuen daytoy a porma tapno masukatan ti adres ti esuratmo. No kayatmo a maikkat ti pannakainaig iti ania man nga adres ti esurat manipud iti pakabilangam, ibati a blanko ti baro nga adres ti esurat no ited ti porma.",
+       "changeemail-passwordrequired": "Masapulmonto nga ikabil ti kontraseniasmo tapno mapasingkedan daytoy a panagbaliw.",
        "changeemail-no-info": "Masapul a nakastrekka tapno dagus a makapan iti ditoy a panid.",
        "changeemail-oldemail": "Agdama nga esurat a pagtaengan:",
        "changeemail-newemail": "Baro nga esurat a pagtaengan:",
+       "changeemail-newemail-help": "Daytoy a pagikabilan ket nasken a blanko no kayatmo a maikkat ti adres ti esuratmo. Saanmonto a mabalin ti mangisaad manen ti nalipatan a kontrasenias ken saankanto a makaawat kadagiti esurat manipud iti daytoy a wiki no maikkat ti adres ti esurat.",
        "changeemail-none": "(awan)",
        "changeemail-password": "Ti bukodmo a kontrasenias ti {{SITENAME}}:",
        "changeemail-submit": "Sukatan ti esurat",
        "sig_tip": "Ti pirmam nga addaan iti oras ken petsa",
        "hr_tip": "Horisontal a linia (manmano laeng nga aramaten)",
        "summary": "Pakabuklan:",
-       "subject": "Suheto/paulo:",
+       "subject": "Suheto:",
        "minoredit": "Daytoy ket bassit a panagurnos",
        "watchthis": "Bantayan daytoy a panid",
        "savearticle": "Idulin ti panid",
        "missingsummary": "<strong>Palagip:</strong> Saanka a nakaited iti pakabuklan ti panagurnos.\nNo pindutem manen ti \"{{int:savearticle}}\", maidulin ti inurnosmo nga awan ti pakabuklanna.",
        "selfredirect": "<strong>Ballaag:</strong> Ibawbaw-ingmo daytoy a panid iti isu met laeng a panid.\nMabalinmo nga innaganan ti kamali a puntaan para iti baw-ing, wenno mabalin nga ur-urnosem ti kamali a panid.\nNo pindutem manen ti \"{{int:savearticle}}\" , mapartuatto lattan ti baw-ing.",
        "missingcommenttext": "Pangngaasi nga agikabil ti komentario dita baba.",
-       "missingcommentheader": "<strong>Palagip:</strong> Saanka a nakaited iti suheto/paulo para iti daytoy a komentario.\nNo pindutem manen ti \"{{int:savearticle}}\", maidulin ti inurnosmo nga awan ti pakabuklanna.",
+       "missingcommentheader": "<strong>Palagip:</strong> Saanka pay a nakaited iti suheto para iti daytoy a komentario.\nNo pindutem manen ti \"{{int:savearticle}}\", maidulin ti inurnosmo nga awan ti pakabuklanna.",
        "summary-preview": "Naipadas a pakabuklan:",
-       "subject-preview": "Suheto/naipadas a paulo:",
+       "subject-preview": "Naipadas a suheto:",
        "previewerrortext": "Adda napasamak a maysa a biddut bayat a nagpadpadas kadagiti binawbaliwam.",
        "blockedtitle": "Naseraan ti agar-aramat",
        "blockedtext": "<strong>Naseraan ti naganmo nga agar-aramat wenno ti IP a pagtaengam.</strong>\n\nTi serra ket inaramid babaen ni $1. \nTi rason a naited ket <em>$2</em>.\n\n* Rugi ti serra: $8\n* Panagpaso ti serra: $6\n* Naikeddeng a serraanna: $7\n\nMabalinmo a kontaken ni $1 wenno sabali pay nga [[{{MediaWiki:Grouppage-sysop}}|administrador]] no kayatmo a maipalawag daytoy a panagserra.\nDimo mabalin nga aramaten ti ramit nga esuratan daytoy nga agar-aramat malaksid no adda napudno nga esurat a pagtaengan a nainaganan iti [[Special:Preferences|pakabilangan ti kakaykayatm]] ken no saanka a naparitan nga agaramat iti daytoy.\nTi agdama nga IP a pagtaengam ket $3, ti naserraan nga ID ket #$5. \nPangngaasi nga iramanmo amin dagiti salaysay dita ngato kadagiti ania man nga aramidem nga usisa.",
        "permissionserrors": "Biddut ti pammalubos",
        "permissionserrorstext": "Awan ti pammalubosmo nga agaramid iti dayta, gapu ti sumaganad {{PLURAL:$1|a rason|a rasrason}}:",
        "permissionserrorstext-withaction": "Awan ti pammalubosmo nga $2, gapu ti sumaganad a {{PLURAL:$1|rason|rasrason}}:",
+       "contentmodelediterror": "Saanmo a maurnos daytoy a rebision gapu ta ti modelo ti linaon ket <code>$1</code>, ken ti agdama a linaon ti panid ket <code>$2</code>.",
        "recreate-moveddeleted-warn": "<strong>Ballaag: Agparpartuatka manen ti dati a naikkat a panid.</strong>\n\nUsigem koma no maitutop ti agtuloy nga agurnos iti daytoy a panid.\nTi listaan ti pannakaikkat ken pannakaiyalis para iti daytoy a panid ket naited ditoy para iti pakainugotan:",
        "moveddeleted-notice": "Naikkaten daytoy a panid.\nTi listaan ti pannakaikkat ken pannakaiyalis para iti panid ket naited dita baba para iti reperensia.",
        "moveddeleted-notice-recent": "Pasensian, daytoy a panid ket kaik-ikkat idi (iti kaunegan dagiti 24 nga oras).\nTi listaan ti pannakaikkat ken pannakaiyalis para iti panid ket naited dita baba para iti reperensia.",
        "mergehistory-go": "Ipakita dagiti mabalin a maitipon a panagurnos",
        "mergehistory-submit": "Pagtitiponen dagiti rebision",
        "mergehistory-empty": "Awan dagiti rebision ti mabalin nga itipon.",
-       "mergehistory-done": "$3 {{PLURAL:$3|a rebision|dagiti rebision}} iti $1 ket nagballigi a naitipon iti [[:$2]].",
+       "mergehistory-done": "$3 {{PLURAL:$3|a rebision|dagiti rebision}} iti $1 ket {{PLURAL:$3|naitipon|naitiponda}} iti [[:$2]].",
        "mergehistory-fail": "Saan a nakaaramid ti panagtipon ti pakasaritaan, pangngaasi a kitaen ti panid ken dagiti parametro ti oras.",
        "mergehistory-fail-toobig": "Di naaramid ti panagtipon ti pakasaritaan gapu ta ad-adu ti patingga ti $1 {{PLURAL:$1|a rebision|kadagiti rebision}} ti maiyalisto.",
        "mergehistory-no-source": "Awan ti taudan ti panid ti $1.",
        "showingresultsinrange": "Mangipakpakita aginggana {{PLURAL:$1|iti <strong>1</strong> a resulta|dagiti <strong>$1</strong> a resulta}} iti sakop ti #<strong>$2</strong> aginggana iti #<strong>$3</strong>.",
        "search-showingresults": "{{PLURAL:$4|Nagbanagan a <strong>$1</strong> iti <strong>$3</strong>|Dagiti nagbanagan a <strong>$1 - $2</strong> iti <strong>$3</strong>}}",
        "search-nonefound": "Awan dagiti nagbanagan a maipada iti usisa.",
+       "search-nonefound-thiswiki": "Awan dagiti resulta a maipada iti panagusisa iti daytoy a sitio.",
        "powersearch-legend": "Napasayat a panagbiruk",
        "powersearch-ns": "Agbiruk kadagiti nagan ti espasio:",
        "powersearch-togglelabel": "Markaan:",
        "prefs-watchlist-token": "Tandaan ti listaan ti bambantayan:",
        "prefs-misc": "Sabsabali",
        "prefs-resetpass": "Sukatan ti kontrasenias",
-       "prefs-changeemail": "Sukatan ti esurat a pagtaengan",
+       "prefs-changeemail": "Sukatan wenno ikkaten ti adres ti esurat",
        "prefs-setemail": "Isaad ti esurat a pagtaengan",
        "prefs-email": "Dagiti pagpilian ti esurat",
        "prefs-rendering": "Tabas",
        "prefs-help-recentchangescount": "Daytoy ket mangiraman iti kaudian a balbaliw, dagiti pakasaritaan ti panid, ken dagiti listaan.",
        "prefs-help-watchlist-token2": "Daytoy ti sekreto a tulbek iti pakan ti web iti listaan ti bambantayam.\nTi sinoman a makaammo daytoy ket mabalinda a basaen ti listaan ti bambantayam, isu a saanmo nga ipabingay.\nNo masapulmo, [[Special:ResetTokens|mabalinmo nga isaad manen]].",
        "savedprefs": "Naidulinen dagiti kakaykayatam.",
+       "savedrights": "Naidulinen dagiti karbengan ti agar-aramat ni {{GENDER:$1|$1}}.",
        "timezonelegend": "Sona ti oras:",
        "localtime": "Lokal nga oras:",
        "timezoneuseserverdefault": "Usaren ti kasisigud ti wiki ($1)",
        "recentchanges-page-added-to-category-bundled": "nainayon ti [[:$1]] ken {{PLURAL:$2|maysa a panid|$2 a pampanid}} iti kategoria",
        "recentchanges-page-removed-from-category": "naikkat ti [[:$1]] manipud iti kategoria",
        "recentchanges-page-removed-from-category-bundled": "Naikkat ti [[:$1]] ken {{PLURAL:$2|maysa a panid|$2 a pampanid}} manipud iti kategoria",
+       "autochange-username": "Automatiko a panagbaliw iti MediaWiki",
        "upload": "Agikarga iti papeles",
        "uploadbtn": "Agikarga iti papeles",
        "reuploaddesc": "Ukasen ti panagikarga ken agsubli idiay porma ti panagikarga",
        "upload-form-label-infoform-description": "Deskripsion",
        "upload-form-label-usage-title": "Panagusar",
        "upload-form-label-usage-filename": "Nagan ti papeles",
+       "foreign-structured-upload-form-label-own-work": "Daytoy ket bukodko nga obra",
+       "foreign-structured-upload-form-label-infoform-categories": "Katkategoria",
+       "foreign-structured-upload-form-label-infoform-date": "Petsa",
        "backend-fail-stream": "Saan a maipan ti papeles $1.",
        "backend-fail-backup": "Saan a makaidulin ti kapada ti papeles ti $1.",
        "backend-fail-notexists": "Awan ti papeles ti $1.",
        "wlnote": "Dita baba ket {{PLURAL:$1|naudi a sinukatan|dagiti naudi a <strong>$1</strong> a sinukatan}} iti napalabas {{PLURAL:$2|nga oras|a <strong>$2</strong> nga or-oras}}, manipud idi $3, $4.",
        "wlshowlast": "Ipakita dagiti naudi a $1 nga or-oras $2 nga al-aldaw",
        "watchlistall2": "amin",
+       "watchlist-hide": "Ilemmeng",
+       "wlshowtime": "Ipakita ti naudi:",
+       "wlshowhideminor": "dagiti bassit a panagurnos",
+       "wlshowhidebots": "dagiti bot",
+       "wlshowhideliu": "dagiti nakarehistro nga agar-aramat",
+       "wlshowhideanons": "dagiti di ammo nga agar-aramat",
+       "wlshowhidepatr": "dagiti napatrulian a panagurnos",
+       "wlshowhidemine": "dagiti inurnosko",
        "watchlist-options": "Dagiti pagpilian ti listaan a bambantayan",
        "watching": "Bambantayan...",
        "unwatching": "Saanen a bantayan...",
        "contributions": "Dagiti kontribusion ti {{GENDER:$1|agar-aramat}}",
        "contributions-title": "Kontribusion ti agar-aramat para kenni $1",
        "mycontris": "Inar-aramid",
+       "anoncontribs": "Dagiti inar-aramid",
        "contribsub2": "Para kenni {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Ti pakabilangan ti agar-aramat ni \"$1\" ket saan a nakarehistro.",
        "nocontribs": "Awan ti nasarakan a nasukatan a kapada dagitoy a kriteria.",
        "cant-move-to-user-page": "Awan ti pammalubosmo nga agiyalis ti panid iti panid ti agar-aramat (malaksid kadagiti subpanid ti agar-aramat).",
        "cant-move-category-page": "Awan ti pammalubosmo nga agiyalis kadagiti panid ti kategoria.",
        "cant-move-to-category-page": "Awan ti pammalubosmo nga agiyalis ti panid iti panid ti kategoria.",
-       "newtitle": "Iti baro a titulo:",
+       "newtitle": "Baro a titulo:",
        "move-watch": "Bantayan ti taudan a panid ken puntaan a panid",
        "movepagebtn": "Iyalis ti panid",
        "pagemovedsub": "Balligi ti panangiyalis",
        "movenosubpage": "Daytoy a panid ket awan ti subpanidna.",
        "movereason": "Rason:",
        "revertmove": "isubli",
-       "delete_and_move": "Ikkaten ken iyalis",
        "delete_and_move_text": "== Masapul nga ikkaten ==\nTi pangipanan ti panid ket \"[[:$1]]\" addan.\nKayatmo nga ikkaten tapno makaiyaliska?",
        "delete_and_move_confirm": "Wen, ikkaten ti panid",
        "delete_and_move_reason": "Naikkat tapno mawayaan ti pannaka-iyalis manipud ti \"[[$1]]\"",
        "tooltip-pt-preferences": "Dagiti kakaykayatam",
        "tooltip-pt-watchlist": "Listaan dagiti panid a sipsiputem para iti pannakabalbaliw",
        "tooltip-pt-mycontris": "Ti listaan dagiti kontribusionmo",
+       "tooltip-pt-anoncontribs": "Ti listaan dagiti panagurnos manipud iti daytoy nga adres ti IP",
        "tooltip-pt-login": "Maaw-awis a sumrekka; nupay kasta, daytoy ket saan a nasken",
        "tooltip-pt-logout": "Rummuar",
        "tooltip-pt-createaccount": "Maaw-awis nga agpartuatka iti pakabilangan ken sumrek; nupay kasta, daytoy ket saan a nasken",
index 69547f4..2ae8f63 100644 (file)
        "nstab-template": "Snið",
        "nstab-help": "Hjálp",
        "nstab-category": "Flokkur",
+       "mainpage-nstab": "Forsíða",
        "nosuchaction": "Aðgerð ekki til",
        "nosuchactiontext": "Aðgerðin sem veffangið tilgreinir þekkir er ekki þekkt af wiki\nÞú gætir haft slegið inn vefslóðina vitlaust eða fylgt eftir röngum tengli.\nÞetta gæti einnig verið villa í hugbúnaðinum sem er notuð á {{SITENAME}}.",
        "nosuchspecialpage": "Kerfissíðan er ekki til",
        "movenosubpage": "Þessi síða hefur engar undirsíður.",
        "movereason": "Ástæða:",
        "revertmove": "taka til baka",
-       "delete_and_move": "Eyða og flytja",
        "delete_and_move_text": "==Beiðni um eyðingu==\n\nSíðan „[[:$1]]“ er þegar til. Viltu eyða henni til þess að rýma til fyrir flutningi?",
        "delete_and_move_confirm": "Já, eyða síðunni",
        "delete_and_move_reason": "Eytt til að rýma til fyrir flutning frá \"[[$1]]\"",
        "tooltip-ca-nstab-main": "Sýna síðuna",
        "tooltip-ca-nstab-user": "Sýna notandasíðuna",
        "tooltip-ca-nstab-media": "Sýna margmiðlunarsíðuna",
-       "tooltip-ca-nstab-special": "Þetta er kerfissíða, þér er óhæft að breyta henni.",
+       "tooltip-ca-nstab-special": "Þetta er kerfissíða, það er ekki hægt að breyta henni.",
        "tooltip-ca-nstab-project": "Sýna verkefnasíðuna",
        "tooltip-ca-nstab-image": "Sýna skráarsíðu",
        "tooltip-ca-nstab-mediawiki": "Sýna kerfisskilaboðin",
index 8694ca5..2f3a858 100644 (file)
        "morenotlisted": "Questo elenco non è completo.",
        "mypage": "Pagina",
        "mytalk": "discussioni",
-       "anontalk": "Discussioni per questo IP",
+       "anontalk": "discussioni",
        "navigation": "Navigazione",
        "and": "&#32;e",
        "qbfind": "Trova",
        "contributions": "Contributi {{GENDER:$1|utente}}",
        "contributions-title": "Contributi di $1",
        "mycontris": "contributi",
+       "anoncontribs": "contributi",
        "contribsub2": "Per {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "L'utenza \"$1\" non è registrata.",
        "nocontribs": "Non sono state trovate modifiche che soddisfino i criteri di ricerca.",
        "movenosubpage": "Questa pagina non ha sottopagine.",
        "movereason": "Motivo:",
        "revertmove": "ripristina",
-       "delete_and_move": "Cancella e sposta",
        "delete_and_move_text": "==Cancellazione richiesta==\n\nLa pagina specificata come destinazione \"[[:$1]]\" esiste già. Vuoi cancellarla per proseguire con lo spostamento?",
        "delete_and_move_confirm": "Sì, sovrascrivi la pagina esistente",
        "delete_and_move_reason": "Cancellata per rendere possibile lo spostamento da \"[[$1]]\"",
        "tooltip-pt-preferences": "Le tue preferenze",
        "tooltip-pt-watchlist": "La lista delle pagine che stai tenendo sotto osservazione",
        "tooltip-pt-mycontris": "La lista dei tuoi contributi",
+       "tooltip-pt-anoncontribs": "Un elenco delle modifiche fatte da questo indirizzo IP",
        "tooltip-pt-login": "Si consiglia di effettuare l'accesso, anche se non è obbligatorio",
        "tooltip-pt-logout": "Uscita (logout)",
        "tooltip-pt-createaccount": "Si consiglia di registrarsi e di effettuare l'accesso, anche se non è obbligatorio",
        "exif-datetimeexpires": "Non utilizzare dopo",
        "exif-datetimereleased": "Rilasciato il",
        "exif-originaltransmissionref": "Codice del luogo di trasmissione originaria",
-       "exif-identifier": "Identificativo",
+       "exif-identifier": "Identificatore",
        "exif-lens": "Obiettivo utilizzato",
        "exif-serialnumber": "Numero di serie della fotocamera",
        "exif-cameraownername": "Proprietario della macchina fotografica",
index 7d17c1e..b969407 100644 (file)
        "morenotlisted": "この一覧は完全ではありません。",
        "mypage": "ページ",
        "mytalk": "トーク",
-       "anontalk": "このIPアドレスについての議論",
+       "anontalk": "議論",
        "navigation": "案内",
        "and": "&#32;と",
        "qbfind": "検索",
        "rev-suppressed-unhide-diff": "この差分の一方の版は<strong>秘匿されています</strong>。\n[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 秘匿記録]に詳細情報があるかもしれません。\nこのまま[$1 この差分を閲覧]できます。",
        "rev-deleted-diff-view": "この差分の一方の版は<strong>削除されています</strong>。\nこの差分を閲覧できます。[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 削除記録]に詳細情報があるかもしれません。",
        "rev-suppressed-diff-view": "この差分の一方の版は<strong>秘匿されています</strong>。\nこの差分を閲覧できます。[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 秘匿記録]に詳細情報があるかもしれません。",
-       "rev-delundel": "表示/非表示 の変更",
+       "rev-delundel": "閲覧レベルの変更",
        "rev-showdeleted": "表示",
        "revisiondelete": "版の削除と復元",
        "revdelete-nooldid-title": "無効な対象の版",
        "movenosubpage": "このページに下位ページはありません。",
        "movereason": "理由:",
        "revertmove": "差し戻し",
-       "delete_and_move": "削除して移動",
        "delete_and_move_text": "== 削除が必要です ==\n移動先「[[:$1]]」は既に存在します。\n移動のためにこのページを削除しますか?",
        "delete_and_move_confirm": "はい、ページを削除します",
        "delete_and_move_reason": "「[[$1]]」からの移動のために削除",
        "tags-create-warnings-below": "このタグの作成を続けますか?",
        "tags-delete-title": "タグを削除",
        "tags-delete-explanation-initial": "あなたはタグ「$1」をデータベースから削除しようとしています。",
-       "tags-delete-explanation-in-use": "ç\8f¾å\9c¨é\81©ç\94¨ã\81\95ã\82\8cã\81¦ã\81\84ã\82\8b{{PLURAL:$2|ç\89\88ã\82\84è¨\98é\8c²é \85ç\9b® $2 ä»¶}}ã\82\92å\89\8aé\99¤ã\81\97ます。",
+       "tags-delete-explanation-in-use": "ç\8f¾å\9c¨é\81©ç\94¨ã\81\95ã\82\8cã\81¦ã\81\84ã\82\8b{{PLURAL:$2|ç\89\88ã\82\84è¨\98é\8c²é \85ç\9b® $2 ä»¶}}ã\81\8bã\82\89å\89\8aé\99¤ã\81\95ã\82\8cます。",
        "tags-delete-explanation-warning": "この操作は<strong>元に戻せず</strong>、データベース管理者をもってしても<strong>取り消しは不可能</strong>です。削除するタグとして間違いがないことをもう一度しっかり確認してください。",
        "tags-delete-explanation-active": "<strong>タグ「$1」はまだ有効であり、今後も付与され続けます。</strong>これを止めるには、タグが付与されるよう設定されているところに行き、そこで無効化してください。",
        "tags-delete-reason": "理由:",
        "logentry-suppress-reblock": "$1 が {{GENDER:$4|$3}} のブロックの期限を$5に{{GENDER:$2|変更しました}} $6",
        "logentry-import-upload": "$1 がファイルをアップロードして $3 を{{GENDER:$2|インポートしました}}",
        "logentry-import-interwiki": "$1 が他のウィキから $3 を{{GENDER:$2|インポートしました}}",
+       "logentry-import-interwiki-details": "$1 が $3 を $5 から{{GENDER:$2|取り込み}}ました ($4 {{PLURAL:$4|版}})",
        "logentry-merge-merge": "$1{{GENDER:$2|統合元}} と$3を$4に統合(改訂版を$5に掲載)",
        "logentry-move-move": "$1 がページ「$3」を「$4」に{{GENDER:$2|移動しました}}",
        "logentry-move-move-noredirect": "$1 がページ「$3」を「$4」に、リダイレクトを残さずに{{GENDER:$2|移動しました}}",
        "logentry-managetags-activate": "$1 がタグ \"$4\" の利用者およびボットによる使用を{{GENDER:$2|有効化しました}}。",
        "logentry-managetags-deactivate": "$1 がタグ \"$4\" の利用者およびボットによる使用を{{GENDER:$2|無効化しました}}。",
        "log-name-tag": "タグ記録",
-       "log-description-tag": "このページには、個々の版またはエントリーの記録から、利用者を追加または削除した[[Special:Tags|タグ]]が表示されます。編集の一部、削除、同様の操作として発生したときの操作はタグ付けされず、記録には表示されません。",
+       "log-description-tag": "このページには、個々の版または記録項目から、いつ利用者が[[Special:Tags|タグ]]を追加または削除したかが記録されます。編集、削除、または同様の操作の一部として発生したタグ付けは記録には表示されません。",
        "logentry-tag-update-add-revision": "$1 がページ $3 の版 $4 に{{PLURAL:$7|タグ}} $6 を{{GENDER:$2|追加しました}}",
        "logentry-tag-update-add-logentry": "$1 がページ $3 の記録項目 $5 に{{PLURAL:$7|タグ}} $6 を{{GENDER:$2|追加しました}}",
        "logentry-tag-update-remove-revision": "$1 がページ $3 の版 $4 から{{PLURAL:$9|タグ}} $8 を{{GENDER:$2|除去しました}}",
        "logentry-tag-update-remove-logentry": "$1 がページ $3 の記録項目 $5 から{{PLURAL:$9|タグ}} $8 を{{GENDER:$2|除去しました}}",
        "logentry-tag-update-revision": "$1 がページ「$3」の版 $4 でのタグを{{GENDER:$2|更新しました}} ($6 が{{PLURAL:$7|追加}}、$8 が{{PLURAL:$9|削除}})",
-       "logentry-tag-update-logentry": "$1 がページ「$3」のエントリー $5 での記録のタグを{{GENDER:$2|更新しました}} ($6 が{{PLURAL:$7|追加}}、$8 が{{PLURAL:$9|削除}})",
+       "logentry-tag-update-logentry": "$1 がページ「$3」の記録項目 $5 のタグを{{GENDER:$2|更新しました}} ($6 を{{PLURAL:$7|追加}}、$8 を{{PLURAL:$9|削除}})",
        "rightsnone": "(なし)",
        "revdelete-summary": "編集内容の要約",
        "feedback-adding": "ページへのフィードバックの追加...",
index cb9f721..3e2c6e7 100644 (file)
@@ -20,6 +20,7 @@
        "tog-hideminor": "Жуықтағы өзгерістерден шағын өңдемелерді жасыру",
        "tog-hidepatrolled": "Тексерілген өңдеулерді жуықтағы өзгерістер тізімінде көрсетпеу",
        "tog-newpageshidepatrolled": "Тексерілген беттерді жаңа беттер тізімінде жасыру",
+       "tog-hidecategorization": "Беттерді санаттауларды жасыру",
        "tog-extendwatchlist": "Бақылау тізімді ұлғайтып барлық өзгерістерді көрсету, ең соңғыларды ғана емес",
        "tog-usenewrc": "Жуықтағы өзгерістер және бақылау тізімінде беті бойынша өзгерістерді топтау",
        "tog-numberheadings": "Мазмұн тақырыптарын автоматты нөмірлеу",
@@ -49,6 +50,7 @@
        "tog-watchlisthideliu": "Бақылау тізіміндегі кірген қатысушылардың өңдеулерін көрсетпеу",
        "tog-watchlisthideanons": "Бақылау тізіміндегі аноним қатысушылардың өңдеулерін көрсетпеу",
        "tog-watchlisthidepatrolled": "Бақылау тізімінде тексерілген өңдеулерді көрсетпеу",
+       "tog-watchlisthidecategorization": "Беттерді санаттауларды жасыру",
        "tog-ccmeonemails": "Басқа қатысушыға жіберген хатымның есесін өзіме жөнелту",
        "tog-diffonly": "Нұсқалар айырмашылықтарының астында бет мағлұматын көрсетпеу",
        "tog-showhiddencats": "Жасырын санаттарды көрсету",
        "prefs-watchlist-token": "Бақылау тізімінің белгісі:",
        "prefs-misc": "Әрқилы",
        "prefs-resetpass": "Құпия сөзді өзгерту",
-       "prefs-changeemail": "E-mail мекен-жайын өзгерту",
+       "prefs-changeemail": "E-mail мекенжайын өзгерту немесе алып тастау",
        "prefs-setemail": "E-mail мекен-жайын жөндеу",
        "prefs-email": "Е-пошта баптаулары",
        "prefs-rendering": "Сырт көрініс",
        "rows": "Жолдар:",
        "columns": "Бағандар:",
        "searchresultshead": "Іздеу",
-       "stub-threshold": "<a href=\"#\" class=\"stub\">Бастама сілтемесін</a> пішімдеу табалдырығы (байт):",
+       "stub-threshold": "Бастама сілтемесін пішімдеу табалдырығы ($1):",
        "stub-threshold-sample-link": "қарапайым",
        "stub-threshold-disabled": "Ажыратылған",
        "recentchangesdays": "Жуықтағы өзгерістерде көрсетілетін күн саны:",
        "right-hideuser": "Баршадан жасырып, қатысушы атын бұғаттау",
        "right-ipblock-exempt": "IP бұғаттауларды, өзбұғаттауларды және ауқым бұғаттауларды орағыту",
        "right-proxyunbannable": "Прокси серверлердің өзбұғаттауларын орағыту",
-       "right-unblockself": "Бұғаттаудан шығару",
+       "right-unblockself": "Өзін бұғатынан шығару",
        "right-protect": "Қорғау деңгейлерін өзгерту және баулы-қорғаулы беттерді өңдеу",
        "right-editprotected": "Қорғалған беттерді өңдеу \"{{int:protect-level-sysop}}\"",
        "right-editsemiprotected": "Қорғалған беттерді өңдеу \"{{int:protect-level-autoconfirmed}}\"",
        "action-mergehistory": "Бұл беттің өзгеріс тарихын қосу",
        "action-userrights": "Қатысушылардың барлық құқықтарын өзгерту",
        "action-userrights-interwiki": "Басқа уикилердегі қатысушылардың құқықтарын өзгерту",
-       "action-siteadmin": "Дерекқорды бұғаттау немесе бұғаттан шығару",
+       "action-siteadmin": "Дерекқорды құлыптау және құлыптауын өшіру",
        "action-sendemail": "электронды хаттарды жіберу",
        "action-editmywatchlist": "бақылауыңызды өңдеу",
        "action-viewmywatchlist": "бақылау тізіміңізді қарау",
        "rcshowhidemine": "Өңдемелерімді $1",
        "rcshowhidemine-show": "көрсету",
        "rcshowhidemine-hide": "жасыру",
+       "rcshowhidecategorization": "Бет санаттауларын $1",
+       "rcshowhidecategorization-show": "Көрсету",
+       "rcshowhidecategorization-hide": "Жасыру",
        "rclinks": "Соңғы $2 күнде болған соңғы $1 өзгерісті көрсет<br />$3",
        "diff": "айырм",
        "hist": "тарихы",
        "recentchangeslinked-page": "Бет атауы:",
        "recentchangeslinked-to": "Керісінше, келтірілген бетке сілтейтін беттердегі өзгерістерді көрсет",
        "recentchanges-page-added-to-category": "[[:$1]] бетіне санат қосты",
+       "autochange-username": "МедиаУики өздікті өзгерісі",
        "upload": "Файл жүктеу",
        "uploadbtn": "Файлды жүктеу",
        "reuploaddesc": "Жүктеу пішініне қайта келу.",
        "wlnote": "Төменде $3, $4 кезіне дейінгі соңғы {{PLURAL:$2|сағатта|<strong>$2</strong>  сағатта}} болған, {{PLURAL:$1|жуықтағы өзгеріс|жуықтағы <strong>$1</strong>  өзгеріс}} көрсетіледі.",
        "wlshowlast": "Соңғы $1 сағаттағы, $2 күндегіні көрсету",
        "watchlistall2": "барлық",
+       "watchlist-hide": "Жасыру",
+       "wlshowtime": "Соңғысын көрсету:",
+       "wlshowhideminor": "шағын өңдемелер",
+       "wlshowhidebots": "боттар",
+       "wlshowhideliu": "тіркелген қатысушылар",
+       "wlshowhideanons": "анонимді қатысушылар",
+       "wlshowhidepatr": "тексерілген өңдемелер",
+       "wlshowhidemine": "өңдемелерім",
        "watchlist-options": "Бақылау тізімінің баптаулары",
        "watching": "Бақылауда…",
        "unwatching": "Бақыламауда…",
        "deletepage": "Бетті жою",
        "confirm": "Құптау",
        "excontent": "болған мағлұматы: $1",
-       "excontentauthor": "болған мағлұматы (тек «[[Special:Contributions/$2|$2]]» үлесі): $1",
+       "excontentauthor": "болған мағлұматы: «$1» және тек «[[Special:Contributions/$2|$2]]» ([[User talk:$2|талқ]]) үлесі",
        "exbeforeblank": "тазарту алдындағы болған мағлұматы: $1",
        "delete-confirm": "«$1» дегенді жою",
        "delete-legend": "Жою",
        "ipblocklist-empty": "Бұғаттау тізімі бос.",
        "ipblocklist-no-results": "Сұратылған IP мекенжай немесе қатысушы аты бұғатталмаған.",
        "blocklink": "бұғаттау",
-       "unblocklink": "бұғатынан шығару",
+       "unblocklink": "бұғатынан босату",
        "change-blocklink": "бұғаттауын өзгерту",
        "contribslink": "үлесі",
        "emaillink": "хат жіберу",
        "cant-move-to-user-page": "Бетті қатысушы бетіне жылжытуға рұқсатыңыз жоқ (төменгі беттерін қоспағанда).",
        "cant-move-category-page": "Сізде санат беттерінің атауын өзгертуге рұқсатыңыз жоқ.",
        "cant-move-to-category-page": "Сізде бетті санат бетіне жылжытуға рұқсатыңыз жоқ.",
-       "newtitle": "Ð\96аңа Ð±ÐµÑ\82 Ð°Ñ\82аÑ\83Ñ\8b:",
+       "newtitle": "Жаңа атауы:",
        "move-watch": "Бұл бетті бақылау",
        "movepagebtn": "Бетті жылжыту",
        "pagemovedsub": "Бет жылжытылды",
        "movenosubpage": "Бұл бетте төменгі беттері жоқ.",
        "movereason": "Жылжытудың себебі:",
        "revertmove": "қайтару",
-       "delete_and_move": "Жою және жылжыту",
        "delete_and_move_text": "== Жоюды қажет етеді ==\nТағайындалған «[[:$1]]» беті әлдеқашан бар.\nЖылжытуға жол беру үшін бұны жойғыңыз келе ме?",
        "delete_and_move_confirm": "Иә, бұл бетті жой",
        "delete_and_move_reason": "«[[$1]]» дегеннен жылжытуға жол беру үшін жойылған",
        "tooltip-ca-nstab-main": "Мағлұмат бетін қарау",
        "tooltip-ca-nstab-user": "Қатысушы бетін қарау",
        "tooltip-ca-nstab-media": "Медиа бетін қарау",
-       "tooltip-ca-nstab-special": "Ð\91ұл Ð°Ñ\80найÑ\8b Ð±ÐµÑ\82, Ð±ÐµÑ\82Ñ\82Ñ\96Ò£ Ó©Ð·Ñ\96 Ó©Ò£Ð´ÐµÐ»Ñ\96нбейді.",
+       "tooltip-ca-nstab-special": "Ð\91ұл Ð°Ñ\80найÑ\8b Ð±ÐµÑ\82, Ð¾Ð» Ó©Ò£Ð´ÐµÐ»Ð¼ейді.",
        "tooltip-ca-nstab-project": "Жоба бетін қарау",
        "tooltip-ca-nstab-image": "Файл бетін қарау",
        "tooltip-ca-nstab-mediawiki": "Жүйе хабарын қарау",
        "logentry-newusers-byemail": "$1 $3 деген аккаунт {{GENDER:$2|тіркеді}} және құпия сөзі е-пошта арқылы жіберілді",
        "logentry-newusers-autocreate": "$1 қатысушы аккаунтын автоматты түрде {{GENDER:$2|тіркеді}}",
        "logentry-protect-move_prot": "$1 protection settings from $4 дегеннен $3 дегенге қорғалу баптауларын {{GENDER:$2|жылжытты}}",
+       "logentry-protect-protect": "$1 $3 бетін {{GENDER:$2|қорғады}}  $4",
        "logentry-rights-rights": "$1 $3 үшін топ мүшелігін $4 дегеннен $5 дегенге {{GENDER:$2|өзгертті}}",
        "logentry-rights-rights-legacy": "$1 $3 үшін топ мүшелігін {{GENDER:$2|өзгертті}}",
        "logentry-rights-autopromote": "$1 $4 дегенен $5 дегенге автоматты түрде {{GENDER:$2|деңгейі көтерілген}}",
index 7530cd4..45b9e74 100644 (file)
@@ -54,7 +54,8 @@
                        "Hwangjy9",
                        "Kurousagi",
                        "Macofe",
-                       "Yearning"
+                       "Yearning",
+                       "고솜"
                ]
        },
        "tog-underline": "링크에 밑줄:",
        "morenotlisted": "이 목록은 완성되지 않았습니다.",
        "mypage": "문서",
        "mytalk": "토론",
-       "anontalk": "이 IP 주소의 사용자와 토론",
+       "anontalk": "토론",
        "navigation": "둘러보기",
        "and": ",",
        "qbfind": "찾기",
        "contributions": "{{GENDER:$1|사용자}} 기여",
        "contributions-title": "$1 사용자의 기여",
        "mycontris": "기여",
+       "anoncontribs": "기여",
        "contribsub2": "{{GENDER:$3|$1}}($2)의 기여",
        "contributions-userdoesnotexist": "\"$1\" 사용자 계정은 등록되어 있지 않습니다.",
        "nocontribs": "지정한 조건과 일치하는 바뀜을 찾을 수 없습니다.",
        "movenosubpage": "이 문서에는 하위 문서가 존재하지 않습니다.",
        "movereason": "이유:",
        "revertmove": "되돌리기",
-       "delete_and_move": "삭제하고 옮기기",
        "delete_and_move_text": "== 삭제 필요 ==\n이동하려는 제목으로 된 \"[[:$1]]\" 문서가 이미 존재합니다.\n삭제하고 이동할까요?",
        "delete_and_move_confirm": "네. 문서를 삭제합니다",
        "delete_and_move_reason": "\"[[$1]]\"에서 문서를 이동하기 위해 삭제함",
        "tooltip-pt-preferences": "사용자 환경 설정",
        "tooltip-pt-watchlist": "주시문서에 대한 바뀜 목록",
        "tooltip-pt-mycontris": "내 기여의 목록",
+       "tooltip-pt-anoncontribs": "이 IP 주소의 편집 목록",
        "tooltip-pt-login": "꼭 로그인해야 하는 것은 아니지만, 로그인을 권장합니다.",
        "tooltip-pt-logout": "로그아웃",
        "tooltip-pt-createaccount": "계정을 만들고 로그인하는 것이 좋습니다; 하지만, 필수는 아닙니다",
index 60a5c84..abcf0d0 100644 (file)
@@ -24,7 +24,8 @@
                        "아라",
                        "Lesgles",
                        "StevenJ81",
-                       "Macofe"
+                       "Macofe",
+                       "Xð"
                ]
        },
        "tog-underline": "Versores linea denotandi:",
        "viewhelppage": "Videre auxilium",
        "categorypage": "Videre categoriam",
        "viewtalkpage": "Videre disputationem",
-       "otherlanguages": "Linguis aliis",
+       "otherlanguages": "In aliis linguis",
        "redirectedfrom": "(Redirectum de $1)",
        "redirectpagesub": "Pagina redirectionis",
        "lastmodifiedat": "Ultima mutatio: $2, $1.",
        "unusedtemplateswlh": "nexus alii",
        "randompage": "Pagina fortuita",
        "randompage-nopages": "Non est ulla pagina {{PLURAL:$2|hoc in spatio nominale|in his spatiis nominalibus}}: $1.",
+       "randomincategory-category": "Categoria:",
        "randomincategory-submit": "Ire",
        "randomredirect": "Redirectio fortuita",
        "randomredirect-nopages": "Non est ulla redirectio in spatio nominali \"$1\".",
        "movenosubpage": "Huic paginae non sunt subpaginae.",
        "movereason": "Causa:",
        "revertmove": "reverti",
-       "delete_and_move": "Delere et movere",
        "delete_and_move_text": "==Deletio necesse est==\nPaginae nomen petitum \"[[:$1]]\" iam existit. Vin tu eam delere ut pagina illic moveatur?",
        "delete_and_move_confirm": "Ita, paginam delere",
        "delete_and_move_reason": "Deleta ut moveatur ex \"[[$1]]\"",
index 6a32ae1..3b7e622 100644 (file)
        "morenotlisted": "Dës Lëscht ass net komplett.",
        "mypage": "Säit",
        "mytalk": "Diskussioun",
-       "anontalk": "Diskussioun fir dës IP Adress",
+       "anontalk": "Diskussioun",
        "navigation": "Navigatioun",
        "and": "&#32;a(n)",
        "qbfind": "Fannen",
        "contributions": "{{GENDER:$1|Benotzer}}kontributiounen",
        "contributions-title": "Kontributioune vum $1",
        "mycontris": "Kontributiounen",
+       "anoncontribs": "Kontributiounen",
        "contribsub2": "Fir {{GENDER:$3|den $1|d'$1|de Benotzer $1}} ($2)",
        "contributions-userdoesnotexist": "De Benotzerkont \"$1\" ass net registréiert.",
        "nocontribs": "Et goufe keng Ännerunge fonnt, déi dëse Kritèren entspriechen.",
        "movenosubpage": "Dës Säit huet keng Ënnersäiten.",
        "movereason": "Grond:",
        "revertmove": "zréck réckelen",
-       "delete_and_move": "Läschen a réckelen",
        "delete_and_move_text": "== Läsche vun der Destinatiounssäit néideg ==\nD'Säit \"[[:$1]]\" existéiert schonn. \nWëll Dir se läsche fir d'Réckelen ze erméiglechen?",
        "delete_and_move_confirm": "Jo, läsch d'Säit",
        "delete_and_move_reason": "Geläscht fir Plaz ze maache fir \"[[$1]]\" heihin ze réckelen",
index 03ff944..6f0a864 100644 (file)
        "tog-enotifwatchlistpages": "Famme savéi via e-mail quande 'na paggina o in file inti mæ osservæ a ven cangiâ.",
        "tog-enotifusertalkpages": "Màndime un'e-mail se gh'é de modìffiche inta mæ pagina de discuscion.",
        "tog-enotifminoredits": "Inviami una email pe e modifiche menoî ascì de pagine e di file",
-       "tog-enotifrevealaddr": "Mostra o mæ indirizzo e-mail inti messaggi de notifica",
+       "tog-enotifrevealaddr": "Mostra o mæ addresso inte e-mail de notiffica",
        "tog-shownumberswatching": "Mostra o numero di utenti che tegnan d'oeuggio sta pagina",
        "tog-oldsig": "Firma attuale:",
        "tog-fancysig": "Tratta a firma comme wikitesto (sensa un collegamento aotomatico)",
        "tog-uselivepreview": "Abillita a fonsion de l'anteprimma in diretta",
+       "tog-forceeditsummary": "Domanda conferma se o campo ogetto o l'è veuo",
        "tog-watchlisthideown": "Ascondi e mæ modiffiche da-a lista che tegno d'oeuggio",
        "tog-watchlisthidebots": "Ascondi e modiffiche di bot da-a lista che tegno d'oeuggio",
        "tog-watchlisthideminor": "Ascondi e modiffiche menoî da-a lista che tegno d'oeuggio",
        "youhavenewmessagesmanyusers": "Ti g'hæ $1 da tanti utenti ($2).",
        "newmessageslinkplural": "{{PLURAL:$1|un neuvo messaggio|999=neuvi messaggi}}",
        "newmessagesdifflinkplural": "{{PLURAL:$1|urtima modiffica|999=urtime modiffiche}}",
-       "youhavenewmessagesmulti": "Ti t'æ neuvi messaggi in scia $1",
+       "youhavenewmessagesmulti": "Ti g'hæ di neuvi messaggi in sce $1",
        "editsection": "Càngia",
        "editold": "càngia",
        "viewsourceold": "veddi a sorgénte",
        "mypreferencesprotected": "No ti g'hæ o permisso pe modificâ e teu preferense.",
        "ns-specialprotected": "No se pœu modificâ e paggine speciali",
        "titleprotected": "A creaçion de 'na paggina con sto tittolo a l'è stæta bloccâ da [[User:$1|$1]].\nA raxon a l'è: ''$2''.",
+       "filereadonlyerror": "N'ho posciuo modificâ o file \"$1\" perché o repository de file \"$2\" o l'è in modalitæ de sola lettua.\n\nL'amministratô ch'o l'ha bloccòu o l'ha fornio sta motivaçion: \"$3\".",
+       "invalidtitle-knownnamespace": "Tittolo non vallido con namespace \"$2\" e testo \"$3\"",
+       "invalidtitle-unknownnamespace": "Tittolo non vallido con namespace sconosciuo \"$1\" e testo \"$2\"",
        "exception-nologin": "No t'ê introu",
-       "exception-nologin-text": "Pe sta paggina ò sta açion ti gh'æ da effettuâ l'accesso inte sta wiki.",
+       "exception-nologin-text": "Pe poei anâ a sta paggina o fâ st'açion, primma ti g'hæ da intrâ.",
+       "exception-nologin-text-manual": "Pe piaxei $1 pe poei accede a sta paggina o açion.",
+       "virus-badscanner": "Errô de configuaçion: antivirus sconosciuo: ''$1''",
        "virus-scanfailed": "scansion fallia (codice $1)",
        "virus-unknownscanner": "antivirus sconosciuo:",
+       "logouttext": "'''Sciortîa effettuâ.'''\n\nDanni a mente che gh'è de paggine che porrieivan continuâ a pai comme se a sciortîa a no foise avegnua, pe scin che no ti nettezzi a cache do to navegatô.",
+       "welcomeuser": "Benvegnuo, $1!",
+       "welcomecreation-msg": "L'utensa a l'è stæta creâ correttamente.\nSe ti veu ti peu personalizzâ e [[Special:Preferences|preferençe de {{SITENAME}}]].",
        "yourname": "Nomme",
        "userlogin-yourname": "Nomme utente",
        "userlogin-yourname-ph": "Scrivi o teu nomme utente",
+       "createacct-another-username-ph": "Scrivi o teu nomme utente",
        "yourpassword": "Pòula segretta:",
        "userlogin-yourpassword": "Pòula segretta:",
        "userlogin-yourpassword-ph": "Scrivi a tu poula segretta.",
        "userlogin-signwithsecure": "Adoeuvia una conescion segua",
        "yourdomainname": "Indirisso do scito:",
        "password-change-forbidden": "No ti peu cangiâ poula segretta in questa wiki.",
+       "externaldberror": "Gh'è stæto un aro co-ol server de autenticaçion esterno, oppû no ti g'hæ i aotorizzaçioin pe aggiornâ o to accesso esterno.",
        "login": "Intra",
        "nav-login-createaccount": "Intra / Registrate",
        "userlogin": "Intra / Registrite",
        "userlogin-resetlink": "T'æ ascordòu i teu dæti de acesso?",
        "userlogin-resetpassword-link": "T'hæ miga ascordou a teu poula segretta?",
        "userlogin-helplink2": "Agiutto pe intrâ",
+       "userlogin-loggedin": "Ti t'ê zà connesso comme {{GENDER:$1|$1}}.\nUsa o formulaio sottostante pe accede comme 'n atro utente.",
+       "userlogin-createanother": "Crea 'n atra utensa",
+       "createacct-emailrequired": "Addresso e-mail:",
        "createacct-emailoptional": "Adresso email (opsionale)",
        "createacct-email-ph": "Scrivi o teu adresso email",
+       "createacct-another-email-ph": "Scrivi o teu adresso email",
        "createaccountmail": "Doeuvia una password temporanea abrettio e mandila a l'adresso de posta elettronica speçificou",
+       "createacct-realname": "Nomme reale (opçionâ)",
        "createaccountreason": "Raxon:",
+       "createacct-reason": "Raxon",
+       "createacct-reason-ph": "Perché t'ê apreuvo a creâ un'atra utensa",
        "createacct-submit": "Crea a to utensa",
        "createacct-another-submit": "Crea utensa",
        "createacct-benefit-heading": "{{SITENAME}} o l'è realizzou da de gente comme ti.",
        "noname": "O nomme d'ûtente o l'è sballiòu.",
        "loginsuccesstitle": "Accesso effettuòu",
        "loginsuccess": "'''O collegamento a-o server de {{SITENAME}} co-o nomme d'ûtente \"$1\" o l'è attivo.'''",
-       "nosuchuser": "No gh'è nisciun utente de nomme \"$1\".\nI nommi utente son senscibbili a-e maiuscole.\nVerifica o nomme inserîo ò crea 'na neuva utensa.",
+       "nosuchuser": "No gh'è nisciun utente de nomme \"$1\".\nI nommi utente son senscibbili a-e maiuscole.\nVerifica o nomme inserîo ò [[Special:UserLogin/signup|crea una neuva utensa]].",
        "nosuchusershort": "No gh'è nisciûn ûtente con quello nomme \"$1\". Verificâ o nomme inserîo.",
        "nouserspecified": "Ti g'hæ da specificâ un nomme utente.",
        "login-userblocked": "St'utente o l'è bloccou. Accesso negou.",
        "password-login-forbidden": "L'utilizzo de sto nomme utente e password o l'è stæto proibio.",
        "mailmypassword": "Reimposta a poula segretta",
        "passwordremindertitle": "Servissio Password Reminder (nêuva paròlla d'ordine temporannia) de {{SITENAME}}",
-       "passwordremindertext": "Quarchedûn (probabilmente ti, con addresso IP $1) o l'ha domandòu l'invîo de 'na nêuva poula segretta pe l'accesso a {{SITENAME}} ($4).\nA poula segretta temporannia pe l'utente \"$2\" a l'è stæta impostâ a \"$3\".\nSe l'è questo che ti voeivi, intra òua e cangia subbito a poula segretta.\n\nSe no t'ê stæto ti a fâ 'sta receseta, oppûre se ti t'ê aregordòu da teu poula segretta e no ti veu ciu cangiâla , ti peu ignorâ 'sto messaggio e andâ avanti deuviando a vegia poula segretta.",
+       "passwordremindertext": "Quarchedûn (probabilmente ti, con addresso IP $1) o l'ha domandòu l'invîo de 'na nêuva poula segretta pe l'accesso a {{SITENAME}} ($4).\nA poula segretta temporannia pe l'utente \"$2\" a l'è stæta impostâ a \"$3\".\nSe l'è questo che ti voeivi, intra òua e cangia subbito a poula segretta. A poula segretta temporannia a descazziâ doppo {{PLURAL:$5|un giorno|$5 giorni}}.\n\nSe no t'ê stæto ti a fâ 'sta recesta, oppûre se ti t'ê aregordòu da teu poula segretta e no ti veu ciu cangiâla , ti peu ignorâ sto messaggio e andâ avanti deuviando a vegia poula segretta.",
        "noemail": "No gh'è nisciûn indirisso e-mail registròu pe l'ûtente \"$1\".",
        "noemailcreate": "Ti devi dâ un addresso e-mail vallido.",
        "passwordsent": "Ûnn-a nêuva paròlla d'ordine a l'è stæta inviâa a l'indirisso e-mail registròu pe l'ûtente \"$1\".\nPe piaxei, fa 'n accesso appenn-a ti a ghe reçeivi.",
        "eauthentsent": "Un messaggio e-mail de conferma o l'è stæto inviòu a l'addresso indicòu.\nPe abilitâ l'invîo de messaggi e-mail pe quest'utensa, se deve seguî e instrussioin indicæ, pe confermâ che ti t'ê o legittimo propietâio de l'utensa.",
        "throttled-mailpassword": "Un'e-mail de reimpostassione da poula segretta a l'è zà stæta inviâ da meno de {{PLURAL:$1|1 oa|$1 oe}}.\nPe prevegnî di abuxi, a fonsion de reimpostassion da poula segretta a peu vese deuviâ solo che 'na votta ogni {{PLURAL:$1|oa|$1 oe}}.",
        "mailerror": "Errô inte l'invio do messaggio: $1",
-       "acct_creation_throttle_hit": "Ne dispiâxe, ma t'hæ zà creòu $1 accesci. No ti pêu creâne ciû!",
-       "emailauthenticated": "O teu indirisso de posta elettronica o l'è stæto autenticou o $2 a $3.",
+       "acct_creation_throttle_hit": "{{PLURAL:$1|1 registraçion a l'è zà stæta effettuâ|$1 registraçioin son zà stæte effettuæ}} da quarcun co-o to mæximo addresso IP inte l'urtimo giorno: o l'è o mascimo consentio inte questo periodo de tempo.\nPerçò, i utenti ch'adeuvian sto addresso IP pe-o momento no peuan registrase.",
+       "emailauthenticated": "O teu adresso e-mail o l'è stæto aotenticòu o $2 a $3.",
+       "emailnotauthenticated": "L'adresso de posta elettronica o no l'è stæto ancon confermòu.\nNo saian inviæ messaggi e-mail pe-e funçioin elencæ chì de sotta.",
        "noemailprefs": "Pe attivâ ste fonçioin ti g'hæ da mette n'adresso e-mail inte preferençe.",
        "emailconfirmlink": "Conferma o teu indirisso de posta elettronega",
+       "invalidemailaddress": "L'adresso e-mail indicòu o l'ha un formato non vallido. Inseisci un adresso valido o donque sveua a casella.",
+       "cannotchangeemail": "I adressi e-mail no peuan ese modificæ in sce sto wiki.",
+       "emaildisabled": "Sto scito o no peu inviâ messaggi de posta eletronnica.",
        "accountcreated": "Graçie pe esëte registroö!!!",
        "accountcreatedtext": "L'utensa pe [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|msg]]) a l'é stæta creâ.",
        "createaccount-title": "Creaçion de 'n conto pe {{SITENAME}}",
+       "createaccount-text": "Quarcun o l'ha creòu un utensa pe quest'adresso e-mail a {{SITENAME}} ($4) a nomme de $2, co-a poula segretta \"$3\".\nTi doviesci intrâ e cangiâ subbito a to poula segretta.\n\nSe quest'utensa a l'è stæta creâ pe sballio, no stanni a dâ a mente a sto messaggio.",
+       "login-throttled": "T'hæ çercòu de intrâ troppe votte tutt'assemme.\nPe piaxei aspeta $1 primma de provâ torna.",
        "login-abort-generic": "O to accesso o no l'ha avuo successo - Abortio",
+       "login-migrated-generic": "A teu utensa a l'è stæta migrâ, e o to nomme utente in sce questo wiki o no l'existe ciù.",
        "loginlanguagelabel": "Lengoa: $1",
+       "suspicious-userlogout": "A teu recesta de desconescion a l'è stæta refuâ perché a pâ  mandâ da un navegatô non funçionante o un proxy de caching.",
+       "createacct-another-realname-tip": "O nomme veo o l'è opçionâ.\nSe ti çerni de inseilo, o saiâ deuviòu pe attribuî a l'aotô a paternitæ di contengnui inviæ.",
        "pt-login": "Intra",
        "pt-login-button": "Intra",
        "pt-createaccount": "Registrite",
        "pt-userlogout": "Sciorti",
+       "php-mail-error-unknown": "Errô sconosciuo intaa funçion PHP mail()",
        "user-mail-no-addy": "T'hæ çercou de mandâ un' e-mail sensa mettighe l'adresso",
        "user-mail-no-body": "T'hæ çercou de mandâ un'e-mail troppo curta o proppio voeua",
        "changepassword": "Cangiâ a pòula segretta",
-       "resetpass_announce": "T'ê introu co in codiçe temporanio de l'e-mail.Pe completâ l'accesso ti devi çerne 'na neuva poula segretta chì:",
+       "resetpass_announce": "Pe completâ l'accesso ti devi çerne 'na neuva poula segretta.",
        "resetpass_header": "Cangia a pòula segretta do conto",
        "oldpassword": "Vegia poula segretta",
        "newpassword": "Neuva poula segretta",
        "retypenew": "Ripette a nêuva paròlla d'ordine:",
        "resetpass_submit": "Çerni a poula segretta e intra",
        "changepassword-success": "O cangio de password o l'é anæto ben!",
+       "changepassword-throttled": "T'hæ çercòu de intrâ troppe votte tutt'assemme.\nPe piaxei aspeta $1 primma de provâ torna.",
        "resetpass_forbidden": "No l'é poscìbile cangiâ e paròlle segrétte",
+       "resetpass-no-info": "Pe anâ direttamente a sta paggina, primma ti g'hæ da intrâ .",
        "resetpass-submit-loggedin": "Cangia a password",
        "resetpass-submit-cancel": "Anulla",
+       "resetpass-wrong-oldpass": "Poula segretta temporannia o attuale non vallida.\nA poula segretta a porriæ za ese stæta cangiâ, oppû una poula segretta neuva a porriæ ese stæta domandâ.",
+       "resetpass-recycled": "Pe piaxei reimposta a to poula segretta con un-a despægia da quella attuale.",
+       "resetpass-temp-emailed": "T'ê intròu co-in codiçe temporannio, inviòu via e-mail. Pe completâ l'accesso, ti g'hæ da impostâ una neuva poula segretta chì:",
+       "resetpass-temp-password": "Poula segretta temporannia:",
+       "resetpass-abort-generic": "A modiffica da poula segretta a l'è stæta interotta da un'estenscion.",
+       "resetpass-expired": "A to poula segretta a l'è descheita. Pe piaxei impòstine un-a neuva pe intrâ.",
+       "resetpass-expired-soft": "A to poula segretta a l'è descheita e a g'ha da ese reimpostâ. Pe piaxei çèrnine un-a neuva òua ò clicca in sce \"{{int:resetpass-submit-cancel}}\" pe reimpostâla ciu tardi.",
+       "resetpass-validity-soft": "A to poula segretta a no l'è vallida: $1\n\nPe piaxei çèrnine un-a neuva òua, ò clicca in sce \"{{int:resetpass-submit-cancel}}\" pe reimpostala ciu tardi.",
        "passwordreset": "Reimposta a poula segretta",
+       "passwordreset-text-one": "Compilla sto formulaio pe riçeive a teu poula segretta temporannia via e-mail.",
+       "passwordreset-text-many": "{{PLURAL:$1|Compilla un di campi pe riçeive una poula segretta temporannia via e-mail.}}",
+       "passwordreset-disabled": "A reimpostaçion de poule segrette a l'è stæta disabilitâ in sce sta wiki",
+       "passwordreset-emaildisabled": "E funçionalitæ de posta elettronnica son stæte disabilitæ in sce sta wiki.",
        "passwordreset-username": "Nomme utente",
+       "passwordreset-domain": "Dominnio:",
+       "passwordreset-capture": "Visualizzâ o contegnuo do messaggio e-mail?",
+       "passwordreset-capture-help": "Se ti seleçion-i sta casella, l'e-mail (co-a poula segretta temporannia), o saiâ mostròu a ti, oltre ch'a ese inviòu a l'utente.",
        "passwordreset-email": "Addresso e-mail:",
        "passwordreset-emailtitle": "Dettaggi account sciu {{SITENAME}}",
+       "passwordreset-emailtext-ip": "Quarcun (probabilmente ti, con adresso IP $1) o l'ha domandòu l'invio de 'na neuva poula segretta per l'accesso a {{SITENAME}} ($4). {{PLURAL:$3|L'utente associòu|I utenti associæ}} a sto addresso e-mail son:\n\n$2\n\n{{PLURAL:$3|Questa poula segretta temporannia a descazziâ|Queste poule segrette temporannie descazzian}} doppo {{PLURAL:$5|un giorno|$5 giorni}}.\nTi doviesci accede e çerne una neuva poula segretta oua. \n\nSe no t'ê stæto t a fâ a domanda, ò se ti t'ê aregordòu a poula segretta originale e no ti veu ciù cangiala, ti peu ignorâ sto messaggio e continuâ a deuviâ a teu vegia poula segretta.",
        "passwordreset-emailelement": "Nomme utente: \n$1\n\nPoula segretta temporannia: \n$2",
-       "changeemail": "Cangia l'adresso e-mail",
-       "changeemail-header": "Cangia l'adresso e-mail de questa utensa",
+       "passwordreset-emailsent": "Se questo o l'è un addresso de posta elettronnica registròu pe-a teu utensa, alloa saiâ inviâ un'e-mail pe reimpostâ a poula segretta.",
+       "passwordreset-emailsent-capture": "L'è stæto inviòu un'e-mail de reimpostaçion da poula segretta, o contegnuo o l'è riportòu chì appreuvo.",
+       "passwordreset-emailerror-capture": "L'è stæto generòu un'e-mail de reimpostaçion da poula segretta, riportà chì appreuvo. L'invio {{GENDER:$2|a l'utente}} o no l'è ariêscîo: $1",
+       "changeemail": "Cangia o elimmina l'adresso e-mail",
+       "changeemail-header": "Completa sto formulaio pe cangiâ o to adresso e-mail. Se ti veu rimeuve l'associaçion de quasesegge addresso e-mail da-a teu utensa, lascia io neuvo addresso e-mail veuo quande ti invii o formulaio.",
+       "changeemail-passwordrequired": "Saiâ necessaio insei a poula segretta pe confermâ a modiffica.",
+       "changeemail-no-info": "Pe anâ direttamente a sta paggina, primma ti g'hæ da intrâ .",
+       "changeemail-oldemail": "Addresso e-mail corrente:",
        "changeemail-newemail": "Noeuvo adresso e-mail",
+       "changeemail-newemail-help": "Sto campo dev'ese lasciòu veuo se ti veu rimeuve o to addresso e-mail. No ti saiæ in graddo de reimpostâ 'na poula segretta desmentegâ e ti no riçeviæ e-mail da questo wiki, se l'adresso de posta elettronnica o ven rimosso.",
        "changeemail-none": "(nisciun)",
        "changeemail-password": "A to password pe {{SITENAME}}:",
        "changeemail-submit": "Cangia e-mail",
+       "changeemail-throttled": "T'hæ çercòu de intrâ troppe votte.\nPe piaxei aspeta $1 primma de provâ torna.",
+       "changeemail-nochange": "Pe piaxei inseisci un neuvo addresso e-mail.",
+       "resettokens": "Reimposta token",
+       "resettokens-text": "Chì ti peu reimpostâ e ciave che permettav l'accesso a di determinæ dæti privæ associæ a-a teu utensa.\n\nTi doviesci falo se ti l'hæ accidentalmente condivise con quarcun o se-a teu utensa a l'è stæta compromissa.",
+       "resettokens-no-tokens": "Token da reimpostâ no ghe n'è.",
+       "resettokens-tokens": "Token:",
        "resettokens-token-label": "$1 (oua o l'è: $2)",
+       "resettokens-watchlist-token": "Token pe-o feed web (Atom/RSS) de [[Special:Watchlist|modiffiche a-e paggine inti teu sott'oservaçion]]",
+       "resettokens-done": "Token reimpostæ.",
+       "resettokens-resetbutton": "Reimposta token selessionæ",
        "bold_sample": "Grascetto",
        "bold_tip": "Grascetto",
        "italic_sample": "Testo in corscivo",
        "sig_tip": "Firma con dæta e ôa",
        "hr_tip": "Linnia orizontâ",
        "summary": "Oggetto:",
-       "subject": "Argomento (tittolo):",
+       "subject": "Sogetto:",
        "minoredit": "Cangiamento minô (m)",
        "watchthis": "Metti sotta oservaçion",
        "savearticle": "Sarva a pàgina",
        "preview": "Anteprìmma",
        "showpreview": "Veddi l'anteprimma",
        "showdiff": "Veddi i cangiamenti",
+       "blankarticle": "<strong>Attençion:</strong> a paggina che ti çerchi a l'è veua.\nCliccando torna in sce \"{{int:savearticle}}\", a paggina a saiâ creâ sensa contegnui.",
        "anoneditwarning": "<strong>Attension:</strong> No t'ê introu. Se ti fæ di cangi o teu adresso IP o saiâ vixibile pubbricamente. Se <strong>[$1 ti intri]</strong> ò <strong>[$2 ti crei un'utensa]</strong>, e teu modifiche saian attribuie a-o teu nomme utente, insemme a di atri benefiççi.",
        "anonpreviewwarning": "No t'hæ fæto l'accesso. Se ti sarvi inta stoia da paggina ghe saiâ solo o to adresso IP",
+       "missingsummary": "<strong>Aregòrdite:</strong> no t'hæ specificòu l'oggetto de questa modiffica. Sciaccando torna \"{{int:savearticle}}\", a modiffica a saiâ sarvâ sensa.",
+       "selfredirect": "<strong>Attençion:</strong> t'ê apreuvo a rendirissâ sta paggina a lê mæxima.\nFoscia t'hæ sballiòu a indicâ a destinaçion pe-o redirect, ò donque ti modiffichi a paggina sbaliâ.\nSe ti clicchi torna \"{{int:savearticle}}\", o redirect o saiâ creòu comunque.",
        "missingcommenttext": "Scrivi un commento chi de sotta",
+       "missingcommentheader": "<strong>Aregòrdite:</strong> no t'hæ specificòu o soggetto de sto commento. Sciaccando torna \"{{int:savearticle}}\", a modiffica a saiâ sarvâ sensa.",
        "summary-preview": "Anteprimma oggetto:",
+       "subject-preview": "Anteprimma do soggetto:",
+       "previewerrortext": "Gh'è stæto un errô mentre se çercava de mostrâ l'anteprimma.",
        "blockedtitle": "L'utente o l'é bloccòu",
        "blockedtext": "''''O to nomme utente ò adresso IP o l'è stæto bloccòu.'''\n\nO blòcco o l'è stæto fæto da $1. A raxon dæta a l'è ''$2''.\n\n* Iniçio do blocco: $8\n* Fin do blocco: $6\n* Utente blocou: $7\n\nL'è poscibbile contattâ $1 o un âtro [[{{MediaWiki:Grouppage-sysop}}|amministratô]] pe discûtte inscio blòcco.\nNo ti poeu doeuviâ o comando \"Manda un'e-mail a st'ûtente\" se no ti g'hæ 'n adresso e-mail registròu inte to [[Special:Preferences|preferençe]] e se no t'ê stæto bloccòu ascì.\nO to adresso IP o l'è $3, e o to blòcco ID o l'è #$5.\nPe piaxei, pe domandâ informaçioin, speçifficali tutti doî.",
        "autoblockedtext": "O teu addresso IP o l'è stæto bloccòu outomaticamente perché o l'ea za usòu da 'n âtro utente, bloccòu da $1.\nA raxon dæta a l'è stæta:\n\n:''$2''\n\n* Prinsippio do blòcco: $8\n* Fin do blòcco: $6\n\nTi peu contattâ $1 ò un âtro\n[[{{MediaWiki:Grouppage-sysop}}|amministratô]] pe discutte o blòcco.\n\nDanni a mente a che no ti pêu ûsâ o comando \"manda 'na e-mail a sto utente\" se non ti g'hæ 'n addresso de posta elettronega registròu in te têu [[Special:Preferences|preferense]] e se ti no t'ê stæto bloccòu ascì.\n\nO to adresso IP o l'è $3, e o to blòcco ID o l'è #$5. Pe piaxei, pe domandâ informaçioin, speçifficali tutti doî.",
+       "blockednoreason": "nisciun-a motivaçion dæta",
        "whitelistedittext": "Pe cangia sta pagina devvi $1.",
+       "confirmedittext": "Pe ese abilitæ a-a modiffica de paggine bezeugna confermâ o proppio addresso e-mail. Pe impostâ e confermâ l'adresso servîse de [[Special:Preferences|preferençe]].",
+       "nosuchsectiontitle": "Imposcibbile trovâ a seçion",
+       "nosuchsectiontext": "T'hæ çercòu de modificâ una seçion inexistente.\nA porriæ ese stæta mesciâ ò eliminâ mentre ti t'amiavi a paggina.",
        "loginreqtitle": "Besêugna registrâse primma de modificâ 'sta paggina.",
        "loginreqlink": "intra",
        "loginreqpagetext": "Pe amiâ di atre paggine gh'è da $1",
        "accmailtitle": "Pòula segretta spedïa",
-       "accmailtext": "Una password abrettio pe [[User talk:$1|$1]] a l'è stæta mandâ a $2.\n\nSta password a poeu ese cangiâ inta paggina pe ''[[Special:ChangePassword|cangiâ a password]]'' subbito doppo l'acesso.",
+       "accmailtext": "Una poula segretta generâ abrettio pe [[User talk:$1|$1]] a l'è stæta mandâ a $2.\n\nSta poula segretta a peu ese cangiâ inta paggina pe ''[[Special:ChangePassword|cangiâ a poula segretta]]'' subbito doppo l'accesso.",
        "newarticle": "(Nêuvo)",
        "newarticletext": "Sto colegaménto o corisponde a 'na pàgina ch'a no l'existe ancon.\n\nSe se vêu creâ a pàgina òua, se pêu comensâ a scrive into spàçio chì sotta.\n(amia e [$1 paggine d'agiûtto] pe ciû informaçioìn).\n\nSe t'ê intròu chì pe sballio,  sciacca '''Inderê''' into navegatô.",
        "anontalkpagetext": "----\n''Sta chì a l'è a paggina de discuscion de un utente anonnimo, ch'o no l'ha ancon creou un'utensa o comunque o no a doeuvia oua. Pe identificâlo l'è quindi necessaio doeuviâ o nummero do so adresso IP. I adresci IP poeuan però ese condivixi da ciù utenti. Se t'ê un utente anonimo e ti ritegni che i commenti inte sta pagina no se riferiscian a ti, [[Special:UserLogin/signup|crea una noeuva utensa]] o donque [[Special:UserLogin|intra con quella che ti g'hæ za]] pe evitâ de chì avanti de ese confuzo con di atri utenti anonnimi .''",
        "recentchangeslinked-page": "Nómme da pàgina:",
        "recentchangeslinked-to": "Fanni védde sôlo i cangiaménti a-e pàgine colegæ a-a pàgina specificâ",
        "upload": "Carrega 'n file",
-       "uploadbtn": "Carega 'n archivvio",
+       "uploadbtn": "Carrega 'n file",
        "uploadlogpage": "Log di file caregæ",
        "filename": "Nomme do file",
        "filedesc": "Detaggi",
        "nolinkstoimage": "No gh'è nisciûnn-a pàgina collegâ con 'sto file.",
        "sharedupload": "'St'archivvio o l'è condiviso; sajeiva a dî c'o pêu ese dêuviòu da ciû progetti wiki.",
        "sharedupload-desc-here": "Sto file o vegne da $1 e o peu êse dêuviòu inti âtri progetti.\nChì apreuvo ti peu védde a descriçión inta [$2 pàgina de descriçión do file].",
-       "uploadnewversion-linktext": "Carega 'na nêuva verscion de 'st'archivvio chì",
+       "uploadnewversion-linktext": "Carrega 'na neuva verscion de sto file",
        "upload-disallowed-here": "Imposcibbile sorvescrive sto file.",
        "filedelete-submit": "Scassa",
        "mimesearch": "Çerca MIME",
        "movelogpage": "Lista di stramûi",
        "movereason": "Raxon",
        "revertmove": "Ristorâ",
-       "delete_and_move": "Scassa e mescia",
        "delete_and_move_confirm": "Scì, scassa a pagina",
        "delete_and_move_reason": "Levoö pe fâ röso pe un remescio",
        "export": "Espòrta pàgine",
        "tooltip-feed-atom": "Feed Atom pe sta pàgina",
        "tooltip-t-contributions": "Lista de contribûssioîn de quest'utente",
        "tooltip-t-emailuser": "Invia 'n messaggio e-mail a quest'utente",
-       "tooltip-t-upload": "Carega inmàgini ò archivi moltimedia",
+       "tooltip-t-upload": "Carrega di file murtimediali",
        "tooltip-t-specialpages": "Lista de tùtte e pagine speçiâli",
        "tooltip-t-print": "Versción da stànpa pe sta pàgina",
        "tooltip-t-permalink": "Colegaménto fisso a sta revixión da pàgina",
        "tooltip-rollback": "\"Rollback\" annulla e modiffiche a sta pagina de l'urtimo contributô co-in solo clic.",
        "tooltip-undo": "\"Anùlla\" o permette de anulâ sto cangiaménto e o l'arve o modolo de cangiaménto into modalitæ anteprìmma. Ti peu ascì métte a raxón inte l'ogetto do cangiaménto.",
        "tooltip-summary": "Scrîvi 'na scintexi",
-       "common.css": "/** o codiçe css scrïo chie o vegne azzounto in tutte e pagine */",
+       "common.css": "/** i stili css scriti chie se applicana tutte e skin */",
        "anonymous": "Utente anonimmo de {{SITENAME}}",
        "lastmodifiedatby": "Sta pagina a l'è stæta cangiâ l'urtima votta a e $2 do $1 da $3.",
        "simpleantispam-label": "Controllo anti-spam.\n<strong>NO</strong> impîlo!",
index fe0777e..3c51189 100644 (file)
        "movelogpage": "Register di San Martin",
        "movereason": "Mutìf:",
        "revertmove": "Riprìstina 'mè che l'era",
-       "delete_and_move": "Scancèla e möf",
        "delete_and_move_confirm": "Sé, surascrìf la pàgina che gh'è zà",
        "export": "Espurtá pagin",
        "allmessages": "Tücc i messacc dal sistéma",
index 810d2c3..9e53ddd 100644 (file)
        "movenosubpage": "ای بلگه زیر بلگه نئ.",
        "movereason": "دلیل:",
        "revertmove": "لرستن",
-       "delete_and_move": "پاکسا و جا وه جا بوئه",
        "delete_and_move_text": "== پاکساکاری میها ==\n\nگوتار ها د مقصد «[[:$1]]» . آیا میهایت ونه پاکسا بکیت  تا جا وه جاکاری دروس بوئه؟",
        "delete_and_move_confirm": "هری بلگه نه پاکسا کو",
        "delete_and_move_reason": "پاکساکاری سی ممکن بیین جا وه جایی «[[$1]]»",
index 95c87c6..ee56860 100644 (file)
        "movenosubpage": "Šis puslapis neturi subpuslapių.",
        "movereason": "Priežastis:",
        "revertmove": "atmesti",
-       "delete_and_move": "Ištrinti ir perkelti",
        "delete_and_move_text": "==Reikia ištrinti==\n\nPaskirties puslapis „[[:$1]]“ jau yra. Ar norite jį ištrinti, kad galėtumėte pervardinti?",
        "delete_and_move_confirm": "Taip, trinti puslapį",
        "delete_and_move_reason": "Ištrinta dėl perkėlimo iš \"[[$1]]\"",
        "logentry-suppress-block": "$1 {{GENDER:$2|užblokavo}} {{GENDER:$4|$3}}, blokavimo laikas – $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|pakeitė}} {{GENDER:$4|$3}} blokavimo nustatymus, blokavimo laikas – $5 $6",
        "logentry-import-upload": "$1 {{GENDER:$2|importavo}} $3 per failų keltuvą",
+       "logentry-import-upload-details": "$1 {{GENDER:$2|importavo}} $3 failo įkėlimo ($4 {{PLURAL:$4|peržiūra|peržiūros}})",
        "logentry-import-interwiki": "$1 {{GENDER:$2|importavo}} $3 iš kitos viki",
+       "logentry-import-interwiki-details": "$1 {{GENDER:$2|importavo}} $3 iš $5 ($4 {{PLURAL:$4|peržiūra|peržiūros}})",
        "logentry-merge-merge": "$1 {{GENDER:$2|sujungė}} $3 į $4 (versijas iki $5)",
        "logentry-move-move": "$1 pervadino puslapį $3 į $4",
        "logentry-move-move-noredirect": "$1 {{GENDER:$2|perkėlė}} puslapį $3 į $4 be nukreipimo",
index a82448d..c38406a 100644 (file)
        "morenotlisted": "Овој список не е целосен.",
        "mypage": "Страница",
        "mytalk": "разговор",
-       "anontalk": "Разговор за оваа IP-адреса",
+       "anontalk": "Разговор",
        "navigation": "Навигација",
        "and": "&#32;и",
        "qbfind": "Најди",
        "delete-hook-aborted": "Бришењето е прекинато со кука.\nНе е дадено никакво образложение.",
        "no-null-revision": "Не можев да направам нова ништовна преработка на страницата „$1“",
        "badtitle": "Неисправен наслов",
-       "badtitletext": "Ð\91аÑ\80аниоÑ\82 Ð½Ð°Ñ\81лов Ðµ Ð³Ñ\80еÑ\88ен, Ð¿Ñ\80азен Ð¸Ð»Ð¸ Ð½ÐµÐ¸Ñ\81пÑ\80авно Ð¿Ð¾Ð²Ñ\80зан Ð¼ÐµÑ\93Ñ\83Ñ\98азиÑ\87ен Ð¸Ð»Ð¸ Ð¼ÐµÑ\93Ñ\83вики наслов. \nМоже да содржи недопуштени знаци.",
+       "badtitletext": "Ð\91аÑ\80аниоÑ\82 Ð½Ð°Ñ\81лов Ðµ Ð³Ñ\80еÑ\88ен, Ð¿Ñ\80азен Ð¸Ð»Ð¸ Ð½ÐµÐ¸Ñ\81пÑ\80авно Ð¿Ð¾Ð²Ñ\80зан Ð¼ÐµÑ\93Ñ\83Ñ\98азиÑ\87ен Ð¸Ð»Ð¸ Ð¼ÐµÑ\93Ñ\83пÑ\80оекÑ\82ен наслов. \nМоже да содржи недопуштени знаци.",
        "title-invalid-empty": "Бараниот наслов е празен или го содржи само називот на именскиот простор.",
        "title-invalid-utf8": "Бараниот наслов содржи неважечка UTF-8-низа.",
        "title-invalid-interwiki": "Бараниот наслов содржи меѓујазична врска што не може да се користи во наслови.",
        "fewestrevisions": "Статии со најмалку преработки",
        "nbytes": "$1 {{PLURAL:$1|бајт|бајти}}",
        "ncategories": "$1 {{PLURAL:$1|категорија|категории}}",
-       "ninterwikis": "$1 {{PLURAL:$1|меÑ\93Ñ\83вики|меÑ\93Ñ\83викиÑ\98а}}",
+       "ninterwikis": "$1 {{PLURAL:$1|меÑ\93Ñ\83пÑ\80оекÑ\82на|меÑ\93Ñ\83пÑ\80оекÑ\82ни}}",
        "nlinks": "$1 {{PLURAL:$1|врска|врски}}",
        "nmembers": "$1 {{PLURAL:$1|член|членови}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|член|членови}}",
        "mostlinkedtemplates": "Најмногу превметнати страници",
        "mostcategories": "Страници со најмногу категории",
        "mostimages": "Најмногу врски до податотеки",
-       "mostinterwikis": "СÑ\82Ñ\80аниÑ\86и Ñ\81о Ð½Ð°Ñ\98многÑ\83 Ð¼ÐµÑ\93Ñ\83вики",
+       "mostinterwikis": "СÑ\82Ñ\80аниÑ\86и Ñ\81о Ð½Ð°Ñ\98многÑ\83 Ð¼ÐµÑ\93Ñ\83пÑ\80оекÑ\82ни",
        "mostrevisions": "Статии со најмногу верзии",
        "prefixindex": "Сите страници (со претставка)",
        "prefixindex-namespace": "Сите страници со претставка (именски простор $1)",
        "allinnamespace": "Сите страници (именски простор $1)",
        "allpagessubmit": "Дај",
        "allpagesprefix": "Прикажи страници со претставка:",
-       "allpagesbadtitle": "Ð\94адениоÑ\82 Ð½Ð°Ñ\81лов Ðµ Ð½ÐµÐ²Ð°Ð¶ÐµÑ\87ки Ð¸Ð»Ð¸ Ð¸Ð¼Ð° Ð¼ÐµÑ\93Ñ\83Ñ\98азиÑ\87ен Ð¸Ð»Ð¸ Ð¼ÐµÑ\93Ñ\83вики-претставка. Може да содржи повеќе знаци кои не смеат да се користат во наслови.",
+       "allpagesbadtitle": "Ð\94адениоÑ\82 Ð½Ð°Ñ\81лов Ðµ Ð½ÐµÐ²Ð°Ð¶ÐµÑ\87ки Ð¸Ð»Ð¸ Ð¸Ð¼Ð° Ð¼ÐµÑ\93Ñ\83Ñ\98азиÑ\87ен Ð¸Ð»Ð¸ Ð¼ÐµÑ\93Ñ\83пÑ\80оекÑ\82на претставка. Може да содржи повеќе знаци кои не смеат да се користат во наслови.",
        "allpages-bad-ns": "Википедија не содржи именски простор „$1“.",
        "allpages-hide-redirects": "Скриј пренасочувања",
        "cachedspecial-viewing-cached-ttl": "Гледате меѓускладирана верзија на оваа страница, која може да е стара $1.",
        "contributions": "{{GENDER:$1|Придонеси на корисникот}}",
        "contributions-title": "Придонеси на корисникот $1",
        "mycontris": "придонеси",
+       "anoncontribs": "Придонеси",
        "contribsub2": "За {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Корисничката сметка „$1“ не е регистрирана.",
        "nocontribs": "Не се пронајдени промени што одговараат на овој критериум.",
        "movenosubpage": "Оваа страница нема потстраници.",
        "movereason": "Причина:",
        "revertmove": "врати",
-       "delete_and_move": "Избриши и премести",
        "delete_and_move_text": "==Потребно бришење==\nЦелната статија „[[:$1]]“ веќе постои.\nДали сакате да ја избришете за да ослободите место за преместувањето?",
        "delete_and_move_confirm": "Да, избриши ја страницата",
        "delete_and_move_reason": "Избришано за да се ослободи место за преместувањето од „[[$1]]“",
        "selfmove": "Појдовната и целната страница се истоветни;\nне можам да преместам.",
        "immobile-source-namespace": "Не може да се преместуваат страници во именскиот простор „$1“",
        "immobile-target-namespace": "Не може да се преместуваат страници во именскиот простор „$1“",
-       "immobile-target-namespace-iw": "Ð\9cеÑ\93Ñ\83вики-врска не може да се користи за преименување на страници.",
+       "immobile-target-namespace-iw": "Ð\9cеÑ\93Ñ\83пÑ\80оекÑ\82на врска не може да се користи за преименување на страници.",
        "immobile-source-page": "Оваа страница не може да се преместува.",
        "immobile-target-page": "Не може да се премести под бараниот наслов.",
        "bad-target-model": "Саканата одредница користи друг содржински модел. Не можам да претворам од $1 во $2.",
        "importfailed": "Неуспешно внесување: $1",
        "importunknownsource": "Непознат тип за внесување",
        "importcantopen": "Не може да се отвори увезената податотека",
-       "importbadinterwiki": "Ð\9bоÑ\88а Ð¼ÐµÑ\93Ñ\83вики-врска",
+       "importbadinterwiki": "Ð\9bоÑ\88а Ð¼ÐµÑ\93Ñ\83пÑ\80оекÑ\82на врска",
        "importsuccess": "Увезувањето е завршено!",
        "importnosources": "Нема викија од кои би се извршил увоз и непосредните подигања на историја се оневозможени.",
        "importnofile": "Нема подигнато увозна податотека.",
        "import-invalid-interwiki": "Не можам да увезам од наведеното вики.",
        "import-error-edit": "Страницата „$1“ не е увезена бидејќи не ви е дозволено да ја уредувате.",
        "import-error-create": "Страницата „$1“ не е увезена бидејќи не ви е дозволено да ја создадете.",
-       "import-error-interwiki": "СÑ\82Ñ\80аниÑ\86аÑ\82а â\80\9e$1â\80\9c Ð½Ðµ Ðµ Ñ\83везена Ð±Ð¸Ð´ÐµÑ\98Ñ\9cи Ð¸Ð¼ÐµÑ\82о Ðµ Ñ\80езеÑ\80виÑ\80ано Ð·Ð° Ð½Ð°Ð´Ð²Ð¾Ñ\80еÑ\88ни Ð²Ñ\80Ñ\81ки (меÑ\93Ñ\83вики).",
+       "import-error-interwiki": "СÑ\82Ñ\80аниÑ\86аÑ\82а â\80\9e$1â\80\9c Ð½Ðµ Ðµ Ñ\83везена Ð±Ð¸Ð´ÐµÑ\98Ñ\9cи Ð¸Ð¼ÐµÑ\82о Ðµ Ñ\80езеÑ\80виÑ\80ано Ð·Ð° Ð½Ð°Ð´Ð²Ð¾Ñ\80еÑ\88ни Ð²Ñ\80Ñ\81ки (меÑ\93Ñ\83пÑ\80оекÑ\82ни).",
        "import-error-special": "Страницата „$1“ не е увезена бидејќи припаѓа на посебен именски простор што не дозволува страници.",
        "import-error-invalid": "Страницата „$1“ не е увезена бидејќи името ѝ е неважечко на ова вики.",
        "import-error-unserialize": "Преработката $2 на страницата „$1“ не може да се отсеријализира. Утврдено е дека користи содржинскиот модел $3 што е серијализиран како $4.",
        "tooltip-pt-preferences": "Ваши нагодувања",
        "tooltip-pt-watchlist": "Список на страници кои сте избрале да ги набљудувате.",
        "tooltip-pt-mycontris": "Список на ваши придонеси",
+       "tooltip-pt-anoncontribs": "Список на уредувања направени од оваа IP-адреса",
        "tooltip-pt-login": "Ви препорачуваме да се најавите, иако тоа не е задолжително.",
        "tooltip-pt-logout": "Одјавување",
        "tooltip-pt-createaccount": "Ви препорачуваме да направите сметка и да се најавите, иако тоа не е задолжително",
index 7b43fd4..08dedd0 100644 (file)
        "movenosubpage": "या पानात उपपाने नाहीत.",
        "movereason": "कारण:",
        "revertmove": "पूर्वपदास न्या",
-       "delete_and_move": "वगळा आणि स्थानांतरित करा",
        "delete_and_move_text": "==वगळण्याची आवश्यकता==\n\nलक्ष्यपान  \"[[:$1]]\" आधीच अस्तित्वात आहे.स्थानांतराचा मार्ग मोकळा करण्याकरिता तुम्हाला ते वगळावयाचे आहे काय?",
        "delete_and_move_confirm": "होय, पान वगळा",
        "delete_and_move_reason": "\"[[$1]]\" पासून वगळून स्थानांतर केले.",
index dfcb78a..2785e00 100644 (file)
        "movenosubpage": "Laman ini tiada sublaman.",
        "movereason": "Sebab:",
        "revertmove": "balik",
-       "delete_and_move": "Hapus dan pindah",
        "delete_and_move_text": "==Penghapusan diperlukan==\n\nLaman destinasi \"[[:$1]]\" telah pun wujud. Adakah anda mahu menghapuskannya supaya laman ini dapat dipindahkan?",
        "delete_and_move_confirm": "Ya, hapuskan laman ini",
        "delete_and_move_reason": "Dihapuskan untuk membuka laluan untuk pemindahan dari \"[[$1]]\"",
index 70e4609..f2580d5 100644 (file)
        "morenotlisted": "Chisto elenco nun è cumpreto.",
        "mypage": "Paggena",
        "mytalk": "'E chiàcchieriate mmie",
-       "anontalk": "Chiacchierate pe chisto IP",
+       "anontalk": "Chiacchierate",
        "navigation": "Navigazzione",
        "and": "&#32;e",
        "qbfind": "Truòva",
        "contributions": "Contribbute {{GENDER:$1|utente}}",
        "contributions-title": "Cuntribbute 'a l'utente pe' $1",
        "mycontris": "'E ffatiche d''e mmeje",
+       "anoncontribs": "Cuntribbute",
        "contribsub2": "Ppe {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "'O cunto utente \"$1\" nun è riggistrato.",
        "nocontribs": "Nisciunu cagnamiento è stato truvato cu sti criterie.",
        "movenosubpage": "Sta paggena nun tene sottopaggene.",
        "movereason": "Raggióne",
        "revertmove": "arrepiglia",
-       "delete_and_move": "Scancèlla e mòve",
        "delete_and_move_text": "== Scancellamiento richiesto ==\n'A paggena 'e destinazione \"[[:$1]]\" esiste già.\n'A vulite scancellà pe' ne putè ffà 'o spazio abbacante necessario?",
        "delete_and_move_confirm": "Sì, suprascrivi 'a paggena asistente",
        "delete_and_move_reason": "Scancellata pe ne fà spazio abbacante e putè spustà 'a \"[[$1]]\"",
        "tooltip-pt-preferences": "Preferenze d''e mmeje",
        "tooltip-pt-watchlist": "'A lista d' 'e paggene ca state a cuntrullà",
        "tooltip-pt-mycontris": "Elenco dde tuje contributte",
+       "tooltip-pt-anoncontribs": "N'elenco 'e cagnamiente fatte 'a st'indirizzo IP",
        "tooltip-pt-login": "A reggistrazione è cunsigliata",
        "tooltip-pt-logout": "Jésce (logout)",
        "tooltip-pt-createaccount": "Pigliateve curaggio e criate n'utente e trasìte; ancora ca chisto nun s'avesse 'a ffà pe' fforza",
index 09026ce..2e62c91 100644 (file)
        "undo-failure": "Redigeringen kunne ikke omgjøres på grunn av konflikterende etterfølgende redigeringer.",
        "undo-norev": "Redigeringen kunne ikke fjernes fordi den ikke eksisterer eller ble slettet",
        "undo-nochange": "Det ser ut til at redigeringen allerede er tilbakestilt.",
-       "undo-summary": "Fjerner revisjon $1 av [[Bruker:$2|$2]] ([[Brukerdiskusjon:$2|diskusjon]] | [[Spesial:Bidrag/$2|bidrag]])",
+       "undo-summary": "Fjerner revisjon $1 av [[Special:Contributions/$2|$2]] ([[User talk:$2|diskusjon]])",
        "undo-summary-username-hidden": "Fjern revisjon $1 av en skjult bruker",
        "cantcreateaccounttitle": "Kan ikke opprette konto",
        "cantcreateaccount-text": "Kontooppretting fra denne IP-adressen ('''$1''') har blitt blokkert av [[User:$3|$3]].\n\nGrunnen som ble oppgitt av $3 er ''$2''",
        "prefs-help-recentchangescount": "Dette inkluderer nylige endringer, sidehistorikk og logger.",
        "prefs-help-watchlist-token2": "Dette er den hemmelige nøkkelen til webmatingen for din overvåkningsliste.\nEnhver som kjenner nøkkelen vil kunne lese din overvåkningsliste, så ikke vis den til andre.\n[[Special:ResetTokens|Klikk her om du trenger å nullstille nøkkelen]].",
        "savedprefs": "Innstillingene ble lagret.",
-       "savedrights": "Brukerrettighetene til {{{{GENDER:$1|$1}} har blitt lagret.",
+       "savedrights": "Brukerrettighetene til {{GENDER:$1|$1}} har blitt lagret.",
        "timezonelegend": "Tidssone:",
        "localtime": "Lokaltid:",
        "timezoneuseserverdefault": "Bruk wikistandard ($1)",
        "movenosubpage": "Denne siden har ingen undersider.",
        "movereason": "Årsak:",
        "revertmove": "tilbakestill",
-       "delete_and_move": "Slett og flytt",
        "delete_and_move_text": "==Sletting nødvendig==\nMålsiden «[[:$1]]» finnes allerede. Vil du slette den så denne siden kan flyttes dit?",
        "delete_and_move_confirm": "Ja, slett siden",
        "delete_and_move_reason": "Slettet for å muliggjøre flytting fra \"[[$1]]\"",
index cfc47b8..1217aa5 100644 (file)
        "wlnote": "Hieronder {{PLURAL:$1|staat de laaste wijziging|staan de laatste $1 wijzigingen}} in {{PLURAL:$2|het laatste uur|de laatste $2 uur}} per $3 om $4.",
        "wlshowlast": "Laatste $1 uur, $2 dagen bekijken",
        "watchlistall2": "alles",
+       "watchlist-hide": "Verbergen",
        "wlshowtime": "Tijdspanne:",
        "wlshowhideminor": "kleine bewerkingen",
        "wlshowhidebots": "bots",
        "movenosubpage": "Deze pagina heeft geen subpagina's.",
        "movereason": "Reden:",
        "revertmove": "terugdraaien",
-       "delete_and_move": "Verwijderen en hernoemen",
        "delete_and_move_text": "==Verwijdering nodig==\nOnder de naam \"[[:$1]]\" bestaat al een pagina.\nWilt u deze verwijderen om plaats te maken voor de te hernoemen pagina?",
        "delete_and_move_confirm": "Ja, de pagina verwijderen",
        "delete_and_move_reason": "Verwijderd in verband met hernoeming van \"[[$1]]\"",
index 0825cc0..00bc20b 100644 (file)
        "wlheader-showupdated": "Sider som har vorte endra sidan du sist såg på dei er '''utheva'''",
        "wlnote": "Nedanfor er {{PLURAL:$1|den siste endringa|dei siste '''$1''' endringane}} {{PLURAL:$2|den siste timen|dei siste '''$2''' timane}}, for $3, kl. $4.",
        "wlshowlast": "Vis siste $1 timane $2 dagane",
-       "watchlistall2": "alle",
+       "watchlistall2": "alt",
+       "watchlist-hide": "Gøym",
+       "wlshowtime": "Vis siste:",
+       "wlshowhideminor": "småplukk",
+       "wlshowhidebots": "robotar",
+       "wlshowhideliu": "registrerte brukarar",
+       "wlshowhideanons": "anonyme brukarar",
+       "wlshowhidepatr": "patruljerte endringar",
+       "wlshowhidemine": "mine endringar",
        "watchlist-options": "Alternativ for overvakingslista",
        "watching": "Overvakar...",
        "unwatching": "Fjernar frå overvakinglista...",
        "movenosubpage": "Denne sida har ingen undersider.",
        "movereason": "Årsak:",
        "revertmove": "flytt attende",
-       "delete_and_move": "Slett og flytt",
        "delete_and_move_text": "== Sletting påkravd ==\n\nMålsida «[[:$1]]» finst allereie. Vil du slette ho for å gje rom for flytting?",
        "delete_and_move_confirm": "Ja, slett sida",
        "delete_and_move_reason": "Sletta for å gje rom for flytting frå «[[$1]]»",
index fa7e2fe..4af83d6 100644 (file)
@@ -14,7 +14,8 @@
                        "לערי ריינהארט",
                        "아라",
                        "Macofe",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Xð"
                ]
        },
        "tog-underline": "Soslinhar los ligams :",
        "viewhelppage": "Vejatz la pagina d'ajuda",
        "categorypage": "Vejatz la pagina de las categorias",
        "viewtalkpage": "Pagina de discussion",
-       "otherlanguages": "Autras lengas",
+       "otherlanguages": "En autras lengas",
        "redirectedfrom": "(Redirigit dempuèi $1)",
        "redirectpagesub": "Pagina de redireccion",
        "redirectto": "Redirigir cap a :",
        "createaccountreason": "Motiu :",
        "createacct-reason": "Motiu",
        "createacct-reason-ph": "Perqué creatz un autre compte",
-       "createacct-captcha": "Contraròtle de seguretat",
-       "createacct-imgcaptcha-ph": "Entratz lo tèxte que vesètz çaisús",
        "createacct-submit": "Creatz vòstre compte",
        "createacct-another-submit": "Crear un autre compte",
        "createacct-benefit-heading": "{{SITENAME}} es escrich per de monde coma vos.",
        "wlheader-showupdated": "Las paginas que son estadas modificadas dempuèi vòstra darrièra visita son afichadas en '''gras'''.",
        "wlnote": "Çaijós {{PLURAL:$1|figura la darrièra modificacion efectuada|figuran las <strong>$1</strong> darrièras modificacions efectuadas}} pendent {{PLURAL:$2|la darrièra ora|las <strong>$2</strong> darrièras oras}}, dempuèi $3, $4.",
        "wlshowlast": "Far veire las darrièras $1 oras, los darrièrs $2 jorns",
+       "watchlistall2": "tot",
        "watchlist-options": "Opcions de la lista de seguiment",
        "watching": "Seguit...",
        "unwatching": "Fin del seguit...",
        "movenosubpage": "Aquesta pagina a pas cap de sospagina.",
        "movereason": "Motiu :",
        "revertmove": "anullar",
-       "delete_and_move": "Suprimir e tornar nomenar",
        "delete_and_move_text": "==Supression requerida==\nL’article de destinacion « [[:$1]] » existís ja.\nLo volètz suprimir per permetre lo cambiament de nom ?",
        "delete_and_move_confirm": "Òc, accèpti de suprimir la pagina de destinacion per permetre lo cambiament de nom.",
        "delete_and_move_reason": "Pagina suprimida per permetre lo cambiament de nom dempuèi « [[$1]] »",
index addacea..8f760e4 100644 (file)
        "sort-ascending": "ସାନରୁ ବଡ଼ କ୍ରମେ ସଜାନ୍ତୁ",
        "nstab-main": "ପୃଷ୍ଠା",
        "nstab-user": "ବ୍ୟବହାରକାରୀଙ୍କର ପୃଷ୍ଠା",
-       "nstab-media": "ମà­\87ଡିà¬\86 à¬ªà¬°à¬¦",
+       "nstab-media": "ମିଡ଼ିà¬\86 à¬ªà­\83ଷà­\8dଠା",
        "nstab-special": "ବିଶେଷ ପୃଷ୍ଠା",
        "nstab-project": "ପ୍ରକଳ୍ପ ପୃଷ୍ଠା",
        "nstab-image": "ଫାଇଲ",
        "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|ସଭ୍ୟ|ସଭ୍ୟଗଣା}}ଙ୍କୁ ଦେଖୁଅଛି]",
        "rc_categories": "ଶ୍ରେଣୀସମୂହ ପାଇଁ ସୀମା ( \"|\" ଦେଇ ଅଲଗା କରିବେ)",
        "rc_categories_any": "ଯେ କୌଣସି",
-       "rc-change-size-new": "ବଦଳପରେ $1 {{PLURAL:$1|ବାଇଟ|ବାଇଟ}}",
+       "rc-change-size-new": "ବଦଳ ପରେ $1 {{PLURAL:$1|ବାଇଟ|ବାଇଟ}}",
        "newsectionsummary": "/* $1 */ ନୂଆ ଭାଗ",
        "rc-enhanced-expand": "ସବିଶେଷ ଦେଖାନ୍ତୁ",
        "rc-enhanced-hide": "ବେଶି କଥାସବୁ ଲୁଚାଇଦିଅ",
        "cachedspecial-viewing-cached-ts": "ଆପଣ ଏହି ପୃଷ୍ଠାର ଏକ ପୁରୁଣା ସଂସ୍କରଣ ଦେଖୁଛନ୍ତି, ଯାହାକି ପ୍ରକୃତରେ ସଂପୂର୍ଣ ନ ହୋଇଥାଇପାରେ ।",
        "cachedspecial-refresh-now": "ନୂତନତମ ଦେଖନ୍ତୁ ।",
        "categories": "ଶ୍ରେଣୀସମୂହ",
-       "categoriespagetext": "ତଳଲିà¬\96ିତ {{PLURAL:$1|ଶà­\8dରà­\87ଣà­\80|ଶà­\8dରà­\87ଣà­\80ସମà­\82ହ}}ରà­\87 à¬ªà­\83ଷà­\8dଠା à¬¬à¬¾ à¬®à­\87ଡ଼ିଆ ରହିଅଛି ।\n[[Special:UnusedCategories|ବ୍ୟବହାର ହୋଇନଥିବା ଶ୍ରେଣୀସବୁ]] ଦେଖାଯାଇନାହିଁ ।\n[[Special:WantedCategories|ଦରକାରୀ ଶ୍ରେଣୀସମୂହ]] ସବୁ ଦେଖନ୍ତୁ ।",
+       "categoriespagetext": "ତଳଲିà¬\96ିତ {{PLURAL:$1|ଶà­\8dରà­\87ଣà­\80|ଶà­\8dରà­\87ଣà­\80ସମà­\82ହ}}ରà­\87 à¬ªà­\83ଷà­\8dଠା à¬¬à¬¾ à¬®à¬¿ଡ଼ିଆ ରହିଅଛି ।\n[[Special:UnusedCategories|ବ୍ୟବହାର ହୋଇନଥିବା ଶ୍ରେଣୀସବୁ]] ଦେଖାଯାଇନାହିଁ ।\n[[Special:WantedCategories|ଦରକାରୀ ଶ୍ରେଣୀସମୂହ]] ସବୁ ଦେଖନ୍ତୁ ।",
        "categoriesfrom": "ଏହି ନାମରେ ଆରମ୍ଭ ହେଉଥିବା ଶ୍ରେଣୀଗୁଡ଼ିକୁ ଦେଖାଇବେ:",
        "special-categories-sort-count": "ଗଣନ କରି ସଜାଇବେ",
        "special-categories-sort-abc": "ଅକ୍ଷରର କ୍ରମ ଅନୁସାରେ ସଜାଇବେ",
        "movenosubpage": "ଏହି ପୃଷ୍ଠାର ଉପପୃଷ୍ଠା ନାହିଁ ।",
        "movereason": "କାରଣ:",
        "revertmove": "ପଛକୁ ଫେରାଇବେ",
-       "delete_and_move": "ଲିଭାଇବେ ଓ ଘୁଞ୍ଚାଇବେ",
        "delete_and_move_text": "== ଲିଭାଇବା ଦରକାର ==\nମୁକାମ ପୃଷ୍ଠା \"[[:$1]]\" ଟି ଆଗରୁ ଅଛି ।\nଆପଣ ଏହାକୁ ଲିଭାଇ ଘୁଞ୍ଚାଇବାକୁ ବାଟ କଢ଼ାଇବାକୁ ଚାହାନ୍ତି କି?",
        "delete_and_move_confirm": "ହଁ, ଏହି ପୃଷ୍ଠାଟିକୁ ଲିଭାଇଦେବେ",
        "delete_and_move_reason": "\"[[$1]]\" ପାଇଁ ପଥ ସଳଖ କରିବା ନିମନ୍ତେ ଲିଭାଇଦିଆଗଲା",
        "feedback-message": "ଖବର:",
        "feedback-subject": "ବିଷୟ:",
        "feedback-submit": "ଦାଖଲ କରିବା",
-       "feedback-thanks": "ଧନà­\8dà­\9fବାଦ ! à¬\86ପଣà¬\99à­\8dà¬\95ର à¬®à¬¤à¬¾à¬®à¬¤  \"[$2 $1]\" à¬ªà­\83ଷà­\8dଠାରà­\87 à¬¦à¬°à­\8dଶାଯାଇଛି ।",
-       "feedback-thanks-title": "ଧନà­\8dà­\9fବାଦ!",
+       "feedback-thanks": "ସାଧà­\81ବାଦ ! à¬\86ପଣà¬\99à­\8dà¬\95ର à¬®à¬¤à¬¾à¬®à¬¤  \"[$2 $1]\" à¬ªà­\83ଷà­\8dଠାରà­\87 à¬¸à¬¾à¬\87ତାଯାଇଛି ।",
+       "feedback-thanks-title": "ସାଧà­\81ବାଦ!",
        "searchsuggest-search": "ଖୋଜନ୍ତୁ",
        "searchsuggest-containing": "ଖୋଜୁଛି...",
        "api-error-badaccess-groups": "ଆପଣଙ୍କୁ ଏହି ଉଇକିରେ ଅପଲୋଡ଼ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇନାହିଁ ।",
index f6ffa81..56ac0e2 100644 (file)
        "underline-never": "Nigdy",
        "underline-default": "według ustawień skórki lub przeglądarki",
        "editfont-style": "Styl czcionki w polu edycyjnym:",
-       "editfont-default": "domyślny przeglądarki",
+       "editfont-default": "Domyślny przeglądarki",
        "editfont-monospace": "czcionka o stałej szerokości",
        "editfont-sansserif": "czcionka bezszeryfowa",
        "editfont-serif": "czcionka szeryfowa",
        "morenotlisted": "Nie jest to kompletna lista.",
        "mypage": "Strona",
        "mytalk": "Dyskusja",
-       "anontalk": "Dyskusja tego IP",
+       "anontalk": "Dyskusja",
        "navigation": "Nawigacja",
        "and": "&#32;oraz",
        "qbfind": "Znajdź",
        "uploaddisabledtext": "Możliwość przesyłania plików została wyłączona.",
        "php-uploaddisabledtext": "Przesyłanie plików PHP zostało zablokowane. Sprawdź ustawienie „file_uploads”.",
        "uploadscripted": "Plik zawiera kod HTML lub skrypt, który może zostać błędnie zinterpretowany przez przeglądarkę internetową.",
+       "uploaded-script-svg": "Znaleziono element skryptowy „$1” we przesyłanym pliku SVG.",
+       "uploaded-hostile-svg": "Znaleziono niebezpieczny kod CSS w przesyłanym pliku SVG.",
        "uploadscriptednamespace": "Ten plik SVG zawiera niedozwoloną przestrzeń nazw '$1'",
        "uploadinvalidxml": "Nie udało się przeanalizować XML w załadowanym pliku.",
        "uploadvirus": "W pliku jest wirus! Szczegóły: $1",
        "wlshowhidebots": "boty",
        "wlshowhideliu": "zarejestrowanych",
        "wlshowhideanons": "anonimowych",
+       "wlshowhidepatr": "sprawdzone edycje",
        "wlshowhidemine": "moje edycje",
        "watchlist-options": "Opcje obserwowanych",
        "watching": "Dodaję do obserwowanych...",
        "cantrollback": "Nie można cofnąć edycji tego autora, ponieważ jest jedynym autorem tej strony.",
        "alreadyrolled": "Nie można dla strony [[:$1|$1]] cofnąć ostatniej zmiany, którą wykonał [[User:$2|$2]] ([[User talk:$2|dyskusja]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]).\nKtoś inny zdążył już to zrobić lub wprowadził własne poprawki do treści strony.\n\nAutorem ostatniej zmiany jest teraz [[User:$3|$3]] ([[User talk:$3|dyskusja]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Edycję opisał „''$1''”.",
-       "revertpage": "Wycofano edycje użytkownika [[Special:Contributions/$2|$2]]. Autor przywróconej wersji to [[User:$1|$1]].",
+       "revertpage": "Wycofano edycje użytkownika [[Special:Contributions/$2|$2]] ([[User talk:$2|dyskusja]]). Autor przywróconej wersji to [[User:$1|$1]].",
        "revertpage-nouser": "Wycofano edycje ukrytego użytkownika. Autor przywróconej wersji to {{GENDER:$1|[[User:$1|$1]]}}.",
        "rollback-success": "Wycofano edycje użytkownika $1;\nprzywrócono ostatnią wersję autorstwa $2.",
        "sessionfailure-title": "Błąd sesji",
        "contributions": "Wkład {{GENDER:$1|użytkownika|użytkowniczki}}",
        "contributions-title": "Wkład {{GENDER:$1|użytkownika|użytkowniczki}} $1",
        "mycontris": "Edycje",
+       "anoncontribs": "Edycje",
        "contribsub2": "Dla {{GENDER:$3|użytkownika|użytkowniczki}} $1 ($2)",
        "contributions-userdoesnotexist": "Konto użytkownika „$1” nie jest zarejestrowane.",
        "nocontribs": "Brak zmian odpowiadających tym kryteriom.",
        "movenosubpage": "Ta strona nie posiada podstron.",
        "movereason": "Powód:",
        "revertmove": "cofnij",
-       "delete_and_move": "Usuń i przenieś",
        "delete_and_move_text": "== Przeniesienie wymaga usunięcia innej strony ==\nStrona docelowa „[[:$1]]” istnieje.\nCzy chcesz ją usunąć, by zrobić miejsce dla przenoszonej strony?",
        "delete_and_move_confirm": "Tak, usuń stronę",
        "delete_and_move_reason": "Usunięto, by zrobić miejsce dla przenoszonej strony „[[$1]]”",
        "tooltip-pt-preferences": "Moje preferencje",
        "tooltip-pt-watchlist": "Lista stron obserwowanych przez Ciebie",
        "tooltip-pt-mycontris": "Lista moich edycji",
+       "tooltip-pt-anoncontribs": "Lista edycji wykonanych z tego adresu IP",
        "tooltip-pt-login": "Zachęcamy do zalogowania się, choć nie jest to obowiązkowe.",
        "tooltip-pt-logout": "Wyloguj",
        "tooltip-pt-createaccount": "Zachęcamy do stworzenia konta i zalogowania, ale nie jest to konieczne.",
index 0ffb96a..9e53166 100644 (file)
        "index-category": "ليکلړلرونکي مخونه",
        "noindex-category": "بې ليکلړه مخونه",
        "broken-file-category": "د دوتنو د ماتو تړنو مخونه",
+       "categoryviewer-pagedlinks": "($1) ($2)",
        "about": "په اړه",
        "article": "مېنځپانگيز مخ",
        "newwindow": "(په نوې کړکۍ کې پرانيستل کېږي)",
        "morenotlisted": "دا لړليک بشپړ نه دی",
        "mypage": "زما مخ",
        "mytalk": "خبرې اترې",
-       "anontalk": "ددÛ\90 IP Ø®Ø¨Ø±Û\90 Ø§ØªØ±Û\90",
+       "anontalk": "خبرې اترې",
        "navigation": "گرځښت",
        "and": "&#32;او",
        "qbfind": "موندل",
        "versionrequired": "د ميډياويکي $1 بڼې ته اړتيا ده",
        "versionrequiredtext": "د دې مخ په ليدلو کې د مېډياويکي $1 بڼې ته اړتيا ده. \n[[Special:Version|د بڼې مخ وگورۍ]].",
        "ok": "ښه",
+       "pagetitle": "$1 - {{SITENAME}}",
        "pagetitle-view-mainpage": "{{SITENAME}}",
+       "backlinksubtitle": "← $1",
        "retrievedfrom": "\"$1\" نه اخيستل شوی",
        "youhavenewmessages": "تاسې $1 لری  ($2).",
        "youhavenewmessagesfromusers": "تاسې د {{PLURAL:$3|يو بل کارن|$3 کارنانو}} لخوا $1 لرۍ ($2).",
        "user-mail-no-addy": "د يوې برېښليک پتې پرته د برېښليک لېږلو هڅه شوې.",
        "changepassword": "پټنوم بدلول",
        "resetpass_announce": "د ننوتلو د بشپړېدلو لپاره بايد تاسې يو نوی پټنوم وټاکئ.",
+       "resetpass_text": "<!-- متن مو دلته وليکئ -->",
        "resetpass_header": "د گڼون پټنوم بدلول",
        "oldpassword": "زوړ پټنوم:",
        "newpassword": "نوی پټنوم:",
        "headline_tip": "د ۲ کچې سرليک",
        "nowiki_sample": "دلته دې بې بڼې متن ځای پر ځای شي",
        "nowiki_tip": "د ويکي بڼه نيونه بابېزه گڼل",
+       "image_sample": "Example.jpg",
        "image_tip": "خښه شوې دوتنه",
+       "media_sample": "Example.ogg",
        "media_tip": "د دوتنې تړنه",
        "sig_tip": "ستاسې لاسليک د وخت د ټاپې سره",
        "hr_tip": "څنډيزه ليکه (ددې په کارولو کې سپما وکړۍ)",
        "template-protected": "(ژغورلی)",
        "template-semiprotected": "(نيم-ژغورلی)",
        "hiddencategories": "دا مخ د {{PLURAL:$1|1 پټې وېشنيزې|$1 پټو وېشنيزو}} يو غړی دی:",
+       "edittools-upload": "-",
        "nocreatetext": "{{SITENAME}} د نوو مخونو د جوړولو وړتيا محدوده کړې.\nتاسو بېرته پر شا تللای شی او په شته مخونو کې سمونې ترسره کولای شی، او يا هم [[Special:UserLogin|غونډال ته ننوتلای او يو گڼون جوړولای شی]].",
        "nocreate-loggedin": "تاسې د نوو مخونو د جوړولو پرېښله نلرۍ.",
        "sectioneditnotsupported-title": "د برخې د سمون ملاتړ نه کېږي",
        "content-model-text": "ساده متن",
        "content-model-javascript": "جاواسکرېپټ",
        "content-model-css": "CSS",
+       "content-model-json": "JSON",
        "content-json-empty-object": "تش څيز",
        "post-expand-template-inclusion-warning": "'''گواښنه:''' دا کينډۍ د خپل ټاکلي بريد نه ډېره لويه ده.\nځينې کينډۍ به په کې گډې نه شي.",
        "post-expand-template-inclusion-category": "هغه مخونه چې په کې د کارېدلو کينډيو شمېر له ټاکلې کچې ډېر دی",
        "mergehistory-comment": "[[:$1]] [[:$2]] کې اخږل شوی: $3",
        "mergehistory-same-destination": "د سرچينې او موخې مخونه بايد يو ډول نه وي",
        "mergehistory-reason": "سبب:",
+       "mergehistory-revisionrow": "$1 ($2) $3 . . $4 $5 $6",
        "mergelog": "د اخږلو يادښت",
        "revertmerge": "بېلول",
        "mergelogpagetext": "دلته لاندې د يو مخ د پېښليک تازه اخږنه بل مخ ته د يو لړليک په توگه راغلی.",
        "youremail": "برېښليک *",
        "username": "{{GENDER:$1|کارن نوم}}:",
        "prefs-memberingroups": "د {{PLURAL:$1|ډله|ډلې}} {{GENDER:$2|غړی}}:",
+       "prefs-memberingroups-type": "$1",
        "prefs-registration": "د نومليکنې وخت:",
+       "prefs-registration-date-time": "$1",
        "yourrealname": "اصلي نوم:",
        "yourlanguage": "ژبه:",
        "yourvariant": "د ژبگړدود مېنځپانگه:",
        "saveusergroups": "کارن ډلې خوندي کول",
        "userrights-groupsmember": "غړی د:",
        "userrights-groupsmember-auto": "ضمني غړی د:",
+       "userrights-groupsmember-type": "$1",
        "userrights-groups-help": "تاسې هغه ډلې چې همدا کارن يې غړی دی بدلولی شی:\n* يو په نښه شوی بکس د دې مانا لري چې کارن د هغې ډلې غړيتوب لري.\n* يو نانښه شوی بکس د دې مانا لري چې کارن د هغې ډلې غړيتوب نلري.\n* د * يوه نښه په دې مانا ده چې هر کله تاسې څوک په همدې ډلې کې غړی کړی بيا يې ترې نشی وېستلی او د دې برعکس هم.",
        "userrights-reason": "سبب:",
        "userrights-no-interwiki": "په همدې ويکي باندې تاسې د کارن رښتو د سمولو اجازه نه لرۍ.",
        "userrights-changeable-col": "هغه ډلې چې تاسې يې بدلولی شی",
        "userrights-unchangeable-col": "هغه ډلې چې تاسې يې نه شی بدلولی",
+       "userrights-irreversible-marker": "$1*",
        "group": "ډله:",
        "group-user": "کارنان",
        "group-autoconfirmed": "تاييد شوي کارنان",
        "recentchanges-label-plusminus": "د بايټونو د شمېر له مخې د مخ د بدلون کچه",
        "recentchanges-legend-heading": "'''لنډونونه:'''",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|د نويو مخونو لړليک]] هم وگورئ)",
+       "recentchanges-legend-plusminus": "(<em>±123</em>)",
        "rcnotefrom": "دلته لاندې د <strong>$2</strong> څخه راپدېخوا پېښ شوي بدلونونه راغلي (تر <strong>$1</strong> پورې ښکاري).",
        "rclistfrom": "نوي بدلونونه چې له $3، $2 څخه پيلېږي ښکاره کول",
        "rcshowhideminor": "وړې سمونې $1",
        "minoreditletter": "و",
        "newpageletter": "ن",
        "boteditletter": "ر",
+       "unpatrolledletter": "!",
        "number_of_watching_users_pageview": "[$1  {{PLURAL:$1|کتونکی کارن|کتونکي کارنان}}]",
        "rc_categories": "د وېشنيزو تر بريده (په \"|\" بېلول)",
        "rc_categories_any": "له ټاکل شويو هر يو",
+       "rc-change-size": "$1",
        "rc-change-size-new": "$1 {{PLURAL:$1|بايټ|بايټونه}} د بدلون وروسته",
        "newsectionsummary": "/* $1 */ نوې برخه",
        "rc-enhanced-expand": "تفصيل ښکاره کول",
        "upload-form-label-infoform-description": "څرگندونه",
        "upload-form-label-usage-title": "کارېدنې",
        "upload-form-label-usage-filename": "د دوتنې نوم",
+       "foreign-structured-upload-form-label-own-work": "دا زما خپل کار دی",
        "foreign-structured-upload-form-label-infoform-categories": "وېشنيزې",
        "foreign-structured-upload-form-label-infoform-date": "نېټه",
        "backend-fail-notexists": "د $1 په نوم دوتنه نشته.",
        "ntransclusions": "په $1 {{PLURAL:$1|مخ|مخونو}} کارېدلی",
        "specialpage-empty": "د دې راپور لپاره کومې پايلې نشته.",
        "lonelypages": "يتيم مخونه",
+       "lonelypagestext": "دا لانديني مخونه په {{SITENAME}} کې د هېڅ کوم بل مخ سره تړنې نه لري او په هېڅ کوم بل مخ کې نه دي رانغاړل شوي.",
        "uncategorizedpages": "ناوېشلي مخونه",
        "uncategorizedcategories": "ناوېشلې وېشنيزې",
        "uncategorizedimages": "ناوېشلي انځورنه",
        "wantedpages": "غوښتلي مخونه",
        "wantedpages-summary": "دا د هغو ناموجودو مخونو لړليک دی چې تر ټولو ډېرې تړنې لري، په دې لړليک کې د مخ گرځونو مخونه شامل نه دي. د هغو ناموجودو مخونو لپاره چې د مخ گرځونو مخونه په کې شامل دي، [[{{#special:BrokenRedirects}}|د ماتو مخ گرځونو لړليک]] کې کتلی شی.",
        "wantedfiles": "غوښتلې دوتنې",
+       "wantedfiletext-cat": "دا لاندې دوتنې دلته په نورو مخونو کې کارېدلي خو لا تر اوسه پورې نشته.. همداراز کېدای شي د باندنيو زېرمتونونو دوتنې د شتون سره سره دلته په لړليک کې راغلي وي. په دې ډول هرې ناسمې مثبته راوړنې باندې به <del>کرښه کښل</del> کېږي.\nد دې تر څنگ هغه مخونه چې ناموجوده دوتنې په ځان کې رانغاړي د لړليک په بڼه، [[:$1]] کې موندلی شئ.",
+       "wantedfiletext-nocat": "دا لاندې دوتنې دلته په نورو مخونو کې کارېدلي خو لا تر اوسه پورې نشته.. همداراز کېدای شي د باندنيو زېرمتونونو دوتنې د شتون سره سره دلته په لړليک کې راغلي وي. په دې ډول هرې ناسمې مثبته راوړنې باندې به <del>کرښه کښل</del> کېږي.",
+       "wantedfiletext-nocat-noforeign": "دا لاندينۍ دوتنې دلته کارېدلي خو لا تر اوسه نشته.",
        "wantedtemplates": "غوښتلې کينډۍ",
        "mostlinked": "د ډېرو تړنو مخونه",
        "mostlinkedcategories": "د گڼو تړنو وېشنيزې",
-       "mostlinkedtemplates": "د ډېرو تړنو کينډۍ",
+       "mostlinkedtemplates": "ډېر رانغاړل شوي مخونه",
        "mostcategories": "د گڼو وېشنيزو مخونه",
        "mostimages": "د ډېرو تړنو انځورونه",
        "mostinterwikis": "د ډېرو خپلمنځي تړنو مخونه",
        "mostrevisions": "ډېر کتلي مخونه",
        "prefixindex": "د مختاړيو ټول مخونه",
        "prefixindex-namespace": "د مختاړي ټول مخونه ($1 نومتشيال)",
+       "prefixindex-strip": "په لړليک کې مختاړی غورځول",
        "shortpages": "لنډ مخونه",
        "longpages": "اوږده مخونه",
        "deadendpages": "بې پايه مخونه",
        "protectedpages-page": "مخ",
        "protectedpages-expiry": "پای نېټه",
        "protectedpages-performer": "ژغورونکی کارن",
+       "protectedpages-params": "د ژغورنې پاراميټرونه",
        "protectedpages-reason": "سبب",
        "protectedpages-unknown-timestamp": "ناجوت",
        "protectedpages-unknown-performer": "ناڅرگنده کارن",
        "apihelp-no-such-module": "د \"$1\" ماډيول و نه موندل شو.",
        "booksources": "د کتاب سرچينې",
        "booksources-search-legend": "د کتابي سرچينو پلټنه",
+       "booksources-isbn": "ISBN:",
        "booksources-search": "پلټل",
        "booksources-text": "دا لاندې د هغه وېبځايونو د تړنو لړليک دی چېرته چې نوي او زاړه کتابونه پلورل کېږي، او يا هم کېدای شي چې د هغه کتاب په هکله مالومات ولري کوم چې تاسو ورپسې لټېږۍ:",
        "booksources-invalid-isbn": "دا ISBN چې تاسې ورکړی سم نه ښکاري؛ د تېروتنو لپاره د لمېسلو اصلي سرچينه وگورئ.",
        "listgrouprights-rights": "رښتې",
        "listgrouprights-helppage": "Help:د ډلې رښتې",
        "listgrouprights-members": "(د غړو لړليک)",
+       "listgrouprights-right-display": "<span class=\"listgrouprights-granted\">$1 <code>($2)</code></span>",
+       "listgrouprights-right-revoked": "<span class=\"listgrouprights-revoked\">$1 <code>($2)</code></span>",
        "listgrouprights-addgroup": "{{PLURAL:$2|ډله|ډلې}} ورگډول: $1",
        "listgrouprights-removegroup": "{{PLURAL:$2|ډله|ډلې}} ليري کول: $1",
        "listgrouprights-addgroup-all": "ټولې ډلې ورگډول",
        "listgrouprights-removegroup-self": "خپل گڼون نه د {{PLURAL:$2|ډله|ډلې}} ليري کول: $1",
        "listgrouprights-addgroup-self-all": "خپل گڼون کې ټولې ډلې ورگډول",
        "listgrouprights-removegroup-self-all": "خپل گڼون نه ټولې ډلې ليري کول",
+       "listgrouprights-namespaceprotection-header": "د نومتشيال محدوديتونه",
        "listgrouprights-namespaceprotection-namespace": "نوم-تشيال",
+       "listgrouprights-namespaceprotection-restrictedto": "د کارن سمون ترسره کولو رښته(رښتې)",
        "trackingcategories": "موندونکې وېشنيزې",
        "trackingcategories-msg": "وېشنيزه موندنه",
        "trackingcategories-name": "پيغام نوم",
        "protect-fallback": "يوازې د \"$1\" اجازې لرونکي کارنان پرېښودل",
        "protect-level-autoconfirmed": "يوازې تاييد شوي کارنان",
        "protect-level-sysop": "يواځې پازوالان پرېښودل",
+       "protect-summary-desc": "[$1=$2] ($3)",
        "protect-summary-cascade": "ځوړاوبيز",
        "protect-expiring": "په $1 (UTC) پای ته رسېږي",
        "protect-expiring-local": "پای نېټه $1",
        "undelete-search-prefix": "هغه مخونه چې پيلېږي په:",
        "undelete-search-submit": "پلټل",
        "undelete-show-file-submit": "هو",
+       "undelete-revision-row": "$1 $2 ($3) $4 . . $5 $6 $7 $8 $9",
        "namespace": "نوم-تشيال:",
        "invert": "ټاکنې سرچپه کول",
        "tooltip-invert": "په ټاکلو نومتشيالونو کې (او اړونده نومتشيال کې که په نښه شوی وي) د مخونو بدلونونو د پټولو لپاره دا بکس په نښه کړئ",
        "contributions": "{{GENDER:$1|کارن}} ونډې",
        "contributions-title": "د $1 کارن ونډې",
        "mycontris": "ونډې",
+       "anoncontribs": "ونډې",
        "contribsub2": "د {{GENDER:$3|$1}} لپاره ($2)",
        "contributions-userdoesnotexist": "کارن گڼون \"$1\" نه دی ثبت شوی.",
        "nocontribs": "دې شرطونو سره سم بدلونونه و نه موندل شول.",
        "movenosubpage": "دا مخ کوم څېرمه مخونه نه لري.",
        "movereason": "سبب:",
        "revertmove": "په څټ گرځول",
-       "delete_and_move": "ړنگول او لېږدول",
        "delete_and_move_text": "== د ړنگولو اړتيا ==\nد \"[[:$1]]\" په نوم مخ له پخوا څخه شته.\nآيا د دې په ړنگولو سره لېږدولو ته لاره هوارول غواړۍ؟",
        "delete_and_move_confirm": "هو, دا مخ ړنگ کړه",
        "immobile-source-page": "دا مخ نه لېږدېدنونکی دی",
        "import-comment": "تبصره:",
        "import-revision-count": "$1 {{PLURAL:$1|بڼه|بڼې}}",
        "importnopages": "د رالېږدولو لپاره مخونه نشته.",
+       "imported-log-entries": "$1 {{PLURAL:$1|يادښتليک راوړل شوی|يادښتليکونه راوړل شوي}}.",
        "importcantopen": "واردونکې دوتنه و نه پرانيستل شوه.",
        "import-upload": "د XML اومتوک پورته کول",
        "import-token-mismatch": "د اومتوک غونډېدنه له لاسه وتلې.\nلطفاً بيا يې وآزمايئ.",
        "tooltip-undo": "\"ناکړ\" همدا سمون پر شا گرځوي او د سمون کړکۍ د مخکتنې په بڼه پرانيزي.\nدا کړنه د لنډيز په برخه کې د سمونونو د سببونو د ورگډولو آسانتيا برابروي.",
        "tooltip-preferences-save": "غوره توبونه خوندي کول",
        "tooltip-summary": "يو لنډ لنډيز کښل",
+       "interlanguage-link-title": "$1 – $2",
+       "interlanguage-link-title-nonlang": "$1 – $2",
        "anonymous": "د {{SITENAME}} {{PLURAL:$1|ورکنومی کارن|ورکنومي کارنان}}",
        "siteuser": "د {{SITENAME}} کارن $1",
        "anonuser": "د {{SITENAME}} ورکنومی کارن $1",
        "pageinfo-watchers": "د مخ د کتونکو شمېر",
        "pageinfo-few-watchers": "له $1 څخه لږ {{PLURAL:$1|کتونکی|کتونکي}}",
        "pageinfo-redirects-name": "دې مخ ته د ورگرځونو شمېر",
+       "pageinfo-redirects-value": "$1",
        "pageinfo-subpages-name": "دې مخ ته څېرمه مخونه",
        "pageinfo-firstuser": "مخ جوړونکی",
        "pageinfo-firsttime": "د مخ جوړېدنې نېټه",
        "exif-isospeedratings": "د ISO چټکتيا ارزونه",
        "exif-shutterspeedvalue": "د APEX بندگر چټکتيا",
        "exif-brightnessvalue": "د APEX رڼښت",
+       "exif-meteringmode": "رڼامېچنې حالت",
        "exif-lightsource": "د رڼا سرچينه",
        "exif-flash": "فلش",
        "exif-focallength": "د عدسيې کانوني واټن",
        "exif-subjectarea": "د جسم سيمه",
        "exif-flashenergy": "د فلش انرژي",
        "exif-subjectlocation": "د جسم ځای",
+       "exif-sensingmethod": "د حس کولو چلندلار",
        "exif-filesource": "د دوتنې سرچينه",
+       "exif-scenetype": "د صحنې ډول",
+       "exif-customrendered": "دوديزه انځور بهير",
+       "exif-exposuremode": "د رڼا غورځولو حالت",
        "exif-whitebalance": "د سپين رنگ توازن",
+       "exif-digitalzoomratio": "د گڼياليز لويواله پرتلنه",
+       "exif-gaincontrol": "د صحنې تنظيم",
+       "exif-contrast": "رڼښت",
+       "exif-saturation": "رنگ گاټه توب",
        "exif-gpsaltituderef": "د لوړوالي سرچينه",
        "exif-gpsaltitude": "لوړوالی",
+       "exif-gpsmeasuremode": "د مېچنې حالت",
+       "exif-gpsdop": "د مېچنې دقت",
        "exif-gpsspeedref": "د سرعت يوون",
+       "exif-gpsspeed": "د جي پي اس اخيستونکي چټکتيا",
+       "exif-gpstrack": "د خوځښت سمت",
        "exif-gpsimgdirection": "د انځور لوری",
        "exif-gpsareainformation": "د جي پي اس د سيمې نوم",
        "exif-gpsdatestamp": "د جي پي اس نېټه",
        "exif-lightsource-11": "سيوری",
        "exif-lightsource-255": "د رڼا بله سرچينه",
        "exif-flash-fired-0": "فلش و نه ځلېده",
+       "exif-flash-mode-3": "خپلکاره حالت",
        "exif-focalplaneresolutionunit-2": "انچه",
        "exif-sensingmethod-1": "ناڅرگنده",
        "exif-filesource-3": "گڼياليزه ولاړه کامره",
        "exif-gpsdestdistance-k": "کيلومتر",
        "exif-gpsdestdistance-m": "مايلونه",
        "exif-gpsdestdistance-n": "سمندري مايلونه",
+       "exif-gpsdop-excellent": "عالي ($1)",
        "exif-gpsdop-good": "ښه ($1)",
        "exif-gpsdop-moderate": "منځوی ($1)",
        "exif-gpsdop-fair": "نه ښه نه بد ($1)",
        "hebrew-calendar-m4": "تيفيت",
        "hebrew-calendar-m5": "شيفات",
        "hebrew-calendar-m6": "آدار",
+       "hebrew-calendar-m10-gen": "تموز",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|خبرې اترې]])",
        "duplicate-defaultsort": "'''گواښنه:'''د \"$2\" تلواليزه اوډون تڼۍ تر دې پخوا ټاکلې تلواليزه اوډون تڼۍ \"$1\" پر ځای چارنه کېږي.",
        "version": "بڼه",
        "specialpages-group-pagetools": "د مخ اوزارونه",
        "specialpages-group-wiki": "توکي او اوزارونه",
        "specialpages-group-redirects": "د ځانگړو مخونو مخ گرځونې",
+       "specialpages-group-developer": "د پرمختگگر اوزار",
        "blankpage": "تش مخ",
        "intentionallyblankpage": "همدا مخ په لوی لاس تش پرېښودل شوی دی",
        "external_image_whitelist": " #دا کرښه چې څنگه ده، همداسې پرېږدۍ<pre>\n#لاندې د منظمو اصطلاحگانو ټوټې (يوازې هغه برخه چې د // په مېنځ کې ليکلې) ځای پر ځای کړی\n#دا به د باندنيو انځورونو د يو آر اېل (hotlinked) سره مطابقه شي \n#هغه څه چې مطابقت لري هغه به د انځورونو په توگه ښکاره شي، کوم چې مطابقت نلري نو يوازې د انځور تړنه به ښکاره کېږي\n#هغه کرښې چې په # پيل کېږي د تبصرو په توگه په نظر کې نيول کېږي\n#دا کرښې د غټو تورو او وړو تورو سره حساسې نه دي\n\n#ټولې regex ټوټې د دغې کرښې نه پورته ځای پر ځای کړی. دا کرښه چې څنگه ده، همداسې يې پرېږدۍ</pre>",
+       "tags": "د کره بدلون نښلنونه",
        "tag-filter": "[[Special:Tags|نښلن]] چاڼگر:",
        "tag-filter-submit": "چاڼگر",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|نښلن|نښلنونه}}]]: $2)",
        "tags-create-already-exists": "د \"$1\" نښلن له پخوا څخه شته.",
        "tags-delete-title": "نښلن ړنگول",
        "tags-delete-reason": "سبب:",
+       "tags-activate-title": "نښلن فعالول",
+       "tags-activate-question": "تاسې د \"$1\" نښلن په فعالولو کې ياست.",
        "tags-activate-reason": "سبب:",
        "tags-activate-submit": "فعالول",
        "tags-deactivate-reason": "سبب:",
        "log-name-tag": "نښلن يادښت",
        "rightsnone": "(هېڅ)",
        "revdelete-summary": "لنډيز سمول",
+       "feedback-back": "پر شا کېدل",
        "feedback-cancel": "ناگارل",
        "feedback-close": "ترسره شو",
        "feedback-external-bug-report-button": "د يوې تخنيکي دندې دوتنه جوړونه",
        "limitreport-cputime-value": "$1 {{PLURAL:$1|ثانيه|ثانيې}}",
        "limitreport-walltime": "اصلي وخت کارېدنه",
        "limitreport-walltime-value": "$1 {{PLURAL:$1|ثانيه|ثانيې}}",
+       "limitreport-ppvisitednodes-value": "$1/$2",
+       "limitreport-ppgeneratednodes-value": "$1/$2",
        "limitreport-postexpandincludesize-value": "$1/$2 {{PLURAL:$2|بايټ|بايټونه}}",
        "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|بايټ|بايټونه}}",
+       "limitreport-expansiondepth-value": "$1/$2",
+       "limitreport-expensivefunctioncount-value": "$1/$2",
        "expandtemplates": "کينډۍ غځول",
        "expand_templates_input": "ځايونکی متن:",
        "expand_templates_output": "پايله",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''ناچارن''')",
        "mediastatistics": "د رسنيو شمار",
        "mediastatistics-summary": "د پورته شويو دوتنو اړونده شمارنې. په دې ځای کې د يوې دوتنې يوازې تر ټولو تازه بڼې شاملې شوي. د دوتنو زړې يا ړنگې شوې بڼې په دې شمارنو کې نه دي شاملې شوي.",
+       "mediastatistics-nfiles": "$1 ($2%)",
        "mediastatistics-nbytes": "{{PLURAL:$1|$1 بايټ|$1 بايټونه}} ($2; $3%)",
        "mediastatistics-table-mimetype": "MIME بڼه",
        "mediastatistics-table-extensions": "ممکنه شاتاړي",
        "special-characters-group-thai": "تايلنډي",
        "special-characters-group-lao": "لاوي",
        "special-characters-group-khmer": "خمري",
+       "mw-widgets-dateinput-placeholder-day": "کککک-م م-و و",
+       "mw-widgets-dateinput-placeholder-month": "کککک-م م",
        "mw-widgets-titleinput-description-new-page": "تر اوسه پورې دا مخ نشته",
        "mw-widgets-titleinput-description-redirect": "$1 ته ورگرځېدنه"
 }
index d674663..e1bc875 100644 (file)
@@ -93,6 +93,7 @@
        "tog-hideminor": "Ocultar edições menores nas mudanças recentes",
        "tog-hidepatrolled": "Ocultar edições patrulhadas nas mudanças recentes",
        "tog-newpageshidepatrolled": "Ocultar páginas patrulhadas da lista de páginas novas",
+       "tog-hidecategorization": "Ocultar a categorização das páginas",
        "tog-extendwatchlist": "Expandir a lista de páginas vigiadas para mostrar todas as mudanças, não apenas as mais recentes",
        "tog-usenewrc": "Agrupar alterações por páginas nas mudanças recentes e nas páginas vigiadas",
        "tog-numberheadings": "Auto-numerar cabeçalhos",
        "tog-watchlisthideliu": "Ocultar edições de usuários autenticados da lista de páginas vigiadas",
        "tog-watchlisthideanons": "Ocultar edições de usuários anônimos da lista de páginas vigiadas",
        "tog-watchlisthidepatrolled": "Ocultar edições patrulhadas da lista de páginas vigiadas",
+       "tog-watchlisthidecategorization": "Ocultar a categorização das páginas",
        "tog-ccmeonemails": "Receber cópias de e-mails que eu enviar a outros usuários",
        "tog-diffonly": "Não mostrar o conteúdo da página ao comparar duas edições",
        "tog-showhiddencats": "Exibir categorias ocultas",
        "category_header": "Páginas na categoria \"$1\"",
        "subcategories": "Subcategorias",
        "category-media-header": "Multimídia na categoria \"$1\"",
-       "category-empty": "''No momento esta categoria não possui nenhuma página ou arquivo multimídia.''",
+       "category-empty": "<em>No momento, esta categoria não possui nenhuma página ou arquivo multimídia.</em>",
        "hidden-categories": "{{PLURAL:$1|Categoria oculta|Categorias ocultas}}",
        "hidden-category-category": "Categorias ocultas",
        "category-subcat-count": "{{PLURAL:$2|Esta categoria possui apenas a seguinte subcategoria.|Esta categoria possui as seguintes $1 subcategorias, de um total de $2.}}",
        "morenotlisted": "Esta lista não está completa.",
        "mypage": "Página",
        "mytalk": "Discussão",
-       "anontalk": "Discussão para este IP",
+       "anontalk": "Discussão para este endereço IP",
        "navigation": "Navegação",
        "and": "&#32;e",
        "qbfind": "Procurar",
        "qbedit": "Editar",
        "qbpageoptions": "Esta página",
        "qbmyoptions": "Minhas páginas",
-       "faq": "FAQ",
-       "faqpage": "Project:FAQ",
+       "faq": "Perguntas frequentes",
+       "faqpage": "Project:Perguntas frequentes",
        "actions": "Ações",
        "namespaces": "Domínios",
        "variants": "Variantes",
        "permalink": "Ligação permanente",
        "print": "Imprimir",
        "view": "Ver",
-       "view-foreign": "Ver no $1",
+       "view-foreign": "Ver em $1",
        "edit": "Editar",
        "edit-local": "Editar descrição local",
        "create": "Criar",
        "create-this-page": "Iniciar esta página",
        "delete": "Eliminar",
        "deletethispage": "Eliminar esta página",
-       "undeletethispage": "Restaure esta página",
+       "undeletethispage": "Restaurar esta página",
        "undelete_short": "Restaurar {{PLURAL:$1|uma edição|$1 edições}}",
        "viewdeleted_short": "Ver {{PLURAL:$1|uma edição eliminada|$1 edições eliminadas}}",
        "protect": "Proteger",
        "unprotect": "Alterar a proteção",
        "unprotectthispage": "Alterar a proteção desta página",
        "newpage": "Página nova",
-       "talkpage": "Dialogar sobre esta página",
+       "talkpage": "Discutir sobre esta página",
        "talkpagelinktext": "Discussão",
        "specialpage": "Página especial",
        "personaltools": "Ferramentas pessoais",
        "upload-form-label-infoform-description": "Descrição",
        "upload-form-label-usage-title": "Uso",
        "upload-form-label-usage-filename": "Nome do arquivo",
+       "foreign-structured-upload-form-label-infoform-categories": "Categorias",
+       "foreign-structured-upload-form-label-infoform-date": "Data",
        "backend-fail-stream": "Não foi possível transmitir o arquivo  $1.",
        "backend-fail-backup": "Não foi possível fazer backup do arquivo  $1 .",
        "backend-fail-notexists": "O arquivo $1 não existe.",
        "emailccsubject": "Cópia de sua mensagem para $1: $2",
        "emailsent": "E-mail enviado",
        "emailsenttext": "Sua mensagem foi enviada.",
-       "emailuserfooter": "Este email foi enviado por $1 para $2 através da função\"{{int:emailuser}}\" do site {{SITENAME}}.",
+       "emailuserfooter": "Este e-mail foi {{GENDER:$1|enviado}} por $1 para {{GENDER:$2|$2}} através do recurso \"{{int:emailuser}}\" do site {{SITENAME}}.",
        "usermessage-summary": "Deixar mensagem de sistema.",
        "usermessage-editor": "Mensagens de sistema",
        "watchlist": "Páginas vigiadas",
        "wlnote": "A seguir {{PLURAL:$1|está a última alteração ocorrida|estão as últimas <strong>$1</strong> alterações ocorridas}} {{PLURAL:$2|na última hora|nas últimas <strong>$2</strong> horas}} até $3, $4.",
        "wlshowlast": "Ver últimas $1 horas $2 dias",
        "watchlistall2": "todas",
+       "watchlist-hide": "Ocultar",
+       "wlshowhideminor": "edições menores",
+       "wlshowhidebots": "robôs",
+       "wlshowhideliu": "usuários registrados",
+       "wlshowhideanons": "usuários anônimos",
+       "wlshowhidepatr": "edições patrulhadas",
+       "wlshowhidemine": "minhas edições",
        "watchlist-options": "Opções da lista de páginas vigiadas",
        "watching": "Vigiando...",
        "unwatching": "Deixando de vigiar...",
        "deletepage": "Eliminar página",
        "confirm": "Confirmar",
        "excontent": "o conteúdo era: '$1'",
-       "excontentauthor": "o conteúdo era: \"$1\" (e o único editor era \"[[Special:Contributions/$2|$2]]\")",
+       "excontentauthor": "o conteúdo era: \"$1\",e o único editor era \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|discussão]])",
        "exbeforeblank": "o conteúdo antes de esvaziar era: '$1'",
        "delete-confirm": "Eliminar \"$1\"",
        "delete-legend": "Eliminar",
        "undeletepagetext": "{{PLURAL:$1|A seguinte página foi eliminada|As $1 páginas seguintes foram eliminadas}}, mas ainda {{PLURAL:$1|permanece|permanecem}} no arquivo e poderem ser restauradas.\nO arquivo pode ser limpo periodicamente.",
        "undelete-fieldset-title": "Restaurar edições",
        "undeleteextrahelp": "Para restaurar o histórico de edições completo desta página, desmarque todas as caixas de seleção e clique '''''{{int:undeletebtn}}'''''.\nPara efectuar uma restauração seletiva, marque as caixas correspondentes às edições que pretende restaurar e clique '''''{{int:undeletebtn}}'''''.",
-       "undeleterevisions": "$1 {{PLURAL:$1|edição disponível|edições disponíveis}}",
+       "undeleterevisions": "$1 {{PLURAL:$1|revisão eliminada|revisões eliminadas}}",
        "undeletehistory": "Se restaurar a página, todas as revisões serão restauradas para o histórico.\nSe uma nova página foi criada com o mesmo nome desde a eliminação, as edições restauradas aparecerão no histórico anterior.",
        "undeleterevdel": "O restauro não será executado se resultar na remoção parcial da versão mais recente da página ou arquivo.\nEm tais casos, deverá desselecionar ou reverter a ocultação da versão apagada mais recente.",
        "undeletehistorynoadmin": "Esta página foi eliminada. O motivo de eliminação é apresentado no súmario abaixo, junto dos detalhes do usuário que editou esta página antes de eliminar. O texto atual destas edições eliminadas encontra-se agora apenas disponível para administradores.",
        "move-page-legend": "Mover página",
        "movepagetext": "Utilizando o formulário a seguir você poderá renomear uma página, movendo todo o histórico para o novo título.\nO título anterior será transformado em um redirecionamento para o novo.\nVocê poderá optar em atualizar automaticamente os redirecionamentos que se destinem ao título original.\nCaso escolha pela não-atualização, se certifique de verificar por redirecionamentos [[Special:DoubleRedirects|duplos]] ou [[Special:BrokenRedirects|quebrados]].\nÉ de sua responsabilidade que os links continuem direcionando para onde eles devem.\n\nNote que a página '''não''' será movida se já existir uma página com o novo título, a não ser que ele seja um redirecionamento e não tenha histórico de edições.\nIsto significa que você pode renomear uma página de volta para o seu nome anterior se cometer algum engano e que não poderá sobrescrever uma página existente.\n\n'''CUIDADO!'''\nEsta pode ser uma mudança drástica e inesperada para uma página popular;\ntenha certeza de que compreende as consequências da mudança antes de prosseguir.",
        "movepagetext-noredirectfixer": "Usando o formulário abaixo, você irá alterar o nome de uma página e moverá todo o histórico desta para o nome novo.\nA página antiga será transformada numa página de redirecionamento para a nova.\nVerifique a existência de [[Special:DoubleRedirects|redirecionamentos duplos]] ou [[Special:BrokenRedirects|quebrados]].\nÉ sua responsabilidade certificar-se de que os links continuam a apontar para onde eles deveriam apontar.\n\nNote que a página '''não''' será movida se já existir uma página com o nome novo, a menos que esta página esteja vazia ou seja uma página de redirecionamento e não tenha um histórico de edições.\nIsto significa que, se você cometer um engano, poderá alterar o nome da página movida de volta para o seu nome original; e que não pode sobrescrever o conteúdo de uma página existente.\n\n'''Aviso!'''\nPara páginas populares, esta operação pode representar uma mudança drástica e inesperada;\ncertifique-se de que compreende as consequências da operação antes de continuar.",
-       "movepagetalktext": "A página de \"discussão\" associada, se existir, será automaticamente movida, '''a não ser que:'''\n*Uma página de discussão com conteúdo já exista sob o novo título, ou\n*Você não marque a caixa abaixo.\n\nNestes casos, você terá que mover ou mesclar a página manualmente, se assim desejar.",
+       "movepagetalktext": "Caso marcar esta caixa, a página de discussão associada será automaticamente movida para um novo título, a menos que uma página de discussão com conteúdo já existir lá.\n\n\nNeste caso, você deverá mover ou mesclar a página manualmente se desejar.",
        "moveuserpage-warning": "'''Aviso:''' Você irá mover uma página de usuário. Note que apenas a página será movida, ''sem'' alterar o nome do usuário.",
        "movecategorypage-warning": "<strong>Aviso:</strong> Você está prestes a mover uma página de categoria. Por favor, note que apenas a página será transferida e quaisquer páginas da categoria antiga <em>não</em> serão recategorizadas para o novo.",
        "movenologintext": "Você precisa ser um usuário registrado e [[Special:UserLogin|autenticado]] para poder mover uma página.",
        "cant-move-to-user-page": "Você não tem permissão para mover uma página para uma página de usuários (exceto para uma subpágina de usuário).",
        "cant-move-category-page": "Você não possui permissão para mover páginas de categorias.",
        "cant-move-to-category-page": "Você não tem permissão para mover uma página para uma categoria de páginas.",
-       "newtitle": "Para novo título",
+       "newtitle": "Novo título:",
        "move-watch": "Vigiar esta página",
        "movepagebtn": "Mover página",
        "pagemovedsub": "Página movida com sucesso",
        "movenosubpage": "Esta página não tem subpáginas.",
        "movereason": "Motivo:",
        "revertmove": "reverter",
-       "delete_and_move": "Eliminar e mover",
        "delete_and_move_text": "==Eliminação necessária==\nA página de destino (\"[[:$1]]\") já existe. Deseja eliminá-la de modo a poder mover?",
        "delete_and_move_confirm": "Sim, eliminar a página",
        "delete_and_move_reason": "Eliminada para mover \"[[$1]]\"",
        "log-description-pagelang": "Este é um registro de alterações aos idiomas das páginas.",
        "logentry-pagelang-pagelang": "$1 {{GENDER:$2|alterou}} o idioma da página $3 de $4 para $5.",
        "default-skin-not-found": "Ops! A aparência padrão para sua wiki, definida em <code dir=\"ltr\">$wgDefaultSkin</code> como <code>$1</code>, não está disponível.\n\nSua instalação parece incluir a(s) seguinte(s) {{PLURAL:$4|aparência|aparências}}. Veja [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Configuração de aparência] para informações sobre como  {{PLURAL:$4|habilitá-la|habilitá-las e escolha a padrão}}.\n\n$2\n\n; Se você já instalou o MediaWiki:\n: Você provavelmente instalou do git, ou diretamente do código fonte usando usando algum outro método. Isto é esperado. Tente instalar algumas aparências do [https://www.mediawiki.org/wiki/Category:All_skins diretório de aparências do mediawiki.org]:\n:* Baixando o [https://www.mediawiki.org/wiki/Download instalador tarball], que vem com várias aparências e extensões. Você pode copiar e colar o diretório <code>skins/</code> dele.\n:* Baixando tarballs individuais de aparência de [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git/pt-br#Usando_o_Git_para_baixar_extensões_do_MediaWiki Usando o Git para baixar aparências].\n: Fazer isso não deve interferir no seu repositório git se você é um desenvolvedor MediaWiki.\n\n; Se você já atualizou o MediaWiki:\n: O MediaWiki 1.24 e os mais recentes não permitem mais aparências instaladas automaticamente (veja [https://www.mediawiki.org/wiki/Manual:Skin_autodiscovery Manual: Skin autodiscovery]). Você pode colar {{PLURAL:$5|a seguinte linha|as seguintes linhas}} em <code>LocalSettings.php</code> para habilitar {{PLURAL:$5|a|todas as}} {{PLURAL:$5|aparência instalada|aparências instaladas}}:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Se você já modificou <code>LocalSettings.php</code>:\n: Verifique cuidadosamente se não há erros de digitação nos nomes das aparências.",
-       "default-skin-not-found-no-skins": "Ops! A aparência padrão para sua wiki, definida em <code>$wgDefaultSkin</code> como <code>$1</code>, não está disponível.\n\nVocê não tem aparências instaladas.\n\n; Se você já instalou ou atualizou o MediaWiki:\n: Você provavelmente instalou do git, ou diretamente do código fonte usando usando algum outro método. Isto é esperado. O MediaWiki 1.24 e mais recentes não incluem todas as aparências no repositório principal.Tente instalar algumas aparências do [https://www.mediawiki.org/wiki/Category:All_skins diretório de aparências do mediawiki.org]:\n:* Baixando o [https://www.mediawiki.org/wiki/Download instalador tarball], que vem com várias aparências e extensões. Você pode copiar e colar o diretório <code>skins/</code> dele.\n:* Baixando tarballs individuais de aparência de [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Clonando um dos repositórios <code>mediawiki/skins/*</code> via git no diretório <code dir=\"ltr\">skins/</code> de sua instalação MediaWiki.\n: Fazer isso não deve interferir no seu repositório git se você é um desenvolvedor MediaWiki.Veja [https://www.mediawiki.org/wiki/Manual:Skin_configuration Manual: Skin configuration] para informações sobre como habilitar aparências e escolhar a padrão.",
+       "default-skin-not-found-no-skins": "Opa! A aparência padrão da sua wiki, definida em <code>$wgDefaultSkin</code> como <code>$1</code>, não está disponível.\n\nVocê não tem aparências instaladas.\n\n; Se você acabou de instalar ou atualizar o MediaWiki:\n: Você provavelmente instalou do git, ou diretamente do código-fonte usando usando algum outro método. Isto é esperado. O MediaWiki 1.24 e mais recentes não incluem aparências no repositório principal. Tente instalar algumas aparências do [https://www.mediawiki.org/wiki/Category:All_skins/pt-br diretório de aparências do mediawiki.org]:\n:* Baixando o [https://www.mediawiki.org/wiki/Download/pt-br instalador tarball], que vem com várias aparências e extensões. Você pode copiar e colar o diretório <code>skins/</code> dele.\n:* Baixando tarballs individuais de aparência do [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* [https://www.mediawiki.org/wiki/Download_from_Git#Usando_o_Git_para_baixar_aparências_do_MediaWiki Usando o Git para baixar aparências].\n: Fazer isso não deve interferir no seu repositório git se você for um(a) desenvolvedor(a) do MediaWiki. Veja [https://www.mediawiki.org/wiki/Manual:Skin_configuration/pt-br Manual:Configuração de aparências] para informações sobre como habilitar aparências e escolher a padrão.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (habilitado)",
        "default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''desabilitado''')",
        "mediastatistics": "Estatísticas de mídia",
index ec8ebcf..ddefe9e 100644 (file)
@@ -72,6 +72,7 @@
        "tog-hideminor": "Esconder edições menores nas mudanças recentes",
        "tog-hidepatrolled": "Esconder edições patrulhadas nas mudanças recentes",
        "tog-newpageshidepatrolled": "Esconder páginas patrulhadas na lista de páginas novas",
+       "tog-hidecategorization": "Ocultar categorização de páginas",
        "tog-extendwatchlist": "Listagem expandida de todas as mudanças às páginas vigiadas, não apenas das mais recentes",
        "tog-usenewrc": "Agrupar alterações por página nas mudanças recentes e páginas vigiadas",
        "tog-numberheadings": "Auto-numerar cabeçalhos",
        "morenotlisted": "Esta lista não está completa.",
        "mypage": "Página",
        "mytalk": "Discussão",
-       "anontalk": "Discussão para este IP",
+       "anontalk": "Discussão",
        "navigation": "Navegação",
        "and": "&#32;e",
        "qbfind": "Procurar",
        "title-invalid-interwiki": "O título da página solicitada contém uma ligação interlíngua que não pode ser utilizada em títulos.",
        "title-invalid-talk-namespace": "O título da página solicitada refere-se a uma página de discussão que não existe.",
        "title-invalid-characters": "O título da página solicitada contém carateres inválidos: \"$1\".",
+       "title-invalid-magic-tilde": "O título da página solicitada possui uma sequência de tis inválida (<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "O título da página solicitada é demasiado longo. Não deverá ser maior que $1 {{PLURAL:$1|byte|bytes}} na codificação UTF-8.",
        "title-invalid-leading-colon": "O título da página solicitada contém um erro de pontuação (:) no início.",
        "perfcached": "Os seguintes dados encontram-se armazenados na ''cache'' e podem não estar atualizados. No máximo {{PLURAL:$1|um resultado é disponível|$1 resultados são disponíveis}} na ''cache''.",
        "permissionserrors": "Erro de permissão",
        "permissionserrorstext": "Não possui permissão para fazer isso, {{PLURAL:$1|pelo seguinte motivo|pelos seguintes motivos}}:",
        "permissionserrorstext-withaction": "Não possui permissão para $2, {{PLURAL:$1|pelo seguinte motivo|pelos seguintes motivos}}:",
+       "contentmodelediterror": "Não pode editar esta revisão pois seu modelo de conteúdo é <code>$1</code>, e o modelo actual do conteúdo da página é <code>$2</code>.",
        "recreate-moveddeleted-warn": "'''Aviso: Está a recriar uma página anteriormente eliminada.'''\n\nVerifique se é apropriado continuar a editar esta página.\nPara sua conveniência, é apresentado de seguida o registo de eliminação e de movimento da página:",
        "moveddeleted-notice": "Esta página foi eliminada.\nPara referência, é apresentado de seguida o registo de eliminações e de movimento da página.",
        "moveddeleted-notice-recent": "Desculpe, esta página foi eliminada recentemente (nas últimas 24 horas).\nA exclusão e registo de movimentação para a página são fornecidos abaixo para referência.",
        "showingresultsinrange": "Apresenta-se abaixo {{PLURAL:$1|<strong>1</strong> resultado|até <strong>$1</strong> resultados}} no intervalo #<strong>$2</strong> a #<strong>$3</strong>.",
        "search-showingresults": "{{PLURAL:$4|Resultado <strong>$1</strong> de <strong>$3</strong>|Resultados <strong>$1 - $2</strong> de <strong>$3</strong>}}",
        "search-nonefound": "A pesquisa não produziu resultados.",
+       "search-nonefound-thiswiki": "Não existem resultados que correspondam à consulta neste sítio.",
        "powersearch-legend": "Pesquisa avançada",
        "powersearch-ns": "Pesquisar nos domínios:",
        "powersearch-togglelabel": "Marcar:",
        "rcshowhidemine": "$1 as minhas edições",
        "rcshowhidemine-show": "Mostrar",
        "rcshowhidemine-hide": "Ocultar",
+       "rcshowhidecategorization": "$1 categorização de páginas",
+       "rcshowhidecategorization-show": "Mostrar",
+       "rcshowhidecategorization-hide": "Ocultar",
        "rclinks": "Mostrar as últimas $1 mudanças nos últimos $2 dias<br />$3",
        "diff": "dif",
        "hist": "his",
        "recentchanges-page-added-to-category-bundled": "[[:$1]] e {{PLURAL:$2|uma outra página|$2 outras páginas}} foram adicionadas à categoria",
        "recentchanges-page-removed-from-category": "[[:$1]] foi removida da categoria",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] e {{PLURAL:$2|uma outra página|$2 outras páginas}} foram removidas da categoria",
+       "autochange-username": "Alteração automática do MediaWiki",
        "upload": "Carregar ficheiro",
        "uploadbtn": "Carregar ficheiro",
        "reuploaddesc": "Cancelar o envio e voltar ao formulário de carregamento",
        "wlnote": "A seguir {{PLURAL:$1|está a última alteração ocorrida|estão as últimas <strong>$1</strong> alterações ocorridas}} {{PLURAL:$2|na última hora|nas últimas <strong>$2</strong> horas}} até $3, $4.",
        "wlshowlast": "Ver últimas $1 horas $2 dias",
        "watchlistall2": "todas",
+       "watchlist-hide": "Ocultar",
+       "wlshowtime": "Mostrar mudanças desde há:",
        "wlshowhideminor": "edições menores",
        "wlshowhidebots": "robôs",
        "wlshowhideliu": "usuários registrados",
        "movenosubpage": "Esta página não tem subpáginas.",
        "movereason": "Motivo:",
        "revertmove": "reverter",
-       "delete_and_move": "Eliminar e mover",
        "delete_and_move_text": "==Eliminação necessária==\nA página de destino (\"[[:$1]]\") já existe. Deseja eliminá-la de modo a poder mover?",
        "delete_and_move_confirm": "Sim, eliminar a página",
        "delete_and_move_reason": "Eliminada para poder mover \"[[$1]]\" para este título",
index bd3776e..dcf26b3 100644 (file)
        "morenotlisted": "An indication that more of a templates list is not shown.\n\nUsed as \"More...\" link for {{msg-mw|pageinfo-templates}} field.\n\nSimilar to {{msg-mw|moredotdotdot}}.",
        "mypage": "A text for the link to the user's user page in the links at the top of the page.\n{{Identical|Page}}",
        "mytalk": "In the personal URLs page section - right upper corner.\n\nUsed as link title in your personal toolbox.\n\nSee also:\n* {{msg-mw|Mytalk}}\n* {{msg-mw|Accesskey-pt-mytalk}}\n* {{msg-mw|Tooltip-pt-mytalk}}\n{{Identical|Talk}}",
-       "anontalk": "Link to the talk page appearing in [[mw:Help:Navigation#User_Links|user links]] for each anonymous users when [[mw:Manual:$wgShowIPinHeader|$wgShowIPinHeader]] is true.\n\nSee also:\n* {{msg-mw|Anontalk}}\n* {{msg-mw|Accesskey-pt-anontalk}}\n* {{msg-mw|Tooltip-pt-anontalk}}",
+       "anontalk": "Same as {{msg-mw|mytalk}} but used for non-logged-in users.\n{{Identical|Talk}}\n\nSee also:\n* {{msg-mw|Accesskey-pt-anontalk}}\n* {{msg-mw|Tooltip-pt-anontalk}}",
        "navigation": "This is shown as a section header in the sidebar of most skins.\n\n{{Identical|Navigation}}",
        "and": "The translation for \"and\" appears in the [[Special:Version]] page, between the last two items of a list. If a comma is needed, add it at the beginning without a gap between it and the \"&\". &amp;#32; is a blank space, one character long. Please leave it as it is.\n\nThis can also appear in the credits page if the credits feature is enabled,for example [{{canonicalurl:Support|action=credits}} the credits of the support page]. (To view any credits page type <nowiki>&action=credits</nowiki> at the end of any URL in the address bar.)\n{{Identical|And}}",
        "qbfind": "Alternative for \"search\" as used in Cologne Blue skin.\n{{Identical|Find}}",
        "contributions-summary": "{{doc-specialpagesummary|contributions}}",
        "contributions-title": "{{Gender}}\nThe page title in your browser bar, but not the page title.\n\nParameters:\n* $1 - the username\nSee also:\n* {{msg-mw|Contributions}}",
        "mycontris": "In the personal urls page section - right upper corner.\n\nSee also:\n* {{msg-mw|Mycontris}}\n* {{msg-mw|Accesskey-pt-mycontris}}\n* {{msg-mw|Tooltip-pt-mycontris}}\n{{Identical|Contribution}}",
+       "anoncontribs": "Same as {{msg-mw|mycontris}} but used for non-logged-in users.\n\nSee also:\n* {{msg-mw|Accesskey-pt-anoncontribs}}\n* {{msg-mw|Tooltip-pt-anoncontribs}}\n{{Identical|Contribution}}",
        "contribsub2": "Contributions for \"user\" (links). Parameters:\n* $1 is an IP address or a username, with a link which points to the user page (if registered user).\n* $2 is list of tool links. The list contains a link which has text {{msg-mw|Sp-contributions-talk}}.\n* $3 is a plain text username used for GENDER.\n{{Identical|For $1}}",
        "contributions-userdoesnotexist": "This message is used in [[Special:Contributions]]. It is used to tell the user that the name he searched for doesn't exists.\n\nParameters:\n* $1 - a username\n\n{{identical|userdoesnotexist}}",
        "nocontribs": "Used in [[Special:Contributions]] and [[Special:DeletedContributions]].\n\nSee examples: [[Special:Contributions/x]] and [[Special:DeletedContributions/x]].\n\nParameters:\n* $1 - (Unused) the user name",
        "move-redirect-text": "{{ignored}}The text that's added to a redirected page when that redirect is created.",
        "category-move-redirect-override": "{{ignored}}The text that's added to a redirected category page when that redirect is created.",
        "revertmove": "{{Identical|Revert}}",
-       "delete_and_move": "Button text on the move page when the target page already exists.",
        "delete_and_move_text": "Used when moving a page, but the destination page already exists and needs deletion.\n\nThis message is to confirm that you really want to delete the page.\n\nParameters:\n* $1 - the destination page title\n\nSee also:\n* {{msg-mw|Delete and move confirm}}",
        "delete_and_move_confirm": "Used when moving a page, but the destination page already exists and needs deletion.\n\nThis message is for a checkbox to confirm that you really want to delete the page.\n\nSee also:\n* {{msg-mw|Delete and move text}}",
        "delete_and_move_reason": "Shown as reason in content language in the deletion log. Parameter:\n* $1 - The page name for which this page was deleted.",
        "accesskey-pt-preferences": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Mypreferences}}\n* {{msg-mw|Accesskey-pt-preferences}}\n* {{msg-mw|Tooltip-pt-preferences}}",
        "accesskey-pt-watchlist": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Mywatchlist}}\n* {{msg-mw|Accesskey-pt-watchlist}}\n* {{msg-mw|Tooltip-pt-watchlist}}",
        "accesskey-pt-mycontris": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Mycontris}}\n* {{msg-mw|Accesskey-pt-mycontris}}\n* {{msg-mw|Tooltip-pt-mycontris}}",
+       "accesskey-pt-anoncontribs": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Anoncontribs}}\n* {{msg-mw|Tooltip-pt-anoncontribs}}",
        "accesskey-pt-login": "{{doc-accesskey}}",
        "accesskey-pt-logout": "{{doc-accesskey}}\nSee also:\n* {{msg-mw|Logout}}\n* {{msg-mw|Accesskey-pt-logout}}\n* {{msg-mw|Tooltip-pt-logout}}",
        "accesskey-pt-createaccount": "{{doc-accesskey}}",
        "tooltip-pt-preferences": "Tooltip shown when hovering over the {{msg-mw|Mypreferences}} link in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Mypreferences}}\n* {{msg-mw|Accesskey-pt-preferences}}\n* {{msg-mw|Tooltip-pt-preferences}}\n{{Identical|Preferences}}",
        "tooltip-pt-watchlist": "Tooltip shown when hovering over the {{msg-mw|Mywatchlist}} link in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Mywatchlist}}\n* {{msg-mw|Accesskey-pt-watchlist}}\n* {{msg-mw|Tooltip-pt-watchlist}}",
        "tooltip-pt-mycontris": "Tooltip shown when hovering over the {{msg-mw|Mycontris}} link in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Mycontris}}\n* {{msg-mw|Accesskey-pt-mycontris}}\n* {{msg-mw|Tooltip-pt-mycontris}}",
+       "tooltip-pt-anoncontribs": "Tooltip shown when hovering over the {{msg-mw|Anoncontribs}} link in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Anoncontribs}}\n* {{msg-mw|Accesskey-pt-anoncontribs}}",
        "tooltip-pt-login": "Tooltip shown when hovering over the link 'Log in' in the upper right corner show on all pages while not logged in.",
        "tooltip-pt-logout": "Tooltip shown when hovering over the {{msg-mw|Logout}} link in your personal toolbox (upper right side).\n\nSee also:\n* {{msg-mw|Logout}}\n* {{msg-mw|Accesskey-pt-logout}}\n* {{msg-mw|Tooltip-pt-logout}}\n{{Identical|Log out}}",
        "tooltip-pt-createaccount": "Tooltip shown when hovering over the link 'Create account' in the upper right corner show on all pages while not logged in.",
        "logentry-suppress-block": "{{Logentry}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string",
        "logentry-suppress-reblock": "{{Logentry}}\n* $4 - user name for gender or empty string for autoblocks\n* $5 - the block duration, localized and formatted with the english tooltip\n* $6 - block detail flags or empty string",
        "logentry-import-upload": "{{Logentry|[[Special:Log/import]]}}",
-       "logentry-import-upload-details": "{{Logentry|[[Special:Log/import]]}}\n* $4 - Number of imported revisions",
+       "logentry-import-upload-details": "{{Logentry|[[Special:Log/import]]}}\n* $4 - Number of imported revisions\n\nCf. {{msg-mw|logentry-import-upload}}",
        "logentry-import-interwiki": "{{Logentry|[[Special:Log/import]]}}",
-       "logentry-import-interwiki-details": "{{Logentry|[[Special:Log/import]]}}\n* $4 - Number of imported revisions\n* $5 - Interwiki title",
+       "logentry-import-interwiki-details": "{{Logentry|[[Special:Log/import]]}}\n* $4 - Number of imported revisions\n* $5 - Interwiki title\n\nCf. {{msg-mw|logentry-import-interwiki}}",
        "logentry-merge-merge": "{{Logentry|[[Special:Log/merge]]}}\n* $4 - the page into which the content is merged\n* $5 - a timestamp of limit\n\nThe log and its associated special page 'MergeHistory' is not enabled by default.\n\nPlease note that the parameters in a log entry will appear in the log only in the default language of the wiki. View [[Special:Log]] for examples on translatewiki.net with English default language.",
        "logentry-move-move": "{{Logentry|[[Special:Log/move]]}}\nParameter $4, the target page, is also not visible to parser functions.",
        "logentry-move-move-noredirect": "{{Logentry|[[Special:Log/move]]}}\nParameter $4, the target page, is also not visible to parser functions.",
index 519c19b..f0d4da5 100644 (file)
        "movenosubpage": "Această pagină nu are subpagini.",
        "movereason": "Motiv:",
        "revertmove": "revenire",
-       "delete_and_move": "Șterge și redenumește",
        "delete_and_move_text": "==Ștergere necesară==\n\nPagina destinație „[[:$1]]” există deja. Doriți să o ștergeți pentru a face loc redenumirii?",
        "delete_and_move_confirm": "Da, șterge pagina.",
        "delete_and_move_reason": "Șters pentru a face loc redenumirii paginii „[[$1]]”",
        "size-bytes": "{{PLURAL:$1|un octet|$1 octeți|$1 de octeți}}",
        "size-pixel": "$1 {{PLURAL:$1|pixel|pixeli|de pixeli}}",
        "lag-warn-normal": "Modificările mai noi de $1 {{PLURAL:$1|secondă|seconde}} pot să nu apară în listă.",
-       "lag-warn-high": "Serverul bazei de date este suprasolicitat, astfel Ã®ncît modificările făcute în ultimele $1 {{PLURAL:$1|secundă|secunde}} pot să nu apară în listă.",
+       "lag-warn-high": "Serverul bazei de date este suprasolicitat, astfel Ã®ncât modificările făcute în ultimele $1 {{PLURAL:$1|secundă|secunde}} pot să nu apară în listă.",
        "watchlistedit-normal-title": "Modificare listă pagini urmărite",
        "watchlistedit-normal-legend": "Ștergere titluri din lista de urmărire",
        "watchlistedit-normal-explain": "Lista de mai jos cuprinde paginile pe care le urmăriți.\nPentru a elimina un titlu, bifați-l și apăsați „{{int:Watchlistedit-normal-submit}}”.\nPuteți modifica și direct [[Special:EditWatchlist/raw|lista brută]].",
index 033221a..21fd01b 100644 (file)
        "movenosubpage": "У этой страницы нет подстраниц.",
        "movereason": "Причина:",
        "revertmove": "возврат",
-       "delete_and_move": "Удалить и переименовать",
        "delete_and_move_text": "== Требуется удаление ==\nСтраница с именем «[[:$1]]» уже существует. \nХотите удалить её, чтобы сделать возможным переименование?",
        "delete_and_move_confirm": "Да, удалить эту страницу",
        "delete_and_move_reason": "Удалено для возможности переименования «[[$1]]»",
index b2c1111..53d0f5a 100644 (file)
        "movenosubpage": "अस्य पुटस्य उपपुटानि न सन्ति ।",
        "movereason": "कारणम् :",
        "revertmove": "प्रत्यावर्तनम्",
-       "delete_and_move": "अपमर्जनं चालनं च ।",
        "delete_and_move_text": "==अपमर्जनम् आवश्यकम्==\nलक्षितपुटं \"[[:$1]]\" पूर्वमेव अस्ति ।\nचालनपथं सृष्टुम् एतत् अपमर्जितुम् इच्छति वा ?",
        "delete_and_move_confirm": "आम्, पुटम् अपमर्जतु ।",
        "delete_and_move_reason": "\"[[$1]]\" तः स्थानान्तरणं कर्तुं पथनिर्माणार्थम् अपमर्जितम् ।",
index d3ff1f4..9d1665a 100644 (file)
        "notargettext": "Ye'v na speceefie'd ae tairget page or uiser tae perform this function oan.",
        "nopagetitle": "Naw sic tairget page",
        "nopagetext": "The tairget page that ye'v speeceefied disna exeest.",
-       "pager-newer-n": "{{PLURAL:$1|اڃا نئون 1|اڃا نئون $1}}",
+       "pager-newer-n": "{{PLURAL:$1|newer 1|newer $1}}",
        "pager-older-n": "{{PLURAL:$1|aulder 1|aulder $1}}",
        "suppress": "Owersicht",
        "querypage-disabled": "This speecial page is disablit fer performance raisons.",
        "movenosubpage": "This page haes naw subpages.",
        "movereason": "Raison:",
        "revertmove": "revert",
-       "delete_and_move": "Delyte n muiv",
        "delete_and_move_text": "==Delytion caad fer==\n\nThe destination airticle \"[[:$1]]\" aareadies exists. Div ye want tae delyte it fer tae mak wey fer the muiv?",
        "delete_and_move_confirm": "Ai, delyte the page",
        "delete_and_move_reason": "Delytit fer tae mak wa fer muiv fae \"[[$1]]\"",
index 61b28a0..17d95e8 100644 (file)
@@ -9,15 +9,15 @@
                ]
        },
        "tog-underline": "ڳنڍڻي هيٺان لڪير:",
-       "tog-hideminor": "تازÙ\8aÙ\88Ù\86 معمولي تبديليون لڪايو",
-       "tog-hidepatrolled": "تازيون گھميل تبديليون لڪايو",
-       "tog-newpageshidepatrolled": "نَوَن صفحن واري فهرست مان تازو گھميل صفحا لڪايو",
+       "tog-hideminor": "تازÙ\8aÙ\86 ØªØ¨Ø¯Ù\8aÙ\84Ù\8aÙ\86 Ù\85Ù\86جھÛ\81 معمولي تبديليون لڪايو",
+       "tog-hidepatrolled": "تازيون نگرانيل تبديليون لڪايو",
+       "tog-newpageshidepatrolled": "نَوَن صفحن واري فهرست مان نگرانيل صفحا لڪايو",
        "tog-hidecategorization": "صفحن جا ذمرا لڪايو",
        "tog-extendwatchlist": "تازه ترين بدران سموريون تبديليون ڏيکارڻ لاءِ ٽيٽ لسٽ کي وسيع ڪريو.",
-       "tog-numberheadings": "سُرخين کي خودڪار طريقي سان نمبر ڏيو",
+       "tog-numberheadings": "سُرخين کي خودڪاراً نمبر ڏيو",
        "tog-showtoolbar": "سنوار اوزار ڏيکاريو",
        "tog-editondblclick": "ٻٽي ڪلڪ تي صفحا سنواريو",
-       "tog-watchcreations": "منهنجا سرجيل صفحا منهنجي ٽيٽ فهرست ۾ رکو",
+       "tog-watchcreations": "منهنجا سرجيل صفحا ۽ منهنجا چاڙهيل فائيل منهنجي ٽيٽ فهرست تي رکو",
        "tog-watchdefault": "منهنجا ترميميل صفحا منهنجي ٽيٽ فهرست تي رکو",
        "tog-watchmoves": "جيڪي صفحا ۽ فائيلس آئون چوريان، سي منهنجي ٽيٽ لسٽ ۾ شامل ڪريو.",
        "tog-watchdeletion": "آئون جيڪي صفحا ڊاهيان، سي منهنجي ٽيٽ فهرست تي رکو",
        "tog-previewonfirst": "پهرين ترميم تي پيش نگاهہ ڏيکاريو",
        "tog-enotifusertalkpages": "منهنجي مباحثي صفحي ۾ تبديليءَ جي صورت ۾ مون کي برق ٽپال اماڻيو",
        "tog-enotifminoredits": "صفحن ۾ معمولي ترميمن جي صورت ۾ بہ مون کي برق ٽپال ڪريو",
+       "tog-enotifrevealaddr": "پڌراين ۾ منهنجو برق ٽپال پتو ظاهر ڪريو.",
        "tog-shownumberswatching": "ٽيٽيندڙ يوزرس جو تعداد ڏيکاريو",
        "tog-oldsig": "موجوده دستخط",
-       "tog-uselivepreview": "سÚ\8cÙ\88سÙ\86ئÙ\88Ù\86 Ù¾Ù\8aØ´ Ù\86گاھ استعمال ڪريو",
+       "tog-uselivepreview": "سÚ\8cÙ\8a Ø³Ù\86ئÙ\8aÙ\86 Ù¾Ù\8aØ´ Ù\86گاھÛ\81 استعمال ڪريو",
        "tog-watchlisthideown": "ٽيٽ فهرست مان منهنجون ڪيل ترميمون لڪايو",
        "tog-watchlisthidebots": "ٽيٽ فهرست تان بوٽ جون ترميمون لڪايو",
        "tog-watchlisthideminor": "ٽيٽ فهرست تان معمولي ترميمون لڪايو",
        "tog-watchlisthideliu": "لاگ اِن ٿيل يوزرس جون ڪيل ترميمون ٽيٽ فهرست ۾ نہ ڏيکاريو",
        "tog-watchlisthideanons": "ٽيٽ فهرست تان اڻڄاتل يوزر جون ترميمون لڪايو",
-       "tog-watchlisthidecategorization": "صفحن جو زمرن ۾ ورهائڻ لڪايو",
+       "tog-watchlisthidecategorization": "صفحن جا زمرا لڪايو",
        "tog-ccmeonemails": "ٻين يوزرس ڏانهن منهنجي موڪليل برق ٽپال جو پرت مون کي اماڻيو",
        "tog-diffonly": "تفاوت هيٺان صفحي جو مواد نہ ڏيکاريو",
        "tog-showhiddencats": "لڪل زمرا ڏيکاريو",
        "morenotlisted": "فهرست مڪمل ڪانهي.",
        "mypage": "منهنجو صفحو",
        "mytalk": "ڳالهہ ٻول",
-       "anontalk": "هن آءِ پِي پتي لاءِ مباحثي صفحو",
+       "anontalk": "ڳالھ ٻولھ",
        "navigation": "رهنمائي",
        "and": "&#32؛۽",
        "qbfind": "ڳوليو",
        "deletethispage": "هيءُ صفحو ڊاهيو",
        "undeletethispage": "هيءُ صفحو اڻ ڊاهيو",
        "undelete_short": "اڻڊاهيو {{PLURAL:$1|هڪ ترميم|$1 ترميمون}}",
-       "viewdeleted_short": "Ú\8fسÙ\88 {{PLURAL:$1|Ù\87Úª Ú\8aاÙ\87Ù\8aÙ\84 ØªØ±Ù\85Ù\8aÙ\85|$1 Ú\8aاÙ\87Ù\8aل ترميمون}}",
+       "viewdeleted_short": "Ú\8fسÙ\88 {{PLURAL:$1|Ù\87Úª Ú\8aاٺÙ\84 ØªØ±Ù\85Ù\8aÙ\85|$1 Ú\8aاٺل ترميمون}}",
        "protect": "تحفظيو",
        "protect_change": "تبديل ڪريو",
        "protectthispage": "هيءُ صفحو تحفظيو",
        "articlepage": "مسودو ڏسو",
        "talk": "بحث",
        "views": "ڏيٺون",
-       "toolbox": "ٽولَ",
+       "toolbox": "اوزارَ",
        "userpage": "يوزر صفحو ڏسو",
        "projectpage": "رٿائي صفحو ڏسو",
        "imagepage": "ذريعاتي صفحو ڏسو",
        "redirectedfrom": "($1 کان چوريل)",
        "redirectpagesub": "چوريل صفحو",
        "redirectto": "ڏانهن چوريو",
-       "lastmodifiedat": "هيءُ صفحو آخري ڀيرو $2، $1ع تي ترميميو ويو هو.",
+       "lastmodifiedat": "هيءُ صفحو آخري دفعو $2، $1ع تي ترميميو ويو هو.",
        "viewcount": "هيءُ صفحو {{PLURAL:$1|دفعو|$1 دفعا}} ڏسجي چڪو آهي.",
        "protectedpage": "تحفظيل صفحو",
        "jumpto": "ڏانهن ٽپ ڏيو",
        "ok": "ٺيڪ",
        "retrievedfrom": "\"$1\" تان ورتل",
        "youhavenewmessages": "توهان لاءِ $1 ($2) آهن.",
+       "youhavenewmessagesmanyusers": "توهان لاءِ ڪيترن ئي يُوزرس ($2) طرفان $1 آيل آهن.",
        "youhavenewmessagesmulti": "$1 تي توهان لاءِ نوان نياپا آهن",
        "editsection": "سنواريو",
        "editold": "سنواريو",
        "nstab-help": "امدادي صفحو",
        "nstab-category": "زمرو",
        "mainpage-nstab": "مک صفحو",
-       "nosuchaction": "اهڙو ڪو به فعل نه آهي",
+       "nosuchaction": "اهڙو ڪو بہ عمل نہ آهي",
        "nosuchspecialpage": "اهڙو ڪو بہ خاص صفحو ناهي",
        "error": "چُڪَ",
        "databaseerror": "اعدادخاني ۾ چڪ",
        "databaseerror-function": "ڪاڄ: $1",
        "databaseerror-error": "چُڪَ: $1",
        "readonly": "اعدادخانو بنديل",
+       "missingarticle-rev": "(ڀيرو#: $1)",
        "missingarticle-diff": "(تفاوت: $1، $2)",
        "readonly_lag": "اعدادخانو خودڪاراً بنجي چڪو آهي، جيستائين غلام اعدادخانہ سَروَر، مالڪ سَروَر کي رسي نہ ٿو.",
        "internalerror": "اندروني خرابي",
        "protectedpagetext": "هيءُ صفحو ترميمن کان تحفظيل آهي.",
        "viewsourcetext": "توهان هن صفحي جو ڪوڊ ڏسي ۽ نقل ڪري سگھو ٿا:",
        "namespaceprotected": "توهان کي نانءُ پولار '''$1''' جا صفحا سنوارڻ جا اختيار ناهن.",
+       "mycustomcssprotected": "توهان کي هيءُ CSS صفحو سنوارڻ جي اجازت ڪانهي.",
        "mycustomjsprotected": "توهان کي هيءُ جاوا اسڪرپٽ صفحو سنوارڻ جي اجازت حاصل ڪانهي.",
+       "myprivateinfoprotected": "توهان کي پنهنجي ذاتي معلومات سنوارڻ جي اجازت حآصل ڪانهي.",
        "mypreferencesprotected": "توهان جي پنهنجون ترجيحات سنوارڻ جي اجات حاصل ڪانهي.",
        "ns-specialprotected": "خاص صفحا سنواري نٿا سگھجن.",
+       "titleprotected": "[[User:$1|$1]] اهڙي عنوان سان صفحو سرجڻ تي روڪ لڳائي ڇڏي آهي. سبب \"<em>$2</em>\" ڄاڻايو ويو آهي.",
        "exception-nologin": "لا اِن ٿيل ناهيو",
        "virus-unknownscanner": "اڻ ڄاتل نِس وائرس:",
        "welcomeuser": "ڀلي ڪري آيا، $1!",
        "createacct-yourpasswordagain-ph": "ٻيهر ڳجھو لفظ داخل ڪريو",
        "remembermypassword": "هن برائوزر تي منهنجي لاگ ان کي (وڌ ۾ وڌ $1 {{PLURAL:$1|ڏينهن}} لاءِ) ياد رکو",
        "userlogin-remembermypassword": "مون کي لاگ اِن رکو",
+       "userlogin-signwithsecure": "محفوظ ڳانڍاپو استعمال ڪريو",
        "yourdomainname": "توهان جو ميدان:",
        "password-change-forbidden": "هن وڪِي تي توهان ڳجھو لفظ بدلائي نہ ٿا سگھو.",
        "login": "لاگ اِن",
        "passwordtooshort": "ڳجھي لفظ گھٽ ۾ گھٽ  {{PLURAL:$1|1 اکر|$1 اکرَن}} تي ٻڌل هوڻ گھرجي.",
        "passwordtoolong": "ڳجھو لفظ {{PLURAL:$1|1 اکر|$1 اکرن}} کان وڏو نہ ٿو ٿي سگھي.",
        "password-name-match": "توهان جو ڳجھو لفظ توهان جي يوزرنانءُ کان مختلف هجڻ گھرجي.",
-       "mailmypassword": "ڳجھو لفظ ٻيهر ترتيب ڪريو",
+       "mailmypassword": "نئون ڳجھو لفظ مقرر ڪريو",
        "passwordremindertitle": "{{SITENAME}} لاءِ نئون عارضي ڳجھو لفظ",
        "passwordremindertext": "ڪنهن (شايد توهان آءِ پي پتي $1 تان) اسان کي {{SITENAME}} ($4) لاءِ نئون ڳجھو لفظ اماڻڻ جي گھُرَ ڪئي.\"$2\" يوزر لاءِ هڪ ڳجھُ لفظ تخليق ڪيو ويو آهي \"$3\" تي ترتيب ڏنو ويو هو. جيڪڏهن اهو توهان جي ارادو هيو، ته هاڻي توهان کي هينئر ئي لاگ اِن ٿي پنهنجو ڳجھو لفظ تبديل ڪرڻ گھرجي.\nتوهان جو عارضي ڳجھو لفظ {{PLURAL:$5|هڪ ڏينهُن|$5 ڏينهَن}} ۾ ختم ٿيندو.\n\nجيڪڏهن اها گھُرَ اوهان نه ڪئي هئي، يا هاڻي اوهان کي پنهنجو ڳجھو لفظ ياد اچي ويو آهي ۽ توهان ان کي تبديل ڪرڻ نه ٿا چاهيو، ته توهان هن نياپي کي نظر انداز ڪندي پنهنجو پراڻو ڳجھو لفظ ئي استعمال ڪري سگھو ٿا.",
-       "noemail": "يُوزر \"$1\" جي ڪو به برق ٽپال پتو درج ٿيل ناهي.",
+       "noemail": "يُوزر \"$1\" جي ڪو بہ برق ٽپال پتو درج ٿيل ناهي.",
        "noemailcreate": "توهان کي قابل ڪار برق ٽپال پتو مهيا ڪرڻو پوندو.",
        "passwordsent": "يوزر \"$1\" لاءِ هڪ نئون ڳجھو لفظ برق ٽپال ذريعي اماڻيو ويو آهي.  مهرباني ڪري اهو حاصل ڪرڻ بعد لاگ اِن ٿيندا.",
        "mailerror": "ٽپال اماڻڻ ۾ چُڪَ: $1",
        "php-mail-error-unknown": "پي ايڇ پي جي  ڪاڄ اندر اڻڄاتل چُڪَ.",
        "user-mail-no-addy": "برق ٽپال پتو ڄاڻائڻ کان سواءِ برق ٽپال اماڻڻ جي ڪوشش ڪئي وئي.",
        "changepassword": "ڳجھو لفظ تبديل ڪريو",
+       "resetpass_announce": "لاگ اِن جو عمل پورو ڪرڻ لاءِ توهان کي نئون ڳجھو لفظ اختيار ڪرڻو پوندو.",
        "resetpass_header": "کاتي جو ڳجھو لفظ بدلايو",
        "oldpassword": "اڳوڻو ڳجھو لفظ:",
        "newpassword": "نئون ڳجھو لفظ:",
        "passwordreset-domain": "ميدان:",
        "passwordreset-email": "برق ٽپال پتو:",
        "passwordreset-emailtitle": "{{SITENAME}} واري کاتي جا تفصيل",
+       "passwordreset-emailelement": "يُوزر نانءُ: \n$1\n\nعارضي ڳجھو لفظ:\n$2",
        "changeemail": "برق ٽپال پتو مِٽايو يا بدلايو",
        "changeemail-passwordrequired": "توهانکي هن تبديلي جي تصديق ڪرڻ جي لاءِ پنهنجو ڳجھو لفظ داخل ڪرڻ جي ضرورت پوندي.",
        "changeemail-oldemail": "هاڻوڪو برق ٽپال پتو:",
        "changeemail-throttled": "توهان تازو ئي لاگ اِن ٿيڻ جون هيڪانديون گھڻيون ڪوششون ڪيون آهن. مهرباني ڪري $1 لاءِ ترسي پوءِ وري ڪوشش ڪريو.",
        "changeemail-nochange": "مهرباني ڪري مختلف نئون برق ٽپال پتو ڄاڻايو.",
        "resettokens-tokens": "ٽوڪنس:",
+       "resettokens-token-label": "$1 (حاليہ قدر: $2)",
        "bold_sample": "گهري تحرير",
        "bold_tip": "گهري لکت",
        "italic_sample": "ترڇي لکت",
        "blockednoreason": "سبب اڻڄاڻايل",
        "whitelistedittext": "صفحا سنوارڻ لاءِ مهرباني ڪري $1.",
        "confirmedittext": "صفحا سنوارڻ کان اڳ توهان کي پنهنجي ايميل پتي جي تصديق ڪرڻي پوندي. مهرباني ڪري [[Special:Preferences|use preferences]] ذريعي پنهنجو ايميل پتو ڄاڻايو ۽ تصديقيو.",
-       "nosuchsectiontitle": "سيڪشن لڀجي نه سگھيو",
+       "nosuchsectiontitle": "سيڪشن لڀجي نہ سگھيو",
        "loginreqtitle": "لاگ اِن گھربل آهي",
        "loginreqlink": "لاگ اِن",
        "loginreqpagetext": "ٻيا صفحا ڏسڻ لاءِ مهرباني ڪري $1",
        "userpage-userdoesnotexist-view": "يُوزر کاتو $1 درج ٿيل نہ آهي.",
        "blocked-notice-logextract": "هيءَ يُوزر في‌الحال بندشيل آهي. تازو بندش لاگ حوالي طور پيش ڪجي ٿو:",
        "previewnote": "<strong>'''هيءَ محظ پيش نگاهہ آهي.</strong> ترميمون اڃا سانڍجوين ناهن!'''",
+       "continue-editing": "ترميم گاھ ڏانهن وڃو",
        "editing": "زير ترميم $1",
        "creating": "$1 سرجيندي",
        "editingsection": "زير ترميم $1 (سيڪشن)",
        "content-model-javascript": "جاوا اسڪرپٽ",
        "content-json-empty-object": "خالي آبجيڪٽ",
        "content-json-empty-array": "خالي اري",
-       "duplicate-args-warning": "وارننگ: [[:$2]]کي [[:$1]] ڪال ڪري رهيو آهي، ساڻ هڪ کان وڌيڪ قدرن لاءِ ’$3‘ پيراميٽرس لاءِ. فقط آخري قدر مهيا ڪيل استعمال ڪيو ويندو.",
+       "duplicate-args-warning": "وارنڱ: [[:$2]] کي [[:$1]] ڪال ڪري رهيو آهي، جنهن منجھہ ’$3‘ نيم‌پيما لاءِ هڪ کان وڌيڪ قدر ڄاڻايل آهن. فقط آخري ڄاڻايل قدر استعمال ڪيو ويندو.",
        "parser-template-loop-warning": "سانچو چڪر لڌو ويو: [[$1]]",
        "cantcreateaccounttitle": "کاتو کولي نہ ٿو سگھجي",
-       "cantcreateaccount-text": "هن آءِ پي پتي تا کاتي جي تخليق تي (<strong>$1</strong>)  [[User:$3|$3]] يوزر پاران بندش وڌي وئي آهي.\n\n$3 جو ڄاڻايل سبب آهي <em>$2</em> آهي.",
-       "cantcreateaccount-range-text": "هن آءِ پي پتن جي حد ۾ '''$1''', جنهن ۾ توهان جو آءِ پي پتو به شامل آهي ('''$4''')،  [[User:$3|$3]] پاران پابندي وڌي وئي آهي.\n$3 جو ڄاڻايل سبب \"$2\" آهي.",
-       "viewpagelogs": "هن صفحي جا لاگ ڏسو",
+       "cantcreateaccount-text": "هن آءِ پي پتي تان کاتي جي تخليق تي يُوز (<strong>$1</strong>)  [[User:$3|$3]] روڪ لڳائي آهي.\n\n$3 جو ڄاڻايل سبب آهي <em>$2</em> آهي.",
+       "cantcreateaccount-range-text": "آءِ پي پتن جي حد '''$1''' ۾ [[User:$3|$3]] کاتو کولڻ تي روڪ لڳاي آهي، جنهن ۾ توهان جو آءِ پي پتو بہ ('''$4''')،  پڻ شامل آهي. \n\n$3 ان روڪَ جو سبب \"$2\" ڄاڻايو آهي.",
+       "viewpagelogs": "هن صفحي جا لاگس ڏسو",
+       "nohistory": "هن صفحي جي ڪا بہ سوانح نہ آهي.",
        "currentrev": "هاڻوڪو مسودو",
        "currentrev-asof": "$1 جو تازو ترين مسودو",
        "revisionasof": "$1 وارو پرت",
        "history-feed-description": "وڪي جي هن صفحي جي ترميمي سوانح",
        "history-feed-item-nocomment": "$2 تي $1",
        "rev-deleted-user": "(يُوزرنانءُ ڊاٺو ويو)",
+       "rev-delundel": "نمائش تبديل ڪريو",
        "rev-showdeleted": "ڏيکاريو",
        "revisiondelete": "مسوادا ڊاهيو/اڻ‌ڊاهيو",
+       "revdelete-no-file": "ڄاڻايل فائيل وجود نہ ٿو رکي.",
        "revdelete-show-file-submit": "ها",
+       "revdelete-legend": "نمائش جون پابنديون ترتيب ڪريو",
+       "revdelete-hide-image": "فائيل جو مواد لڪايو",
+       "revdelete-hide-comment": "ترميم جو تتُ",
+       "revdelete-hide-user": "ايڊيٽر جو يوزرنانءُ / آء پي پتو",
+       "revdelete-radio-same": "(نہ بدلايو)",
        "revdelete-radio-set": "لڪل",
        "revdelete-radio-unset": "ظاهر",
        "revdelete-log": "سبب:",
+       "revdel-restore": "نمائش تبديل ڪريو",
        "pagehist": "صفحي جي سوانح",
        "deletedhist": "ڊاٺل سوانح",
        "revdelete-otherreason": "ٻيا/اضافي ڪارڻ:",
        "revdelete-reasonotherlist": "ٻيو ڪارڻ",
        "revdelete-edit-reasonlist": "ڊاٺ جا سبب سنواريو",
+       "revdelete-offender": "ڀيري جو ليکڪ:",
        "mergehistory": "صفحن جون سوانح ضم ڪريو",
+       "mergehistory-box": "ٻن صفحن جي ڀيرن کي ضم ڪريو:",
        "mergehistory-from": "ذريعہ صفحو:",
        "mergehistory-into": "مقصود صفحو:",
        "mergehistory-list": "ضمائتي ترميم سوانح",
+       "mergehistory-submit": "ڀيرن کي ضم ڪريو",
+       "mergehistory-empty": "ڪي بہ ڀيرا ضم ڪري نہ ٿا سگھجن.",
+       "mergehistory-no-source": "مصدر صفحو $1 وجود نٿو رکي!",
+       "mergehistory-no-destination": "مقصود صفحو $1 وجود نہ ٿو رکي.",
+       "mergehistory-invalid-source": "مصدر صفحي جو عنوان قابل‌ڪار هجڻ گھرجي.",
+       "mergehistory-invalid-destination": "مقصود صفحي جو عنوان قابل‌ڪار هجڻ گھرجي.",
        "mergehistory-autocomment": "[[:$1]] کي [[:$2]] ۾ ضم ڪيو ويو",
+       "mergehistory-comment": "[[:$1]]، [[:$2]] ۾ ضم ٿي ويو: $3",
+       "mergehistory-same-destination": "مصدر ۽ مقصود صفحو ساڳيو نہ ٿو ٿي سگھي.",
        "mergehistory-reason": "سبب:",
        "mergelog": "ضم لاگ",
        "revertmerge": "اڻ ضم",
        "history-title": "\"$1\" جي ترميمي سوانح",
        "difference-title": "\"$1\" جي مسودن ۾ تفاوت",
+       "difference-title-multipage": "صفحن \"$1\" ۽ \"$2\" ۾ تفاوت",
        "difference-multipage": "(صفحن درميان تفاوت)",
        "lineno": "سِٽَ $1:",
        "compareselectedversions": "چونڊيل پرت ڀيٽيو",
        "diff-empty": "(ڪو بہ تفاوت ڪونهي)",
        "searchresults": "ڳولا نتيجا",
        "searchresults-title": "”$1“ لاءِ ڳولا نتيجا",
+       "titlematches": "صفحي جو عنوان مشابهت رکي ٿو",
+       "textmatches": "صفحي جو متن مشابهت رکي ٿو",
+       "notextmatches": "ڪنهن به صفحي جو متن مشابهت نٿو رکي",
        "prevn": "پويان {{PLURAL:$1|$1}}",
        "nextn": "اڳيان {{PLURAL:$1|$1}}",
        "prev-page": "اڳوڻو صفحو",
        "search-category": "(ذمرو $1)",
        "search-suggest": "ڇا توهان جو مطلب $1 آهي؟",
        "search-interwiki-caption": "برادر رٿائون",
+       "search-interwiki-default": "$1 مان نتيجا",
        "search-interwiki-more": "(وڌيڪ)",
        "search-relatedarticle": "لاڳاپيل",
        "searchrelated": "لاڳاپيل",
        "searchall": "سڀ",
        "search-nonefound": "توهان جي ڳولا جي نتيجي ۾ ڪجھہ بہ ڪو نہ لڌو.",
+       "powersearch-legend": "اعليٰ ڳولا",
        "powersearch-togglelabel": "چڪاسيو:",
        "powersearch-toggleall": "سڀ",
        "powersearch-togglenone": "ڪو بہ نہ",
        "prefs-watchlist-days-max": "وڌ ۾ وڌ $1 {{PLURAL:$1|ڏينهن}}",
        "prefs-watchlist-edits-max": "وڌ ۾ وڌ تعداد: 1000",
        "prefs-watchlist-token": "ٽيٽ لسٽ جو ٽوڪن:",
+       "prefs-misc": "متفرق",
        "prefs-resetpass": "ڳجھو لفظ بدلايو",
        "prefs-changeemail": "برق ٽپال پتو مِٽايو يا بدلايو",
        "prefs-setemail": "ڪو برق ٽپال پتو ڄاڻايو",
        "prefs-email": "برق ٽپال چارا",
        "prefs-rendering": "حليو",
        "saveprefs": "سانڍيو",
+       "prefs-editing": "سنوارڻ",
        "rows": "قطارون:",
+       "columns": "ڪالمَ:",
        "searchresultshead": "ڳولا",
        "stub-threshold-sample-link": "نمونو",
        "stub-threshold-disabled": "غيرفعال",
+       "recentchangesdays": "تازين تبديلين ۾ ڏيکارڻ جي لاءِ ڏينهن:",
        "recentchangesdays-max": "وڌ ۾ وڌ $1 {{PLURAL:$1|ڏينهن}}",
+       "recentchangescount": "عدم پيروي جي صورت ۾ ڏيکارڻ جي لاءِ ترميمون:",
        "prefs-help-recentchangescount": "ان ۾ تازيون تبديليون، صفحن جي سوانح، ۽ لاگ شامل آهن.",
-       "savedprefs": "توهان جو ترجيحات سانڍجي چڪيون آهن.",
+       "savedprefs": "توهان جون ترجيحات سانڍجي چڪيون آهن.",
        "savedrights": "{{GENDER:$1|$1}} نالي يوزر جا حق سانڇجي چڪا آهن.",
        "timezonelegend": "اوقاتي زون:",
        "localtime": "مقامي وقت:",
+       "timezoneuseserverdefault": "وڪي عدم پيروي استعمال ڪريو ($1)",
        "servertime": "سَروَر پٽاندر وقت:",
        "guesstimezone": "جھانگُوءَ مان ڀريو",
        "timezoneregion-africa": "آفريڪا",
        "allowemail": "ٻين يُوزرس کان ايندڙ برق ٽپال بحال ڪريو",
        "prefs-searchoptions": "ڳولا",
        "prefs-namespaces": "نانءُپولار",
+       "default": "ڏنل",
        "prefs-files": "فائيلس",
        "prefs-emailconfirm-label": "برق ٽپال جي خاطري:",
        "youremail": "برق ٽپال:",
        "prefs-info": "بنيادي ڄاڻ",
        "prefs-i18n": "بين‌الاقوامڪاري",
        "prefs-signature": "صحيح",
+       "prefs-dateformat": "تاريخ جو طرز",
        "prefs-advancedediting": "عمومي چارا",
        "prefs-editor": "ايڊيٽر",
        "prefs-preview": "پيش نگاهہ",
        "prefs-help-prefershttps": "هيءَ ترجيح توهان جي ايندڙ لاگ اِن تي عمل ۾ ايندي.",
        "email-address-validity-valid": "برق ٽپال پتو قابل ڪار ڏسجي ٿو.",
        "email-address-validity-invalid": "قابل ڪار برق ٽپال پتو ڄاڻايو",
-       "userrights": "يُوزر حقن جي انتظامڪاري",
+       "userrights": "يُوزر حقن جو بندوبست",
+       "userrights-lookup-user": "يوزر گروپَ سنڀاليو",
        "userrights-user-editname": "يُوزرنانءُ ڄاڻايو:",
+       "editusergroup": "يوزر گروپَ سنواريو",
+       "userrights-editusergroup": "يوزر گروپَ سنواريو",
+       "saveusergroups": "يوزر گروپَ سنڀاليو",
        "userrights-groupsmember": "برڪن:",
        "userrights-groupsmember-auto": "رڪن واجبي:",
        "userrights-reason": "سبب:",
        "userrights-no-interwiki": "توهان کي ٻين وڪيز تي يُوزر حقن ۾ ترميم ڪرڻ جو حق حاصل نہ آهي.",
        "userrights-nodatabase": "اعداخانو $1 يا تہ وجود نہ ٿو رکي يا تہ اهو مقامي اعدادخانو نہ آهي.",
+       "userrights-notallowed": "توهان کي يوزر جا حق شامل يا هٽائڻ جي اجازت نه آهي.",
+       "userrights-changeable-col": "گروپَ جيڪي توهان تبديل ڪري سگھو ٿا",
+       "userrights-unchangeable-col": "گروپَ جيڪي توهان تبديل نٿا ڪري سگھو",
        "group": "گروپ:",
        "group-user": "يوزرس",
+       "group-autoconfirmed": "خودبخود پڪ ڪيل يوزرس",
+       "group-bot": "بوٽس",
+       "group-sysop": "منتظم",
+       "group-bureaucrat": "ڪامورا",
        "group-all": "(سڀ)",
        "group-user-member": "{{GENDER:$1|يُوزر}}",
        "group-sysop-member": "{{GENDER:$1|منتظم}}",
        "right-move-subpages": "ذيلي صفحن سميت صفحا چوريو",
        "right-movefile": "فائيل چوريو",
        "right-upload": "فائيل چاڙهيو",
-       "right-upload_by_url": "ڪنهن يُو آر ايل کان فائيل چاڙهيو",
+       "right-upload_by_url": "ڪنهن يُو آر ايل تان فائيل چاڙهيو",
+       "right-writeapi": "اي پر آءِ لکڻ جو استعمال",
        "right-delete": "صفحا ڊاهيو",
        "right-bigdelete": "ڊگھيون سوانح رکندڙ صفحا ڊاهيو",
        "right-browsearchive": "ڊاٺل صفحا ڳوليو",
        "right-undelete": "ڪو صفحو اڻڊاهيو",
+       "right-unblockself": "ڪنهن تان بندش ختم ڪريو",
        "right-editinterface": "يُوزر باهمرُو کي سنواريو",
        "right-viewmywatchlist": "پنهنجي ٽيٽ لسٽ ڏسو",
        "right-editmyoptions": "پنهنجون ترجيحات سنواريو",
        "right-import": "ٻين وڪيز کان صفحا درآمديو",
        "right-mergehistory": "صفحن جي سوانح سنواريو",
+       "right-userrights": "سڀ يوزر حق ترميم ڪريو",
+       "right-userrights-interwiki": "هن وڪي جي يوزرس جا حق ترميم ڪريو",
+       "right-sendemail": "ٻين يوزرس ڏانهن ايميل موڪليو",
        "newuserlogpage": "يوزر کاتن جو لاگ",
        "rightslog": "يُوزر حق لاگ",
+       "action-read": "هي صفحو پڙهو",
+       "action-edit": "هن صفحي کي سسنواريو",
+       "action-createpage": "صفحا تخليق ڪريو",
+       "action-createtalk": "مباحثي صفحا تخليق ڪريو",
+       "action-createaccount": "هي يوزر کاتو تخليق ڪريو",
+       "action-history": "هن صفحي جي سوانح ڏسو",
+       "action-minoredit": "هن ترميم کي معمولي طور نشان لڳايو",
        "action-move": "هيءَُ صفحو چوريو",
        "action-move-subpages": "هيءُ صفحو، ۽ ان جا ذيلي صفحا چوريو",
        "action-move-categorypages": "زمرن جا صفحا چوريو",
        "action-import": "ٻي ڪنهن وڪي کان صفحا درآمد ڪريو",
        "action-importupload": "ڪو فائيل چاڙهي صفحا درآمديو",
        "action-mergehistory": "هن صفحي جي سوانح ضم ڪريو",
+       "action-userrights": "سڀ يوزر حق ترميم ڪريو",
+       "action-userrights-interwiki": "ٻين وڪيز جي يوزرس جا حق ترميم ڪريو",
        "action-siteadmin": "اعدادخاني کي بند ڪريو يا کوليو",
        "action-sendemail": "برق ٽپال اماڻيو",
        "action-editmywatchlist": "پنهنجي ٽيٽ فهرست سنواريو",
        "action-viewmywatchlist": "پنهنجي ٽيٽ فهرست ڏسو",
+       "action-viewmyprivateinfo": "پنهنجي ذاتي معلومات ڏسو",
+       "action-editmyprivateinfo": "پنهنجي ذاتي معلومات سنواريو",
        "nchanges": "$1 {{PLURAL:$1|تبديلي|تبديليون}}",
        "enhancedrc-history": "سوانح",
        "recentchanges": "تازيون تبديليون",
        "filename": "فائيل نانءُ",
        "filedesc": "خلاصو",
        "fileuploadsummary": "خلاصو:",
+       "filereuploadsummary": "فائيل تبديليون:",
+       "filesource": "ذريعو:",
        "filename-tooshort": "فائيل نانءَُ هيڪاندو ننڍو آهي.",
+       "uploadwarning": "چاڙھ جو چتاءُ",
        "savefile": "فائيل سانڍيو",
+       "uploaddisabled": "چاڙھ ناقابلِ ڪار بڻيل.",
        "upload-scripted-pi-callback": "ن فائيل کي اپلوڊ نه ٿو ڪري سگهي جنهن ۾ ايڪس ايم ايل اسٽائيل شيٽ جون پراسيسنگ هدايتون شامل هجن.",
        "uploaded-script-svg": "اسڪرپٽ جوڳو ايليمينٽ ”$1” مليو آهي، اپلوڊ ٿيل ايس وي جي فائيل ۾.",
        "uploaded-hostile-svg": "اپلوڊ ٿيل ايس وي جي فائيل جو غير محفوظ سي ايس ايس ۾ اسٽائيل ايلمينٽ مليو",
-       "uploaded-event-handler-on-svg": "واقعي جون هينڊل ڪندڙ وصفون \n<code>$1=\"$2\"</code> ايس وي جي فائيل ۾ اجازت نه آهي.",
+       "uploaded-event-handler-on-svg": "ايس وي جي فائيل ۾ ايوينٽ هينڊلر خصوصيتون <code>$1=\"$2\"</code> مقرر ڪرڻ جي اجازت نہ آهي.",
        "uploaded-href-attribute-svg": "Href خاصيتون <code>&lt;$1 $2=\"$3\"&gt;</code> نان لوڪل ٽارگيٽ سان جهڙوڪ ( http://, javascript:, وغيره) ايس وي جي فائيل ۾ اجازت مليل نه آهن.",
        "uploaded-href-unsafe-target-svg": "href جو غير محفوظ نشانو مليو آهي <code>&lt;$1 $2=\"$3\"&gt;</code> اپلوڊ ٿيل ايس وي جي فائيل ۾",
        "uploaded-animate-svg": "”اينيميٽ“ ٽيگ ڳوليو  جيڪا ٿي سگهي ٿو href کي تبديل ڪري رهي هجي. \"form\" وصف استعمال ڪندي <code>&lt;$1 $2=\"$3\"&gt;</code> اپلوڊ ٿيل ايس وي جي فائيل ۾",
        "uploaded-remote-url-svg": "ايس وي جي جيڪا سيٽ ڪري ٿي ڪنهن اسٽائيل وصف  رموٽ يو آر ايل سان  بلاڪ ٿيل آهي.\n <code>$1=\"$2\"</code> اپلوڊ ٿيل ايس وي جي فائيل ۾ مليو",
        "uploaded-image-filter-svg": "هن يو آر ايل سان <code>&lt;$1 $2=\"$3\"&gt;</code> اميج فلٽر مليو آهي، اپلوڊ ٿيل ايس وي جي فائيل ۾،",
        "uploadvirus": "هن فائيل ۾ وائرس آهي! \nتفصيل: $1",
+       "upload-source": "ذريعي جو فائيل",
+       "sourcefilename": "ذريعي جي فائيل جو نالو:",
        "upload-description": "فائيل جي تشريح",
+       "upload-options": "چاڙھ جا چارا",
        "watchthisupload": "هيءُ فائيل ٽيٽيو",
        "upload-success-subj": "چاڙهہ ڪامياب",
+       "upload-failure-subj": "چاڙھ جو مسئلو",
+       "upload-warning-subj": "چاڙھ جو چتاءُ",
        "upload-file-error": "اندروني چُڪَ",
        "upload-dialog-title": "فائيل چاڙهيو",
        "upload-dialog-button-cancel": "رد",
+       "upload-dialog-button-done": "ٿي ويو",
        "upload-dialog-button-save": "سانڍيو",
        "upload-dialog-button-upload": "چاڙهيو",
        "upload-form-label-select-file": "فائيل چونڊيو",
        "foreign-structured-upload-form-label-own-work": "هيءُ منهنجو پنهنجو ڪم آهي.",
        "foreign-structured-upload-form-label-infoform-categories": "زمرا",
        "foreign-structured-upload-form-label-infoform-date": "تاريخ",
+       "backend-fail-notexists": "فائيل ''$1'' وجود نٿو رکي.",
+       "backend-fail-delete": "\"$1\" فائيل ڊهي نہ سگھيو.",
+       "backend-fail-alreadyexists": "\"$1\" فائيل اڳ ئي وجود رکي ٿو.",
+       "backend-fail-copy": "فائيل \"$1\" کي \"$2\" ڏانهن نقل نه ڪري سگھيو.",
+       "backend-fail-move": "فائيل \"$1\" کي \"$2\" ڏانهن چوري نه سگھيو.",
+       "backend-fail-opentemp": "عارضي فائيئ کولي نه سگھيو.",
+       "backend-fail-read": "فائيل \"$1\" کي پڙهي نه سگھيو.",
        "license-header": "لائيسنسڪاري",
        "listfiles-delete": "ڊاهيو",
        "imgfile": "فائيل",
        "listfiles": "فائيل فهرست",
+       "listfiles_date": "تاريخ",
        "listfiles_name": "نالو",
        "listfiles_user": "يُوزر",
        "listfiles_size": "ماپَ",
        "listfiles_description": "تشريح",
+       "listfiles_count": "ورزن",
+       "listfiles-latestversion": "هاڻوڪو ورزن",
        "listfiles-latestversion-yes": "ها",
        "listfiles-latestversion-no": "نہ",
        "file-anchor-link": "فائيل",
        "filehist": "فائيل جي سوانح",
-       "filehist-help": "ڪنهن به تاريخ/وقت تي ڪلڪ ڪري ڏسندا ته تڏڻي اهو فائيل ڪيئن هو.",
+       "filehist-help": "ڪنهن بہ تاريخ/وقت تي ڪلڪ ڪري ڏسندا تہ تڏڻي اهو فائيل ڪيئن هو.",
        "filehist-deleteall": "سڀ ڊاهيو",
        "filehist-deleteone": "ڊاهيو",
        "filehist-revert": "واپس ورايو",
-       "filehist-current": "هاڻوڪو",
+       "filehist-current": "حاليہ",
        "filehist-datetime": "تاريخ/وقت",
        "filehist-thumb": "آڱوٺي ننهن",
+       "filehist-thumbtext": "$1 جي نظرثاني لاءِ تصويري نشان",
        "filehist-user": "يُوزر",
        "filehist-dimensions": "ماپَ",
        "filehist-filesize": "فائيل سائيز",
        "filehist-comment": "تاثرات",
        "imagelinks": "فائيل جو استعمال",
        "linkstoimage": "هن فائيل سان {{PLURAL:$1|هيٺيون صفحو ڳنڍيل آهي |$1 هيٺيان صفحا ڳنڍيل آهن}}:",
-       "nolinkstoimage": "هن فائيل سان ڪو به صفحو ڳنڍيل ناهي.",
+       "nolinkstoimage": "هن فائيل سان ڪو بہ صفحو ڳنڍيل ناهي.",
        "sharedupload": "هيءَ فائيل $1 کان آهي ۽ ان کي ٻيون رٿائون به استعمال ڪري سگھن ٿيون.",
+       "sharedupload-desc-here": "هي فائيل $1 مان آهي ۽ ٻين رٿائن پاران پڻ استعمال ٿي سگهي ٿو. تشريح انجي [[$2 جو تشريحي صفحو]] هيٺان ڏنل آهي.",
        "uploadnewversion-linktext": "هن فائيل جو نئون پرت چاڙهيو",
        "shared-repo-from": "$1 کان",
        "upload-disallowed-here": "توهان هن فائيل مٿان لکي نہ ٿا سگھو.",
        "listusers-noresult": "ڪو بہ يُوزر نہ لڌو",
        "listusers-blocked": "(بندشيل)",
        "activeusers": "سرگرم يُوزرس جي فهرست",
+       "activeusers-hidebots": "بوٽس لڪايو",
        "activeusers-hidesysops": "منتظمن کي لڪايو",
        "activeusers-noresult": "ڪي بہ يُوزرس نہ لڌا.",
+       "listgrouprights": "يوزر گروپ جا حق",
        "listgrouprights-group": "گروهہ:",
        "listgrouprights-rights": "حق",
        "listgrouprights-members": "(رڪنن جي لسٽ)",
+       "listgrouprights-addgroup-all": "سڀ گروپَ شامل ڪريو",
+       "listgrouprights-removegroup-all": "سڀ گروپ هٽايو",
        "listgrouprights-namespaceprotection-namespace": "نانءُ پولار:",
+       "trackingcategories-name": "پيغام جو نالو",
+       "trackingcategories-nodesc": "ڪا به تشريح موجود نه آهي.",
+       "trackingcategories-disabled": "زمرو ناقابلِ ڪار بڻايل آهي.",
        "emailuser": "هن يوزر کي برق ٽپال اماڻيو",
        "emailuser-title-notarget": "يُوزر ڏانهن برق ٽپال اماڻيو",
+       "usermaildisabled": "يوزر ايميل ناقابلِ ڪار بڻيل",
+       "usermaildisabledtext": "توهان هن وڪي تي ٻين يوزرس ڏانهن ايميل نٿا موڪلي سگھو",
        "noemailtitle": "برق ٽپال پتو نامعلوم",
        "noemailtext": "هن يُوزر ڪو بہ قابل ڪار برق ٽپال پتو نہ ڄاڻايو آهي.",
        "emailusername": "يُوزرنانءُ:",
        "watchlist-details": "{{PLURAL:$1|$1 صفحو|$1 صفحا}} توهان جي ٽيٽ فهرست، ڳالھ ٻولھ جا صفحا الڳ شمار نٿا ٿين.",
        "wlshowlast": "گذريل $1 ڪلاڪ $2 ڏينهن ڏيکاريو",
        "watchlistall2": "سڀ",
+       "watchlist-hide": "لڪايو",
        "wlshowtime": "آخري ڏيکاريو",
        "wlshowhideminor": "معمولي ترميم",
+       "wlshowhidebots": "بوٽس",
        "wlshowhideliu": "کاتيدار يُوزرس",
        "wlshowhideanons": "گمنام يُوزرس",
        "wlshowhidemine": "منهنجون ترميمون",
+       "watchlist-options": "زيرِ نظر فهرست جا چارا",
        "watching": "ٽيٽيندي...",
        "unwatching": "اڻ ٽيٽيندي...",
+       "enotif_reset": "سڀ گھميل صفحن تي نشان لڳايو",
        "enotif_impersonal_salutation": "{{SITENAME}} يُوزر",
+       "enotif_lastdiff": "هي تبديلي ڏسڻ لاءِ $1 ڏسو",
        "enotif_anon_editor": "گمنام يُوزر $1",
        "created": "ٺهي چڪو",
        "changed": "تبديل ٿي ويو",
        "historywarning": "<strong>خبردار:</strong> جيڪو صفحو توهان ڊاهڻ وڃي رهيا آهيو ان ساڻ هڪ تاريخ آهي $1 {{PLURAL:$1|revision|revisions}}:",
        "confirmdeletetext": "توهان هڪ صفحي کي ان جي سموري سوانح سميت ڊاهڻ وارا آهيو. مهرباني ڪري پڪ ڪندا ته توهان اهو ئي ڪرڻ گھرو ٿا، ۽ اهو ته توهان ان جي نتيجن کان واقف آهيو، ۽ اهو پڻ ته توهان اهو ڪم [[{{MediaWiki:Policy-url}}|پاليسي]]ءَ مطابق ڪري رهيا آهيو.",
        "actioncomplete": "ڪم پُورو",
+       "actionfailed": "عمل ناڪام",
        "deletedtext": "\"$1\" ڊهي چڪو آهي.\nتازو ڊاٺل صفحن جي فهرست لاءِ $2 ڏسندا.",
        "dellogpage": "ڊاٺ لاگ",
        "deletionlog": "ڊاٺ لاگ",
        "rollbacklinkcount": "اڻ ڪريو $1 {{PLURAL:$1|ترميم|ترميمون}}",
        "changecontentmodel-title-label": "صفحي جو عنوان",
        "changecontentmodel-reason-label": "سبب:",
+       "logentry-contentmodel-change-revertlink": "واپس ورايو",
+       "logentry-contentmodel-change-revert": "واپس ورايو",
        "protectlogpage": "تحفظ لاگ",
+       "protectedarticle": "محفوظ ٿيل \"[[$1]]\"",
        "prot_1movedto2": "[[$1]] کي چوري [[$2]] تي رکيو ويو",
        "protect-legend": "تحفظڻ جي پڪ ڪريو",
        "protectcomment": "سبب:",
        "protect-level-autoconfirmed": "خودڪار نموني پڪ ڪيل يوزرس کي اجازت ڏيو",
        "protect-level-sysop": "صرف منتظمين کي اجازت ڏيو",
        "protect-summary-cascade": "تحفظ در تحفظ",
+       "protect-expiry-indefinite": "لامحدود",
        "protect-cascade": "هن صفحي ۾ شامل صفحن کي تحفظيو (تحفظ در تحفظ)",
        "protect-cantedit": "توهان هن صفحي جي تحفظاتي سطح نٿا بدلائي سگھو، ڇاڪاڻ ته توهان ان کي سنوارڻ جي اجازت نٿا رکو.",
+       "protect-othertime": "ٻيو وقت:",
+       "protect-othertime-op": "ٻيو وقت",
+       "protect-existing-expiry": "موجوده پڄاڻي جو وقت: $3, $2",
+       "protect-existing-expiry-infinity": "موجوده پڄاڻي جو وقت: لامحدود",
        "protect-otherreason-op": "ٻيو سبب",
        "protect-expiry-options": "1 ڪلاڪ:1 hour,1 ڏينهن:1 day,1 هفتو:1 week,2 هفتو:2 weeks,1 مهينا:1 month,3 مهينا:3 months,6 مهينا:6 months,1 سال:1 year,اڻ کٽ:infinite",
        "restriction-type": "اجازتنامو:",
        "undeletebtn": "بحاليو",
        "undeleteviewlink": "ڏسو",
        "undeletecomment": "سبب:",
+       "undelete-search-title": "ڊاٺل صفحا ڳوليو",
+       "undelete-search-box": "ڊاٺل صفحا ڳوليو",
+       "undelete-search-prefix": "سان شروع ٿيندڙ صفحا ڏيکاريو:",
        "undelete-search-submit": "ڳوليو",
        "undelete-error-short": "هيءُ فائيل اڻڊاهيندي چُڪَ ٿي آهي: $1",
        "undelete-show-file-submit": "ها",
        "namespace": "نانءُ پولار:",
        "invert": "چونڊ ابتيو",
+       "tooltip-invert": "هن دٻي تي نشان لڳايو صحفن ۾ تبديليون لڪائڻ لاءِ چونڊيل نيم اسپيس مان (۽ لاڳاپيل نيم اسپيس جيڪڏهن نشان لڳل)",
        "namespace_association": "منسلڪ نانءُپولار",
        "blanknamespace": "(مُک)",
        "contributions": "{{GENDER:$1|يوزر}} جون ڀاڱيداريون",
        "contributions-title": "يُوزر ڀاڱيداريون براءِ $1",
        "mycontris": "ڀاڱيداريون",
+       "anoncontribs": "ڀاڱيداريون",
        "contribsub2": "{{GENDER:$3|$1}} ($2) لاءِ",
+       "contributions-userdoesnotexist": "يُوزر کاتو \"$1\" درج ٿيل نہ آهي.",
        "uctop": "(هاڻوڪو)",
        "month": "مهينو (۽ اڳوڻيون):",
        "year": "سال (۽ اڳوڻيون):",
+       "sp-contributions-newbies": "صرف نون کاتن جون ڀاڱيداريون ڏيکاريو",
        "sp-contributions-newbies-sub": "نون کاتن لاءِ",
+       "sp-contributions-newbies-title": "نون کاتن جي لاءِ يوزر جون ڀاڱيداريون",
        "sp-contributions-blocklog": "بنسش لاگ",
-       "sp-contributions-talk": "ڳالھ",
+       "sp-contributions-deleted": "يُوزر جون ڊاٺل ڀاڱيداريون",
+       "sp-contributions-uploads": "چاڙھَ",
+       "sp-contributions-logs": "لاگس",
+       "sp-contributions-talk": "ڳالھہ",
+       "sp-contributions-userrights": "يُوزر حقن جي سنڀال",
+       "sp-contributions-search": "ڀاڱيدارين لاءِ ڳولا ڪريو",
+       "sp-contributions-username": "آءِپي پتو يا يوزرنانءُ:",
        "sp-contributions-submit": "ڳوليو",
        "whatlinkshere": "هتان ڇا ڳنڍيل آهي",
        "whatlinkshere-title": "$1 سان ڳنڍيل صفحا",
        "blockip-legend": "يُوزر کي بندشيو",
        "ipbexpiry": "اختتام:",
        "ipbreason": "سبب:",
+       "ipbother": "ٻيو وقت:",
        "ipboptions": "2 ڪلاڪ:2 hours,1 ڏينهن:1 day,3 days:3 days,1 هفتو:1 week,2 weeks:2 weeks,1 مهينا:1 month,3 مهينا:3 months,6 مهينا:6 months,1 سال:1 year,اڻ کٽ:infinite",
        "ipb-confirm": "بندش جي پڪ ڪريو",
        "badipaddress": "ناقابلڪار آءِ پي پتو",
        "blockipsuccesssub": "بندش ڪامياب ٿي",
        "unblockip": "يُوزر کي اڻبندشيو",
        "ipusubmit": "اها بندش هٽايو",
-       "unblocked-range": "$1 تان بندش هتي چڪي آهي.",
+       "unblocked-range": "$1 تان بندش هٽي چڪي آهي.",
        "unblocked-id": "بندش $1 هٽي چڪي آهي.",
        "blocklist": "بندشيل يُوزرس",
-       "ipblocklist": "بندش وڌل يوزرس",
+       "ipblocklist": "بندشيل يوزرس",
        "blocklist-timestamp": "اوقاتي مهر",
        "blocklist-target": "هدف",
+       "blocklist-expiry": "اختتام:",
        "blocklist-reason": "سبب",
        "ipblocklist-submit": "ڳوليو",
        "ipblocklist-localblock": "مقامي بندش",
        "infiniteblock": "لامحدود",
-       "anononlyblock": "فقط نامعلوم",
-       "noautoblockblock": "Ø®Ù\88دڪار Ø¨Ù\86دش Ø±Ù\88ÚªÙ\8aل",
+       "anononlyblock": "فقط گمنام",
+       "noautoblockblock": "Ø®Ù\88دڪار Ø¨Ù\86دش ØºÙ\8aر Ù\81عال",
        "createaccountblock": "کاتو کولڻ جي روڪَ ٿيل",
        "emailblock": "برق ٽپال غير فعال",
        "blocklink": "بندشيو",
        "movelogpage": "چورڻ لاگ",
        "movereason": "سبب:",
        "revertmove": "ورايو",
-       "delete_and_move": "ڊاهيو ۽ چوريو",
        "delete_and_move_confirm": "جي ها، صفحو ڊاهيو",
        "delete_and_move_reason": "\"[[$1]]\" کان چورڻ جو عمل ممڪن بڻائڻ لاءِ ڊاٺو ويو",
        "export": "صفحا برآمديو",
        "tooltip-pt-mycontris": "توهان جون ڀاڱيداريون",
        "tooltip-pt-login": "توهان کي همٿائجي ٿو تہ توهان لاگ اِن ٿيو، بهرحال اهو لازمي نہ آهي.",
        "tooltip-pt-logout": "لاگ آئوٽ",
-       "tooltip-pt-createaccount": "توهان جي همٿ افزائي ڪئي وئي آهي ته هڪ کاتو کوليو ۽ لاگ ان ٿيو؛ جيتوڻيڪ، اهو ضروري نه آهي",
+       "tooltip-pt-createaccount": "کاتو کولڻ ۽ لاگ اِن ٿيڻ تي توهان کي همٿايو ويندو؛  جيتوڻيڪ، اهو ضروري نہ آهي",
        "tooltip-ca-talk": "موادي صفحي تي بحث",
        "tooltip-ca-edit": "هيءُ صفحو سنواريو",
        "tooltip-ca-addsection": "نئون سيڪشن شروع ڪريو",
        "tooltip-ca-viewsource": "هيءُ صفحو تحفظيل آهي. توهان ان جو ڪوڊ ڏسي سگھو ٿا.",
-       "tooltip-ca-history": "Ù\87Ù\86 ØµÙ\81Ø­Ù\8a Ø¬Ù\88Ù\86 Ú¯Ø°Ø±Ù\8aÙ\84 Ù\86ظرثاÙ\86Ù\8aÙ\88Ù\86",
+       "tooltip-ca-history": "Ù\87Ù\86 ØµÙ\81Ø­Ù\8a Ø¬Ù° Ú¯Ø°Ø±Ù\8aÙ\84 Ú\80Ù\8aرا",
        "tooltip-ca-protect": "هيءُ صفحو تحفظيو",
        "tooltip-ca-delete": "هيءُ صفحو ڊاهيو",
        "tooltip-ca-move": "هيءُ صفحو چوريو",
        "tooltip-ca-watch": "هيءُ صفحو پنهنجي ٽيٽ فهرست ۾ شامل ڪريو",
-       "tooltip-ca-unwatch": "هيءُ صفحو پنهنجي ٽيٽ فهرست مان هٽايو",
-       "tooltip-search": "جھڙتيو {{SITENAME}}",
-       "tooltip-search-go": "صÙ\81Ø­Ù\8a ØªÙ\8a Ù\88Ú\83Ù\88 Ø¨Ù\84ÚªÙ\84 Ù\87Ù\86 Ø³Ø§Ú³Ø¦Ù\8a Ù\86اÙ\84Ù\8a Ø³Ø§Ù\86 Ø¬Ù\8aÚªÚ\8fÙ\87Ù\86 Ù\85Ù\88جÙ\88د Ø¢Ù\87Ù\8a ØªÛ\81",
+       "tooltip-ca-unwatch": "هيءُ صفحو پنهنجي ٽيٽ فهرست تان هٽايو",
+       "tooltip-search": "{{SITENAME}} ۾ ڳوليو",
+       "tooltip-search-go": "تز Ø§Ù\86 Ø¦Ù\8a Ù\86اÙ\84Ù\8a Ø³Ø§Ù\86 ÚªÙ\88 ØµÙ\81Ø­Ù\88 Ù\85Ù\88جÙ\88د Ø¢Ù\87Ù\8a ØªÛ\81 Ú©Ù\88Ù\84Ù\8aÙ\88",
        "tooltip-search-fulltext": "هن متن لاءِ صفحا ڳوليو",
-       "tooltip-p-logo": "مک صفحو وزٽ ڪريو",
+       "tooltip-p-logo": "مک صفحو گھمو",
        "tooltip-n-mainpage": "مک صفحو گھمو",
-       "tooltip-n-mainpage-description": "مکيه صفحو وزٽ ڪريو",
+       "tooltip-n-mainpage-description": "مک صفحو گھمو",
        "tooltip-n-portal": "هن رٿا بابت، توهان ڇا ٿا ڪري سگھو، ڪهڙي شَي ڪٿي ملندي",
        "tooltip-n-currentevents": "تازن واقعن تي تفصيلي ڄاڻ لهو",
        "tooltip-n-recentchanges": "هن وڪيءَ ۾ تازين تبديلين جي فهرست.",
-       "tooltip-n-randompage": "بلاترتيب ڪو به صفحو اتاريو",
-       "tooltip-n-help": "ڳولي لهڻ جي جاءِ.",
+       "tooltip-n-randompage": "بلاترتيب ڪو بہ صفحو اتاريو",
+       "tooltip-n-help": "ڳولي لهڻ جي جاءِ",
        "tooltip-t-whatlinkshere": "هتان ڳنڍيل سمورا وڪي صفحا",
        "tooltip-t-recentchangeslinked": "ويجھڙائيءَ ۾ صفحن ۾ ٿيل تبديليون هن صفحي سان ڳنڍيل آهن",
        "tooltip-feed-atom": "هن صفحي لاءِ ايٽم فيڊ",
        "tooltip-diff": "پنهنجون ڪيل تبديليون ڏسو.",
        "tooltip-compareselectedversions": "هن صفحي جن ٻن چونڊيل پرتن درميان تفاوت ڏسو.",
        "tooltip-watch": "هيءُ صفحو پنهنجي ٽيٽ فهرست ۾ شامل ڪريو",
-       "tooltip-rollback": "هن صفحي ۾ پوئين ڀاڱيدار جي ڪيل ترميم (ترميمن) کي هڪ ڪلڪ سان اڻ ڪريو.",
+       "tooltip-rollback": "\"واپس پرايو\" هن صفحي ۾ پوئين ڀاڱيدار جي ڪيل ترميم (ترميمن) کي هڪ ڪلڪ سان اڻڪري ٿو.",
        "tooltip-summary": "ننڍو خلاصو ڏيو",
        "anonymous": "گمنام {{PLURAL:$1|يوزر|يوزرس}} جو {{SITENAME}}",
        "pageinfo-toolboxlink": "صفحي جي معلومات",
        "exif-imagedescription": "عڪس عنوان",
        "exif-make": "ڪيمرا ٺاهيندڙ",
        "exif-model": "ڪيميرا ماڊل",
-       "exif-software": "Ù\85ستعÙ\85Ù\84 Ù\85Ù\86تقگري",
+       "exif-software": "Ù\85ستعÙ\85Ù\84 Ù\85Ù\86Ø·قگري",
        "exif-artist": "ليکڪ",
-       "exif-copyright": "حق ۽ واطا رکندڙ",
+       "exif-copyright": "Ø­Ù\82 Û½ Ù\88اسطا Ø±Ú©Ù\86دÚ\99",
        "exif-colorspace": "رنگ پولار",
        "exif-pixelydimension": "عڪس جي ويڪر",
        "exif-pixelxdimension": "عڪس جي اوچائي",
        "exif-unknowndate": "نامعلوم تاريخ",
        "exif-orientation-1": "نارمل",
        "exif-orientation-3": "180° موڙيل",
-       "exif-componentsconfiguration-0": "وجود نه ٿو رکي",
+       "exif-componentsconfiguration-0": "وجود نہ ٿو رکي",
        "exif-exposureprogram-1": "دستينامو",
        "exif-meteringmode-0": "اڻڄاتل",
        "exif-meteringmode-1": "سراسري",
        "confirmemail": "برق ٽپال پتي جي پَڪَ ڪندا",
        "confirmemail_send": "خاطري ڪوڊ اماڻيو",
        "confirmemail_sent": "خاطري برق ٽپال اماڻي وئي.",
-       "confirmemail_success": "تÙ\88Ù\87اÙ\86 Ø¬Ù\8a Ø§Ù\8aÙ\85Ù\8aÙ\84 Ù¾ØªÙ\8a Ø¬Ù\8a Ù¾Úª ÚªØ¦Ù\8a Ù\88ئÙ\8a Ø¢Ù\87Ù\8a.\nÙ\87اڻ ØªÙ\88Ù\87اÙ\86 [[Special:UserLogin|Ù\84اگ Ø§Ù\90Ù\86]] ۽ وڪي جو مزو وٺي سگھو ٿا.",
+       "confirmemail_success": "تÙ\88Ù\87اÙ\86 Ø¬Ù\8a Ø¨Ø±Ù\82 Ù½Ù¾Ø§Ù\84 Ù¾ØªÙ\8a Ø¬Ù\8a ØªØµØ¯Ù\8aÙ\82 ÚªØ¦Ù\8a Ù\88ئÙ\8a Ø¢Ù\87Ù\8a.\nÙ\87اڻ ØªÙ\88Ù\87اÙ\86 [[Special:UserLogin|Ù\84اگ Ø§Ù\90Ù\86]] Ù¿Ù\8a ۽ وڪي جو مزو وٺي سگھو ٿا.",
        "confirmemail_loggedin": "توهان جي برق ٽپال پتي جي تصديق هاڻي ٿي چڪي آهي.",
        "confirmemail_subject": "{{SITENAME}} برق ٽپال پتي جي تصديق",
        "recreate": "ورسرجيو",
        "watchlisttools-edit": "ٽيٽ فهرست ڏسو ۽ سنواريو",
        "watchlisttools-raw": "ڪچي ٽيٽ فهرست سنواريو",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|ڳالهہ]])",
-       "version": "ورزن",
+       "version": "ڀيرو",
        "version-extensions": "تنصيب شده توسيعات",
-       "version-skins": "تنصيبشده چَمُون",
+       "version-skins": "تنصيب شده چَمُون",
        "version-specialpages": "خاص صفحا",
-       "version-variables": "ڦرڻا",
+       "version-variables": "ڦِرڻا",
        "version-other": "ٻيو",
        "version-license": "ذريعات‌وڪي لائيسنس",
        "version-ext-license": "لائيسنس",
        "version-ext-colheader-name": "توسيع",
        "version-skin-colheader-name": "چَمَ",
-       "version-ext-colheader-version": "ورزن",
+       "version-ext-colheader-version": "ڀيرو",
        "version-ext-colheader-license": "لائيسنس",
        "version-ext-colheader-description": "تشريح",
        "version-ext-colheader-credits": "ليکڪ",
        "version-poweredby-translators": "translatewiki.net جا ترجميڪار",
        "version-software": "تنصيب شده منطقگري",
        "version-software-product": "پراڊڪٽ",
-       "version-software-version": "ورزن",
+       "version-software-version": "ڀيرو",
        "version-libraries-library": "لائبريري",
-       "version-libraries-version": "ورزن",
+       "version-libraries-version": "ڀيرو",
        "version-libraries-license": "لائيسنس",
        "version-libraries-description": "تشريح",
        "version-libraries-authors": "ليکڪ",
        "redirect-submit": "ھلو",
-       "redirect-file": "فائيل نانءُ",
-       "fileduplicatesearch-filename": "فائيل نانءُ:",
+       "redirect-file": "فائيلنانءُ",
+       "fileduplicatesearch-filename": "فائيلنانءُ:",
        "fileduplicatesearch-submit": "ڳوليو",
        "specialpages": "خاص صفحا",
-       "specialpages-note-top": "ڪنجي",
+       "specialpages-note-top": "ÚªÙ\8fÙ\86جÙ\8a",
        "specialpages-group-login": "لاگ اِن ٿيو / کاتو کوليو",
        "specialpages-group-users": "يوزرس ۽ حق",
        "blankpage": "خالي صفحو",
        "intentionallyblankpage": "هيءُ صفحو ڄاڻي خالي ڇڏيو ويو آهي.",
-       "tag-filter": "[[Special:Tags|ٽيگ]] ڇاڻيون:",
+       "tag-filter": "[[Special:Tags|ٽيگ]] ڇاڻي:",
        "tag-filter-submit": "ڇاڻي",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ٽيگ|ٽيگز}}]]: $2)",
-       "tags-title": "ٽيگ",
+       "tags-title": "ٽيگس",
        "tags-tag": "ٽيگ نانءُ",
        "tags-source-header": "ذريعو",
        "tags-active-yes": "ها",
        "tags-active-no": "نہ",
        "tags-edit": "سنواريو",
        "tags-delete": "ڊاهيو",
-       "tags-activate": "Ù\85Ù\88ثر بڻايو",
-       "tags-deactivate": "غÙ\8aر Ù\85Ù\88ثر بڻايو",
+       "tags-activate": "Ù\81عاÙ\84 بڻايو",
+       "tags-deactivate": "غÙ\8aر Ù\81عاÙ\84 بڻايو",
        "tags-create-tag-name": "ٽيگ نانءُ:",
        "tags-create-reason": "سبب:",
        "tags-create-submit": "سرجيو",
-       "tags-delete-title": "Ù½Ù\8aÚ¯ Ú©Ù\8a Ú\8aاÙ\87Ù\8aÙ\88",
+       "tags-delete-title": "ٽيگ ڊاهيو",
        "tags-delete-reason": "سبب:",
        "tags-activate-reason": "سبب:",
-       "tags-activate-submit": "Ù\85Ù\88ثر Ø¨Ú»Ø§يو",
-       "tags-deactivate-title": "Ù½Ù\8aÚ¯ Ú©Ù\8a ØºÙ\8aرÙ\85Ù\88ثر Ø¨Ú»Ø§يو.",
+       "tags-activate-submit": "Ù\81عاÙ\84يو",
+       "tags-deactivate-title": "Ù½Ù\8aÚ¯ Ú©Ù\8a Ø§Ú»Ù\81عاÙ\84يو.",
        "tags-deactivate-reason": "سبب:",
        "tags-edit-existing-tags-none": "\"ڪو بہ نہ\"",
        "tags-edit-new-tags": "نوان ٽيگس:",
        "htmlform-cloner-delete": "هٽايو",
        "htmlform-title-not-exists": "$1 وجود نٿو رکي.",
        "logentry-delete-delete": "$1 {{GENDER:$2|ڊاٺو}} صفحو $3",
-       "revdelete-uname-hid": "Ù\84ÚªÙ\84 Ù\8aÙ\8fÙ\88زرÙ\86اÙ\86Ø¡Ù\8f",
+       "revdelete-uname-hid": "Ù\8aÙ\8fÙ\88زرÙ\86اÙ\86Ø¡Ù\8f Ù\84ÚªÙ\84",
        "logentry-move-move": "$1 {{GENDER:$2|چوريو}} صفحو $3 ڏانهن $4",
-       "logentry-newusers-create": "Ù\8aÙ\88زر Ú©Ø§ØªÙ\88 $1 {{GENDER:$2|جÙ\88Ú\99يو ويو}}",
+       "logentry-newusers-create": "Ù\8aÙ\88زر Ú©Ø§ØªÙ\88 $1 {{GENDER:$2|سرجيو ويو}}",
        "logentry-upload-upload": "$1 {{GENDER:$2|چاڙهيو}} $3",
        "rightsnone": "(ڪو بہ نہ)",
        "revdelete-summary": "ترميمي خلاصو",
        "feedback-submit": "جمع ڪرايو",
        "feedback-thanks-title": "توهان جي مهرباني!",
        "searchsuggest-search": "ڳوليو",
-       "api-error-filename-tooshort": "فائيل نانءَُ هيڪاندو ننڍو آهي.",
+       "api-error-filename-tooshort": "فائيلنانءَُ هيڪاندو ننڍو آهي.",
        "api-error-unclassified": "ڪا اڻجاتل چُڪَ واقع ٿي.",
        "api-error-unknown-code": "اڻڄاتل چُڪَ: \"$1\".",
        "api-error-unknown-warning": "اڻڄاتل چتاءُ: \"$1\".",
        "mw-widgets-dateinput-no-date": "ڪا بہ تاريخ نہ چونڊيل",
        "mw-widgets-titleinput-description-new-page": "اڃا اهو صفحو وجود نہ ٿو رکي",
        "mw-widgets-titleinput-description-redirect": "$1 ڏانهن چوريل",
-       "api-error-blacklisted": "براءِ مهرباني ڪو مختلف، وضاحتي عنوان چونڊيو."
+       "api-error-blacklisted": "براءِ مهرباني ڪو مختلف، تشريحي عنوان چونڊيو."
 }
index f7ec7e5..312d4ed 100644 (file)
        "movelogpagetext": "Sārašos parvadintu poslapiu.",
        "movereason": "Dingstės:",
        "revertmove": "atmestė",
-       "delete_and_move": "Ėštrintė ė parkeltė",
        "delete_and_move_text": "==Rēkalings ėštrīnims==\nPaskėrties straipsnis „[[:$1]]“ jau īr. A nuorėt ana ėštrintė, kū galietomiet parvadintė?",
        "delete_and_move_confirm": "Tēp, trintė poslapi",
        "delete_and_move_reason": "Ėštrinta, ka $1 galietom būtė parvadints",
index 96ee497..a673d6e 100644 (file)
        "movenosubpage": "Ova stranica nema podstranica.",
        "movereason": "Razlog:",
        "revertmove": "vrati - врати",
-       "delete_and_move": "Brisanje i premještanje",
        "delete_and_move_text": "==Brisanje neophodno==\nOdredišna stranica \"[[:$1]]\" već postoji.\nDa li je želite obrisati kako bi ste mogli izvršiti premještanje?",
        "delete_and_move_confirm": "Da, izbriši stranicu - Да, избриши страницу",
        "delete_and_move_reason": "Obrisano da se oslobodi mjesto za premještanje iz „[[$1]]“",
index d15128d..9e6c226 100644 (file)
        "morenotlisted": "Seznam ni popoln.",
        "mypage": "Stran",
        "mytalk": "Pogovor",
-       "anontalk": "Pogovorna stran IP-naslova",
+       "anontalk": "Pogovorna stran",
        "navigation": "Navigacija",
        "and": "&#32;in",
        "qbfind": "Poišči",
        "contributions": "{{GENDER:$1|Uporabnikovi|Uporabničini}} prispevki",
        "contributions-title": "Prispevki uporabnika $1",
        "mycontris": "Prispevki",
+       "anoncontribs": "Prispevki",
        "contribsub2": "Za {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Uporabniški račun »$1« ni registriran.",
        "nocontribs": "Ne najdem nobene merilom ustrezajoče spremembe.",
        "movenosubpage": "Ta stran nima podstrani.",
        "movereason": "Razlog:",
        "revertmove": "vrni",
-       "delete_and_move": "Briši in prestavi",
        "delete_and_move_text": "==Treba bi bilo brisati==\n\nCiljna stran »[[:$1]]« že obstaja. Ali jo želite, da bi pripravili prostor za prestavitev, izbrisati?",
        "delete_and_move_confirm": "Da, izbriši stran",
        "delete_and_move_reason": "Izbrisano z namenom pripraviti prostor za »[[$1]]«",
        "tooltip-pt-preferences": "Vaše nastavitve",
        "tooltip-pt-watchlist": "Seznam strani, katerih spremembe spremljate",
        "tooltip-pt-mycontris": "Seznam vaših prispevkov",
+       "tooltip-pt-anoncontribs": "Seznam urejanj s tega IP-naslova",
        "tooltip-pt-login": "Prijava ni obvezna, vendar je zaželena",
        "tooltip-pt-logout": "Odjavite se",
        "tooltip-pt-createaccount": "Predlagamo vam, da ustvarite račun in se prijavite, vendar pa to ni obvezno.",
index 5b7aaf8..33ddb6c 100644 (file)
        "passwordreset-emailtext-ip": "Dikush (ndoshta ju, nga IP adresa $1) kërkoi një kujtesë për \ndetajet e llogarisë suaj {{SITENAME}} ($4).Përdoruesi në vijim {{PLURAL:$3|llogari është|llogaritë janë}} të lidhur me këtë postë elektronike:\n\n$2\n\n{{PLURAL:$3|Ky fjalëkalim i përkohshëm|Këto fjalëkalime të përkohshme}} do të përfundojë për {{PLURAL:$5|një ditë|$5 ditë}}.\n\nJu duhet të kyçeni dhe të zgjidhni një fjalëkalim të ri tani. Nëse dikush tjetër e ka bërë këtë kërkesës, ose në qoftë se ju mbani mend fjalëkalimin tuaj origjinal, dhe ju nuk dëshirojni të ndryshoni atë, ju mund të injoroni këtë mesazh dhe do të vazhdoni përdorimin e fjalëkalimit tuaj të vjetër.",
        "passwordreset-emailtext-user": "Përdoruesi  $1 në {{SITENAME }} ka kërkuar një kujtesë për të dhënat e llogarisë suaj për {{SITENAME }} ($4). Përdoruesi në vijim {{PLURAL:$3 | llogaria është | llogaritë janë}} të lidhur me këtë postë elektronike: \n\n$2\n\n{{PLURAL:$3 | Ky fjalëkalim i përkohshëm | Këto fjalëkalime të përkohshme}} do të përfundojë në {{PLURAL:$5 | një ditë | $5 ditë}}.\nJu duhet të kyçeni dhe të zgjidhni një fjalëkalim të ri tani. Nëse dikush tjetër e ka bërë këtë kërkesës, ose në qoftë se ju mbani mend fjalëkalimin tuaj origjinal, dhe ju nuk dëshirojni të ndryshoni atë, ju mund të injoroni këtë mesazh dhe do të vazhdoni përdorimin e fjalëkalimit tuaj të vjetër.",
        "passwordreset-emailelement": "Emri i përdoruesit: \n$1\n\nFjalëkalimi i përkohshëm: \n$2",
-       "passwordreset-emailsent": "Nëse ky është një email adresë e regjistruar për llogarinë tuaj, atëherë një email për rivendosjen e fjalëkalimit do të dërgohet.",
+       "passwordreset-emailsent": "Nëse kjo është një adresë emaili e regjistruar për llogarinë tuaj, atëherë një email për rivendosjen e fjalëkalimit do të dërgohet.",
        "passwordreset-emailsent-capture": "Një email për rivendosjen e fjalëkalimit është dërguar, i cili tregohet më poshtë.",
        "passwordreset-emailerror-capture": "U dërgua një e-mail kujtesë, i cili tregohet më poshtë, por dërgesa për tek përdoruesi qe e pamundur: $1",
        "changeemail": "Ndrysho ose hiq postën elektronike",
        "wlheader-showupdated": "Faqet që kanë ndryshuar nga vizita juaj e fundit do të tregohen të '''trasha'''",
        "wlnote": "Më poshtë {{PLURAL:$1|është ndryshimi i fundit|janë '''$1''' ndryshimet e fundit}} në {{PLURAL:$2|orën e fundit|'''$2''' orët e fundit}}, që nga $3, $4.",
        "wlshowlast": "Trego $1 orët $2 ditët",
+       "watchlistall2": "të gjitha",
        "watchlist-options": "Mundësitë e listës mbikqyrëse",
        "watching": "Duke mbikqyrur...",
        "unwatching": "Mos e mbikqyr më...",
        "movenosubpage": "Kjo faqe nuk ka nën-faqe.",
        "movereason": "Arsyeja:",
        "revertmove": "ktheje",
-       "delete_and_move": "Grise dhe zhvendose",
        "delete_and_move_text": "==Nevojitet grisje==\n\nFaqja \"[[:$1]]\" ekziston, dëshironi ta grisni për të mundësuar zhvendosjen?",
        "delete_and_move_confirm": "Po, fshi këtë faqe",
        "delete_and_move_reason": "U gris për të liruar vendin për përcjellim të \"[[$1]]\"",
index 35a12b8..7702e8b 100644 (file)
@@ -29,7 +29,8 @@
                        "Aktron",
                        "Srdjan m",
                        "Macofe",
-                       "Сербијана"
+                       "Сербијана",
+                       "Xð"
                ]
        },
        "tog-underline": "Подвлачење веза:",
        "morenotlisted": "Ова листа није комплетна.",
        "mypage": "Страница",
        "mytalk": "Разговор",
-       "anontalk": "Разговор за ову ИП адресу",
+       "anontalk": "Разговор",
        "navigation": "Навигација",
        "and": "&#32;и",
        "qbfind": "Пронађи",
        "viewhelppage": "Погледај страницу помоћи",
        "categorypage": "Погледај страницу категорија",
        "viewtalkpage": "Погледај разговор",
-       "otherlanguages": "Ð\9dа Ð¾Ñ\81Ñ\82алим језицима",
+       "otherlanguages": "Ð\9dа Ð´Ñ\80Ñ\83гим језицима",
        "redirectedfrom": "(преусмерено са $1)",
        "redirectpagesub": "Преусмерење",
        "redirectto": "Преусмерава на:",
        "contributions": "{{GENDER:$1|Кориснички}} доприноси",
        "contributions-title": "Доприноси {{GENDER:$1|корисника|кориснице}} $1",
        "mycontris": "Доприноси",
+       "anoncontribs": "Доприноси",
        "contribsub2": "За {{GENDER:$3|$1}} ($2)",
        "contributions-userdoesnotexist": "Кориснички налог „$1“ није регистрован.",
        "nocontribs": "Нема измена које одговарају наведеним критеријумима.",
        "movenosubpage": "Ова страница нема подстрана.",
        "movereason": "Разлог:",
        "revertmove": "врати",
-       "delete_and_move": "Обриши и премести",
        "delete_and_move_text": "== Потребно брисање ==\n\nОдредишна страница „[[:$1]]“ већ постоји. \nЖелите ли да је обришете да бисте ослободили место за премештање?",
        "delete_and_move_confirm": "Да, обриши страницу",
        "delete_and_move_reason": "Обрисано да се ослободи место за премештање из „[[$1]]“",
        "tooltip-pt-preferences": "Ваша подешавања",
        "tooltip-pt-watchlist": "Списак страница које надгледате",
        "tooltip-pt-mycontris": "Списак ваших доприноса",
+       "tooltip-pt-anoncontribs": "Списак измена направљених са ове IP адресе",
        "tooltip-pt-login": "Препоручујемо вам да се пријавите, иако то није обавезно.",
        "tooltip-pt-logout": "Одјавите се",
        "tooltip-pt-createaccount": "Охрабрујемо вас да отворите налог и пријавите се али то није обавезно",
        "tags-deactivate-not-allowed": "Није могуће деактивирати ознаку „$1“.",
        "tags-deactivate-submit": "Декативирај",
        "tags-edit-title": "Уреди ознаке",
+       "tags-edit-manage-link": "Управљај ознакама",
        "tags-edit-existing-tags": "Постојеће ознаке:",
        "tags-edit-new-tags": "Нове ознаке:",
        "tags-edit-reason": "Разлог:",
        "htmlform-cloner-create": "Додај још",
        "htmlform-cloner-delete": "Уклони",
        "htmlform-cloner-required": "Бар једна вредност је потребна.",
+       "htmlform-title-badnamespace": "[[:$1]] није у именском простору „{{ns:$2}}“.",
        "htmlform-title-not-exists": "$1 не постоји.",
        "htmlform-user-not-exists": "<strong>$1</strong> не постоји.",
        "htmlform-user-not-valid": "<strong>$1</strong> није исправно корисничко име.",
        "special-characters-group-thai": "тајландски",
        "special-characters-group-lao": "лаоски",
        "special-characters-group-khmer": "кмерски",
+       "mw-widgets-dateinput-no-date": "Датум није изабран",
        "mw-widgets-dateinput-placeholder-day": "ГГГГ-ММ-ДД",
        "mw-widgets-dateinput-placeholder-month": "ГГГГ-ММ",
        "mw-widgets-titleinput-description-new-page": "страница још увек не постоји",
index ff1c936..ec82bcb 100644 (file)
@@ -20,7 +20,8 @@
                        "Nemo bis",
                        "Srdjan m",
                        "Macofe",
-                       "Сербијана"
+                       "Сербијана",
+                       "Xð"
                ]
        },
        "tog-underline": "Podvlačenje veza:",
        "morenotlisted": "Ova lista nije kompletna.",
        "mypage": "Stranica",
        "mytalk": "Razgovor",
-       "anontalk": "Razgovor za ovu IP adresu",
+       "anontalk": "Razgovor",
        "navigation": "Navigacija",
        "and": "&#32;i",
        "qbfind": "Pronađi",
        "viewhelppage": "Pogledaj stranicu pomoći",
        "categorypage": "Pogledaj stranicu kategorija",
        "viewtalkpage": "Pogledaj razgovor",
-       "otherlanguages": "Drugi jezici",
+       "otherlanguages": "Na drugim jezicima",
        "redirectedfrom": "(preusmereno sa $1)",
        "redirectpagesub": "Preusmerenje",
        "redirectto": "Preusmerava na:",
        "movenosubpage": "Ova stranica nema podstrana.",
        "movereason": "Razlog:",
        "revertmove": "vrati",
-       "delete_and_move": "Obriši i premesti",
        "delete_and_move_text": "== Potrebno brisanje ==\n\nOdredišna stranica „[[:$1]]“ već postoji. \nŽelite li da je obrišete da biste oslobodili mesto za premeštanje?",
        "delete_and_move_confirm": "Da, obriši stranicu",
        "delete_and_move_reason": "Obrisano da se oslobodi mesto za premeštanje iz „[[$1]]“",
index 2951941..c12640e 100644 (file)
        "movenosubpage": "Denna sida har inga undersidor.",
        "movereason": "Anledning:",
        "revertmove": "återställ",
-       "delete_and_move": "Radera och flytta",
        "delete_and_move_text": "==Radering krävs==\nDen titel du vill flytta sidan till, \"[[:$1]]\", finns redan. Vill du radera den för att möjliggöra flytt av denna sida dit?",
        "delete_and_move_confirm": "Ja, radera sidan",
        "delete_and_move_reason": "Raderad för att göra plats till flyttning av \"[[$1]]\"",
index c227d45..e5ddf98 100644 (file)
        "sig_tip": "ลายเซ็นของคุณพร้อมตราเวลา",
        "hr_tip": "เส้นนอน (ใช้อย่างจำกัด)",
        "summary": "คำอธิบายอย่างย่อ:",
-       "subject": "เรื่อง/พาดหัว:",
+       "subject": "เรื่อง:",
        "minoredit": "เป็นการแก้ไขเล็กน้อย",
        "watchthis": "เฝ้าดูหน้านี้",
        "savearticle": "บันทึกหน้า",
        "missingsummary": "<strong>อย่าลืม:</strong> คุณยังไม่ได้ให้คำอธิบายการแก้ไข \nถ้าคุณคลิก \"{{int:savearticle}}\" อีก จะบันทึกการแก้ไขของคุณโดยไม่มีคำอธิบายการแก้ไข",
        "selfredirect": "<strong>คำเตือน:</strong> คุณกำลังสร้างการเปลี่ยนทางไปบทความเดียวกัน\nคุณอาจระบุเป้าหมายของการเปลี่ยนทางผิด หรือคถณอาจแก้ไขหน้าผิด \nหากคุณคลิก \"{{int:savearticle}}\" อีกครั้ง จะสร้างการเปลี่ยนทาง",
        "missingcommenttext": "กรุณากรอกความเห็นด้านล่าง",
-       "missingcommentheader": "<strong>อยà¹\88าลืม:</strong> à¸\84ุà¸\93ยัà¸\87à¹\84มà¹\88à¹\84à¸\94à¹\89à¹\83สà¹\88หัวà¸\82à¹\89อ/à¸\9eาà¸\94หัวสำหรัà¸\9aà¸\84วามà¹\80หà¹\87à¸\99à¸\99ีà¹\89 \nà¸\96à¹\89าà¸\84ุà¸\93à¸\84ลิà¸\81 \"{{int:savearticle}}\" à¸­à¸µà¸\81 à¸\88ะà¸\9aัà¸\99à¸\97ึà¸\81à¸\81ารà¹\81à¸\81à¹\89à¹\84à¸\82à¸\82อà¸\87à¸\84ุà¸\93à¹\82à¸\94ยà¹\84มà¹\88มีหัวà¸\82à¹\89อ/à¸\9eาà¸\94หัว",
+       "missingcommentheader": "<strong>อยà¹\88าลืม:</strong> à¸\84ุà¸\93ยัà¸\87à¹\84มà¹\88à¹\84à¸\94à¹\89à¹\83สà¹\88à¹\80รืà¹\88อà¸\87สำหรัà¸\9aà¸\84วามà¹\80หà¹\87à¸\99à¸\99ีà¹\89 \nà¸\96à¹\89าà¸\84ุà¸\93à¸\84ลิà¸\81 \"{{int:savearticle}}\" à¸­à¸µà¸\81 à¸\88ะà¸\9aัà¸\99à¸\97ึà¸\81à¸\81ารà¹\81à¸\81à¹\89à¹\84à¸\82à¸\82อà¸\87à¸\84ุà¸\93à¹\82à¸\94ยà¹\84มà¹\88ระà¸\9aุà¹\80รืà¹\88อà¸\87",
        "summary-preview": "ตัวอย่างคำอธิบาย:",
-       "subject-preview": "ตัวอย่างเรื่อง/พาดหัว:",
+       "subject-preview": "ตัวอย่างเรื่อง:",
        "previewerrortext": "เกิดข้อผิดพลาดขณะกำลังพยายามดูตัวอย่างการเปลี่ยนแปลงของคุณ",
        "blockedtitle": "ผู้ใช้ถูกบล็อก",
        "blockedtext": "<strong>ชื่อผู้ใช้หรือเลขที่อยู่ไอพีของคุณถูกบล็อก</strong>\n\nการบล็อกนี้ดำเนินการโดย $1\nซึ่งให้เหตุผลว่า ''$2''\n\n* เริ่มการบล็อก: $8\n* หมดเขตการบล็อก: $6\n* ผู้ถูกบล็อกที่เจตนา: $7\n\nคุณสามารถติดต่อ $1 หรือ[[{{MediaWiki:Grouppage-sysop}}|ผู้ดูแลระบบ]]คนอื่นเพื่ออภิปรายการบล็อกนี้ได้\nคุณไม่สามารถใช้คุณลักษณะ \"ส่งอีเมลหาผู้ใช้รายนี้ได้\" จนกว่าจะระบุที่อยู่อีเมลให้ถูกต้องใน[[Special:Preferences|การตั้งค่าบัญชี]]ของคุณ และคุณมิได้ถูกห้ามใช้ความสามารถนี้\nเลขที่อยู่ไอพีปัจจุบันของคุณคือ $3 และหมายเลขการบล็อกคือ #$5 \nโปรดแสดงรายละเอียดข้างต้นทั้งหมดในการสอบถามใด ๆ",
        "prefs-help-recentchangescount": "นี่รวมถึงการปรับปรุงล่าสุด ประวิติหน้า และปูม",
        "prefs-help-watchlist-token2": "นี่คือแป้นลับสำหรับเข้าการป้อนเว็บรายการเฝ้าดูของคุณ\nใครก็ตามที่ทราบจะสามารถอ่านรายการเฝ้าดูของคุณได้ ฉะนั้นอย่าบอกผู้อื่น\n[[Special:ResetTokens|คลิกที่นี่หากคุณต้องการตั้งใหม่]]",
        "savedprefs": "บันทึกการตั้งค่าของคุณแล้ว",
+       "savedrights": "บันทึกสิทธิผู้ใช้ของ {{GENDER:$1|$1}} แล้ว",
        "timezonelegend": "เขตเวลา:",
        "localtime": "เวลาท้องถิ่น:",
        "timezoneuseserverdefault": "ใช้ค่าโดยปริยายของวิกิ ($1)",
        "emailccsubject": "คัดลอกสารของคุณไป $1: $2",
        "emailsent": "ส่งอีเมลแล้ว",
        "emailsenttext": "ส่งสารอีเมลของคุณแล้ว",
-       "emailuserfooter": "$1 à¸ªà¹\88à¸\87อีà¹\80มลà¸\96ึà¸\87 $2 à¸\94à¹\89วยà¸\9fัà¸\87à¸\81à¹\8cà¸\8aัà¸\99 \"อีà¹\80มลà¸\9cูà¹\89à¹\83à¸\8aà¹\89รายà¸\99ีà¹\89\" ที่ {{SITENAME}}",
+       "emailuserfooter": "$1 à¸ªà¹\88à¸\87อีà¹\80มลà¸\99ีà¹\89à¸\96ึà¸\87 $2 à¹\82à¸\94ยà¸\9fัà¸\87à¸\81à¹\8cà¸\8aัà¸\99 \"{{int:emailuser}}\" ที่ {{SITENAME}}",
        "usermessage-summary": "ฝากสารระบบ",
        "usermessage-editor": "ตัวส่งสารของระบบ",
        "watchlist": "รายการเฝ้าดู",
        "wlnote": "ด้านล่างเป็น{{PLURAL:$1|การเปลี่ยนแปลงหลังสุด| <strong>$1</strong> การเปลี่ยนแปลงหลังสุด}} ใน{{PLURAL:$2|ชั่วโมง| <strong>$2</strong> ชั่วโมง}}ที่หลังสุด จนถึง $3, $4",
        "wlshowlast": "แสดง $1 ชั่วโมง $2 วันล่าสุด",
        "watchlistall2": "ทั้งหมด",
+       "watchlist-hide": "ซ่อน",
+       "wlshowtime": "แสดงล่าสุด:",
+       "wlshowhideminor": "การแก้ไขเล็กน้อย",
+       "wlshowhidebots": "บอต",
+       "wlshowhideliu": "ผู้ใช้ลงทะเบียน",
+       "wlshowhideanons": "ผู้ใช้นิรนาม",
+       "wlshowhidepatr": "การแก้ไขที่ตรวจสอบแล้ว",
+       "wlshowhidemine": "การแก้ไขของฉัน",
        "watchlist-options": "ตัวเลือกรายการเฝ้าดู",
        "watching": "กำลังเฝ้าดู...",
        "unwatching": "กำลังเลิกเฝ้าดู...",
        "deletepage": "ลบหน้า",
        "confirm": "ยืนยัน",
        "excontent": "เนื้อหาเดิม: \"$1\"",
-       "excontentauthor": "เนื้อหาเดิม: \"$1\" (และมีผู้เขียนคนเดียวคือ \"[[Special:Contributions/$2|$2]]\")",
+       "excontentauthor": "เนื้อหาเดิม: \"$1\" และมีผู้เขียนคนเดียวคือ \"[[Special:Contributions/$2|$2]]\" ([[User talk:$2|พูดคุย]])",
        "exbeforeblank": "เนื้อหาก่อนถูกทำว่างคือ: \"$1\"",
        "delete-confirm": "ลบ \"$1\"",
        "delete-legend": "ลบ",
        "undeletepagetext": "{{PLURAL:$1||$1 }}หน้าต่อไปนี้ถูกลบแล้ว แต่เนื้อหายังคงอยู่ในหน่วยเก็บถาวรและสามารถกู้คืนได้ \nหน่วยเก็บถาวรอาจถูกลบเป็นระยะ",
        "undelete-fieldset-title": "กู้คืนรุ่นปรับปรุง",
        "undeleteextrahelp": "ในการกู้ประวัติของหน้าคืนทั้งหมด ให้เว้นทุกกล่องและคลิก <strong><em>{{int:undeletebtn}}</em></strong>\nถ้าต้องการกู้ประวัติคืนเฉพาะบางส่วน ให้เลือกกล่องที่มีประวัติส่วนที่ต้องการและคลิก <strong><em>{{int:undeletebtn}}</em></strong>",
-       "undeleterevisions": "$1 à¸£à¸¸à¹\88à¸\99à¸\81ารà¹\81à¸\81à¹\89à¹\84à¸\82à¸\96ูà¸\81à¹\80à¸\81à¹\87à¸\9aà¸\96าวร",
+       "undeleterevisions": "$1 à¸£à¸¸à¹\88à¸\99à¸\81ารà¹\81à¸\81à¹\89à¹\84à¸\82à¸\96ูà¸\81ลà¸\9a",
        "undeletehistory": "เมื่อคุณกู้หน้าคืน รุ่นทั้งหมดจะถูกกู้คืนไปยังประวัติ \nหากมีการสร้างหน้าใหม่ชื่อเดียวกันหลังการลบ รุ่นที่กู้คืนนั้นจะปรากฏในประวัติก่อนหน้า",
        "undeleterevdel": "จะไม่ดำเนินการกู้คืนหากส่งผลให้รุ่นบนสุดของหน้าหรือไฟล์ถูกลบบางส่วน\nในกรณีเช่นนั้น คุณต้องไม่เลือกหรือแสดงรุ่นที่ถูกลบใหม่สุด",
        "undeletehistorynoadmin": "หน้านี้ถูกลบแล้ว\nสาเหตุการลบแสดงในความย่อด้านล่าง ร่วมกับรายละเอียดผู้ใช้ที่เคยแก้ไขหน้านี้ก่อนลบ\nเฉพาะผู้ดูแลระบบที่ดูข้อความแท้จริงของรุ่นที่ถูกลบเหล่านี้ได้",
        "movenosubpage": "หน้านี้ไม่มีหน้าย่อย",
        "movereason": "เหตุผล:",
        "revertmove": "ย้อน",
-       "delete_and_move": "ลบและย้าย",
        "delete_and_move_text": "== ต้องการลบ ==\nมีหน้าปลายทาง \"[[:$1]]\" แล้ว \nคุณต้องการลบหน้าดังกล่าวเพื่อสร้างหนทางสำหรับการย้ายหรือไม่",
        "delete_and_move_confirm": "ใช่ ลบหน้านั้น",
        "delete_and_move_reason": "ถูกลบเพื่อสร้างหนทางสำหรับการย้ายจาก \"[[$1]]\"",
index 1bf8c7a..5965091 100644 (file)
@@ -88,6 +88,7 @@
        "tog-hideminor": "Son değişiklikler sayfasında küçük değişiklikleri gizle",
        "tog-hidepatrolled": "Son değişikliklerde devriye görmüş değişiklikleri gizle",
        "tog-newpageshidepatrolled": "Yeni sayfalar listesinde, devriye görmüş sayfaları gizle",
+       "tog-hidecategorization": "Sayfa kategorilendirmesni gizle",
        "tog-extendwatchlist": "İzleme listesini sadece en son değil, tüm değişiklikleri göstermek üzere genişlet",
        "tog-usenewrc": "Son değişiklikler sayfasındaki ve izleme listesindeki değişiklikleri sayfalara gruplandır",
        "tog-numberheadings": "Başlıkları otomatik numaralandır",
        "tog-watchlisthideliu": "İzleme listemde, kayıtlı kullanıcılar tarafından yapılan değişiklikleri gizle",
        "tog-watchlisthideanons": "İzleme listemde, anonim kullanıcılar tarafından yapılan değişiklikleri gizle",
        "tog-watchlisthidepatrolled": "İzleme listesinde, devriye görmüş değişiklikleri gizle",
+       "tog-watchlisthidecategorization": "Sayfa kategorilendirmesni gizle",
        "tog-ccmeonemails": "Diğer kullanıcılara gönderdiğim e-postaların bir kopyasını bana da gönder",
        "tog-diffonly": "Sayfa içeriğini, sürüm farklarının altında gösterme",
        "tog-showhiddencats": "Gizli kategorileri göster",
        "search-category": "(kategori $1)",
        "search-file-match": "(dosya içeriğiyle eşleşiyor)",
        "search-suggest": "Bunu mu demek istediniz: $1",
+       "search-rewritten": "$1 için sonuçlar gösteriliyor. Bunun yerine $2 için arama yapılsın mı?",
        "search-interwiki-caption": "Kardeş projeler",
        "search-interwiki-default": "$1 sonuçları:",
        "search-interwiki-more": "(daha çok)",
        "showingresultsinrange": "<strong>$2</strong> ile <strong>$3</strong> arasında toplam <strong>$1</strong> sonuç gösteriliyor.",
        "search-showingresults": "{{PLURAL:$4|<strong>$3</strong> için sonuç|<strong>$3</strong> için <strong>$1 - $2</strong> sonuçlar}}",
        "search-nonefound": "Sorguyla eşleşen bir sonuç yok.",
+       "search-nonefound-thiswiki": "Bu sitede aramanızla eşleşen herhangi bir sonuç yok.",
        "powersearch-legend": "Gelişmiş arama",
        "powersearch-ns": "Ad alanlarında ara:",
        "powersearch-togglelabel": "Seç:",
        "movenosubpage": "Bu sayfanın altsayfası yoktur.",
        "movereason": "Neden:",
        "revertmove": "geri al",
-       "delete_and_move": "Sil ve taşı",
        "delete_and_move_text": "==Silinmesi gerekiyor==\n\n\"[[:$1]]\" isimli bir sayfa zaten mevcut. O sayfayı silerek, isim değişikliğini gerçekleştirmeye devam etmek istiyor musunuz?",
        "delete_and_move_confirm": "Evet, sayfayı sil",
        "delete_and_move_reason": "[[$1]] sayfasının isim değişikliğinin gerçekleşmesi için silindi.",
index 60fddad..af67776 100644 (file)
        "passwordtooshort": "Сезсүз $1 {{PLURAL:$1|символдан}} торырга тиеш.",
        "password-name-match": "Кертелгән серсүз кулланучы исеменнән аерылырга тиеш.",
        "password-login-forbidden": "Бу кулланучы исемен һәм серсүзне куллану тыелган",
-       "mailmypassword": "ЭлекÑ\82Ñ\80он Ð¿Ð¾Ñ\87Ñ\82ага Ñ\8fңа Ñ\81еÑ\80Ñ\81үз Ò\97ибÓ\99рү",
+       "mailmypassword": "СеÑ\80Ñ\81үзне Ð±ÐµÑ\82ерү",
        "passwordremindertitle": "{{SITENAME}} кулланучысына вакытлы серсүз тапшыру",
        "passwordremindertext": "Кемдер (бәлки, сездер, IP адресы: $1) {{SITENAME}} ($4) өчен яңа серсүз соратты. $2 өчен яңа серсүз: $3. Әгәр бу сез булсагыз, системага керегез һәм серсүзне алмаштырыгыз. Яңа серсүз $5 {{PLURAL:$5|көн}} гамәлдә булачак.\n\nӘгәр сез серсүзне алмаштыруны сорамаган булсагыз яки, оныткан очракта, исегезгә төшергән булсагыз, бу хәбәргә игътибар бирмичә, иске серсүзегезне куллануны дәвам итегез.",
        "noemail": "$1 исемле кулланучы өчен электрон почта адресы язылмаган.",
        "throttled-mailpassword": "Серсүзне электрон почтага җибәрү гамәлен сез {{PLURAL:$1|1=соңгы $1 сәгать}} эчендә кулландыгыз инде. Бу гамәлне явызларча куллануны кисәтү максатыннан аны $1 {{PLURAL:$1|сәгать}} аралыгында бер генә тапкыр башкарып була.",
        "mailerror": "Хат җибәрү хатасы: $1",
        "acct_creation_throttle_hit": "Сезнең IP адресыннан бу тәүлек эчендә {{PLURAL:$1|$1 хисап язмасы}} төзелде инде. Шунлыктан бу гамәл сезнең өчен вакытлыча ябык.",
-       "emailauthenticated": "ЭлекÑ\82Ñ\80он Ð¿Ð¾Ñ\87Ñ\82а Ð°Ð´Ñ\80еÑ\81Ñ\8bгÑ\8bз Ñ\80аÑ\81ландÑ\8b: $3, $2.",
+       "emailauthenticated": "Сезнең Ñ\8dлекÑ\82Ñ\80он Ð¿Ð¾Ñ\87Ñ\82а Ð°Ð´Ñ\80еÑ\81Ñ\8bгÑ\8bз $2 $3 Ñ\80аÑ\81ландÑ\8b.",
        "emailnotauthenticated": "Электрон почта адресыгыз әле дәлилләнмәгән, шуңа викиның электрон почта белән эшләү гамәлләре сүндерелде.",
        "noemailprefs": "Электрон почта адресыгыз күрсәтелмәгән, шуңа викиның электрон почта белән эшләү гамәлләре сүндерелгән.",
        "emailconfirmlink": "Электрон почта адресыгызны дәлилләгез.",
        "sig_tip": "Имза һәм вакыт",
        "hr_tip": "Горизонталь сызык (еш кулланмагыз)",
        "summary": "Үзгәртүләр тасвирламасы:",
-       "subject": "Тема/башисем:",
+       "subject": "Тема:",
        "minoredit": "Бу кече үзгәртү",
        "watchthis": "Бу битне күзәтү",
        "savearticle": "Битне саклау",
        "missingcommenttext": "Аска тасвирлама язуыгыз сорала.",
        "missingcommentheader": "''Искәртү:''' Сез тасвирламага исем бирмәдегез.\n«{{int:savearticle}}» төймәсенә кабат бассагыз, үзгәртүләр исемсез язылачак.",
        "summary-preview": "Тасвирламаны алдан карау:",
-       "subject-preview": "Ð\91аÑ\88иÑ\81емне Ð°Ð»Ð´Ð°Ð½ ÐºÐ°Ñ\80аÑ\83:",
+       "subject-preview": "Ð\91аÑ\88иÑ\81емне Ð±Ð¾Ð»Ð°Ð¹ Ð±Ñ\83лаÑ\87ак:",
        "blockedtitle": "Кулланучы тыелды",
        "blockedtext": "'''Сезнең хисап язмагыз яки IP адресыгыз тыелган.'''\n\nТыючы идарәче: $1.\nКүрсәтелгән сәбәп: ''$2''.\n\n* Тыю башланган вакыт: $8\n* Тыю ахыры: $6\n* Тыелулар саны: $7\n\nСез $1 яки башка [[{{MediaWiki:Grouppage-sysop}}|идарәчегә]] тыю буенча сорауларыгызны җибәрә аласыз.\nИсегездә тотыгыз: әгәр сез теркәлмәгән һәм электрон почта адресыгызны дәлилләмәгән булсагыз ([[Special:Preferences|дәлилләү өчен шәхси көйләүләр монда]]), идарәчегә хат җибәрә алмыйсыз. Шулай ук тыю вакытында сезнең хат җибәрү мөмкинлегегезне чикләгән булырга да мөмкиннәр.\nСезнең IP адресы — $3, тыю идентификаторы — #$5.\nХатларда бу мәгълүматны күрсәтергә онытмагыз.",
        "autoblockedtext": "Сезнең IP адресыгыз, аның тыелган кулланучы тарафыннан кулланылуы сәбәпле, автомат рәвештә тыелды.\nУл кулланучыны тыючы идарәче: $1. Күрсәтелгән сәбәп:\n\n:''$2''\n\n* Тыю башланган вакыт: $8\n* Тыю ахыры: $6\n* Тыелулар саны: $7\n\nСез $1 яки башка [[{{MediaWiki:Grouppage-sysop}}|идарәчегә]] тыю буенча сорауларыгызны җибәрә аласыз.\nИсегездә тотыгыз: әгәр сез теркәлмәгән һәм электрон почта адресыгызны дәлилләмәгән булсагыз ([[Special:Preferences|дәлилләү өчен шәхси көйләүләр монда]]), идарәчегә хат җибәрә алмыйсыз. Шулай ук тыю вакытында сезнең хат җибәрү мөмкинлегегезне чикләгән булырга да мөмкиннәр.\nСезнең IP адресы — $3, тыю идентификаторы — #$5.\nХатларда бу мәгълүматны күрсәтергә онытмагыз.",
        "nosuchsectiontitle": "Мондый бүлекне табып булмый.",
        "nosuchsectiontext": "Сез булмаган бүлекне төзәтергә телисез.\nСез бу сәхифәне караганда ул бетерелә алды.",
        "loginreqtitle": "Керү кирәк",
-       "loginreqlink": "керү",
+       "loginreqlink": "керергә",
        "loginreqpagetext": "Сез башка битләр карау өчен $1 тиеш.",
        "accmailtitle": "Серсүз җибәрелде.",
        "accmailtext": "[[User talk:$1|$1]] кулланучысы өчен төзелгән серсүз $2 адресына җибәрелде.\n\nСайтка кергәч сез ''[[Special:ChangePassword|серсүзегезне үзгәртә аласыз]]''.",
        "nocreate-loggedin": "Сезгә яңа битләр төзү хокукы бирелмәгән.",
        "sectioneditnotsupported-title": "Бүлекләрне үзгәртү рөхсәт ителми.",
        "sectioneditnotsupported-text": "Бу биттә бүлекләрне үзгәртү рөхсәт ителми.",
-       "permissionserrors": "Ð\9aеÑ\80Ò¯ Ñ\85окÑ\83кÑ\8b Ñ\85аÑ\82алаÑ\80ы",
+       "permissionserrors": "Ð\9aеÑ\80Ò¯ Ñ\85аÑ\82аÑ\81ы",
        "permissionserrorstext": "Түбәндәге {{PLURAL:$1|1=сәбәп|сәбәпләр}} аркасында сез бу гамәлне башкара алмыйсыз:",
        "permissionserrorstext-withaction": "$2 гамәлен башкара алмыйсыз. {{PLURAL:$1|1=Сәбәбе|Сәбәпләре}}:",
        "recreate-moveddeleted-warn": "'''Игътибар: Сез бетерелгән бит урынына яңа бит ясамакчы буласыз.'''\n\nСезгә чыннан да бу битне яңадан ясау кирәкме?\nТүбәндә битнең бетерү һәм күчерү көндәлеге китерелә:",
        "revdelete-show-file-submit": "Әйе",
        "logdelete-selected": "Журналның {{PLURAL:$1|1=Сайланган язма|сайланган язмалары}} :",
        "revdelete-legend": "Чикләүләр урнаштыр:",
-       "revdelete-hide-text": "Битнең бу юрамасы текстын яшер",
+       "revdelete-hide-text": "Үзгәртү тексты",
        "revdelete-hide-image": "Файл эчендәгеләрне качыр",
-       "revdelete-hide-name": "Ð\93амÓ\99лне Ò»Ó\99м Ð¾Ð±Ñ\8aекÑ\82нÑ\8b яшерү",
-       "revdelete-hide-comment": "Үзгәртүләр тасвирламасы яшерелсен",
-       "revdelete-hide-user": "Үзгәртүченең исемен/IP адресын яшер",
+       "revdelete-hide-name": "Ð\93амÓ\99лне Ò»Ó\99м ÐºÓ©Ð¹Ð»Ó\99үне яшерү",
+       "revdelete-hide-comment": "Үзгәртүләр тасвирламасы",
+       "revdelete-hide-user": "Кулланучы исеме/IP-адрес",
        "revdelete-hide-restricted": "Мәгълүматлар идарәчеләрдән дә яшерелсен",
        "revdelete-radio-same": "(үзгәртмәү)",
        "revdelete-radio-set": "Яшеренлек",
        "revdelete-radio-unset": "Күренүчәнлек",
        "revdelete-suppress": "Мәгълүматлар идарәчеләрдән дә яшерелсен",
        "revdelete-log": "Сәбәп:",
-       "revdelete-submit": "{{PLURAL:$1|сайланылган версиягә}} кулланырга",
+       "revdelete-submit": "{{PLURAL:$1|1=сайланылган юрамага|сайланылган юрамаларга}} кулланырга",
        "revdelete-success": "'''Версиянең күренүчәнлеге уңышлы рәвештә үзгәртелде'''",
        "revdelete-failure": "'''Версиянең күренүчәнлеге үзгәртелә алмый:'''\n$1",
        "logdelete-success": "Вакыйганың күренүчәнлеге үзгәртелде.",
        "search-relatedarticle": "Бәйле",
        "searchrelated": "бәйле",
        "searchall": "барлык",
-       "showingresults": "Аста № '''$2''' {{PLURAL:$1|башлап}} '''$1''' {{PLURAL:$1|результат}} күрсәтелгән.",
+       "showingresults": "Аста №<strong>$2</strong> башлап {{PLURAL:$1|<strong>1</strong> нәтиҗә күрсәтелгән}}.",
        "search-showingresults": "{{PLURAL:$4|<strong>$3</strong> нәтиҗәдән <strong>$1</strong>| <strong>$3</strong> нәтиҗәләрдән <strong>$1 — $2</strong>}}",
        "search-nonefound": "Сорауга туры килгән нәтиҗәләр табылмады.",
        "powersearch-legend": "Өстәмә эзләү",
        "rows": "Юллар:",
        "columns": "Баганалар:",
        "searchresultshead": "Эзләү",
-       "stub-threshold": "<a href=\"#\" class=\"stub\">Ясалма сылтамаларның</a> бизәлеше буенча чикләүләр (байтларда):",
+       "stub-threshold": "Ясалма сылтамаларның бизәлеше буенча чикләүләр ($1):",
        "stub-threshold-disabled": "Ябылган",
        "recentchangesdays": "Соңгы үзгәртүләрне күрсәтүче көннәр саны:",
-       "recentchangesdays-max": "( $1 {{PLURAL:$1|көннән}} дә артык булмаска тиеш)",
+       "recentchangesdays-max": "(иң күбе $1 {{PLURAL:$1|көн}})",
        "recentchangescount": "Төп буларак кулланучы үзгәртүләр саны:",
        "prefs-help-recentchangescount": "Үз өченә үзгәртүләрне, битләрнең тарихын һәм язлу көндәлеген дә кертә.",
        "savedprefs": "Көйләнмәләрегез сакланды.",
        "timezoneregion-indian": "Һинд океаны",
        "timezoneregion-pacific": "Тын океан",
        "allowemail": "Башка кулланучылардан хатлар алырга рөхсәт ителсен",
-       "prefs-searchoptions": "Эзләү көйләнмәләре",
+       "prefs-searchoptions": "Эзләү",
        "prefs-namespaces": "Исемнәр мәйданы",
        "default": "килешү буенча",
        "prefs-files": "Файллар",
        "prefs-reset-intro": "Бу бит сезнең көйләнмәләрегезне бетерү өчен кулланыла. Бу эшне башкару нәтиҗәсендә сез яңадан үз көйләнмәләрне яңадан кайтара алмыйсыз.",
        "prefs-emailconfirm-label": "E-mail раслау",
        "youremail": "Электрон почта:",
-       "username": "Кулланучы исеме:",
-       "prefs-memberingroups": "Төркем {{PLURAL:$1|әгъзасы}}:",
+       "username": "{{GENDER:$1|Кулланучы исеме}}:",
+       "prefs-memberingroups": "{{PLURAL:$1|Төркем}} {{GENDER:$2|әгъзасы}}:",
        "prefs-memberingroups-type": "$1",
        "prefs-registration": "Теркәлү вакыты:",
        "prefs-registration-date-time": "$1",
        "prefs-help-signature": "Бәхәслек битләрендә сезнең язмаларыгызны калдыру «<nowiki>~~~~</nowiki>» тамгалары куелу нәтиҗәсендә булырга тиеш.",
        "badsig": "Имза дөрес түгел. HTML теглары тикшерегез.",
        "badsiglength": "Имзагыз бигрәк озын.\nУл $1 {{PLURAL:$1|хәрефтән}} күбрәк булырга тиеш түгел.",
-       "yourgender": "Җенес:",
-       "gender-unknown": "билгеÑ\81ез",
+       "yourgender": "Сезгә нинди тасвирлама күбрәк туры килә?",
+       "gender-unknown": "Сезне Ð¸Ñ\81кÓ\99 Ð°Ð»Ð³Ð°Ð½Ð´Ð° Ð¿Ñ\80огÑ\80амма, Ð¼Ó©Ð¼ÐºÐ¸Ð½ Ð±Ñ\83лган Ð¾Ñ\87Ñ\80акÑ\82а, Ò\97енÑ\81и-нейÑ\82Ñ\80алÑ\8c Ñ\81үзлÓ\99Ñ\80 ÐºÑ\83лланаÑ\87ак",
        "gender-male": "Вики-битләрне ир-ат үзгәртә",
        "gender-female": "Вики-битләрне хатын-кыз үзгәртә",
-       "prefs-help-gender": "Мәҗбүри түгел: Ул бары тик кайбер хатларда гына күренәчәк һәм бу мәгълүмат барлык кулланучыларга да билгеле булачак.",
+       "prefs-help-gender": "Әлеге параметрларны куллану мәҗбүри түгел. Ул бары тик Сезгә дөрес итеп өндәшү өчен генә кирәк булачак. Бу мәгълүмат барлык кулланучыларга да билгеле булачак.",
        "email": "Электрон почта",
-       "prefs-help-realname": "Чын исемегез (кирәкми): аны күрсәтсәгез, ул битне үзгәртүче күрсәтү өчен файдалаячак.",
+       "prefs-help-realname": "Чын исемегезне кертү мәҗбүри тугел. Аны күрсәткән очракта, ул Сезнең эшләрдә автор хокуклары буенча күрсәтеләчәк.",
        "prefs-help-email": "Электрон почта адресын күрсәтү мәҗбүри түгел, ләкин әгәрдә сез үзегезнең серсүзне онытсагыз бу сезгә аны яңадан кайтарырга ярдәм итәчәк.",
        "prefs-help-email-others": "Ул шулай ук сезгә башка кулланучылар белән аралашырга ярдәм итчәк, шул ук вакытта сезнең почтагызның юлламасы күрсәтелмәячәк.",
        "prefs-help-email-required": "Электрон почта адресы кирәк.",
        "prefs-signature": "Имза",
        "prefs-dateformat": "Вакытың форматы",
        "prefs-timeoffset": "Вакыт билгеләнеше",
-       "prefs-advancedediting": "Ð\9aиңÓ\99йÑ\82елгÓ\99н көйләүләр",
+       "prefs-advancedediting": "Ð\93омÑ\83ми көйләүләр",
        "prefs-advancedrc": "Киңәйтелгән көйләүләр",
        "prefs-advancedrendering": "Киңәйтелгән көйләүләр",
        "prefs-advancedsearchoptions": "Киңәйтелгән көйләүләр",
        "userrights-lookup-user": "Кулланучы төркемнәре белән идарә итү",
        "userrights-user-editname": "Кулланучының исемен кертегез:",
        "editusergroup": "Кулланучының төркемнәрен алмаштыру",
-       "editinguser": "Кулланучы <strong>[[User:$1|$1]]</strong> $2 хокукларын үзгәртү",
+       "editinguser": "{{GENDER:$1|Кулланучы}} <strong>[[User:$1|$1]]</strong> $2 хокукларын үзгәртү",
        "userrights-editusergroup": "Кулланучының төркемнәрен алмаштыру",
        "saveusergroups": "Кулланучы төркемнәрен саклау",
        "userrights-groupsmember": "Әгъза:",
        "group-bot-member": "{{GENDER:$1|бот}}",
        "group-sysop-member": "{{GENDER:$1|идарәче}}",
        "group-bureaucrat-member": "{{GENDER:$1|бюрократ}}",
-       "group-suppress-member": "{{GENDER:$1|Ð\9dазир}}",
+       "group-suppress-member": "{{GENDER:$1|назир}}",
        "grouppage-user": "{{ns:project}}:Кулланучылар",
        "grouppage-autoconfirmed": "{{ns:project}}:Авторасланган кулланучылар",
        "grouppage-bot": "{{ns:project}}:Ботлар",
        "action-createpage": "битләрне язырга",
        "action-createtalk": "бәхәс битен ясарга",
        "action-move": "бу битне күчерерге",
-       "nchanges": "$1 {{PLURAL:$1|1=үзгәртү|үзгәртү}}",
+       "nchanges": "$1 {{PLURAL:$1|үзгәртү}}",
        "enhancedrc-history": "тарих",
        "recentchanges": "Соңгы үзгәртүләр",
        "recentchanges-legend": "Соңгы үзгәртүләр көйләүләре",
        "recentchanges-label-plusminus": "Битнең зурлыгы шуның кадәрле байтка үзгәрде",
        "recentchanges-legend-heading": "'''Легенда:&nbsp;'''",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|яңа бит]])",
-       "rcnotefrom": "Астарак '''$2''' башлап ('''$1''' кадәр) үзгәртүләр күрсәтелгән.",
+       "rcnotefrom": "Астарак <strong>$3, $4</strong> өчен {{PLURAL:$5|үзгәртүләр күрсәтелгән}} (<strong>$1</strong> артык түгел).",
        "rclistfrom": "$3 $2 башлап яңа үзгәртүләрне күрсәт",
        "rcshowhideminor": "кече үзгәртүләрне $1",
        "rcshowhideminor-show": "күрсәт",
        "minoreditletter": "к",
        "newpageletter": "Я",
        "boteditletter": "б",
-       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|күзәтеп тора кулланучы}}]",
-       "rc_categories": "Төркемнәрдә генә тора («|» бүлүче)",
-       "rc_categories_any": "Һәрбер",
+       "number_of_watching_users_pageview": "[$1 {{PLURAL:$1|күзәтүче кулланучы}}]",
+       "rc_categories": "Төркемнәрдән генә («|» бүлүче):",
+       "rc_categories_any": "Сайланганның һәрберсе",
        "rc-change-size-new": "Кертелгән үзгәрешләр белән бергә зурлык: $1 {{PLURAL:$1|байт}}",
        "newsectionsummary": "/* $1 */ яңа бүлек",
        "rc-enhanced-expand": "Ваклыкларны күрсәтү",
        "reuploaddesc": "Файлны йөкләүгә кире кату",
        "upload-tryagain": "Яңартылган файлны җибәрү",
        "uploadnologin": "Сез хисап язмагызга кермәгәнсез",
-       "uploadnologintext": "ФайлнÑ\8b Ð¹Ó©ÐºÐ»Ó\99Ò¯ Ó©Ñ\87ен Ñ\81ез Ð±Ñ\83 Ð±Ð¸Ñ\82кÓ\99 [[Special:UserLogin|кеÑ\80еÑ\80гÓ\99]] Ñ\82иеÑ\88Ñ\81ез.",
+       "uploadnologintext": "ФайллаÑ\80нÑ\8b Ñ\81еÑ\80веÑ\80га Ð¹Ó©ÐºÐ»Ó\99Ò¯ Ó©Ñ\87ен Ð¡ÐµÐ· Ñ\81Ó\99Ñ\85иÑ\84Ó\99гÓ\99 $1 Ñ\82иеÑ\88.",
        "upload_directory_missing": "$1 Йөкләнү директориясе юк",
        "upload_directory_read_only": "Моңа Сезнең хокукларыгыз юк һәм веб-сервер $1 папкасыны йөкли алмый.",
        "uploaderror": "Файлны йөкләүдә хата",
        "upload-recreate-warning": "'''Игътибар: Мондый исемле файл бетерелгән яки исеме алмаштырылган '''",
        "uploadtext": "Бу форманы кулланып серверга файллар йөкли аласыз. Элегрәк йөкләнелгән файлларны карау өчен [[Special:FileList|йөкләнелгән файллар исемлегенә]] мәрәҗәгать итегез. Шулай ук ул [[Special:Log/upload|йөкләнмәләр исемлегенә]] һәм [[Special:Log/delete|бетерелгән файллар]] исемлегенә дә языла.\n\nФайлны мәкаләгә йөкләү өчен Сез менә бу үрнәкләрне куллана аласыз:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Рәсем.jpg]]</nowiki></code>''' файлның тулы юрамасын кую өчен;\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Räsem.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",
+       "upload-permitted": "{{PLURAL:$2|Рөхсәт ителгән файл төрләре}}: $1.",
+       "upload-preferred": "{{PLURAL:$2|Мөмкин булган файл төрләре}}: $1.",
+       "upload-prohibited": "{{PLURAL:$2|Тыелган файл төрләре}}: $1.",
        "uploadlogpage": "Йөкләү көндәлеге",
        "uploadlogpagetext": "Аста яңа йөкләнелгән файллар исемлеге бирелә.\nШулай ук [[Special:NewFiles|яңа файллар галлереясын]] карагыз",
        "filename": "Файл исеме",
        "filetype-mime-mismatch": "Файлның кинәйтелмәсе «.$1» аның MIME-төренә туры килми ($2).",
        "filetype-badmime": "MIME-төре «$1» булган файллар, йөкләнмәячәк.",
        "filetype-bad-ie-mime": "Файлны йөкләргә мөмкин түгел, чөнки Internet Explorer аны «$1» дип кабул итәчәк.",
-       "filetype-unwanted-type": "'''\".$1\"''' — тыелган файл төре.\n{{PLURAL:$3|1=Мөмкин булган файл төре булып|Мөмкин булган файл төре:}} $2.",
-       "filetype-banned-type": "'''\".$1\"''' — {{PLURAL:$4|1=тыелган файл төре|тыелган файллар төре}}.\n{{PLURAL:$3|1=Киңәйтелгән файл төре булып|Киңәйтелгән  файл төрләре:}} $2.",
+       "filetype-unwanted-type": "<strong>«.$1»</strong> — тыелган файл төре.\n{{PLURAL:$3|Мөмкин булган файл төре:}} $2.",
+       "filetype-banned-type": "<strong>«.$1»</strong> — {{PLURAL:$4|1=тыелган файл төре|тыелган файллар төре}}.\n{{PLURAL:$3|1=Киңәйтелгән файл төре булып|Киңәйтелгән  файл төрләре:}} $2.",
        "filetype-missing": "Файлның киңәйтелмәсе юк ''(мәсәлән,«.jpg»)''.",
        "empty-file": "Сезнең тарафтан җибәрелгән файл буш.",
        "file-too-large": "Сезнең тарафтан җибәрелгән файл артык зур.",
        "license-header": "Лицензиясе",
        "nolicense": "Юк",
        "license-nopreview": "(Алдан карау мөмкин түгел)",
-       "upload_source_file": "(сезнең санактагы файл)",
+       "upload_source_file": "(сезнең санакта сайланган файл)",
        "imgfile": "файл",
        "listfiles": "Сүрәтләр исемлеге",
        "listfiles_thumb": "Миниатюра",
        "wantedtemplates": "Кирәкле үрнәкләр",
        "mostlinked": "Күп үзенә сылтамалы битләр",
        "mostlinkedcategories": "Күп үзенә сылтамалы төркемнәр",
-       "mostlinkedtemplates": "Иң күп кулланылган үрнәкләр",
+       "mostlinkedtemplates": "Иң күп кулланылган битләр",
        "mostcategories": "Күп төркемләргә кертелгән битләр",
        "mostimages": "Иң кулланган сүрәтләр",
        "mostrevisions": "Күп үзгәртүләр белән битләр",
        "movethispage": "Бу битне күчерү",
        "nopagetitle": "Мондый бит юк",
        "nopagetext": "Күрсәтелгән бит юк.",
-       "pager-newer-n": "{{PLURAL:$1|1=1 яңарак|$1 яңарак}}",
+       "pager-newer-n": "{{PLURAL:$1|$1 яңарак}}",
        "pager-older-n": "$1 {{PLURAL:$1|искерәк}}",
        "suppress": "Яшерү",
        "booksources": "Китап чыганаклары",
        "booksources-text": "Әлеге биттә күрсәтелгән сылтамалар ярәмендә сезнең кызыксындырган китап буенча өстәмә мәгълүматлар табарга мөмкин. Болар интернет-кибетләр һәм китапханә җыентыгында эзләүче системалар.",
        "booksources-invalid-isbn": "Бирелгән ISBN саны бәлки хаталдыр. Зинһар, бирелгән саннарны яңадан тикшерегез.",
        "specialloguserlabel": "Башкаручы:",
-       "speciallogtitlelabel": "Ð\91аÑ\88лам:",
+       "speciallogtitlelabel": "Ð\9cакÑ\81аÑ\82 (аÑ\82ама Ñ\8fиÑ\81Ó\99 {{ns:user}}:кÑ\83лланÑ\83Ñ\87Ñ\8b Ð¸Ñ\81еме):",
        "log": "Көндәлекләр",
        "all-logs-page": "Барлык көндәлекләр",
        "alllogstext": "{{SITENAME}} сәхифәсенең гомуми көндәлекләре исемлеге.\nСез нәтиҗәләрне көндәлек төре, кулланучы исеме (хәреф зурлыгын истә тотыгыз) яки куззаллаган бит (шулай ук хәреф зурлыгын истә тотыгыз) буенча тәртипкә салырга мөмкин.",
        "special-categories-sort-count": "исәп буенча тәртипләү",
        "special-categories-sort-abc": "әлифба буенча тәртипләү",
        "sp-deletedcontributions-contribs": "кертем",
-       "linksearch": "Тышкы сылтамалар",
+       "linksearch": "Тышкы сылтамаларны эзләү",
        "linksearch-pat": "Эзләү өчен үрнәк:",
        "linksearch-ns": "Исемнәр мәйданы:",
        "linksearch-ok": "Эзләү",
        "emailuser-title-target": "{{GENDER:$1|Кулланучыга}} электрон хат язу",
        "emailuser-title-notarget": "Кулланучыга хат җибәрү",
        "emailpagetext": "Әлеге форма ярдәмендә {{GENDER:$1|кулланучының}} электрон почта адресына хат җибәрергә мөмкин. Җибәрелгән адрес исемендә Сезнең [[Special:Preferences|көйләнмәләрдә]] күрсәтелгән адресыгыз күрсәтеләчәк, шуның ярдәмендә Сез ул кулланучы белән турыдан-туры сөйләшә аласыз.",
-       "defemailsubject": "{{SITENAME}}: хат",
+       "defemailsubject": "{{SITENAME}} — $1 кулланучысыннан хат",
        "noemailtitle": "Электрон почта адресы юк",
        "noemailtext": "Бу кулланучы чын электрон әрҗә адресын күрсәтмәде.",
        "nowikiemailtext": "Бу кулланучы башкалардан хат алырга теләмәвен белдерде.",
        "watchlistfor2": "$1 өчен $2",
        "nowatchlist": "Күзәтү исемлегегездә битләр юк.",
        "watchnologin": "Кермәдегез",
-       "addedwatchtext": "\"[[:$1]]\" бите [[Special:Watchlist|күзәтү исемлегегезгә]] өстәлде.\nБу биттә һәм аның бәхәслегендә барлык булачак үзгәртүләр шунда күрсәтелер, һәм, [[Special:RecentChanges|соңгы үзгәртүләр]] исемлегендә бу битне җиңелрәк табу өчен, ул '''калын мәтен''' белән күрсәтелер.",
-       "removedwatchtext": "«[[:$1]]» Ð±Ð¸Ñ\82е [[Special:Watchlist|Ñ\81езнең ÐºÒ¯Ð·Ó\99Ñ\82Ò¯ Ð¸Ñ\81емлегеннән]] бетерелде.",
+       "addedwatchtext": "\"[[:$1]]\" бите [[Special:Watchlist|күзәтү исемлегегезгә]] өстәлде.",
+       "removedwatchtext": "«[[:$1]]» Ð¼Ó\99калÓ\99Ñ\81е 1Ó\99м Ð°Ð½Ñ\8bÒ£ Ð±Ó\99Ñ\85Ó\99Ñ\81 Ð±Ð¸Ñ\82е [[Special:Watchlist|Ñ\81езнең ÐºÒ¯Ð·Ó\99Ñ\82Ò¯ Ð¸Ñ\81емлегегездән]] бетерелде.",
        "watch": "Күзәтү",
        "watchthispage": "Бу битне күзәтү",
        "unwatch": "Күзәтмәү",
        "unwatchthispage": "Күзәтүне туктат",
        "notanarticle": "Мәкалә түгел",
-       "watchlist-details": "Күзәтү исемлегегездә, бәхәс битләрен санамыйча, {{PLURAL:$1|1=$1 бит|$1 бит}} бар.",
-       "wlshowlast": "Баягы $1 сәгать $2 көн эчендә яки ны күрсәт",
+       "watchlist-details": "Күзәтү исемлегегездә, бәхәс битләрен санамыйча, {{PLURAL:$1|$1 бит}} бар.",
+       "wlshowlast": "$1 сәгать $2 көн өчендә күрсәтү",
+       "watchlistall2": "барлык",
        "watchlist-options": "Күзәтү исемлеге көйләүләре",
        "watching": "Күзәтү исемлегемә өстәүе…",
        "unwatching": "Күзәтү исемлегемнән чыгаруы…",
        "enotif_impersonal_salutation": "{{SITENAME}} кулланучы",
        "enotif_lastvisited": "Соңгы керүегездән соң булган барлык үзгәртүләрне күрер өчен, бу сылтама аша узыгыз: $1",
-       "enotif_body": "Хөрмәтле $WATCHINGUSERNAME,\n\n«{{SITENAME}}» проектының «$PAGETITLE» бите  $PAGEEDITOR  тарафыннан  $PAGEEDITDATE  көнне  $CHANGEDORCREATED. Битне карар өчен $PAGETITLE_URL  буенча узыгыз.\n\n$NEWPAGE\n\nҮзгәртүнең кыска эчтәлеге: $PAGESUMMARY $PAGEMINOREDIT\n\nҮзгәртүчегә язу:\nэл. почта $PAGEEDITOR_EMAIL\nвики $PAGEEDITOR_WIKI\n\nБу биткә кермәсәгез, аның башка үзгәртүләре турында хат җибәрелмәячәк. Шулай ук сез күзәтү исемлегегездә булган битләр өчен хәбәр бирү флагын алып куя аласыз.\n\n             {{grammar:genitive|{{SITENAME}}}} хәбәр бирү системасы\n\n--\nХәбәр итүләр көйләүләрен үзгәртү:\n{{canonicalurl:{{#special:Preferences}}}}\n\nКүзәтү исемлеге көйләүләрен үзгәртү:\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nБитне сезнең күзәтү исемлегездән бетерү:\n$UNWATCHURL\n\nЭлемтә һәм ярдәм:\n$HELPPAGE",
+       "enotif_body": "Хөрмәтле $WATCHINGUSERNAME,\n\n\n$PAGEINTRO $NEWPAGE\n\nҮзгәртүнең кыска эчтәлеге: $PAGESUMMARY $PAGEMINOREDIT\n\nҮзгәртүчегә язу:\nэл. почта $PAGEEDITOR_EMAIL\nвики $PAGEEDITOR_WIKI\n\nБу биткә кермәсәгез, аның башка үзгәртүләре турында хат җибәрелмәячәк. Шулай ук сез күзәтү исемлегегездә булган битләр өчен хәбәр бирү флагын алып куя аласыз.\n\n             {{grammar:genitive|{{SITENAME}}}} хәбәр бирү системасы\n\n--\nХәбәр итүләр көйләүләрен үзгәртү:\n{{canonicalurl:{{#special:Preferences}}}}\n\nКүзәтү исемлеге көйләүләрен үзгәртү:\n$HELPPAGE\n\nБитне сезнең күзәтү исемлегездән бетерү:\n$UNWATCHURL\n\nЭлемтә һәм ярдәм:\n$HELPPAGE",
        "created": "төзелгән",
        "changed": "үзгәртелде",
        "deletepage": "Битне бетерү",
        "confirm": "Раслау",
        "excontent": "эчтәлек: «$1»",
-       "excontentauthor": "эчтәлеге: \"$1\" (бердәнбер үзгәртүче \"[[Special:Contributions/$2|$2]]\" иде)",
+       "excontentauthor": "эчтәлеге: «$1», бердәнбер авторы [[Special:Contributions/$2|$2]] ([[User talk:$2|бәхәс]])",
        "exbeforeblank": "чистартуга кадәр булган эчтәлек: «$1»",
        "delete-confirm": "«$1» бетерү",
        "delete-legend": "Бетерү",
-       "historywarning": "'''Кисәтү''': сез бетерергә теләгән биттә үзгәртү тарихы бар, ул $1дән {{PLURAL:$1|юрамалар}}:",
+       "historywarning": "<strong>Игътибар:</strong> Сез бетерергә теләгән биттә үзгәртү тарихы бар, ул $1 {{PLURAL:$1|юрамадан тора}}:",
        "confirmdeletetext": "Сез бу битнең (яки рәсемнең) тулысынча бетерелүен сорадыгыз.\nЗинһар, моны чыннан да эшләргә теләгәнегезне, моның нәтиҗәләрен аңлаганыгызны һәм [[{{MediaWiki:Policy-url}}]] бүлегендәге кагыйдәләр буенча эшләгәнегезне раслагыз.",
        "actioncomplete": "Гамәл башкарган",
        "actionfailed": "Эш башкарылмаган",
        "deletecomment": "Сәбәп:",
        "deleteotherreason": "Башка/өстәмә сәбәп:",
        "deletereasonotherlist": "Башка сәбәп",
-       "deletereason-dropdown": "* Бетерүнең сәбәпләре\n** вандаллык\n** автор соравы буенча\n** автор хокукларын бозу",
+       "deletereason-dropdown": "* Бетерүнең сәбәпләре\n** спам\n** вандаллык\n** автор хокукларын бозу\n** автор соравы буенча\n** эшсез күчермә",
        "delete-edit-reasonlist": "Сәбәпләр исемлеген үзгәртү",
        "rollbacklink": "кире кайтару",
        "rollbacklinkcount": "$1 {{PLURAL:$1|төзәтмәне}} кире кагу",
        "protect-unchain-permissions": "Өстәмә яклау чараларын ачу",
        "protect-text": "Биредә сез '''$1''' бите өчен яклау дәрәҗәсене карый һәм үзгәрә аласыз.",
        "protect-locked-access": "Хисап язмагызга битләрнең яклау дәрәҗәсен үзгәртү өчен хак җитми. '''$1''' битенең хәзерге көйләүләре:",
-       "protect-cascadeon": "Бу бит якланган, чөнки ул әлеге каскадлы яклаулы {{PLURAL:$1|1=биткә|битләргә}} керә. Сез бу битнең яклау дәрәҗәсен үзгәртә аласыз, әмма каскадлы яклау үзгәрмәячәк.",
+       "protect-cascadeon": "Бу бит якланган, чөнки ул соңрак күрсәтелгән каскадлы яклаулы {{PLURAL:$1|1=биткә|битләргә}} керә. Бу битнең яклау дәрәҗәсен үзгәртү, аның каскадлы яклау дәрәҗәсен үзгәрмәячәк.",
        "protect-default": "Яклаусыз",
-       "protect-fallback": "«$1»нең рөхсәте кирәк",
-       "protect-level-autoconfirmed": "Яңа Ò»Ó\99м Ñ\82еÑ\80кÓ\99лмÓ\99гÓ\99н ÐºÑ\83лланÑ\83Ñ\87Ñ\8bлаÑ\80нÑ\8b ÐºÑ\8bÑ\81Ñ\83",
-       "protect-level-sysop": "Идарәчеләр генә",
+       "protect-fallback": "«$1» хокуклы кулланучыларга гына рөхсәт ителә",
+       "protect-level-autoconfirmed": "Ð\90вÑ\82омаÑ\82ик Ñ\80Ó\99веÑ\88Ñ\82Ó\99 Ñ\80аÑ\81ланган ÐºÑ\83лланÑ\83Ñ\87Ñ\8bлаÑ\80га Ð³Ñ\8bна Ñ\80Ó©Ñ\85Ñ\81Ó\99Ñ\82 Ð¸Ñ\82елÓ\99",
+       "protect-level-sysop": "Идарәчеләргә генә рөхсәт ителә",
        "protect-summary-cascade": "каскадлы",
        "protect-expiring": "$1 үтә (UTC)",
        "protect-expiry-indefinite": "Вакыт чикләнмәгән",
        "undeleteviewlink": "карау",
        "undeleteinvert": "Киресен сайлау",
        "undeletecomment": "Сәбәп:",
-       "undeletedrevisions": "{{PLURAL:$1|1=1 үзгәртү|$1 үзгәртү}} торгызылды",
+       "undeletedrevisions": "$1 {{PLURAL:$1|үзгәреш}} яңадан {{PLURAL:$1|торгызылды}}",
        "undelete-search-submit": "Эзләү",
        "undelete-error-long": "Файлны торгызу вакытында хаталар чыкты:\n\n$1",
        "undelete-show-file-submit": "Әйе",
        "contributions": "{{GENDER:$1|Кулланучының}} кертеме",
        "contributions-title": "$1 исемле кулланучының кертеме",
        "mycontris": "Кертем",
-       "contribsub2": "$1 ($2) өчен",
+       "contribsub2": "Кертем {{GENDER:$3|$1}} ($2)",
        "uctop": "(хәзерге)",
        "month": "Айдан башлап (һәм элегрәк):",
        "year": "Елдан башлап (һәм элегрәк):",
        "whatlinkshere-hidelinks": "сылтамаларны $1",
        "whatlinkshere-hideimages": "$1 файл сылтамалары",
        "whatlinkshere-filters": "Фильтрлар",
-       "blockip": "Кулланучыны тыю",
+       "blockip": "{{GENDER:$1|Кулланучыны}} тыю",
        "blockip-legend": "Кулланучыны тыю",
        "ipaddressorusername": "IP адресы яки кулланучы исеме:",
        "ipbexpiry": "Бетә:",
        "unlockbtn": "Мәгълүматлар базасына язу мөмкинлеген кайтару",
        "move-page": "$1 — исемен алмаштыру",
        "move-page-legend": "Битне күчерү",
-       "movepagetext": "Астагы форманы куллану битнең исемен алыштырып, аның барлык тарихын яңа исемле биткә күчерер.\nИске исемле бит яңа исемле биткә юнәлтү булып калыр.\nСез иске исемгә юнәлтүләрне автоматик рәвештә яңа исемгә күчерә аласыз.\nӘгәр моны эшләмәсәгез, [[Special:DoubleRedirects|икеле]] һәм [[Special:BrokenRedirects|өзелгән юнәлтүләрне]] тикшерегез.\nСез барлык сылтамаларның кирәкле җиргә сылтавына җаваплы.\n\nКүздә тотыгыз: әгәр яңа исем урынында бит булса инде, һәм ул буш яки юнәлтү түгел исә, бит '''күчерелмәячәк'''.\nБу шуны аңлата: сез ялгышып күчерсәгез, битне кайтара аласыз, әмма инде булган битне бетерә алмыйсыз.\n\n'''Игътибар!'''\nПопуляр битләрне күчерү зур һәм көтелмәгән нәтиҗәләргә китерә ала.\nДәвам иткәнче, барлык нәтиҗәләрне аңлавыгызны тагын бер кат уйлагыз.",
+       "movepagetext": "Астагы форманы куллану битнең исемен алыштырып, аның барлык тарихын яңа исемле биткә күчерер.\nИске исемле бит яңа исемле биткә юнәлтү булып калыр.\nСез иске исемгә юнәлтүләрне автоматик рәвештә яңа исемгә күчерә аласыз.\nӘгәр моны эшләмәсәгез, [[Special:DoubleRedirects|икеле]] һәм [[Special:BrokenRedirects|өзелгән юнәлтүләрне]] тикшерегез.\nСез барлык сылтамаларның кирәкле җиргә сылтавына җаваплы.\n\nКүздә тотыгыз: әгәр яңа исем урынында бит булса инде, һәм ул буш яки юнәлтү түгел исә, бит <strong>күчерелмәячәк</strong>.\nБу шуны аңлата: сез ялгышып күчерсәгез, битне кайтара аласыз, әмма инде булган битне бетерә алмыйсыз.\n\n<strong>Игътибар!</strong>\nПопуляр битләрне күчерү зур һәм көтелмәгән нәтиҗәләргә китерә ала.\nДәвам иткәнче, барлык нәтиҗәләрне аңлавыгызны тагын бер кат уйлагыз.",
        "movepagetalktext": "Бу битнең бәхәс бите дә күчереләчәк, '''бу очраклардан тыш''':\n*Андый исемле буш булмаган бәхәс бите бар инде, яисә\n*Сез астагы флажокны куймагансыз.\n\nБу очракларда сезгә битләрне үз кулыгыз белән күчерергә яки кушарга туры килер.",
        "movenotallowed": "Сездә мәкаләләрне күчерү хокуклары юк.",
-       "newtitle": "Яңа Ð±Ð°Ñ\88лам:",
+       "newtitle": "Яңа Ð¸Ñ\81ем:",
        "move-watch": "Бу битне күзәтү",
        "movepagebtn": "Битне күчерү",
        "pagemovedsub": "Бит күчерелде",
        "movelogpage": "Күчерү көндәлеге",
        "movereason": "Сәбәп:",
        "revertmove": "кире кайту",
-       "delete_and_move": "Бетерү һәм исемен алмаштыру",
-       "delete_and_move_reason": "Күчерүне мөмкин итәр өчен бетерелде",
+       "delete_and_move_reason": "Күчерүне мөмкин итәр өчен бетерелде «[[$1]]»",
        "move-leave-redirect": "Юнәлтү калдырылсын",
        "export": "Битләрне чыгаруы",
        "export-submit": "Экспортлау",
        "htmlform-submit": "Җибәрү",
        "htmlform-reset": "Үзгәртүләрне кире кайтару",
        "htmlform-selectorother-other": "Башка",
+       "htmlform-cloner-delete": "Бетерү",
        "logentry-delete-delete": "$1 $3 битен {{GENDER:$2|бетерә}}",
        "revdelete-content-hid": "эчтәлек яшерелгән",
        "revdelete-summary-hid": "төзәтмәнең тасвирламасы яшерелгән",
        "logentry-patrol-patrol-auto": "$1 $3 мәкаләсенең $4 санлы версиясен автоматик рәвештә {{GENDER:$2|тикшерде}}",
        "logentry-newusers-newusers": "{{GENDER:$2|Кулланучы}} $1 хисап язмасын төзеде",
        "logentry-newusers-create": "{{GENDER:$2|Кулланучы}} $1 хисап язмасын төзеде",
-       "logentry-newusers-create2": "$1 $3 кулланучы хисап язмасын төзеде",
-       "logentry-newusers-autocreate": "Автоматик рәвештә $1 хисап язмасы төзелде.",
+       "logentry-newusers-create2": "$1 - $3 исемле хисап язмасы {{GENDER:$2|төзеде}}",
+       "logentry-newusers-autocreate": "{{GENDER:$2|кулланучының}} автоматик рәвештә $1 хисап язмасы төзелде",
        "logentry-upload-upload": "$1 {{GENDER:$2|йөкләде}} $3",
        "rightsnone": "(юк)",
        "revdelete-summary": "үзгәртүләр тасвирламасы",
index dfa7a1f..05fd3b7 100644 (file)
        "movelogpage": "Küçerü köndälege",
        "movereason": "Säbäp:",
        "revertmove": "kire qaytu",
-       "delete_and_move": "Beterü häm isemen almaştıru",
        "delete_and_move_reason": "Küçerüne mömkin itär öçen beterelde",
        "move-leave-redirect": "Yünältü qaldırılsın",
        "export": "Bitlärne çığaruı",
index fdf75ba..a0a7d61 100644 (file)
        "recentchanges-label-minor": "Це незначна зміна",
        "recentchanges-label-bot": "Це редагування зроблене ботом",
        "recentchanges-label-unpatrolled": "Це редагування ще не було відпатрульоване",
-       "recentchanges-label-plusminus": "Розмір сторінки змінився на таке число байтів",
+       "recentchanges-label-plusminus": "Розмір сторінки змінився на таку кількість байтів",
        "recentchanges-legend-heading": "'''Легенда:'''",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (див. також [[Special:NewPages|список нових сторінок]])",
        "recentchanges-legend-plusminus": "(''±123'')",
        "undelete-error-long": "Під час відновлення файлу виникли помилки:\n\n$1",
        "undelete-show-file-confirm": "Ви впевнені, що хочете переглянути вилучену версію файлу «<nowiki>$1</nowiki>» від $3 $2?",
        "undelete-show-file-submit": "Так",
-       "namespace": "Простір назв:",
+       "namespace": "Простір&nbsp;назв:",
        "invert": "Крім вибраного",
        "tooltip-invert": "Встановіть цей прапорець, щоб приховати зміни на сторінках, в межах обраного простору імен (і пов'язаних просторів імен, за потреби)",
        "tooltip-whatlinkshere-invert": "Поставте цю галочку, щоб приховати зміни на сторінках із обраного простору назв.",
        "movenosubpage": "Ця сторінка не має підсторінок.",
        "movereason": "Причина:",
        "revertmove": "відкинути",
-       "delete_and_move": "Вилучити і перейменувати",
        "delete_and_move_text": "== Потрібне вилучення ==\nСторінка з назвою [[:$1|«$1»]] вже існує.\nБажаєте вилучити її для можливості перейменування?",
        "delete_and_move_confirm": "Так, вилучити для перейменування",
        "delete_and_move_reason": "Вилучена для можливості перейменування сторінки «[[$1]]»",
        "intentionallyblankpage": "Цю сторінку навмисне залишили порожньою",
        "external_image_whitelist": "  #Залиште цей рядок таким, яким він є<pre>\n#Записуйте тут фрагменти регулярних виразів (ту частину, що знаходиться між //)\n#Вони будуть зіставлені з URL зовнішніх зображень.\n#Потрібні будуть показані як зображення, решта будуть показані як посилання на зображення\n#Рядки, що починаються з #, вважаються коментарями.\n#Рядки чутливі до регістра\n\n#Розміщуйте фрагменти регулярних виразів над цією строчкою. Залиште цей рядок таким, яким він є.</pre>",
        "tags": "Чинні мітки змін",
-       "tag-filter": "Фільтр [[Special:Tags|міток]]:",
+       "tag-filter": "Фільтр&nbsp;[[Special:Tags|міток]]:",
        "tag-filter-submit": "Відфільтрувати",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Мітка|Мітки|Міток}}]]: $2)",
        "tags-title": "Мітки",
index 312fae9..1707a61 100644 (file)
        "changeemail-newemail": "نیا برقی ڈاک پتہ:",
        "changeemail-none": "(کوئی نہیں)",
        "changeemail-submit": "برقی ڈاک تبدیل کریں",
+       "resettokens-tokens": "ٹوکن:",
+       "resettokens-token-label": "$1 (موجودہ قدر: $2)",
        "bold_sample": "دبیز متن",
        "bold_tip": "دبیز متن",
        "italic_sample": "ترچھا متن",
        "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-suggest": "کیا آپ کا مطلب تھا: $1",
        "search-interwiki-caption": "ساتھی منصوبے",
        "search-interwiki-default": "$1 نتائج:",
        "prefs-advancedrendering": "اعلی اختیارات",
        "prefs-advancedsearchoptions": "اعلی اختیارات",
        "prefs-advancedwatchlist": "اعلی اختیارات",
+       "prefs-tokenwatchlist": "ٹوکن",
        "prefs-diffs": "فروق",
        "userrights": "حقوقِ صارف کی نظامت",
        "userrights-lookup-user": "گروہائے صارف کا انتظام",
        "movelogpage": "نوشتۂ منتقلی",
        "movereason": "وجہ:",
        "revertmove": "رجوع",
-       "delete_and_move": "حذف اور منتقل",
        "delete_and_move_text": "==حذف شدگی لازم==\n\nمنتقلی کے سلسلے میں انتخاب کردہ مضمون \"[[:$1]]\" پہلے ہی موجود ہے۔ کیا آپ اسے حذف کرکے منتقلی کیلیۓ راستہ بنانا چاہتے ہیں؟",
        "delete_and_move_confirm": "ہاں، صفحہ حذف کر دیا جائے",
        "delete_and_move_reason": "[[$1]] سے منتقلی کے سلسلے میں حذف",
index 7d705e2..0d8c1b9 100644 (file)
        "protectedpagetext": "Bu sahifa tahrirlash va boshqa oʻzgarishlar kiritishdan himoyalangan.",
        "viewsourcetext": "Siz bu sahifaning manbasini koʻrishingiz va uni nusxasini olishingiz mumkin:",
        "protectedinterface": "Ushbu sahifada dasturiy taʼminot interfeysi xabari mavjud. Bezoriliklardan saqlash uchun uni oʻzgartirish taʼqiqlangan.\nUshbu xabar tarjimasini qoʻshish yoki oʻzgartirish uchun, iltimos, MediaWikining [//translatewiki.net/ translatewiki.net] mahalliylashtirish saytidan foydalaning.",
-       "editinginterface": "<strong>Eʼtibor bering:</strong> Siz interfeys matnini aks ettiruvchi sahifani tahrirlamoqdasiz.\nUning oʻzgartirilishi barcha ushbu vikidan foydalanuvchilar uchun ham interfeys oʻzgarishiga olib keladi.",
+       "editinginterface": "<strong>Eʼtibor bering:</strong> Siz interfeys matnini aks ettiruvchi sahifani tahrirlamoqdasiz.\nUning oʻzgartirilishi boshqa foydalanuvchilar uchun ham interfeys oʻzgarishiga olib keladi.",
        "translateinterface": "Ushbu xabar tarjimasini qoʻshish yoki oʻzgartirish uchun, iltimos, MediaWikining [//translatewiki.net/ translatewiki.net] mahalliylashtirish saytidan foydalaning.",
        "namespaceprotected": "Sizda '''$1''' nomfazosi sahifalarini tahrirlash huquqi yoʻq",
        "customcssprotected": "Sizda uchbu CSS sahifani tahrirlash huquqi yoʻq, chunki bu yerda boshqa foydalanuvchining shaxsiy moslamalari saqlanadi.",
        "post-expand-template-inclusion-category": "Qo'llaniladigan andozalarning mumkin bo'lgan miqdoridan oshgan sahifalar",
        "post-expand-template-argument-category": "Andozalarning to'ldirilmagan o'zgaruvchilariga ega sahifalar",
        "undo-success": "Tahrirni bekor qilish imkoniyati bor. Iltimos, solishtirish oynasini koʻrib chiqib, aynan shu oʻzgarishlarni bekor qilmoqchiligingizga ishonch hosil qiling va undan keyin «Saqla» tugmasini bosing.",
+       "undo-failure": "Keyingi tahrirlar bilan chalkashib ketgani sababli, ushbu tahrirni alohida oʻzini bekor qilishni iloji yoʻq.",
        "undo-summary": "[[Special:Contributions/$2|$2]] ([[User talk:$2|mun.]]) tomonidan qilingan $1-sonli tahrir qaytarildi",
        "cantcreateaccounttitle": "Ro‘yxatdan o‘tib bo‘lmadi",
        "cantcreateaccount-text": "[[User:$3|$3]] ushbu IP manzil (<strong>$1</strong>) orqali ro‘yxatdan o‘tishni bloklab qo‘ygan.\n\n$3 <em>$2</em>ni sabab qilib ko‘rsatdi",
        "brokenredirects-edit": "tahrirlash",
        "nbytes": "$1 {{PLURAL:$1|bayt}}",
        "ncategories": "$1 {{PLURAL:$1|turkum|turkumlar}}",
-       "nmembers": "$1 {{PLURAL:$1|ta a'zo}}",
+       "nmembers": "$1 {{PLURAL:$1|ta sahifa}}",
        "lonelypages": "Yetim sahifalar",
        "uncategorizedpages": "Turkumlashtirilmagan sahifalar",
        "uncategorizedcategories": "Turkumlashtirilmagan turkumlar",
        "wlheader-showupdated": "Siz oxirgi marta kirganingizdan keyin oʻzgartirilgan sahifalar '''qalin''' yozuv bilan ajratib koʻrsatilgan.",
        "wlnote": "Quyida oxirgi $2 soat ichida sodir boʻlgan {{PLURAL:$1|oxirgi oʻzgarish|<strong>$1</strong> ta oʻzgarishlar}} koʻrsatilgan. $3, $4.",
        "wlshowlast": "Oxirgi $1 soatdagi $2 kundagi tahrirlarni koʻrsatish",
+       "watchlistall2": "hammasi",
        "watchlist-options": "Kuzatuv roʻyxati moslamalari",
        "watching": "Kuzatish...",
        "unwatching": "Kuzatuv roʻyxatidan oʻchirilmoqda...",
        "movepage-moved": "'''Sahifa nomi «$1»dan «$2»ga koʻchirildi'''",
        "movepage-moved-redirect": "Qayta yo‘naltirish yaratildi.",
        "movetalk": "Mos munozara sahifasini qayta nomlash",
-       "move-subpages": "Ostsahifalarni ham qayta nomlash ($1 gacha)",
-       "move-talk-subpages": "Munozara sahifasining ostsahifalarini ham qayta nomlash ($1 gacha)",
+       "move-subpages": "Ostsahifalarni ham qayta nomlash ($1 tadan kam)",
+       "move-talk-subpages": "Munozara sahifasining ostsahifalarini ham qayta nomlash ($1 tadan kam)",
        "movepage-page-moved": "Sahifa nomi «$1»dan «$2»ga koʻchirilgan edi.",
        "movelogpage": "Koʻchirish qaydlari",
        "movesubpage": "{{PLURAL:$1|Ostsahifa|Ostsahifalar}}",
        "movenosubpage": "Bu sahifa ostsahifalarga ega emas.",
        "movereason": "Sabab:",
        "revertmove": "qaytarish",
-       "delete_and_move": "O‘chirish va qayta nomlash",
        "delete_and_move_confirm": "Ha, ushbu sahifa o‘chirilsin",
        "fix-double-redirects": "Oldingi nomga yoʻnaltirishlarni toʻgʻrilash",
        "move-leave-redirect": "Qayta yoʻnaltirish qoldirish",
        "tooltip-ca-protect": "Bu sahifani himoyalash",
        "tooltip-ca-unprotect": "Ushbu sahifaning himoyasini o'zgaritish",
        "tooltip-ca-delete": "Ushbu sahifani o‘chirish",
-       "tooltip-ca-undelete": "Bu sahifa o'chirilmasdan oldin qilingan tahrirlarni tiklash",
+       "tooltip-ca-undelete": "Bu sahifa oʻchirilmasidan oldin qilingan tahrirlarni tiklash",
        "tooltip-ca-move": "Bu sahifani koʻchir",
        "tooltip-ca-watch": "Bu sahifani kuzatuv roʻyxatingizga qoʻshish",
        "tooltip-ca-unwatch": "Bu sahifani kuzatuv roʻyxatingizdan oʻchirish",
index 3ecc5fd..01629cb 100644 (file)
        "movenosubpage": "Sta pagina no la gà nissuna sotopagina.",
        "movereason": "Motivo:",
        "revertmove": "ripristina",
-       "delete_and_move": "Scanceła e sposta",
        "delete_and_move_text": "==Scancełassion richiesta==\n\nLa voxe specificà come destinassion \"[[:$1]]\" l'esiste xà. Vóto scancełarla par proseguir con ło spostamento?",
        "delete_and_move_confirm": "Sì, scancèla la pagina",
        "delete_and_move_reason": "Scanselà par rendar posibiłe el spostamento da \"[[$1]]\"",
index 9422a77..c1a700f 100644 (file)
@@ -32,7 +32,8 @@
                        "KhangND",
                        "Darcy Le",
                        "Quenhitran",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Xð"
                ]
        },
        "tog-underline": "Gạch chân liên kết:",
        "viewhelppage": "Xem trang trợ giúp",
        "categorypage": "Xem trang thể loại",
        "viewtalkpage": "Xem trang thảo luận",
-       "otherlanguages": "Ngôn ngữ khác",
+       "otherlanguages": "Trong các ngôn ngữ khác",
        "redirectedfrom": "(đổi hướng từ $1)",
        "redirectpagesub": "Trang đổi hướng",
        "redirectto": "Đổi hướng đến:",
        "movenosubpage": "Trang này không có trang con.",
        "movereason": "Lý do:",
        "revertmove": "lùi lại",
-       "delete_and_move": "Xóa và đổi tên",
        "delete_and_move_text": "==Cần xóa==\n\nTrang với tên “[[:$1]]” đã tồn tại. Bạn có muốn xóa nó để dọn chỗ di chuyển tới tên này không?",
        "delete_and_move_confirm": "Xóa trang để đổi tên",
        "delete_and_move_reason": "Xóa để có chỗ đổi tên “[[$1]]”",
index c187396..dbbf59f 100644 (file)
@@ -32,6 +32,7 @@
        "tog-hideminor": "最新更改唔顯示細修改",
        "tog-hidepatrolled": "響最近修改度隱藏巡查過嘅編輯",
        "tog-newpageshidepatrolled": "響新頁清單度隱藏巡查過嘅版",
+       "tog-hidecategorization": "隱藏頁面分類",
        "tog-extendwatchlist": "展開監視清單去顯示全部更改,唔係淨係最新嘅",
        "tog-usenewrc": "最近修改同監視清單顯示群組修改",
        "tog-numberheadings": "標題自動編號",
@@ -61,6 +62,7 @@
        "tog-watchlisthideliu": "響監視清單度隱藏登入用戶",
        "tog-watchlisthideanons": "響監視清單度隱藏匿名用戶",
        "tog-watchlisthidepatrolled": "響監視清單度隱藏巡查過嘅編輯",
+       "tog-watchlisthidecategorization": "隱藏頁面分類",
        "tog-ccmeonemails": "喺我寄電郵畀其他人嗰陣,寄返封副本畀我。",
        "tog-diffonly": "響差異下面唔顯示頁面內容",
        "tog-showhiddencats": "顯示隱藏類",
        "viewsource": "睇吓原始碼",
        "viewsource-title": "睇 $1 嘅原碼",
        "actionthrottled": "動作已壓制",
-       "actionthrottledtext": "基於反垃圾嘢嘅考量,你而家響呢段短時間之內限制咗去做呢一個動作,而你已經超過咗個上限。請響幾分鐘之後再試過。",
+       "actionthrottledtext": "基於反濫用嘅考量,你而家響呢段短時間之內限制咗去做呢一個動作,而你已經超過咗個上限。請響幾分鐘之後再試過。",
        "protectedpagetext": "呢一版已經保護咗唔畀改或者做其他動作。",
        "viewsourcetext": "你可以睇吓或者複製呢一頁嘅原始碼。",
        "viewyourtext": "你可以睇同複製呢版入面<strong>由你改</strong>嘅原碼。",
        "createaccountreason": "原因:",
        "createacct-reason": "原因",
        "createacct-reason-ph": "開過個戶口嘅原因",
-       "createacct-captcha": "安全檢查",
-       "createacct-imgcaptcha-ph": "入你下面見到嘅字",
        "createacct-submit": "開戶口",
        "createacct-another-submit": "開戶口",
        "createacct-benefit-heading": "{{SITENAME}}係由你同其他人貢獻。",
        "passwordreset-emailtext-ip": "有人(可能係閣下自己,來自IP地址$1)請求更改閣下喺{{SITENAME}}($4)嘅密碼。同爾個電子郵件有關聯嘅用戶包括:\n\n$2\n\n{{PLURAL:$3|爾個|爾啲}}臨時密碼會喺{{$5}}日之後失效。\n\n如果係閣下自己請求改密碼嘅,請馬上登錄{{SITENAME}}並且更改密碼。如果閣下諗返起自己個密碼,或者根本無申請過改密碼嘅話,請忽略爾條訊息,繼續用返舊密碼。",
        "passwordreset-emailtext-user": "{{SITENAME}}用戶$1請求更改閣下喺{{SITENAME}}道嘅密碼$4。同爾個電子郵件有關聯嘅用戶包括:\n\n$2\n\n{{PLURAL:$3|爾個|爾啲}}臨時密碼會喺{{$5}}日之後失效。\n\n如果係閣下自己請求改密碼嘅,請馬上登錄{{SITENAME}}並且更改密碼。如果閣下諗返起自己個密碼,或者根本無申請過改密碼嘅話,請忽略爾條訊息,繼續用返舊密碼。",
        "passwordreset-emailelement": "用戶名:\n$1\n\n臨時密碼:\n$2",
-       "passwordreset-emailsent": "密碼重設電郵經已送出。",
+       "passwordreset-emailsent": "若果你個戶口有登記電郵,密碼重設電郵經已送出。",
        "passwordreset-emailsent-capture": "密碼重設電郵經已送出,下面有顯示。",
        "passwordreset-emailerror-capture": "密碼重設電郵經已送出,下面有顯示,但送畀{{GENDER:$2|user}}時失敗: $1",
-       "changeemail": "改電郵地址",
-       "changeemail-text": "填呢份表去改戶口電郵地址。你需要入密碼確認改動。",
+       "changeemail": "改或者剷走電郵地址",
+       "changeemail-header": "填好呢份表去改戶口電郵地址。若果你想剷走你戶口個電郵地址,填表時請將電郵地址欄留空。",
+       "changeemail-passwordrequired": "你要入密碼去確認改動。",
        "changeemail-no-info": "你一定要簽到咗去直接入來呢一版。",
        "changeemail-oldemail": "而家個電郵地址:",
        "changeemail-newemail": "新電郵地址:",
+       "changeemail-newemail-help": "若果你想剷走你戶口個電翻地址,請留空呢欄,不過萬一你唔記得密碼,就唔會收到幫你重設密碼嘅電郵。",
        "changeemail-none": "(冇)",
        "changeemail-password": "你{{SITENAME}}個密碼:",
        "changeemail-submit": "轉電郵",
        "sig_tip": "你嘅簽名同埋時間戳",
        "hr_tip": "橫線(請小心用)",
        "summary": "摘要:",
-       "subject": "主é¡\8cï¼\8fæ¨\99é¡\8c:",
+       "subject": "主é¡\8cï¼\9a",
        "minoredit": "呢個係小修改",
        "watchthis": "睇實呢一頁",
        "savearticle": "儲存呢頁",
        "missingsummary": "'''提醒:''' 你未提供編輯摘要。如果你再撳多一下「{{int:savearticle}}」嘅話,咁你儲存嘅編輯就會無摘要。",
        "selfredirect": "<strong>警告:</strong> 你個跳轉彈返去自己度。\n你可能設錯咗跳轉目標,或者改錯咗版。\n如果你再撳多「{{int:savearticle}}」一下,就會照幫你開呢個跳轉。",
        "missingcommenttext": "請輸入一個註解。",
-       "missingcommentheader": "'''提醒:'''你響呢個註解度並無提供一個主題/標題。如果你再撳一次「{{int:savearticle}}」,你嘅編輯就會無題。",
+       "missingcommentheader": "<strong>提醒:</strong>你響呢個註解度並無提供一個主題/標題。如果你再撳一次「{{int:savearticle}}」,你嘅編輯就會無題。",
        "summary-preview": "摘要預覽:",
-       "subject-preview": "標題/頭條預覽:",
+       "subject-preview": "標題預覽:",
        "previewerrortext": "預覽你嘅修改嗰陣出錯。",
        "blockedtitle": "用戶已經封鎖",
        "blockedtext": "你嘅用戶名或者 IP 位址已經被 $1 封咗。\n\n呢次封鎖係由$1所封嘅。當中嘅原因係''$2''。\n\n* 呢次封鎖嘅開始時間係:$8\n* 呢次封鎖嘅到期時間係:$6\n* 對於被封鎖者:$7\n\n你可以聯絡 $1 或者其他嘅[[{{MediaWiki:Grouppage-sysop}}|管理員]],討論呢次封鎖。\n除非你已經響你嘅[[Special:Preferences|戶口喜好設定]]入面設定咗有效嘅電郵地址,否則你係唔可以用「電郵呢個用戶」嘅功能。當設定咗一個有效嘅電郵地址之後,呢個功能係唔會封鎖嘅。\n\n你現時嘅 IP 位址係 $3 ,而個封鎖 ID 係 #$5。 請你喺你嘅查詢都註明以上封鎖嘅資料。",
        "permissionserrors": "權限出錯",
        "permissionserrorstext": "根據下面嘅{{PLURAL:$1|原因|原因}},你並無權限去做呢樣嘢:",
        "permissionserrorstext-withaction": "根據下面嘅{{PLURAL:$1|原因|原因}},你並無權限去做$2:",
+       "contentmodelediterror": "你唔改得呢版修訂,因為呢個修訂嘅內容模型係 <code>$1</code> ,而家嘅內容模型係 <code>$2</code>。",
        "recreate-moveddeleted-warn": "'''警告: 你而家重開一版係先前曾經刪除過嘅。'''\n\n你應該要考慮吓繼續編輯呢一版係唔係適合嘅。\n為咗方便起見,呢一版嘅刪除同搬版記錄已經響下面提供:",
        "moveddeleted-notice": "呢一版已經刪咗。\n呢版嘅刪除同搬版日誌響下面提供咗以便參考。",
        "moveddeleted-notice-recent": "唔好意思,呢版啱啱刪走咗(最近24個鐘內)。\n呢版刪版同搬版紀錄喺下低做參考。",
        "showingresultsinrange": "下面顯示由第 <strong>$2</strong> 個到第 <strong>$3</strong> 個入面嘅第 {{PLURAL:$1|<strong>$1</strong> 個結果}}:",
        "search-showingresults": "{{PLURAL:$4|第 <strong>$1</strong>個結果,一共有 <strong>$3</strong> 個|第 <strong>$1 - $2</strong> 個結果,一共有 <strong>$3</strong> 個}}",
        "search-nonefound": "響個查詢度無結果配合。",
+       "search-nonefound-thiswiki": "呢個網站無符合呢個查詢條件嘅結果。",
        "powersearch-legend": "進階搵嘢",
        "powersearch-ns": "喺以下嘅空間名度搵:",
        "powersearch-togglelabel": "检查:",
        "prefs-watchlist-token": "監視清單幣:",
        "prefs-misc": "雜項",
        "prefs-resetpass": "改密碼",
-       "prefs-changeemail": "改電郵地址",
+       "prefs-changeemail": "改或者剷走電郵地址",
        "prefs-setemail": "入電郵地址",
        "prefs-email": "電郵選項",
        "prefs-rendering": "外觀",
        "prefs-help-recentchangescount": "呢個包埋最近修改、頁歷史同埋日誌紀錄。",
        "prefs-help-watchlist-token2": "呢個係網上訂閱你個監視清單嘅密匙。\n任何人只要知道個密匙,就會睇到你個監視清單,所以唔好畀人知。\n如果有需要嘅話,[[Special:ResetTokens|你可以重設佢]]。",
        "savedprefs": "你嘅喜好設定已經儲存。",
+       "savedrights": "儲存咗 {{GENDER:$1|$1}} 嘅用戶權限。",
        "timezonelegend": "時區:",
        "localtime": "本地時間:",
        "timezoneuseserverdefault": "用維基預設值($1)",
        "right-sendemail": "寄電郵畀其他用戶",
        "right-passwordreset": "檢查密碼/重設電郵",
        "right-managechangetags": "從數據庫度開或刪走[[Special:Tags|tags]]",
+       "right-applychangetags": "套用[[Special:Tags|標籤]]到某個人嘅改動",
        "newuserlogpage": "使用者開戶記錄",
        "newuserlogpagetext": "呢個係一個使用者開戶嘅日誌",
        "rightslog": "用戶權限日誌",
        "action-viewmywatchlist": "睇監視清單",
        "action-viewmyprivateinfo": "睇你嘅私人資料",
        "action-editmyprivateinfo": "改你嘅私人資料",
+       "action-editcontentmodel": "改頁面內容模型",
        "action-managechangetags": "從數據庫開或刪走啲符",
+       "action-applychangetags": "套用標籤到你嘅改動",
        "nchanges": "$1次更改",
        "enhancedrc-since-last-visit": "{{PLURAL:$1|你上次嚟之後}}有 $1 個",
        "enhancedrc-history": "歷史",
        "rcshowhidemine": "$1我嘅編輯",
        "rcshowhidemine-show": "顯示",
        "rcshowhidemine-hide": "收埋",
+       "rcshowhidecategorization": "$1 頁面分類",
+       "rcshowhidecategorization-show": "顯示",
+       "rcshowhidecategorization-hide": "收埋",
        "rclinks": "顯示最後$1次喺$2日內嘅更改<br />$3",
        "diff": "差異",
        "hist": "歷史",
        "recentchangeslinked-summary": "呢一個特別頁列示咗''由''所畀到嘅一版連結到頁嘅最近更改(或者係指定分類嘅成員)。\n響[[Special:Watchlist|你張監視清單]]嘅版會以'''粗體'''顯示。",
        "recentchangeslinked-page": "頁名:",
        "recentchangeslinked-to": "顯示連到所畀到嘅版",
+       "recentchanges-page-added-to-category": "[[:$1]] 加咗落分類",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] 同另外 {{PLURAL:$2|1 版|$2 版}}加咗落分類",
+       "recentchanges-page-removed-from-category": "[[:$1]] 拎走咗分類",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] 同另外 {{PLURAL:$2|1 版|$2 版}}拎走咗分類",
+       "autochange-username": "MediaWiki 自動改動",
        "upload": "上載檔案",
        "uploadbtn": "上載檔案",
        "reuploaddesc": "取消上載再返到去上載表格",
        "upload-dialog-button-done": "搞掂",
        "upload-dialog-button-save": "儲存",
        "upload-dialog-button-upload": "上載",
-       "upload-process-error": "出錯",
-       "upload-process-warning": "警告",
        "upload-form-label-select-file": "揀檔案",
        "upload-form-label-infoform-title": "細節",
        "upload-form-label-infoform-name": "名",
        "upload-form-label-infoform-description": "描述",
        "upload-form-label-usage-title": "用法",
        "upload-form-label-usage-filename": "文件名",
+       "foreign-structured-upload-form-label-own-work": "呢個係我自己嘅作品",
+       "foreign-structured-upload-form-label-infoform-categories": "分類",
+       "foreign-structured-upload-form-label-infoform-date": "日子",
        "backend-fail-stream": "傳送唔到檔案「$1」。",
        "backend-fail-backup": "檔案 \"$1\" 唔備份得。",
        "backend-fail-notexists": "檔案$1唔存在。",
        "wlheader-showupdated": "標'''粗體字'''嘅頁響你上次嚟之後畀人改過。",
        "wlnote": "下面係直到$3 $4為止,最近'''$2'''個鐘之內嘅最新$1次修改。",
        "wlshowlast": "顯示最近 $1 個鐘 $2 日",
+       "watchlistall2": "全部",
+       "watchlist-hide": "收埋",
+       "wlshowtime": "顯示最後:",
+       "wlshowhideminor": "細編輯",
+       "wlshowhidebots": "機械人",
+       "wlshowhideliu": "註冊用戶",
+       "wlshowhideanons": "匿名用戶",
+       "wlshowhidepatr": "巡過嘅編輯",
+       "wlshowhidemine": "我嘅編輯",
        "watchlist-options": "監視清單選項",
        "watching": "監視緊...",
        "unwatching": "唔再監視緊...",
        "deletepage": "刪除頁面",
        "confirm": "確認",
        "excontent": "內容係:「$1」",
-       "excontentauthor": "內容係:「$1」 (而且唯一嘅貢獻者係「[[Special:Contributions/$2|$2]]」)",
+       "excontentauthor": "內容係:「$1」,而且唯一嘅貢獻者係「[[Special:Contributions/$2|$2]]」([[User talk:$2|talk]])",
        "exbeforeblank": "喺清空之前嘅內容係:「$1」",
        "delete-confirm": "刪除\"$1\"",
        "delete-legend": "刪除",
        "move-page-legend": "搬頁",
        "movepagetext": "用下面個表改版名,搬埋佢嘅歷史。\n舊標題會變做跳轉。\n你可以自動噉更新指到原先標題嘅跳轉。\n如果你揀咗唔去做嘅話,請務必要檢查吓有冇[[Special:DoubleRedirects|雙重跳轉]]或者[[Special:BrokenRedirects|死跳轉]](嘅情況發生)。\n你有責任確保啲連結依然指去佢哋應該指去嘅地方。\n\n注意如果已經有一個同個新名同名嘅頁,噉呢個頁係搬'''唔到'''嘅,除非嗰個同名嘅頁係空嘅或者佢係一個跳轉頁,兼且要之前冇編輯過(冇編輯歷史)先得。噉即係講萬一你搞錯咗,你可以將呢個頁改返去佢改之前噉,你唔可以覆蓋一個現有嘅頁。\n\n<strong>警告!</strong>\n噉樣對於一個好多人經過嘅頁面嚟講可能係一個好大嘅同埋出人意表嘅修改;請你喺行動之前確認你清楚噉做嘅後果。",
        "movepagetext-noredirectfixer": "用下面個表改版名,搬埋佢嘅歷史。\n舊標題會變做跳轉。\n請肯定檢查清楚[[Special:DoubleRedirects|雙重]]或者[[Special:BrokenRedirects|死跳轉]]。\n你有責任確保啲連結依然指去佢哋應該指去嘅地方。\n\n注意如果已經有一個同個新名同名嘅頁,噉呢個頁係搬'''唔到'''嘅,除非嗰個同名嘅頁係空嘅或者佢係一個跳轉頁,兼且要之前冇編輯過(冇編輯歷史)先得。噉即係講萬一你搞錯咗,你可以將呢個頁改返去佢改之前噉,你唔可以覆蓋一個現有嘅頁。\n\n'''警告!'''\n噉樣對於一個好多人經過嘅頁面嚟講可能係一個好大嘅同埋出人意表嘅修改;請你喺行動之前確認你清楚噉做嘅後果。",
-       "movepagetalktext": "相應嘅討論頁會連同佢一齊自動搬過去,'''除非''':\n*新嘅頁面名下面已經有咗一個非空嘅討論頁,又或者\n*你唔剔下面個框。\n\n喺呢啲情況下,需要嘅話你唯有手動搬同合併個頁。",
+       "movepagetalktext": "若果你剔呢格,相應嘅討論頁會連同佢一齊自動搬過去,除非新嘅頁面名下面已經有咗一個唔係空嘅討論頁。\n\n喺呢啲情況下,需要嘅話你唯有手動搬同合併個頁。",
        "moveuserpage-warning": "'''警告:'''你將會搬一個用戶版。請留意嗰版搬咗之後個用戶係''唔會''改名。",
        "movenologintext": "你要係註冊用戶而且要[[Special:UserLogin|登入]]咗先可以搬頁",
        "movenotallowed": "你並無權限去搬版。",
        "movenotallowedfile": "你並無權限去搬檔。",
        "cant-move-user-page": "你並無權限去搬用戶版(佢嘅細版之外)。",
        "cant-move-to-user-page": "你並無權限去搬到一個用戶版(佢嘅細版之外)。",
-       "newtitle": "到新標題:",
+       "cant-move-category-page": "你無權去搬分類頁。",
+       "cant-move-to-category-page": "你無權去搬一版去分類頁。",
+       "newtitle": "新標題:",
        "move-watch": "睇實來源同埋目標版",
        "movepagebtn": "搬頁",
        "pagemovedsub": "搬頁成功",
        "movenosubpage": "呢版無細頁。",
        "movereason": "原因",
        "revertmove": "恢復",
-       "delete_and_move": "刪除並移動",
        "delete_and_move_text": "==需要刪除==\n\n目標頁「[[:$1]]」已經存在。你要唔要刪咗佢空個位出嚟畀個搬文動作?",
        "delete_and_move_confirm": "好,刪咗嗰個頁面",
        "delete_and_move_reason": "已經刪咗「[[$1]]」嚟畀位畀個搬文動作",
        "exif-copyrightowner": "版權人",
        "exif-pngfilecomment": "PNG文件註",
        "exif-disclaimer": "免責聲明",
+       "exif-contentwarning": "內容警告",
        "exif-giffilecomment": "GIF文件註",
        "exif-intellectualgenre": "項類",
        "exif-subjectnewscode": "項碼",
index 7178717..cf80d0b 100644 (file)
        "morenotlisted": "本列表不完整。",
        "mypage": "页面",
        "mytalk": "讨论",
-       "anontalk": "该IPå\9c°å\9d\80ç\9a\84讨论",
+       "anontalk": "讨论",
        "navigation": "导航",
        "and": "和",
        "qbfind": "查找",
        "userpage-userdoesnotexist": "用户账户“$1”没有注册。请在创建/编辑本页前检查。",
        "userpage-userdoesnotexist-view": "用户账户“$1”没有被注册。",
        "blocked-notice-logextract": "这位用户目前已被封禁。以下提供最近的封禁日志以供参考:",
-       "clearyourcache": "'''注意:'''在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。\n* '''Firefox/Safari:'''按住“Shift”的同时单击“刷新”,或按“Ctrl-F5”或“Ctrl-R”(Mac为“⌘-R”)\n* '''Google Chrome:'''按“Ctrl-Shift-R”(Mac为“⌘-Shift-R”)\n* '''Internet Explorer:'''按住“Ctrl”的同时单击“刷新”,或按“Ctrl-F5”\n* '''Opera:'''在“工具→首选项”中清除缓存",
+       "clearyourcache": "<strong>注意:</strong>在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。\n* <strong>Firefox或Safari:</strong>按住“Shift”的同时单击“刷新”,或按“Ctrl-F5”或“Ctrl-R”(Mac为“⌘-R”)\n* <strong>Google Chrome:</strong>按“Ctrl-Shift-R”(Mac为“⌘-Shift-R”)\n* <strong>Internet Explorer:</strong>按住“Ctrl”的同时单击“刷新”,或按“Ctrl-F5”\n* <strong>Opera:</strong>在“工具→首选项”中清除缓存",
        "usercssyoucanpreview": "<strong>提示:</strong>在保存前请用“{{int:showpreview}}”按钮来测试您新的 CSS 。",
        "userjsyoucanpreview": "<strong>提示:</strong>在保存前请用“{{int:showpreview}}”按钮来测试您新的 JavaScript 。",
        "usercsspreview": "'''请记住你现在只是在预览你的用户CSS。它尚未保存!'''",
        "contributions": "{{GENDER:$1|用户}}贡献",
        "contributions-title": "$1的用户贡献",
        "mycontris": "贡献",
+       "anoncontribs": "贡献",
        "contribsub2": "{{GENDER:$3|$1}}的贡献($2)",
        "contributions-userdoesnotexist": "用户“$1”尚未注册。",
        "nocontribs": "没有找到匹配这些规则的更改。",
        "movenosubpage": "这个页面没有子页面。",
        "movereason": "原因:",
        "revertmove": "恢复",
-       "delete_and_move": "删除并移动",
        "delete_and_move_text": "== 需要删除 ==\n\n目标页面“[[:$1]]”已存在。是否确认删除该页面以便进行移动?",
        "delete_and_move_confirm": "是,删除该页面",
        "delete_and_move_reason": "删除以便移动[[$1]]",
        "tooltip-pt-preferences": "你的设置",
        "tooltip-pt-watchlist": "你正在监视更改的页面的列表",
        "tooltip-pt-mycontris": "你的贡献的列表",
+       "tooltip-pt-anoncontribs": "来自此IP地址的编辑列表",
        "tooltip-pt-login": "我们鼓励您登录;然而,这不是强制性的",
        "tooltip-pt-logout": "退出登录",
        "tooltip-pt-createaccount": "建议您创建一个账户并登录,但这不是强制的",
index d23590d..3cf72c4 100644 (file)
        "movenosubpage": "此頁面沒有任何子頁面。",
        "movereason": "原因",
        "revertmove": "還原",
-       "delete_and_move": "刪除並移動",
        "delete_and_move_text": "== 需要刪除 ==\n目標頁面 \"[[:$1]]\" 已存在。\n您是否要刪除該頁面以完成移動?",
        "delete_and_move_confirm": "是的,刪除該頁面",
        "delete_and_move_reason": "已刪除讓來自 [[$1]] 頁面可移動",
index caf6dab..d3b74f2 100644 (file)
@@ -36,6 +36,7 @@ return call_user_func( function () {
        $modules['oojs-ui'] = array(
                'scripts' => array(
                        'resources/lib/oojs-ui/oojs-ui.js',
+                       'resources/src/oojs-ui-local.js',
                ),
                'skinScripts' => array_combine(
                        array_keys( $themes ),
@@ -51,6 +52,7 @@ return call_user_func( function () {
                        'oojs-ui.styles.icons',
                        'oojs-ui.styles.indicators',
                        'oojs-ui.styles.textures',
+                       'mediawiki.language',
                ),
                'messages' => array(
                        'ooui-dialog-message-accept',
index 5cd4a7e..6de537a 100644 (file)
                                        diffHtml = query.pages[ query.pageids[ 0 ] ]
                                                .revisions[ 0 ].diff[ '*' ];
                                        $wikiDiff.find( 'table.diff tbody' ).html( diffHtml );
+                                       mw.hook( 'wikipage.diff' ).fire( $wikiDiff.find( 'table.diff' ) );
                                } catch ( e ) {
                                        // "result.blah is undefined" error, ignore
                                        mw.log.warn( e );
index c336676..5e79039 100644 (file)
         * @return {string}
         */
        ForeignStructuredUpload.prototype.getDescriptions = function () {
-               var i, desc, templateCalls = [];
+               var i, desc, hasEquals, templateCalls = [];
 
                for ( i = 0; i < this.descriptions.length; i++ ) {
                        desc = this.descriptions[ i ];
-                       templateCalls.push( '{{' + desc.language + '|' + desc.text + '}}' );
+                       hasEquals = desc.text.indexOf( '=' ) !== -1;
+                       templateCalls.push( '{{' + desc.language + ( hasEquals ? '|1=' : '|' ) + desc.text + '}}' );
                }
 
                return templateCalls.join( '\n' );
index 708dcb5..f2509e2 100644 (file)
                 *   root)
                 */
                mw.hook( 'wikipage.content' ).fire( $( '#mw-content-text' ) );
+
+               var $diff = $( 'table.diff' );
+               if ( $diff.length ) {
+                       /**
+                        * Fired when the diff is added to a page containing a diff
+                        *
+                        * Similar to the {@link mw.hook#event-wikipage_content wikipage.content hook}
+                        * $diff may still be detached when the hook is fired.
+                        *
+                        * @event wikipage_diff
+                        * @member mw.hook
+                        * @param {jQuery} $diff The root element of the MediaWiki diff (`table.diff`).
+                        */
+                       mw.hook( 'wikipage.diff' ).fire( $diff.eq( 0 ) );
+               }
        } );
 
 }( mediaWiki, jQuery ) );
diff --git a/resources/src/oojs-ui-local.js b/resources/src/oojs-ui-local.js
new file mode 100644 (file)
index 0000000..84ec92d
--- /dev/null
@@ -0,0 +1,5 @@
+// Connect OOjs UI to MediaWiki's localisation system
+( function ( mw ) {
+       OO.ui.getUserLanguages = mw.language.getFallbackLanguageChain;
+       OO.ui.msg = mw.msg;
+}( mediaWiki ) );
diff --git a/tests/phpunit/includes/UserArrayFromResultTest.php b/tests/phpunit/includes/UserArrayFromResultTest.php
deleted file mode 100644 (file)
index 469ad29..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-
-/**
- * @author Adam Shorland
- * @covers UserArrayFromResult
- */
-class UserArrayFromResultTest extends MediaWikiTestCase {
-
-       private function getMockResultWrapper( $row = null, $numRows = 1 ) {
-               $resultWrapper = $this->getMockBuilder( 'ResultWrapper' )
-                       ->disableOriginalConstructor();
-
-               $resultWrapper = $resultWrapper->getMock();
-               $resultWrapper->expects( $this->atLeastOnce() )
-                       ->method( 'current' )
-                       ->will( $this->returnValue( $row ) );
-               $resultWrapper->expects( $this->any() )
-                       ->method( 'numRows' )
-                       ->will( $this->returnValue( $numRows ) );
-
-               return $resultWrapper;
-       }
-
-       private function getRowWithUsername( $username = 'fooUser' ) {
-               $row = new stdClass();
-               $row->user_name = $username;
-               return $row;
-       }
-
-       private function getUserArrayFromResult( $resultWrapper ) {
-               return new UserArrayFromResult( $resultWrapper );
-       }
-
-       /**
-        * @covers UserArrayFromResult::__construct
-        */
-       public function testConstructionWithFalseRow() {
-               $row = false;
-               $resultWrapper = $this->getMockResultWrapper( $row );
-
-               $object = $this->getUserArrayFromResult( $resultWrapper );
-
-               $this->assertEquals( $resultWrapper, $object->res );
-               $this->assertSame( 0, $object->key );
-               $this->assertEquals( $row, $object->current );
-       }
-
-       /**
-        * @covers UserArrayFromResult::__construct
-        */
-       public function testConstructionWithRow() {
-               $username = 'addshore';
-               $row = $this->getRowWithUsername( $username );
-               $resultWrapper = $this->getMockResultWrapper( $row );
-
-               $object = $this->getUserArrayFromResult( $resultWrapper );
-
-               $this->assertEquals( $resultWrapper, $object->res );
-               $this->assertSame( 0, $object->key );
-               $this->assertInstanceOf( 'User', $object->current );
-               $this->assertEquals( $username, $object->current->mName );
-       }
-
-       public static function provideNumberOfRows() {
-               return array(
-                       array( 0 ),
-                       array( 1 ),
-                       array( 122 ),
-               );
-       }
-
-       /**
-        * @dataProvider provideNumberOfRows
-        * @covers UserArrayFromResult::count
-        */
-       public function testCountWithVaryingValues( $numRows ) {
-               $object = $this->getUserArrayFromResult( $this->getMockResultWrapper(
-                       $this->getRowWithUsername(),
-                       $numRows
-               ) );
-               $this->assertEquals( $numRows, $object->count() );
-       }
-
-       /**
-        * @covers UserArrayFromResult::current
-        */
-       public function testCurrentAfterConstruction() {
-               $username = 'addshore';
-               $userRow = $this->getRowWithUsername( $username );
-               $object = $this->getUserArrayFromResult( $this->getMockResultWrapper( $userRow ) );
-               $this->assertInstanceOf( 'User', $object->current() );
-               $this->assertEquals( $username, $object->current()->mName );
-       }
-
-       public function provideTestValid() {
-               return array(
-                       array( $this->getRowWithUsername(), true ),
-                       array( false, false ),
-               );
-       }
-
-       /**
-        * @dataProvider provideTestValid
-        * @covers UserArrayFromResult::valid
-        */
-       public function testValid( $input, $expected ) {
-               $object = $this->getUserArrayFromResult( $this->getMockResultWrapper( $input ) );
-               $this->assertEquals( $expected, $object->valid() );
-       }
-
-       // @todo unit test for key()
-       // @todo unit test for next()
-       // @todo unit test for rewind()
-}
diff --git a/tests/phpunit/includes/UserTest.php b/tests/phpunit/includes/UserTest.php
deleted file mode 100644 (file)
index 4c6f083..0000000
+++ /dev/null
@@ -1,534 +0,0 @@
-<?php
-
-define( 'NS_UNITTEST', 5600 );
-define( 'NS_UNITTEST_TALK', 5601 );
-
-/**
- * @group Database
- */
-class UserTest extends MediaWikiTestCase {
-       /**
-        * @var User
-        */
-       protected $user;
-
-       protected function setUp() {
-               parent::setUp();
-
-               $this->setMwGlobals( array(
-                       'wgGroupPermissions' => array(),
-                       'wgRevokePermissions' => array(),
-               ) );
-
-               $this->setUpPermissionGlobals();
-
-               $this->user = new User;
-               $this->user->addGroup( 'unittesters' );
-       }
-
-       private function setUpPermissionGlobals() {
-               global $wgGroupPermissions, $wgRevokePermissions;
-
-               # Data for regular $wgGroupPermissions test
-               $wgGroupPermissions['unittesters'] = array(
-                       'test' => true,
-                       'runtest' => true,
-                       'writetest' => false,
-                       'nukeworld' => false,
-               );
-               $wgGroupPermissions['testwriters'] = array(
-                       'test' => true,
-                       'writetest' => true,
-                       'modifytest' => true,
-               );
-
-               # Data for regular $wgRevokePermissions test
-               $wgRevokePermissions['formertesters'] = array(
-                       'runtest' => true,
-               );
-
-               # For the options test
-               $wgGroupPermissions['*'] = array(
-                       'editmyoptions' => true,
-               );
-       }
-
-       /**
-        * @covers User::getGroupPermissions
-        */
-       public function testGroupPermissions() {
-               $rights = User::getGroupPermissions( array( 'unittesters' ) );
-               $this->assertContains( 'runtest', $rights );
-               $this->assertNotContains( 'writetest', $rights );
-               $this->assertNotContains( 'modifytest', $rights );
-               $this->assertNotContains( 'nukeworld', $rights );
-
-               $rights = User::getGroupPermissions( array( 'unittesters', 'testwriters' ) );
-               $this->assertContains( 'runtest', $rights );
-               $this->assertContains( 'writetest', $rights );
-               $this->assertContains( 'modifytest', $rights );
-               $this->assertNotContains( 'nukeworld', $rights );
-       }
-
-       /**
-        * @covers User::getGroupPermissions
-        */
-       public function testRevokePermissions() {
-               $rights = User::getGroupPermissions( array( 'unittesters', 'formertesters' ) );
-               $this->assertNotContains( 'runtest', $rights );
-               $this->assertNotContains( 'writetest', $rights );
-               $this->assertNotContains( 'modifytest', $rights );
-               $this->assertNotContains( 'nukeworld', $rights );
-       }
-
-       /**
-        * @covers User::getRights
-        */
-       public function testUserPermissions() {
-               $rights = $this->user->getRights();
-               $this->assertContains( 'runtest', $rights );
-               $this->assertNotContains( 'writetest', $rights );
-               $this->assertNotContains( 'modifytest', $rights );
-               $this->assertNotContains( 'nukeworld', $rights );
-       }
-
-       /**
-        * @dataProvider provideGetGroupsWithPermission
-        * @covers User::getGroupsWithPermission
-        */
-       public function testGetGroupsWithPermission( $expected, $right ) {
-               $result = User::getGroupsWithPermission( $right );
-               sort( $result );
-               sort( $expected );
-
-               $this->assertEquals( $expected, $result, "Groups with permission $right" );
-       }
-
-       public static function provideGetGroupsWithPermission() {
-               return array(
-                       array(
-                               array( 'unittesters', 'testwriters' ),
-                               'test'
-                       ),
-                       array(
-                               array( 'unittesters' ),
-                               'runtest'
-                       ),
-                       array(
-                               array( 'testwriters' ),
-                               'writetest'
-                       ),
-                       array(
-                               array( 'testwriters' ),
-                               'modifytest'
-                       ),
-               );
-       }
-
-       /**
-        * @dataProvider provideIPs
-        * @covers User::isIP
-        */
-       public function testIsIP( $value, $result, $message ) {
-               $this->assertEquals( $this->user->isIP( $value ), $result, $message );
-       }
-
-       public static function provideIPs() {
-               return array(
-                       array( '', false, 'Empty string' ),
-                       array( ' ', false, 'Blank space' ),
-                       array( '10.0.0.0', true, 'IPv4 private 10/8' ),
-                       array( '10.255.255.255', true, 'IPv4 private 10/8' ),
-                       array( '192.168.1.1', true, 'IPv4 private 192.168/16' ),
-                       array( '203.0.113.0', true, 'IPv4 example' ),
-                       array( '2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff', true, 'IPv6 example' ),
-                       // Not valid IPs but classified as such by MediaWiki for negated asserting
-                       // of whether this might be the identifier of a logged-out user or whether
-                       // to allow usernames like it.
-                       array( '300.300.300.300', true, 'Looks too much like an IPv4 address' ),
-                       array( '203.0.113.xxx', true, 'Assigned by UseMod to cloaked logged-out users' ),
-               );
-       }
-
-       /**
-        * @dataProvider provideUserNames
-        * @covers User::isValidUserName
-        */
-       public function testIsValidUserName( $username, $result, $message ) {
-               $this->assertEquals( $this->user->isValidUserName( $username ), $result, $message );
-       }
-
-       public static function provideUserNames() {
-               return array(
-                       array( '', false, 'Empty string' ),
-                       array( ' ', false, 'Blank space' ),
-                       array( 'abcd', false, 'Starts with small letter' ),
-                       array( 'Ab/cd', false, 'Contains slash' ),
-                       array( 'Ab cd', true, 'Whitespace' ),
-                       array( '192.168.1.1', false, 'IP' ),
-                       array( 'User:Abcd', false, 'Reserved Namespace' ),
-                       array( '12abcd232', true, 'Starts with Numbers' ),
-                       array( '?abcd', true, 'Start with ? mark' ),
-                       array( '#abcd', false, 'Start with #' ),
-                       array( 'Abcdകഖഗഘ', true, ' Mixed scripts' ),
-                       array( 'ജോസ്‌തോമസ്', false, 'ZWNJ- Format control character' ),
-                       array( 'Ab cd', false, ' Ideographic space' ),
-                       array( '300.300.300.300', false, 'Looks too much like an IPv4 address' ),
-                       array( '302.113.311.900', false, 'Looks too much like an IPv4 address' ),
-                       array( '203.0.113.xxx', false, 'Reserved for usage by UseMod for cloaked logged-out users' ),
-               );
-       }
-
-       /**
-        * Test, if for all rights a right- message exist,
-        * which is used on Special:ListGroupRights as help text
-        * Extensions and core
-        */
-       public function testAllRightsWithMessage() {
-               // Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
-               $allRights = User::getAllRights();
-               $allMessageKeys = Language::getMessageKeysFor( 'en' );
-
-               $rightsWithMessage = array();
-               foreach ( $allMessageKeys as $message ) {
-                       // === 0: must be at beginning of string (position 0)
-                       if ( strpos( $message, 'right-' ) === 0 ) {
-                               $rightsWithMessage[] = substr( $message, strlen( 'right-' ) );
-                       }
-               }
-
-               sort( $allRights );
-               sort( $rightsWithMessage );
-
-               $this->assertEquals(
-                       $allRights,
-                       $rightsWithMessage,
-                       'Each user rights (core/extensions) has a corresponding right- message.'
-               );
-       }
-
-       /**
-        * Test User::editCount
-        * @group medium
-        * @covers User::getEditCount
-        */
-       public function testEditCount() {
-               $user = User::newFromName( 'UnitTestUser' );
-
-               if ( !$user->getId() ) {
-                       $user->addToDatabase();
-               }
-
-               // let the user have a few (3) edits
-               $page = WikiPage::factory( Title::newFromText( 'Help:UserTest_EditCount' ) );
-               for ( $i = 0; $i < 3; $i++ ) {
-                       $page->doEdit( (string)$i, 'test', 0, false, $user );
-               }
-
-               $user->clearInstanceCache();
-               $this->assertEquals(
-                       3,
-                       $user->getEditCount(),
-                       'After three edits, the user edit count should be 3'
-               );
-
-               // increase the edit count and clear the cache
-               $user->incEditCount();
-
-               $user->clearInstanceCache();
-               $this->assertEquals(
-                       4,
-                       $user->getEditCount(),
-                       'After increasing the edit count manually, the user edit count should be 4'
-               );
-       }
-
-       /**
-        * Test changing user options.
-        * @covers User::setOption
-        * @covers User::getOption
-        */
-       public function testOptions() {
-               $user = User::newFromName( 'UnitTestUser' );
-
-               if ( !$user->getId() ) {
-                       $user->addToDatabase();
-               }
-
-               $user->setOption( 'userjs-someoption', 'test' );
-               $user->setOption( 'cols', 200 );
-               $user->saveSettings();
-
-               $user = User::newFromName( 'UnitTestUser' );
-               $this->assertEquals( 'test', $user->getOption( 'userjs-someoption' ) );
-               $this->assertEquals( 200, $user->getOption( 'cols' ) );
-       }
-
-       /**
-        * Bug 37963
-        * Make sure defaults are loaded when setOption is called.
-        * @covers User::loadOptions
-        */
-       public function testAnonOptions() {
-               global $wgDefaultUserOptions;
-               $this->user->setOption( 'userjs-someoption', 'test' );
-               $this->assertEquals( $wgDefaultUserOptions['cols'], $this->user->getOption( 'cols' ) );
-               $this->assertEquals( 'test', $this->user->getOption( 'userjs-someoption' ) );
-       }
-
-       /**
-        * Test password validity checks. There are 3 checks in core,
-        *      - ensure the password meets the minimal length
-        *      - ensure the password is not the same as the username
-        *      - ensure the username/password combo isn't forbidden
-        * @covers User::checkPasswordValidity()
-        * @covers User::getPasswordValidity()
-        * @covers User::isValidPassword()
-        */
-       public function testCheckPasswordValidity() {
-               $this->setMwGlobals( array(
-                       'wgPasswordPolicy' => array(
-                               'policies' => array(
-                                       'sysop' => array(
-                                               'MinimalPasswordLength' => 8,
-                                               'MinimumPasswordLengthToLogin' => 1,
-                                               'PasswordCannotMatchUsername' => 1,
-                                       ),
-                                       'default' => array(
-                                               'MinimalPasswordLength' => 6,
-                                               'PasswordCannotMatchUsername' => true,
-                                               'PasswordCannotMatchBlacklist' => true,
-                                               'MaximalPasswordLength' => 30,
-                                       ),
-                               ),
-                               'checks' => array(
-                                       'MinimalPasswordLength' => 'PasswordPolicyChecks::checkMinimalPasswordLength',
-                                       'MinimumPasswordLengthToLogin' => 'PasswordPolicyChecks::checkMinimumPasswordLengthToLogin',
-                                       'PasswordCannotMatchUsername' => 'PasswordPolicyChecks::checkPasswordCannotMatchUsername',
-                                       'PasswordCannotMatchBlacklist' => 'PasswordPolicyChecks::checkPasswordCannotMatchBlacklist',
-                                       'MaximalPasswordLength' => 'PasswordPolicyChecks::checkMaximalPasswordLength',
-                               ),
-                       ),
-               ) );
-
-               $user = User::newFromName( 'Useruser' );
-               // Sanity
-               $this->assertTrue( $user->isValidPassword( 'Password1234' ) );
-
-               // Minimum length
-               $this->assertFalse( $user->isValidPassword( 'a' ) );
-               $this->assertFalse( $user->checkPasswordValidity( 'a' )->isGood() );
-               $this->assertTrue( $user->checkPasswordValidity( 'a' )->isOK() );
-               $this->assertEquals( 'passwordtooshort', $user->getPasswordValidity( 'a' ) );
-
-               // Maximum length
-               $longPass = str_repeat( 'a', 31 );
-               $this->assertFalse( $user->isValidPassword( $longPass ) );
-               $this->assertFalse( $user->checkPasswordValidity( $longPass )->isGood() );
-               $this->assertFalse( $user->checkPasswordValidity( $longPass )->isOK() );
-               $this->assertEquals( 'passwordtoolong', $user->getPasswordValidity( $longPass ) );
-
-               // Matches username
-               $this->assertFalse( $user->checkPasswordValidity( 'Useruser' )->isGood() );
-               $this->assertTrue( $user->checkPasswordValidity( 'Useruser' )->isOK() );
-               $this->assertEquals( 'password-name-match', $user->getPasswordValidity( 'Useruser' ) );
-
-               // On the forbidden list
-               $this->assertFalse( $user->checkPasswordValidity( 'Passpass' )->isGood() );
-               $this->assertEquals( 'password-login-forbidden', $user->getPasswordValidity( 'Passpass' ) );
-       }
-
-       /**
-        * @covers User::getCanonicalName()
-        * @dataProvider provideGetCanonicalName
-        */
-       public function testGetCanonicalName( $name, $expectedArray, $msg ) {
-               foreach ( $expectedArray as $validate => $expected ) {
-                       $this->assertEquals(
-                               $expected,
-                               User::getCanonicalName( $name, $validate === 'false' ? false : $validate ),
-                               $msg . ' (' . $validate . ')'
-                       );
-               }
-       }
-
-       public static function provideGetCanonicalName() {
-               return array(
-                       array( ' Trailing space ', array( 'creatable' => 'Trailing space' ), 'Trailing spaces' ),
-                       // @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' ),
-                       array( 'Multi  spaces', array( 'creatable' => 'Multi spaces',
-                               'usable' => 'Multi spaces' ), 'Multi spaces' ),
-                       array( 'lowercase', array( 'creatable' => 'Lowercase' ), 'Lowercase' ),
-                       array( 'in[]valid', array( 'creatable' => false, 'usable' => false, 'valid' => false,
-                               'false' => 'In[]valid' ), 'Invalid' ),
-                       array( 'with / slash', array( 'creatable' => false, 'usable' => false, 'valid' => false,
-                               'false' => 'With / slash' ), 'With slash' ),
-               );
-       }
-
-       /**
-        * @covers User::equals
-        */
-       public function testEquals() {
-               $first = User::newFromName( 'EqualUser' );
-               $second = User::newFromName( 'EqualUser' );
-
-               $this->assertTrue( $first->equals( $first ) );
-               $this->assertTrue( $first->equals( $second ) );
-               $this->assertTrue( $second->equals( $first ) );
-
-               $third = User::newFromName( '0' );
-               $fourth = User::newFromName( '000' );
-
-               $this->assertFalse( $third->equals( $fourth ) );
-               $this->assertFalse( $fourth->equals( $third ) );
-
-               // Test users loaded from db with id
-               $user = User::newFromName( 'EqualUnitTestUser' );
-               if ( !$user->getId() ) {
-                       $user->addToDatabase();
-               }
-
-               $id = $user->getId();
-
-               $fifth = User::newFromId( $id );
-               $sixth = User::newFromName( 'EqualUnitTestUser' );
-               $this->assertTrue( $fifth->equals( $sixth ) );
-       }
-
-       /**
-        * @covers User::getId
-        */
-       public function testGetId() {
-               $user = User::newFromName( 'UTSysop' );
-               $this->assertTrue( $user->getId() > 0 );
-
-       }
-
-       /**
-        * @covers User::isLoggedIn
-        * @covers User::isAnon
-        */
-       public function testLoggedIn() {
-               $user = User::newFromName( 'UTSysop' );
-               $this->assertTrue( $user->isLoggedIn() );
-               $this->assertFalse( $user->isAnon() );
-
-               // Non-existent users are perceived as anonymous
-               $user = User::newFromName( 'UTNonexistent' );
-               $this->assertFalse( $user->isLoggedIn() );
-               $this->assertTrue( $user->isAnon() );
-
-               $user = new User;
-               $this->assertFalse( $user->isLoggedIn() );
-               $this->assertTrue( $user->isAnon() );
-       }
-
-       /**
-        * @covers User::checkAndSetTouched
-        */
-       public function testCheckAndSetTouched() {
-               $user = TestingAccessWrapper::newFromObject( User::newFromName( 'UTSysop' ) );
-               $this->assertTrue( $user->isLoggedIn() );
-
-               $touched = $user->getDBTouched();
-               $this->assertTrue(
-                       $user->checkAndSetTouched(), "checkAndSetTouched() succeded" );
-               $this->assertGreaterThan(
-                       $touched, $user->getDBTouched(), "user_touched increased with casOnTouched()" );
-
-               $touched = $user->getDBTouched();
-               $this->assertTrue(
-                       $user->checkAndSetTouched(), "checkAndSetTouched() succeded #2" );
-               $this->assertGreaterThan(
-                       $touched, $user->getDBTouched(), "user_touched increased with casOnTouched() #2" );
-       }
-
-       public static function setExtendedLoginCookieDataProvider() {
-               $data = array();
-               $now = time();
-
-               $secondsInDay = 86400;
-
-               // Arbitrary durations, in units of days, to ensure it chooses the
-               // right one.  There is a 5-minute grace period (see testSetExtendedLoginCookie)
-               // to work around slow tests, since we're not currently mocking time() for PHP.
-
-               $durationOne = $secondsInDay * 5;
-               $durationTwo = $secondsInDay * 29;
-               $durationThree = $secondsInDay * 17;
-
-               // If $wgExtendedLoginCookieExpiration is null, then the expiry passed to
-               // set cookie is time() + $wgCookieExpiration
-               $data[] = array(
-                       null,
-                       $durationOne,
-                       $now + $durationOne,
-               );
-
-               // If $wgExtendedLoginCookieExpiration isn't null, then the expiry passed to
-               // set cookie is $now + $wgExtendedLoginCookieExpiration
-               $data[] = array(
-                       $durationTwo,
-                       $durationThree,
-                       $now + $durationTwo,
-               );
-
-               return $data;
-       }
-
-       /**
-        * @dataProvider setExtendedLoginCookieDataProvider
-        * @covers User::getRequest
-        * @covers User::setCookie
-        * @backupGlobals enabled
-        */
-       public function testSetExtendedLoginCookie(
-               $extendedLoginCookieExpiration,
-               $cookieExpiration,
-               $expectedExpiry
-       ) {
-               $this->setMwGlobals( array(
-                       'wgExtendedLoginCookieExpiration' => $extendedLoginCookieExpiration,
-                       'wgCookieExpiration' => $cookieExpiration,
-               ) );
-
-               $response = $this->getMock( 'WebResponse' );
-               $setcookieSpy = $this->any();
-               $response->expects( $setcookieSpy )
-                       ->method( 'setcookie' );
-
-               $request = new MockWebRequest( $response );
-               $user = new UserProxy( User::newFromSession( $request ) );
-               $user->setExtendedLoginCookie( 'name', 'value', true );
-
-               $setcookieInvocations = $setcookieSpy->getInvocations();
-               $setcookieInvocation = end( $setcookieInvocations );
-               $actualExpiry = $setcookieInvocation->parameters[2];
-
-               // TODO: ± 300 seconds compensates for
-               // slow-running tests. However, the dependency on the time
-               // function should be removed.  This requires some way
-               // to mock/isolate User->setExtendedLoginCookie's call to time()
-               $this->assertEquals( $expectedExpiry, $actualExpiry, '', 300 );
-       }
-}
-
-class UserProxy extends User {
-
-       /**
-        * @var User
-        */
-       protected $user;
-
-       public function __construct( User $user ) {
-               $this->user = $user;
-       }
-
-       public function setExtendedLoginCookie( $name, $value, $secure ) {
-               $this->user->setExtendedLoginCookie( $name, $value, $secure );
-       }
-}
index 95822ad..cd0f139 100644 (file)
@@ -7,6 +7,7 @@ require_once __DIR__ . '/NewParserTest.php';
  * an PHPUnit_Framework_Test object
  *
  * @group Parser
+ * @group ParserTests
  * @group Database
  */
 class MediaWikiParserTest {
index 6948082..5c6c17d 100644 (file)
@@ -673,6 +673,7 @@ class NewParserTest extends MediaWikiTestCase {
 
        /**
         * @group medium
+        * @group ParserTests
         * @dataProvider parserTestProvider
         * @param string $desc
         * @param string $input
diff --git a/tests/phpunit/includes/user/CentralIdLookupTest.php b/tests/phpunit/includes/user/CentralIdLookupTest.php
new file mode 100644 (file)
index 0000000..386e7ab
--- /dev/null
@@ -0,0 +1,181 @@
+<?php
+
+/**
+ * @covers CentralIdLookup
+ * @group Database
+ */
+class CentralIdLookupTest extends MediaWikiTestCase {
+
+       public function testFactory() {
+               $mock = $this->getMockForAbstractClass( 'CentralIdLookup' );
+
+               $this->setMwGlobals( array(
+                       'wgCentralIdLookupProviders' => array(
+                               'local' => array( 'class' => 'LocalIdLookup' ),
+                               'local2' => array( 'class' => 'LocalIdLookup' ),
+                               'mock' => array( 'factory' => function () use ( $mock ) {
+                                       return $mock;
+                               } ),
+                               'bad' => array( 'class' => 'stdClass' ),
+                       ),
+                       'wgCentralIdLookupProvider' => 'mock',
+               ) );
+
+               $this->assertSame( $mock, CentralIdLookup::factory() );
+               $this->assertSame( $mock, CentralIdLookup::factory( 'mock' ) );
+               $this->assertSame( 'mock', $mock->getProviderId() );
+
+               $local = CentralIdLookup::factory( 'local' );
+               $this->assertNotSame( $mock, $local );
+               $this->assertInstanceOf( 'LocalIdLookup', $local );
+               $this->assertSame( $local, CentralIdLookup::factory( 'local' ) );
+               $this->assertSame( 'local', $local->getProviderId() );
+
+               $local2 = CentralIdLookup::factory( 'local2' );
+               $this->assertNotSame( $local, $local2 );
+               $this->assertInstanceOf( 'LocalIdLookup', $local2 );
+               $this->assertSame( 'local2', $local2->getProviderId() );
+
+               $this->assertNull( CentralIdLookup::factory( 'unconfigured' ) );
+               $this->assertNull( CentralIdLookup::factory( 'bad' ) );
+       }
+
+       public function testCheckAudience() {
+               $mock = TestingAccessWrapper::newFromObject(
+                       $this->getMockForAbstractClass( 'CentralIdLookup' )
+               );
+
+               $user = User::newFromName( 'UTSysop' );
+               $this->assertSame( $user, $mock->checkAudience( $user ) );
+
+               $user = $mock->checkAudience( CentralIdLookup::AUDIENCE_PUBLIC );
+               $this->assertInstanceOf( 'User', $user );
+               $this->assertSame( 0, $user->getId() );
+
+               $this->assertNull( $mock->checkAudience( CentralIdLookup::AUDIENCE_RAW ) );
+
+               try {
+                       $mock->checkAudience( 100 );
+                       $this->fail( 'Expected exception not thrown' );
+               } catch ( InvalidArgumentException $ex ) {
+                       $this->assertSame( 'Invalid audience', $ex->getMessage() );
+               }
+       }
+
+       public function testNameFromCentralId() {
+               $mock = $this->getMockForAbstractClass( 'CentralIdLookup' );
+               $mock->expects( $this->once() )->method( 'lookupCentralIds' )
+                       ->with(
+                               $this->equalTo( array( 15 => null ) ),
+                               $this->equalTo( CentralIdLookup::AUDIENCE_RAW ),
+                               $this->equalTo( CentralIdLookup::READ_LATEST )
+                       )
+                       ->will( $this->returnValue( array( 15 => 'FooBar' ) ) );
+
+               $this->assertSame(
+                       'FooBar',
+                       $mock->nameFromCentralId( 15, CentralIdLookup::AUDIENCE_RAW, CentralIdLookup::READ_LATEST )
+               );
+       }
+
+       /**
+        * @dataProvider provideLocalUserFromCentralId
+        * @param string $name
+        * @param bool $succeeds
+        */
+       public function testLocalUserFromCentralId( $name, $succeeds ) {
+               $mock = $this->getMockForAbstractClass( 'CentralIdLookup' );
+               $mock->expects( $this->any() )->method( 'isAttached' )
+                       ->will( $this->returnValue( true ) );
+               $mock->expects( $this->once() )->method( 'lookupCentralIds' )
+                       ->with(
+                               $this->equalTo( array( 42 => null ) ),
+                               $this->equalTo( CentralIdLookup::AUDIENCE_RAW ),
+                               $this->equalTo( CentralIdLookup::READ_LATEST )
+                       )
+                       ->will( $this->returnValue( array( 42 => $name ) ) );
+
+               $user = $mock->localUserFromCentralId(
+                       42, CentralIdLookup::AUDIENCE_RAW, CentralIdLookup::READ_LATEST
+               );
+               if ( $succeeds ) {
+                       $this->assertInstanceOf( 'User', $user );
+                       $this->assertSame( $name, $user->getName() );
+               } else {
+                       $this->assertNull( $user );
+               }
+
+               $mock = $this->getMockForAbstractClass( 'CentralIdLookup' );
+               $mock->expects( $this->any() )->method( 'isAttached' )
+                       ->will( $this->returnValue( false ) );
+               $mock->expects( $this->once() )->method( 'lookupCentralIds' )
+                       ->with(
+                               $this->equalTo( array( 42 => null ) ),
+                               $this->equalTo( CentralIdLookup::AUDIENCE_RAW ),
+                               $this->equalTo( CentralIdLookup::READ_LATEST )
+                       )
+                       ->will( $this->returnValue( array( 42 => $name ) ) );
+               $this->assertNull(
+                       $mock->localUserFromCentralId( 42, CentralIdLookup::AUDIENCE_RAW, CentralIdLookup::READ_LATEST )
+               );
+       }
+
+       public static function provideLocalUserFromCentralId() {
+               return array(
+                       array( 'UTSysop', true ),
+                       array( 'UTDoesNotExist', false ),
+                       array( null, false ),
+                       array( '', false ),
+                       array( '<X>', false ),
+               );
+       }
+
+       public function testCentralIdFromName() {
+               $mock = $this->getMockForAbstractClass( 'CentralIdLookup' );
+               $mock->expects( $this->once() )->method( 'lookupUserNames' )
+                       ->with(
+                               $this->equalTo( array( 'FooBar' => 0 ) ),
+                               $this->equalTo( CentralIdLookup::AUDIENCE_RAW ),
+                               $this->equalTo( CentralIdLookup::READ_LATEST )
+                       )
+                       ->will( $this->returnValue( array( 'FooBar' => 23 ) ) );
+
+               $this->assertSame(
+                       23,
+                       $mock->centralIdFromName( 'FooBar', CentralIdLookup::AUDIENCE_RAW, CentralIdLookup::READ_LATEST )
+               );
+       }
+
+       public function testCentralIdFromLocalUser() {
+               $mock = $this->getMockForAbstractClass( 'CentralIdLookup' );
+               $mock->expects( $this->any() )->method( 'isAttached' )
+                       ->will( $this->returnValue( true ) );
+               $mock->expects( $this->once() )->method( 'lookupUserNames' )
+                       ->with(
+                               $this->equalTo( array( 'FooBar' => 0 ) ),
+                               $this->equalTo( CentralIdLookup::AUDIENCE_RAW ),
+                               $this->equalTo( CentralIdLookup::READ_LATEST )
+                       )
+                       ->will( $this->returnValue( array( 'FooBar' => 23 ) ) );
+
+               $this->assertSame(
+                       23,
+                       $mock->centralIdFromLocalUser(
+                               User::newFromName( 'FooBar' ), CentralIdLookup::AUDIENCE_RAW, CentralIdLookup::READ_LATEST
+                       )
+               );
+
+               $mock = $this->getMockForAbstractClass( 'CentralIdLookup' );
+               $mock->expects( $this->any() )->method( 'isAttached' )
+                       ->will( $this->returnValue( false ) );
+               $mock->expects( $this->never() )->method( 'lookupUserNames' );
+
+               $this->assertSame(
+                       0,
+                       $mock->centralIdFromLocalUser(
+                               User::newFromName( 'FooBar' ), CentralIdLookup::AUDIENCE_RAW, CentralIdLookup::READ_LATEST
+                       )
+               );
+       }
+
+}
diff --git a/tests/phpunit/includes/user/LocalIdLookupTest.php b/tests/phpunit/includes/user/LocalIdLookupTest.php
new file mode 100644 (file)
index 0000000..2bea575
--- /dev/null
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * @covers LocalIdLookup
+ * @group Database
+ */
+class LocalIdLookupTest extends MediaWikiTestCase {
+       private $localUsers = array();
+
+       protected function setUp() {
+               global $wgGroupPermissions;
+
+               parent::setUp();
+
+               $this->stashMwGlobals( array( 'wgGroupPermissions' ) );
+               $wgGroupPermissions['local-id-lookup-test']['hideuser'] = true;
+       }
+
+       public function addDBData() {
+               for ( $i = 1; $i <= 4; $i++ ) {
+                       $user = User::newFromName( "UTLocalIdLookup$i" );
+                       if ( $user->getId() == 0 ) {
+                               $user->addToDatabase();
+                       }
+                       $this->localUsers["UTLocalIdLookup$i"] = $user->getId();
+               }
+
+               User::newFromName( 'UTLocalIdLookup1' )->addGroup( 'local-id-lookup-test' );
+
+               $block = new Block( array(
+                       'address' => 'UTLocalIdLookup3',
+                       'by' => User::idFromName( 'UTSysop' ),
+                       'reason' => __METHOD__,
+                       'expiry' => '1 day',
+                       'hideName' => false,
+               ) );
+               $block->insert();
+
+               $block = new Block( array(
+                       'address' => 'UTLocalIdLookup4',
+                       'by' => User::idFromName( 'UTSysop' ),
+                       'reason' => __METHOD__,
+                       'expiry' => '1 day',
+                       'hideName' => true,
+               ) );
+               $block->insert();
+       }
+
+       public function testLookupCentralIds() {
+               $lookup = new LocalIdLookup();
+               $user1 = User::newFromName( 'UTLocalIdLookup1' );
+               $user2 = User::newFromName( 'UTLocalIdLookup2' );
+
+               $this->assertTrue( $user1->isAllowed( 'hideuser' ), 'sanity check' );
+               $this->assertFalse( $user2->isAllowed( 'hideuser' ), 'sanity check' );
+
+               $this->assertSame( array(), $lookup->lookupCentralIds( array() ) );
+
+               $expect = array_flip( $this->localUsers );
+               $expect[123] = 'X';
+               ksort( $expect );
+
+               $expect2 = $expect;
+               $expect2[$this->localUsers['UTLocalIdLookup4']] = '';
+
+               $arg = array_fill_keys( array_keys( $expect ), 'X' );
+
+               $this->assertSame( $expect2, $lookup->lookupCentralIds( $arg ) );
+               $this->assertSame( $expect, $lookup->lookupCentralIds( $arg, CentralIdLookup::AUDIENCE_RAW ) );
+               $this->assertSame( $expect, $lookup->lookupCentralIds( $arg, $user1 ) );
+               $this->assertSame( $expect2, $lookup->lookupCentralIds( $arg, $user2 ) );
+       }
+
+       public function testLookupUserNames() {
+               $lookup = new LocalIdLookup();
+               $user1 = User::newFromName( 'UTLocalIdLookup1' );
+               $user2 = User::newFromName( 'UTLocalIdLookup2' );
+
+               $this->assertTrue( $user1->isAllowed( 'hideuser' ), 'sanity check' );
+               $this->assertFalse( $user2->isAllowed( 'hideuser' ), 'sanity check' );
+
+               $this->assertSame( array(), $lookup->lookupUserNames( array() ) );
+
+               $expect = $this->localUsers;
+               $expect['UTDoesNotExist'] = 'X';
+               ksort( $expect );
+
+               $expect2 = $expect;
+               $expect2['UTLocalIdLookup4'] = 'X';
+
+               $arg = array_fill_keys( array_keys( $expect ), 'X' );
+
+               $this->assertSame( $expect2, $lookup->lookupUserNames( $arg ) );
+               $this->assertSame( $expect, $lookup->lookupUserNames( $arg, CentralIdLookup::AUDIENCE_RAW ) );
+               $this->assertSame( $expect, $lookup->lookupUserNames( $arg, $user1 ) );
+               $this->assertSame( $expect2, $lookup->lookupUserNames( $arg, $user2 ) );
+       }
+
+       public function testIsAttached() {
+               $lookup = new LocalIdLookup();
+               $user1 = User::newFromName( 'UTLocalIdLookup1' );
+               $user2 = User::newFromName( 'DoesNotExist' );
+
+               $this->assertTrue( $lookup->isAttached( $user1 ) );
+               $this->assertFalse( $lookup->isAttached( $user2 ) );
+
+               $wiki = wfWikiId();
+               $this->assertTrue( $lookup->isAttached( $user1, $wiki ) );
+               $this->assertFalse( $lookup->isAttached( $user2, $wiki ) );
+
+               $wiki = 'not-' . wfWikiId();
+               $this->assertFalse( $lookup->isAttached( $user1, $wiki ) );
+               $this->assertFalse( $lookup->isAttached( $user2, $wiki ) );
+       }
+
+       /**
+        * @dataProvider provideIsAttachedShared
+        * @param bool $sharedDB $wgSharedDB is set
+        * @param bool $sharedTable $wgSharedTables contains 'user'
+        * @param bool $localDBSet $wgLocalDatabases contains the shared DB
+        */
+       public function testIsAttachedShared( $sharedDB, $sharedTable, $localDBSet ) {
+               global $wgDBName;
+               $this->setMwGlobals( array(
+                       'wgSharedDB' => $sharedDB ? $wgDBName : null,
+                       'wgSharedTables' => $sharedTable ? array( 'user' ) : array(),
+                       'wgLocalDatabases' => $localDBSet ? array( 'shared' ) : array(),
+               ) );
+
+               $lookup = new LocalIdLookup();
+               $this->assertSame(
+                       $sharedDB && $sharedTable && $localDBSet,
+                       $lookup->isAttached( User::newFromName( 'UTLocalIdLookup1' ), 'shared' )
+               );
+       }
+
+       public static function provideIsAttachedShared() {
+               $ret = array();
+               for ( $i = 0; $i < 7; $i++ ) {
+                       $ret[] = array(
+                               (bool)( $i & 1 ),
+                               (bool)( $i & 2 ),
+                               (bool)( $i & 4 ),
+                       );
+               }
+               return $ret;
+       }
+
+}
diff --git a/tests/phpunit/includes/user/UserArrayFromResultTest.php b/tests/phpunit/includes/user/UserArrayFromResultTest.php
new file mode 100644 (file)
index 0000000..469ad29
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @author Adam Shorland
+ * @covers UserArrayFromResult
+ */
+class UserArrayFromResultTest extends MediaWikiTestCase {
+
+       private function getMockResultWrapper( $row = null, $numRows = 1 ) {
+               $resultWrapper = $this->getMockBuilder( 'ResultWrapper' )
+                       ->disableOriginalConstructor();
+
+               $resultWrapper = $resultWrapper->getMock();
+               $resultWrapper->expects( $this->atLeastOnce() )
+                       ->method( 'current' )
+                       ->will( $this->returnValue( $row ) );
+               $resultWrapper->expects( $this->any() )
+                       ->method( 'numRows' )
+                       ->will( $this->returnValue( $numRows ) );
+
+               return $resultWrapper;
+       }
+
+       private function getRowWithUsername( $username = 'fooUser' ) {
+               $row = new stdClass();
+               $row->user_name = $username;
+               return $row;
+       }
+
+       private function getUserArrayFromResult( $resultWrapper ) {
+               return new UserArrayFromResult( $resultWrapper );
+       }
+
+       /**
+        * @covers UserArrayFromResult::__construct
+        */
+       public function testConstructionWithFalseRow() {
+               $row = false;
+               $resultWrapper = $this->getMockResultWrapper( $row );
+
+               $object = $this->getUserArrayFromResult( $resultWrapper );
+
+               $this->assertEquals( $resultWrapper, $object->res );
+               $this->assertSame( 0, $object->key );
+               $this->assertEquals( $row, $object->current );
+       }
+
+       /**
+        * @covers UserArrayFromResult::__construct
+        */
+       public function testConstructionWithRow() {
+               $username = 'addshore';
+               $row = $this->getRowWithUsername( $username );
+               $resultWrapper = $this->getMockResultWrapper( $row );
+
+               $object = $this->getUserArrayFromResult( $resultWrapper );
+
+               $this->assertEquals( $resultWrapper, $object->res );
+               $this->assertSame( 0, $object->key );
+               $this->assertInstanceOf( 'User', $object->current );
+               $this->assertEquals( $username, $object->current->mName );
+       }
+
+       public static function provideNumberOfRows() {
+               return array(
+                       array( 0 ),
+                       array( 1 ),
+                       array( 122 ),
+               );
+       }
+
+       /**
+        * @dataProvider provideNumberOfRows
+        * @covers UserArrayFromResult::count
+        */
+       public function testCountWithVaryingValues( $numRows ) {
+               $object = $this->getUserArrayFromResult( $this->getMockResultWrapper(
+                       $this->getRowWithUsername(),
+                       $numRows
+               ) );
+               $this->assertEquals( $numRows, $object->count() );
+       }
+
+       /**
+        * @covers UserArrayFromResult::current
+        */
+       public function testCurrentAfterConstruction() {
+               $username = 'addshore';
+               $userRow = $this->getRowWithUsername( $username );
+               $object = $this->getUserArrayFromResult( $this->getMockResultWrapper( $userRow ) );
+               $this->assertInstanceOf( 'User', $object->current() );
+               $this->assertEquals( $username, $object->current()->mName );
+       }
+
+       public function provideTestValid() {
+               return array(
+                       array( $this->getRowWithUsername(), true ),
+                       array( false, false ),
+               );
+       }
+
+       /**
+        * @dataProvider provideTestValid
+        * @covers UserArrayFromResult::valid
+        */
+       public function testValid( $input, $expected ) {
+               $object = $this->getUserArrayFromResult( $this->getMockResultWrapper( $input ) );
+               $this->assertEquals( $expected, $object->valid() );
+       }
+
+       // @todo unit test for key()
+       // @todo unit test for next()
+       // @todo unit test for rewind()
+}
diff --git a/tests/phpunit/includes/user/UserTest.php b/tests/phpunit/includes/user/UserTest.php
new file mode 100644 (file)
index 0000000..45c4b8c
--- /dev/null
@@ -0,0 +1,534 @@
+<?php
+
+define( 'NS_UNITTEST', 5600 );
+define( 'NS_UNITTEST_TALK', 5601 );
+
+/**
+ * @group Database
+ */
+class UserTest extends MediaWikiTestCase {
+       /**
+        * @var User
+        */
+       protected $user;
+
+       protected function setUp() {
+               parent::setUp();
+
+               $this->setMwGlobals( array(
+                       'wgGroupPermissions' => array(),
+                       'wgRevokePermissions' => array(),
+               ) );
+
+               $this->setUpPermissionGlobals();
+
+               $this->user = new User;
+               $this->user->addGroup( 'unittesters' );
+       }
+
+       private function setUpPermissionGlobals() {
+               global $wgGroupPermissions, $wgRevokePermissions;
+
+               # Data for regular $wgGroupPermissions test
+               $wgGroupPermissions['unittesters'] = array(
+                       'test' => true,
+                       'runtest' => true,
+                       'writetest' => false,
+                       'nukeworld' => false,
+               );
+               $wgGroupPermissions['testwriters'] = array(
+                       'test' => true,
+                       'writetest' => true,
+                       'modifytest' => true,
+               );
+
+               # Data for regular $wgRevokePermissions test
+               $wgRevokePermissions['formertesters'] = array(
+                       'runtest' => true,
+               );
+
+               # For the options test
+               $wgGroupPermissions['*'] = array(
+                       'editmyoptions' => true,
+               );
+       }
+
+       /**
+        * @covers User::getGroupPermissions
+        */
+       public function testGroupPermissions() {
+               $rights = User::getGroupPermissions( array( 'unittesters' ) );
+               $this->assertContains( 'runtest', $rights );
+               $this->assertNotContains( 'writetest', $rights );
+               $this->assertNotContains( 'modifytest', $rights );
+               $this->assertNotContains( 'nukeworld', $rights );
+
+               $rights = User::getGroupPermissions( array( 'unittesters', 'testwriters' ) );
+               $this->assertContains( 'runtest', $rights );
+               $this->assertContains( 'writetest', $rights );
+               $this->assertContains( 'modifytest', $rights );
+               $this->assertNotContains( 'nukeworld', $rights );
+       }
+
+       /**
+        * @covers User::getGroupPermissions
+        */
+       public function testRevokePermissions() {
+               $rights = User::getGroupPermissions( array( 'unittesters', 'formertesters' ) );
+               $this->assertNotContains( 'runtest', $rights );
+               $this->assertNotContains( 'writetest', $rights );
+               $this->assertNotContains( 'modifytest', $rights );
+               $this->assertNotContains( 'nukeworld', $rights );
+       }
+
+       /**
+        * @covers User::getRights
+        */
+       public function testUserPermissions() {
+               $rights = $this->user->getRights();
+               $this->assertContains( 'runtest', $rights );
+               $this->assertNotContains( 'writetest', $rights );
+               $this->assertNotContains( 'modifytest', $rights );
+               $this->assertNotContains( 'nukeworld', $rights );
+       }
+
+       /**
+        * @dataProvider provideGetGroupsWithPermission
+        * @covers User::getGroupsWithPermission
+        */
+       public function testGetGroupsWithPermission( $expected, $right ) {
+               $result = User::getGroupsWithPermission( $right );
+               sort( $result );
+               sort( $expected );
+
+               $this->assertEquals( $expected, $result, "Groups with permission $right" );
+       }
+
+       public static function provideGetGroupsWithPermission() {
+               return array(
+                       array(
+                               array( 'unittesters', 'testwriters' ),
+                               'test'
+                       ),
+                       array(
+                               array( 'unittesters' ),
+                               'runtest'
+                       ),
+                       array(
+                               array( 'testwriters' ),
+                               'writetest'
+                       ),
+                       array(
+                               array( 'testwriters' ),
+                               'modifytest'
+                       ),
+               );
+       }
+
+       /**
+        * @dataProvider provideIPs
+        * @covers User::isIP
+        */
+       public function testIsIP( $value, $result, $message ) {
+               $this->assertEquals( $this->user->isIP( $value ), $result, $message );
+       }
+
+       public static function provideIPs() {
+               return array(
+                       array( '', false, 'Empty string' ),
+                       array( ' ', false, 'Blank space' ),
+                       array( '10.0.0.0', true, 'IPv4 private 10/8' ),
+                       array( '10.255.255.255', true, 'IPv4 private 10/8' ),
+                       array( '192.168.1.1', true, 'IPv4 private 192.168/16' ),
+                       array( '203.0.113.0', true, 'IPv4 example' ),
+                       array( '2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff', true, 'IPv6 example' ),
+                       // Not valid IPs but classified as such by MediaWiki for negated asserting
+                       // of whether this might be the identifier of a logged-out user or whether
+                       // to allow usernames like it.
+                       array( '300.300.300.300', true, 'Looks too much like an IPv4 address' ),
+                       array( '203.0.113.xxx', true, 'Assigned by UseMod to cloaked logged-out users' ),
+               );
+       }
+
+       /**
+        * @dataProvider provideUserNames
+        * @covers User::isValidUserName
+        */
+       public function testIsValidUserName( $username, $result, $message ) {
+               $this->assertEquals( $this->user->isValidUserName( $username ), $result, $message );
+       }
+
+       public static function provideUserNames() {
+               return array(
+                       array( '', false, 'Empty string' ),
+                       array( ' ', false, 'Blank space' ),
+                       array( 'abcd', false, 'Starts with small letter' ),
+                       array( 'Ab/cd', false, 'Contains slash' ),
+                       array( 'Ab cd', true, 'Whitespace' ),
+                       array( '192.168.1.1', false, 'IP' ),
+                       array( 'User:Abcd', false, 'Reserved Namespace' ),
+                       array( '12abcd232', true, 'Starts with Numbers' ),
+                       array( '?abcd', true, 'Start with ? mark' ),
+                       array( '#abcd', false, 'Start with #' ),
+                       array( 'Abcdകഖഗഘ', true, ' Mixed scripts' ),
+                       array( 'ജോസ്‌തോമസ്', false, 'ZWNJ- Format control character' ),
+                       array( 'Ab cd', false, ' Ideographic space' ),
+                       array( '300.300.300.300', false, 'Looks too much like an IPv4 address' ),
+                       array( '302.113.311.900', false, 'Looks too much like an IPv4 address' ),
+                       array( '203.0.113.xxx', false, 'Reserved for usage by UseMod for cloaked logged-out users' ),
+               );
+       }
+
+       /**
+        * Test, if for all rights a right- message exist,
+        * which is used on Special:ListGroupRights as help text
+        * Extensions and core
+        */
+       public function testAllRightsWithMessage() {
+               // Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
+               $allRights = User::getAllRights();
+               $allMessageKeys = Language::getMessageKeysFor( 'en' );
+
+               $rightsWithMessage = array();
+               foreach ( $allMessageKeys as $message ) {
+                       // === 0: must be at beginning of string (position 0)
+                       if ( strpos( $message, 'right-' ) === 0 ) {
+                               $rightsWithMessage[] = substr( $message, strlen( 'right-' ) );
+                       }
+               }
+
+               sort( $allRights );
+               sort( $rightsWithMessage );
+
+               $this->assertEquals(
+                       $allRights,
+                       $rightsWithMessage,
+                       'Each user rights (core/extensions) has a corresponding right- message.'
+               );
+       }
+
+       /**
+        * Test User::editCount
+        * @group medium
+        * @covers User::getEditCount
+        */
+       public function testEditCount() {
+               $user = User::newFromName( 'UnitTestUser' );
+
+               if ( !$user->getId() ) {
+                       $user->addToDatabase();
+               }
+
+               // let the user have a few (3) edits
+               $page = WikiPage::factory( Title::newFromText( 'Help:UserTest_EditCount' ) );
+               for ( $i = 0; $i < 3; $i++ ) {
+                       $page->doEdit( (string)$i, 'test', 0, false, $user );
+               }
+
+               $user->clearInstanceCache();
+               $this->assertEquals(
+                       3,
+                       $user->getEditCount(),
+                       'After three edits, the user edit count should be 3'
+               );
+
+               // increase the edit count and clear the cache
+               $user->incEditCount();
+
+               $user->clearInstanceCache();
+               $this->assertEquals(
+                       4,
+                       $user->getEditCount(),
+                       'After increasing the edit count manually, the user edit count should be 4'
+               );
+       }
+
+       /**
+        * Test changing user options.
+        * @covers User::setOption
+        * @covers User::getOption
+        */
+       public function testOptions() {
+               $user = User::newFromName( 'UnitTestUser' );
+
+               if ( !$user->getId() ) {
+                       $user->addToDatabase();
+               }
+
+               $user->setOption( 'userjs-someoption', 'test' );
+               $user->setOption( 'cols', 200 );
+               $user->saveSettings();
+
+               $user = User::newFromName( 'UnitTestUser' );
+               $this->assertEquals( 'test', $user->getOption( 'userjs-someoption' ) );
+               $this->assertEquals( 200, $user->getOption( 'cols' ) );
+       }
+
+       /**
+        * Bug 37963
+        * Make sure defaults are loaded when setOption is called.
+        * @covers User::loadOptions
+        */
+       public function testAnonOptions() {
+               global $wgDefaultUserOptions;
+               $this->user->setOption( 'userjs-someoption', 'test' );
+               $this->assertEquals( $wgDefaultUserOptions['cols'], $this->user->getOption( 'cols' ) );
+               $this->assertEquals( 'test', $this->user->getOption( 'userjs-someoption' ) );
+       }
+
+       /**
+        * Test password validity checks. There are 3 checks in core,
+        *      - ensure the password meets the minimal length
+        *      - ensure the password is not the same as the username
+        *      - ensure the username/password combo isn't forbidden
+        * @covers User::checkPasswordValidity()
+        * @covers User::getPasswordValidity()
+        * @covers User::isValidPassword()
+        */
+       public function testCheckPasswordValidity() {
+               $this->setMwGlobals( array(
+                       'wgPasswordPolicy' => array(
+                               'policies' => array(
+                                       'sysop' => array(
+                                               'MinimalPasswordLength' => 8,
+                                               'MinimumPasswordLengthToLogin' => 1,
+                                               'PasswordCannotMatchUsername' => 1,
+                                       ),
+                                       'default' => array(
+                                               'MinimalPasswordLength' => 6,
+                                               'PasswordCannotMatchUsername' => true,
+                                               'PasswordCannotMatchBlacklist' => true,
+                                               'MaximalPasswordLength' => 30,
+                                       ),
+                               ),
+                               'checks' => array(
+                                       'MinimalPasswordLength' => 'PasswordPolicyChecks::checkMinimalPasswordLength',
+                                       'MinimumPasswordLengthToLogin' => 'PasswordPolicyChecks::checkMinimumPasswordLengthToLogin',
+                                       'PasswordCannotMatchUsername' => 'PasswordPolicyChecks::checkPasswordCannotMatchUsername',
+                                       'PasswordCannotMatchBlacklist' => 'PasswordPolicyChecks::checkPasswordCannotMatchBlacklist',
+                                       'MaximalPasswordLength' => 'PasswordPolicyChecks::checkMaximalPasswordLength',
+                               ),
+                       ),
+               ) );
+
+               $user = User::newFromName( 'Useruser' );
+               // Sanity
+               $this->assertTrue( $user->isValidPassword( 'Password1234' ) );
+
+               // Minimum length
+               $this->assertFalse( $user->isValidPassword( 'a' ) );
+               $this->assertFalse( $user->checkPasswordValidity( 'a' )->isGood() );
+               $this->assertTrue( $user->checkPasswordValidity( 'a' )->isOK() );
+               $this->assertEquals( 'passwordtooshort', $user->getPasswordValidity( 'a' ) );
+
+               // Maximum length
+               $longPass = str_repeat( 'a', 31 );
+               $this->assertFalse( $user->isValidPassword( $longPass ) );
+               $this->assertFalse( $user->checkPasswordValidity( $longPass )->isGood() );
+               $this->assertFalse( $user->checkPasswordValidity( $longPass )->isOK() );
+               $this->assertEquals( 'passwordtoolong', $user->getPasswordValidity( $longPass ) );
+
+               // Matches username
+               $this->assertFalse( $user->checkPasswordValidity( 'Useruser' )->isGood() );
+               $this->assertTrue( $user->checkPasswordValidity( 'Useruser' )->isOK() );
+               $this->assertEquals( 'password-name-match', $user->getPasswordValidity( 'Useruser' ) );
+
+               // On the forbidden list
+               $this->assertFalse( $user->checkPasswordValidity( 'Passpass' )->isGood() );
+               $this->assertEquals( 'password-login-forbidden', $user->getPasswordValidity( 'Passpass' ) );
+       }
+
+       /**
+        * @covers User::getCanonicalName()
+        * @dataProvider provideGetCanonicalName
+        */
+       public function testGetCanonicalName( $name, $expectedArray, $msg ) {
+               foreach ( $expectedArray as $validate => $expected ) {
+                       $this->assertEquals(
+                               $expected,
+                               User::getCanonicalName( $name, $validate === 'false' ? false : $validate ),
+                               $msg . ' (' . $validate . ')'
+                       );
+               }
+       }
+
+       public static function provideGetCanonicalName() {
+               return array(
+                       array( ' Trailing space ', array( 'creatable' => 'Trailing space' ), 'Trailing spaces' ),
+                       // @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' ),
+                       array( 'Multi  spaces', array( 'creatable' => 'Multi spaces',
+                               'usable' => 'Multi spaces' ), 'Multi spaces' ),
+                       array( 'lowercase', array( 'creatable' => 'Lowercase' ), 'Lowercase' ),
+                       array( 'in[]valid', array( 'creatable' => false, 'usable' => false, 'valid' => false,
+                               'false' => 'In[]valid' ), 'Invalid' ),
+                       array( 'with / slash', array( 'creatable' => false, 'usable' => false, 'valid' => false,
+                               'false' => 'With / slash' ), 'With slash' ),
+               );
+       }
+
+       /**
+        * @covers User::equals
+        */
+       public function testEquals() {
+               $first = User::newFromName( 'EqualUser' );
+               $second = User::newFromName( 'EqualUser' );
+
+               $this->assertTrue( $first->equals( $first ) );
+               $this->assertTrue( $first->equals( $second ) );
+               $this->assertTrue( $second->equals( $first ) );
+
+               $third = User::newFromName( '0' );
+               $fourth = User::newFromName( '000' );
+
+               $this->assertFalse( $third->equals( $fourth ) );
+               $this->assertFalse( $fourth->equals( $third ) );
+
+               // Test users loaded from db with id
+               $user = User::newFromName( 'EqualUnitTestUser' );
+               if ( !$user->getId() ) {
+                       $user->addToDatabase();
+               }
+
+               $id = $user->getId();
+
+               $fifth = User::newFromId( $id );
+               $sixth = User::newFromName( 'EqualUnitTestUser' );
+               $this->assertTrue( $fifth->equals( $sixth ) );
+       }
+
+       /**
+        * @covers User::getId
+        */
+       public function testGetId() {
+               $user = User::newFromName( 'UTSysop' );
+               $this->assertTrue( $user->getId() > 0 );
+
+       }
+
+       /**
+        * @covers User::isLoggedIn
+        * @covers User::isAnon
+        */
+       public function testLoggedIn() {
+               $user = User::newFromName( 'UTSysop' );
+               $this->assertTrue( $user->isLoggedIn() );
+               $this->assertFalse( $user->isAnon() );
+
+               // Non-existent users are perceived as anonymous
+               $user = User::newFromName( 'UTNonexistent' );
+               $this->assertFalse( $user->isLoggedIn() );
+               $this->assertTrue( $user->isAnon() );
+
+               $user = new User;
+               $this->assertFalse( $user->isLoggedIn() );
+               $this->assertTrue( $user->isAnon() );
+       }
+
+       /**
+        * @covers User::checkAndSetTouched
+        */
+       public function testCheckAndSetTouched() {
+               $user = TestingAccessWrapper::newFromObject( User::newFromName( 'UTSysop' ) );
+               $this->assertTrue( $user->isLoggedIn() );
+
+               $touched = $user->getDBTouched();
+               $this->assertTrue(
+                       $user->checkAndSetTouched(), "checkAndSetTouched() succeded" );
+               $this->assertGreaterThan(
+                       $touched, $user->getDBTouched(), "user_touched increased with casOnTouched()" );
+
+               $touched = $user->getDBTouched();
+               $this->assertTrue(
+                       $user->checkAndSetTouched(), "checkAndSetTouched() succeded #2" );
+               $this->assertGreaterThan(
+                       $touched, $user->getDBTouched(), "user_touched increased with casOnTouched() #2" );
+       }
+
+       public static function setExtendedLoginCookieDataProvider() {
+               $data = array();
+               $now = time();
+
+               $secondsInDay = 86400;
+
+               // Arbitrary durations, in units of days, to ensure it chooses the
+               // right one.  There is a 5-minute grace period (see testSetExtendedLoginCookie)
+               // to work around slow tests, since we're not currently mocking time() for PHP.
+
+               $durationOne = $secondsInDay * 5;
+               $durationTwo = $secondsInDay * 29;
+               $durationThree = $secondsInDay * 17;
+
+               // If $wgExtendedLoginCookieExpiration is null, then the expiry passed to
+               // set cookie is time() + $wgCookieExpiration
+               $data[] = array(
+                       null,
+                       $durationOne,
+                       $now + $durationOne,
+               );
+
+               // If $wgExtendedLoginCookieExpiration isn't null, then the expiry passed to
+               // set cookie is $now + $wgExtendedLoginCookieExpiration
+               $data[] = array(
+                       $durationTwo,
+                       $durationThree,
+                       $now + $durationTwo,
+               );
+
+               return $data;
+       }
+
+       /**
+        * @dataProvider setExtendedLoginCookieDataProvider
+        * @covers User::getRequest
+        * @covers User::setCookie
+        * @backupGlobals enabled
+        */
+       public function testSetExtendedLoginCookie(
+               $extendedLoginCookieExpiration,
+               $cookieExpiration,
+               $expectedExpiry
+       ) {
+               $this->setMwGlobals( array(
+                       'wgExtendedLoginCookieExpiration' => $extendedLoginCookieExpiration,
+                       'wgCookieExpiration' => $cookieExpiration,
+               ) );
+
+               $response = $this->getMock( 'WebResponse' );
+               $setcookieSpy = $this->any();
+               $response->expects( $setcookieSpy )
+                       ->method( 'setcookie' );
+
+               $request = new MockWebRequest( $response );
+               $user = new UserProxy( User::newFromSession( $request ) );
+               $user->setExtendedLoginCookie( 'name', 'value', true );
+
+               $setcookieInvocations = $setcookieSpy->getInvocations();
+               $setcookieInvocation = end( $setcookieInvocations );
+               $actualExpiry = $setcookieInvocation->parameters[2];
+
+               // TODO: ± 600 seconds compensates for
+               // slow-running tests. However, the dependency on the time
+               // function should be removed.  This requires some way
+               // to mock/isolate User->setExtendedLoginCookie's call to time()
+               $this->assertEquals( $expectedExpiry, $actualExpiry, '', 600 );
+       }
+}
+
+class UserProxy extends User {
+
+       /**
+        * @var User
+        */
+       protected $user;
+
+       public function __construct( User $user ) {
+               $this->user = $user;
+       }
+
+       public function setExtendedLoginCookie( $name, $value, $secure ) {
+               $this->user->setExtendedLoginCookie( $name, $value, $secure );
+       }
+}
index d93dafb..bdabdc1 100644 (file)
@@ -24,6 +24,10 @@ phpunit.php enables colors for other OSs at runtime
                <testsuite name="languages">
                        <directory>languages</directory>
                </testsuite>
+               <testsuite name="parsertests">
+                       <file>includes/parser/MediaWikiParserTest.php</file>
+                       <file>suites/ExtensionsParserTestSuite.php</file>
+               </testsuite>
                <testsuite name="skins">
                        <directory>skins</directory>
                        <directory>structure</directory>